From 58e747506e961732c2dbedecfca7d6f8e5318c23 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 27 Nov 2021 10:12:27 +0000 Subject: [PATCH] Update core, api and ROM to match latest CC:T Mostly fine, but breaking change in that getWorld -> getLevel. Possibly worth deferring to 1.18 --- .../dan200/computercraft/ComputerCraft.java | 3 - .../computercraft/api/ComputerCraftAPI.java | 80 +- .../api/client/TransformedModel.java | 8 +- .../api/filesystem/FileAttributes.java | 1 - .../filesystem/FileOperationException.java | 1 - .../api/filesystem/IFileSystem.java | 1 - .../computercraft/api/filesystem/IMount.java | 81 +- .../api/filesystem/IWritableMount.java | 24 +- .../computercraft/api/lua/IArguments.java | 388 ++++----- .../api/lua/IComputerSystem.java | 4 +- .../api/lua/IDynamicLuaObject.java | 18 +- .../dan200/computercraft/api/lua/ILuaAPI.java | 9 +- .../computercraft/api/lua/ILuaAPIFactory.java | 1 - .../computercraft/api/lua/ILuaCallback.java | 4 +- .../computercraft/api/lua/ILuaContext.java | 6 +- .../computercraft/api/lua/ILuaFunction.java | 9 +- .../computercraft/api/lua/ILuaTask.java | 11 +- .../computercraft/api/lua/LuaException.java | 4 +- .../computercraft/api/lua/LuaFunction.java | 8 +- .../computercraft/api/lua/LuaValues.java | 106 +-- .../computercraft/api/lua/MethodResult.java | 45 +- .../api/lua/ObjectArguments.java | 42 +- .../computercraft/api/lua/TaskCallback.java | 53 ++ .../computercraft/api/media/IMedia.java | 15 +- .../api/media/IMediaProvider.java | 1 - .../api/network/IPacketNetwork.java | 9 +- .../api/network/IPacketReceiver.java | 16 +- .../api/network/IPacketSender.java | 7 +- .../computercraft/api/network/Packet.java | 124 +-- .../api/network/wired/IWiredElement.java | 13 +- .../api/network/wired/IWiredNetwork.java | 24 +- .../network/wired/IWiredNetworkChange.java | 9 +- .../api/network/wired/IWiredNode.java | 44 +- .../api/network/wired/IWiredSender.java | 7 +- .../api/peripheral/GenericPeripheral.java | 45 ++ .../api/peripheral/IComputerAccess.java | 96 ++- .../api/peripheral/IDynamicPeripheral.java | 32 +- .../api/peripheral/IPeripheral.java | 44 +- .../api/peripheral/IPeripheralProvider.java | 10 +- .../api/peripheral/IWorkMonitor.java | 53 +- .../api/peripheral/NotAttachedException.java | 4 +- .../api/peripheral/PeripheralType.java | 62 ++ .../api/pocket/AbstractPocketUpgrade.java | 1 - .../api/pocket/IPocketAccess.java | 15 +- .../api/pocket/IPocketUpgrade.java | 11 +- .../redstone/IBundledRedstoneProvider.java | 4 +- .../api/turtle/ITurtleAccess.java | 114 +-- .../api/turtle/ITurtleCommand.java | 5 +- .../api/turtle/ITurtleUpgrade.java | 31 +- .../api/turtle/TurtleAnimation.java | 21 +- .../api/turtle/TurtleCommandResult.java | 34 +- .../computercraft/api/turtle/TurtleSide.java | 1 - .../api/turtle/TurtleUpgradeType.java | 14 +- .../computercraft/api/turtle/TurtleVerb.java | 6 +- .../api/turtle/event/TurtleAction.java | 84 -- .../api/turtle/event/TurtleActionEvent.java | 85 -- .../api/turtle/event/TurtleAttackEvent.java | 73 -- .../api/turtle/event/TurtleBlockEvent.java | 224 ----- .../api/turtle/event/TurtleEvent.java | 14 +- .../turtle/event/TurtleInspectItemEvent.java | 90 --- .../turtle/event/TurtleInventoryEvent.java | 87 -- .../api/turtle/event/TurtlePlayerEvent.java | 44 - .../api/turtle/event/TurtleRefuelEvent.java | 14 +- .../core/apis/ComputerAccess.java | 1 + .../dan200/computercraft/core/apis/FSAPI.java | 88 +- .../dan200/computercraft/core/apis/OSAPI.java | 63 +- .../computercraft/core/apis/RedstoneAPI.java | 16 +- .../computercraft/core/apis/TermAPI.java | 1 + .../computercraft/core/apis/TermMethods.java | 12 + .../apis/handles/BinaryReadableHandle.java | 5 + .../apis/handles/BinaryWritableHandle.java | 2 + .../apis/handles/EncodedReadableHandle.java | 2 + .../core/apis/http/NetworkUtils.java | 2 +- .../core/apis/http/options/AddressRule.java | 2 +- .../apis/http/request/HttpResponseHandle.java | 1 + .../apis/http/websocket/WebsocketHandle.java | 3 + .../computercraft/core/asm/Generator.java | 11 +- .../computercraft/core/asm/GenericMethod.java | 51 +- .../computercraft/core/asm/LuaMethod.java | 2 +- .../computercraft/core/asm/NamedMethod.java | 14 +- .../core/asm/PeripheralMethod.java | 2 +- .../computercraft/core/asm/ResultHelpers.java | 27 + .../core/computer/Environment.java | 6 +- .../core/computer/MainThread.java | 2 +- .../core/filesystem/ResourceMount.java | 80 +- .../computercraft/core/lua/LuaContext.java | 9 - .../core/lua/ResultInterpreterFunction.java | 2 +- .../core/tracking/ComputerMBean.java | 155 ++++ .../peripheral/modem/ModemPeripheral.java | 144 ++-- .../peripheral/modem/wired/TileCable.java | 2 +- .../modem/wired/TileWiredModemFull.java | 2 +- .../modem/wired/WiredModemPeripheral.java | 4 +- .../modem/wireless/TileWirelessModem.java | 2 +- .../wireless/WirelessModemPeripheral.java | 2 +- .../modem/wireless/WirelessNetwork.java | 38 +- .../peripherals/PocketModemPeripheral.java | 2 +- .../proxy/ComputerCraftProxyCommon.java | 2 - .../shared/turtle/FurnaceRefuelHandler.java | 2 +- .../shared/turtle/SignInspectHandler.java | 33 - .../shared/turtle/apis/TurtleAPI.java | 9 - .../shared/turtle/core/TurtleBrain.java | 20 +- .../turtle/core/TurtleCompareCommand.java | 2 +- .../turtle/core/TurtleCraftCommand.java | 4 +- .../turtle/core/TurtleDetectCommand.java | 2 +- .../shared/turtle/core/TurtleDropCommand.java | 13 +- .../turtle/core/TurtleEquipCommand.java | 11 +- .../turtle/core/TurtleInspectCommand.java | 12 +- .../shared/turtle/core/TurtleMoveCommand.java | 10 +- .../turtle/core/TurtlePlaceCommand.java | 18 +- .../shared/turtle/core/TurtlePlayer.java | 6 +- .../turtle/core/TurtleRefuelCommand.java | 22 +- .../shared/turtle/core/TurtleSuckCommand.java | 12 +- .../shared/turtle/core/TurtleTurnCommand.java | 9 - .../upgrades/TurtleInventoryCrafting.java | 108 +-- .../shared/turtle/upgrades/TurtleModem.java | 6 +- .../shared/turtle/upgrades/TurtleSpeaker.java | 2 +- .../shared/turtle/upgrades/TurtleTool.java | 22 +- .../computercraft/shared/util/Config.java | 28 +- .../shared/wired/WiredNetwork.java | 763 ++++++++---------- .../computercraft/shared/wired/WiredNode.java | 114 ++- .../computercraft/lua/rom/apis/rednet.lua | 52 +- .../computercraft/lua/rom/apis/window.lua | 2 + .../rom/help/{changelog.txt => changelog.md} | 0 .../rom/help/{whatsnew.txt => whatsnew.md} | 0 .../computercraft/lua/rom/programs/about.lua | 4 + .../computercraft/lua/rom/programs/motd.lua | 2 + .../lua/rom/programs/rednet/repeat.lua | 6 +- 127 files changed, 1923 insertions(+), 2622 deletions(-) create mode 100644 src/main/java/dan200/computercraft/api/lua/TaskCallback.java create mode 100644 src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java create mode 100644 src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java delete mode 100644 src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java create mode 100644 src/main/java/dan200/computercraft/core/asm/ResultHelpers.java create mode 100644 src/main/java/dan200/computercraft/core/tracking/ComputerMBean.java delete mode 100644 src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java rename src/main/resources/data/computercraft/lua/rom/help/{changelog.txt => changelog.md} (100%) rename src/main/resources/data/computercraft/lua/rom/help/{whatsnew.txt => whatsnew.md} (100%) create mode 100644 src/main/resources/data/computercraft/lua/rom/programs/about.lua diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index 317bfd0ef..00f116d64 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -6,7 +6,6 @@ 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.shared.ComputerCraftRegistry.ModBlocks; @@ -40,7 +39,6 @@ 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.concurrent.TimeUnit; @@ -91,7 +89,6 @@ public final class ComputerCraft implements ModInitializer public static int advancedTurtleFuelLimit = 100000; public static boolean turtlesObeyBlockProtection = true; public static boolean turtlesCanPush = true; - public static EnumSet turtleDisabledActions = EnumSet.noneOf( TurtleAction.class ); public static int computerTermWidth = 51; public static int computerTermHeight = 19; diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index 7e7ae52ee..bef9f90d7 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.filesystem.IMount; @@ -32,19 +31,11 @@ import javax.annotation.Nullable; /** * 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 { - private static IComputerCraftAPI instance; - - @Nonnull - @Deprecated - public static String getAPIVersion() - { - return getInstalledVersion(); - } - @Nonnull public static String getInstalledVersion() { @@ -52,23 +43,10 @@ public final class ComputerCraftAPI } @Nonnull - private static IComputerCraftAPI getInstance() + @Deprecated + public static String getAPIVersion() { - if( instance != null ) - { - return instance; - } - - try - { - return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" ) - .getField( "INSTANCE" ) - .get( null ); - } - catch( ReflectiveOperationException e ) - { - throw new IllegalStateException( "Cannot find ComputerCraft API", e ); - } + return getInstalledVersion(); } /** @@ -80,7 +58,8 @@ public final class ComputerCraftAPI * @param parentSubPath The folder path within the save directory where the new directory should be created. eg: "computercraft/disk" * @return The numerical value of the name of the new folder, or -1 if the folder could not be created for some reason. * - * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now available for writing. + * eg: if createUniqueNumberedSaveDir( world, "computer/disk" ) was called returns 42, then "computer/disk/42" is now + * available for writing. * @see #createSaveDirMount(Level, String, long) */ public static int createUniqueNumberedSaveDir( @Nonnull Level world, @Nonnull String parentSubPath ) @@ -91,15 +70,15 @@ public final class ComputerCraftAPI /** * Creates a file system mount that maps to a subfolder of the save directory for a given world, and returns it. * - * Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the users save directory onto a computers - * file system. + * Use in conjunction with IComputerAccess.mount() or IComputerAccess.mountWritable() to mount a folder from the + * users save directory onto a computers file system. * * @param world The world for which the save dir can be found. This should be the server side world object. - * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42". Use createUniqueNumberedSaveDir() - * to create a new numbered folder to use. + * @param subPath The folder path within the save directory that the mount should map to. eg: "computer/disk/42". + * Use createUniqueNumberedSaveDir() to create a new numbered folder to use. * @param capacity The amount of data that can be stored in the directory before it fills up, in bytes. - * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() to mount this on a - * Computers' file system. + * @return The mount, or null if it could be created for some reason. Use IComputerAccess.mount() or IComputerAccess.mountWritable() + * to mount this on a Computers' file system. * @see #createUniqueNumberedSaveDir(Level, String) * @see IComputerAccess#mount(String, IMount) * @see IComputerAccess#mountWritable(String, IWritableMount) @@ -115,8 +94,8 @@ public final class ComputerCraftAPI /** * 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. + * 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. For instance, ComputerCraft's resources are stored in @@ -137,7 +116,7 @@ public final class ComputerCraftAPI } /** - * Registers a peripheral provider to convert blocks into {@link IPeripheral} implementations. + * rers a peripheral provider to convert blocks into {@link IPeripheral} implementations. * * @param provider The peripheral provider to register. * @see IPeripheral @@ -160,8 +139,9 @@ public final class ComputerCraftAPI } /** - * Registers a new turtle turtle for use in ComputerCraft. After calling this, users should be able to craft Turtles with your new turtle. It is - * recommended to call this during the load() method of your mod. + * Registers a new turtle turtle for use in ComputerCraft. After calling this, + * users should be able to craft Turtles with your new turtle. It is recommended to call + * this during the load() method of your mod. * * @param upgrade The turtle upgrade to register. * @see ITurtleUpgrade @@ -188,8 +168,8 @@ public final class ComputerCraftAPI * @param world The world this block is in. * @param pos The position this block is at. * @param side The side to extract the bundled redstone output from. - * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned. If there is no block - * capable of emitting bundled redstone at the location, -1 will be returned. + * @return If there is a block capable of emitting bundled redstone at the location, it's signal (0-65535) will be returned. + * If there is no block capable of emitting bundled redstone at the location, -1 will be returned. * @see IBundledRedstoneProvider */ public static int getBundledRedstoneOutput( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ) @@ -256,6 +236,24 @@ public final class ComputerCraftAPI return getInstance().getWiredElementAt( world, pos, side ); } + private static IComputerCraftAPI instance; + + @Nonnull + private static IComputerCraftAPI getInstance() + { + if( instance != null ) return instance; + + try + { + return instance = (IComputerCraftAPI) Class.forName( "dan200.computercraft.ComputerCraftAPIImpl" ) + .getField( "INSTANCE" ).get( null ); + } + catch( ReflectiveOperationException e ) + { + throw new IllegalStateException( "Cannot find ComputerCraft API", e ); + } + } + public interface IComputerCraftAPI { @Nonnull diff --git a/src/main/java/dan200/computercraft/api/client/TransformedModel.java b/src/main/java/dan200/computercraft/api/client/TransformedModel.java index f0c3658ff..5a439da61 100644 --- a/src/main/java/dan200/computercraft/api/client/TransformedModel.java +++ b/src/main/java/dan200/computercraft/api/client/TransformedModel.java @@ -43,17 +43,13 @@ public final class TransformedModel public static TransformedModel of( @Nonnull ModelResourceLocation location ) { - ModelManager modelManager = Minecraft.getInstance() - .getModelManager(); + ModelManager modelManager = Minecraft.getInstance().getModelManager(); return new TransformedModel( modelManager.getModel( location ) ); } public static TransformedModel of( @Nonnull ItemStack item, @Nonnull Transformation transform ) { - BakedModel model = Minecraft.getInstance() - .getItemRenderer() - .getItemModelShaper() - .getItemModel( item ); + BakedModel model = Minecraft.getInstance().getItemRenderer().getItemModelShaper().getItemModel( item ); return new TransformedModel( model, transform ); } diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java index 20db37caa..82aa83686 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileAttributes.java @@ -3,7 +3,6 @@ * 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; import java.nio.file.attribute.BasicFileAttributes; diff --git a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java index dc08e0268..638c61486 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java +++ b/src/main/java/dan200/computercraft/api/filesystem/FileOperationException.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; diff --git a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java index 8c74731e3..7ce152db7 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java @@ -3,7 +3,6 @@ * 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; 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 0e23748be..680f6fac3 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IMount.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; @@ -17,10 +16,12 @@ import java.nio.file.attribute.BasicFileAttributes; 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)}. + * Represents a read only part of a virtual filesystem that can be mounted onto a computer using + * {@link IComputerAccess#mount(String, IMount)}. * - * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)} or {@link - * ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves! + * Ready made implementations of this interface can be created using + * {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)} or + * {@link ComputerCraftAPI#createResourceMount(String, String)}, or you're free to implement it yourselves! * * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -29,43 +30,6 @@ import java.util.List; */ public interface IMount { - /** - * Returns the file names of all the files in a directory. - * - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms". - * @param contents A list of strings. Add all the file names to this list. - * @throws IOException If the file was not a directory, or could not be listed. - */ - void list( @Nonnull String path, @Nonnull List contents ) throws IOException; - - /** - * Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents. - * - * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". - * @return A channel representing the contents of the file. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one will be able to - * seek to arbitrary positions when using binary mode. - * @throws IOException If the file does not exist, or could not be opened. - */ - @Nonnull - ReadableByteChannel openForRead( @Nonnull String path ) throws IOException; - - /** - * 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 ) ); - } - /** * Returns whether a file with a given path exists or not. * @@ -84,6 +48,15 @@ public interface IMount */ boolean isDirectory( @Nonnull String path ) throws IOException; + /** + * Returns the file names of all the files in a directory. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprograms". + * @param contents A list of strings. Add all the file names to this list. + * @throws IOException If the file was not a directory, or could not be listed. + */ + void list( @Nonnull String path, @Nonnull List contents ) throws IOException; + /** * Returns the size of a file with a given path, in bytes. * @@ -92,4 +65,30 @@ public interface IMount * @throws IOException If the file does not exist, or its size could not be determined. */ long getSize( @Nonnull String path ) throws IOException; + + /** + * Opens a file with a given path, and returns an {@link ReadableByteChannel} representing its contents. + * + * @param path A file path in normalised format, relative to the mount location. ie: "programs/myprogram". + * @return A channel representing the contents of the file. If the channel implements + * {@link java.nio.channels.SeekableByteChannel}, one will be able to seek to arbitrary positions when using binary + * mode. + * @throws IOException If the file does not exist, or could not be opened. + */ + @Nonnull + ReadableByteChannel openForRead( @Nonnull String path ) throws IOException; + + /** + * 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 713e290fa..b1d7ca8ee 100644 --- a/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java +++ b/src/main/java/dan200/computercraft/api/filesystem/IWritableMount.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; @@ -17,11 +16,11 @@ 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)} or {@link - * IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to. + * Represents a part of a virtual filesystem that can be mounted onto a computer using {@link IComputerAccess#mount(String, IMount)} + * or {@link IComputerAccess#mountWritable(String, IWritableMount)}, that can also be written to. * - * Ready made implementations of this interface can be created using {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)}, or you're free to - * implement it yourselves! + * Ready made implementations of this interface can be created using + * {@link ComputerCraftAPI#createSaveDirMount(Level, String, long)}, or you're free to implement it yourselves! * * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see IComputerAccess#mount(String, IMount) @@ -50,8 +49,8 @@ public interface IWritableMount extends IMount * 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. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one will be able to seek to arbitrary - * positions when using binary mode. + * @return A stream for writing to. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one + * will be able to seek to arbitrary positions when using binary mode. * @throws IOException If the file could not be opened for writing. */ @Nonnull @@ -61,16 +60,16 @@ public interface IWritableMount extends IMount * 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. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one will be able to seek to arbitrary - * positions when using binary mode. + * @return A stream for writing to. If the channel implements {@link java.nio.channels.SeekableByteChannel}, one + * will be able to seek to arbitrary positions when using binary mode. * @throws IOException If the file could not be opened for writing. */ @Nonnull 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 mount, and write operations should fail - * once it reaches zero. + * Get the amount of free space on the mount, in bytes. You should decrease this value as the user writes to the + * mount, and write operations should fail once it reaches zero. * * @return The amount of free space, in bytes. * @throws IOException If the remaining space could not be computed. @@ -78,7 +77,8 @@ public interface IWritableMount extends IMount 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()}. + * 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. */ diff --git a/src/main/java/dan200/computercraft/api/lua/IArguments.java b/src/main/java/dan200/computercraft/api/lua/IArguments.java index 5546176ca..02e8b659d 100644 --- a/src/main/java/dan200/computercraft/api/lua/IArguments.java +++ b/src/main/java/dan200/computercraft/api/lua/IArguments.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; @@ -19,25 +18,6 @@ import static dan200.computercraft.api.lua.LuaValues.checkFinite; */ public interface IArguments { - /** - * 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 the number of arguments passed to this function. * @@ -62,6 +42,37 @@ public interface IArguments @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. * @@ -84,12 +95,8 @@ public interface IArguments 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(); + if( !(value instanceof Number) ) throw LuaValues.badArgumentOf( index, "number", value ); + return LuaValues.checkFiniteNum( index, (Number) value ).longValue(); } /** @@ -104,24 +111,6 @@ public interface IArguments return checkFinite( index, getDouble( index ) ); } - /** - * 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 a boolean. * @@ -132,26 +121,10 @@ public interface IArguments default boolean getBoolean( int index ) throws LuaException { Object value = get( index ); - if( !(value instanceof Boolean) ) - { - throw LuaValues.badArgumentOf( index, "boolean", value ); - } + if( !(value instanceof Boolean) ) throw LuaValues.badArgumentOf( index, "boolean", value ); return (Boolean) 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 an argument as a string. * @@ -163,13 +136,23 @@ public interface IArguments default String getString( int index ) throws LuaException { Object value = get( index ); - if( !(value instanceof String) ) - { - throw LuaValues.badArgumentOf( index, "string", value ); - } + 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. * @@ -196,75 +179,10 @@ public interface IArguments default Map getTable( int index ) throws LuaException { Object value = get( index ); - if( !(value instanceof Map) ) - { - throw LuaValues.badArgumentOf( index, "table", value ); - } + if( !(value instanceof Map) ) throw LuaValues.badArgumentOf( index, "table", value ); return (Map) 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 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 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 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 a double. * @@ -276,30 +194,11 @@ public interface IArguments 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 ); - } + 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. - * @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 an int. * @@ -323,16 +222,122 @@ public interface IArguments 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() ); + 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 ); } /** @@ -361,23 +366,6 @@ public interface IArguments return optFiniteDouble( index ).orElse( def ); } - /** - * 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. * @@ -391,27 +379,6 @@ public interface IArguments return optBoolean( index ).orElse( def ); } - /** - * 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. * @@ -437,25 +404,4 @@ public interface IArguments { return optTable( index ).orElse( def ); } - - /** - * 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 ); - } } diff --git a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java index d9069b52a..fb76aceb4 100644 --- a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java +++ b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.filesystem.IFileSystem; @@ -12,7 +11,8 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import javax.annotation.Nullable; /** - * An interface passed to {@link ILuaAPIFactory} in order to provide additional information about a computer. + * An interface passed to {@link ILuaAPIFactory} in order to provide additional information + * about a computer. */ public interface IComputerSystem extends IComputerAccess { diff --git a/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java index 49c4d6a47..ac3d3ce15 100644 --- a/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java +++ b/src/main/java/dan200/computercraft/api/lua/IDynamicLuaObject.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.peripheral.IDynamicPeripheral; @@ -13,13 +12,15 @@ 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. + * 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. + * 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() @@ -30,10 +31,13 @@ public interface IDynamicLuaObject /** * 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 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. + * @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 diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java index ca33136dc..e1a1d4a54 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java @@ -3,17 +3,16 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; /** - * 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}. + * 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. + * Before implementing this interface, consider alternative methods of providing methods. It is generally preferred + * to use peripherals to provide functionality to users. * * @see ILuaAPIFactory * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java index 9b4fbbc47..7db976eb9 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java index b24e4b25e..e999042af 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaCallback.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; @@ -18,7 +17,8 @@ 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}. + * @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. */ diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java index 6d1aba949..4d29b57d1 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaContext.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaContext.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; @@ -41,5 +40,8 @@ public interface ILuaContext * @throws LuaException If the task could not be queued, or if the task threw an exception. */ @Nonnull - MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException; + default MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException + { + return TaskCallback.make( this, task ); + } } diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java index 70d900c2c..7813cbbdc 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaFunction.java @@ -3,14 +3,13 @@ * 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; 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}. + * 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) */ @@ -18,8 +17,8 @@ import javax.annotation.Nonnull; 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. + * 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. diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java index 44a429ed4..808e635b5 100644 --- a/src/main/java/dan200/computercraft/api/lua/ILuaTask.java +++ b/src/main/java/dan200/computercraft/api/lua/ILuaTask.java @@ -3,14 +3,14 @@ * 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; import javax.annotation.Nullable; /** - * 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. + * 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#issueMainThreadTask(ILuaTask) */ @@ -21,8 +21,9 @@ public interface ILuaTask * Execute this task. * * @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. + * @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. */ @Nullable Object[] execute() throws LuaException; diff --git a/src/main/java/dan200/computercraft/api/lua/LuaException.java b/src/main/java/dan200/computercraft/api/lua/LuaException.java index df97ed0fa..e2738ea91 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaException.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaException.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nullable; @@ -42,7 +41,8 @@ public class LuaException extends Exception } /** - * The level this error is raised at. Level 1 is the function's caller, level 2 is that function's caller, and so on. + * The level this error is raised at. Level 1 is the function's caller, level 2 is that function's caller, and so + * on. * * @return The level to raise the error at. */ diff --git a/src/main/java/dan200/computercraft/api/lua/LuaFunction.java b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java index 064149466..5558b153c 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaFunction.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaFunction.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.peripheral.IComputerAccess; @@ -16,8 +15,8 @@ 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: + * 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})
  • @@ -49,7 +48,8 @@ public @interface LuaFunction 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. + * 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) diff --git a/src/main/java/dan200/computercraft/api/lua/LuaValues.java b/src/main/java/dan200/computercraft/api/lua/LuaValues.java index a78091060..8eec784ff 100644 --- a/src/main/java/dan200/computercraft/api/lua/LuaValues.java +++ b/src/main/java/dan200/computercraft/api/lua/LuaValues.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; @@ -38,8 +37,41 @@ public final class LuaValues chars[i] = c < 256 ? (byte) c : 63; } - return ByteBuffer.wrap( chars ) - .asReadOnlyBuffer(); + 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"; } /** @@ -70,38 +102,6 @@ public final class LuaValues return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" ); } - /** - * 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"; - } - /** * Ensure a numeric argument is finite (i.e. not infinite or {@link Double#NaN}. * @@ -126,38 +126,10 @@ public final class LuaValues */ public static double checkFinite( int index, double value ) throws LuaException { - if( !Double.isFinite( value ) ) - { - throw badArgument( index, "number", getNumericType( value ) ); - } + 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"; - } - /** * Ensure a string is a valid enum value. * @@ -172,11 +144,7 @@ public final class LuaValues { for( T possibility : klass.getEnumConstants() ) { - if( possibility.name() - .equalsIgnoreCase( value ) ) - { - return possibility; - } + 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 index 8787bf911..7d15d60b7 100644 --- a/src/main/java/dan200/computercraft/api/lua/MethodResult.java +++ b/src/main/java/dan200/computercraft/api/lua/MethodResult.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.peripheral.IComputerAccess; @@ -18,8 +17,8 @@ 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. + * 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 { @@ -57,11 +56,12 @@ public final class MethodResult /** * 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. {@link ILuaFunction} will be treated as a function. + * 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. {@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}. + * 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. @@ -85,8 +85,8 @@ public final class MethodResult } /** - * 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. + * 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. @@ -98,17 +98,15 @@ public final class MethodResult { 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 ); - } + 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. + * 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. @@ -123,8 +121,8 @@ public final class MethodResult } /** - * 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. + * 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() @@ -156,7 +154,8 @@ public final class MethodResult } /** - * Increase the Lua error by a specific amount. One should never need to use this function - it largely exists for some CC internal code. + * 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. @@ -164,14 +163,8 @@ public final class MethodResult @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; - } + 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 index d800d0ac6..6dd7e3c0f 100644 --- a/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java +++ b/src/main/java/dan200/computercraft/api/lua/ObjectArguments.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nullable; @@ -36,41 +35,32 @@ public final class ObjectArguments implements IArguments this.args = Objects.requireNonNull( args ); } - @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() ) ); - } - - @Override - public Object[] getAll() - { - return args.toArray(); - } - @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/lua/TaskCallback.java b/src/main/java/dan200/computercraft/api/lua/TaskCallback.java new file mode 100644 index 000000000..85870a221 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/TaskCallback.java @@ -0,0 +1,53 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * 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; + +import javax.annotation.Nonnull; +import java.util.Arrays; + +final class TaskCallback implements ILuaCallback +{ + private final MethodResult pull = MethodResult.pullEvent( "task_complete", this ); + private final long task; + + private 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" ); + } + } + + 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/api/media/IMedia.java b/src/main/java/dan200/computercraft/api/media/IMedia.java index 414d9895b..da0be8da7 100644 --- a/src/main/java/dan200/computercraft/api/media/IMedia.java +++ b/src/main/java/dan200/computercraft/api/media/IMedia.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.filesystem.IMount; @@ -18,7 +17,8 @@ import javax.annotation.Nullable; /** * Represents an item that can be placed in a disk drive and used by a Computer. * - * Implement this interface on your {@link Item} class to allow it to be used in the drive. Alternatively, register a {@link IMediaProvider}. + * Implement this interface on your {@link Item} class to allow it to be used in the drive. Alternatively, register + * a {@link IMediaProvider}. */ public interface IMedia { @@ -44,7 +44,8 @@ public interface IMedia } /** - * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: "Jonathan Coulton - Still Alive" + * If this disk represents an item with audio (like a record), get the readable name of the audio track. ie: + * "Jonathan Coulton - Still Alive" * * @param stack The {@link ItemStack} to modify. * @return The name, or null if this item does not represent an item with audio. @@ -68,13 +69,13 @@ public interface IMedia } /** - * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will be mounted onto the filesystem of - * the computer while the media is in the disk drive. + * If this disk represents an item with data (like a floppy disk), get a mount representing it's contents. This will + * be mounted onto the filesystem of the computer while the media is in the disk drive. * * @param stack The {@link ItemStack} to modify. * @param world The world in which the item and disk drive reside. - * @return The mount, or null if this item does not represent an item with data. If the mount returned also implements {@link - * dan200.computercraft.api.filesystem.IWritableMount}, it will mounted using mountWritable() + * @return The mount, or null if this item does not represent an item with data. If the mount returned also + * implements {@link dan200.computercraft.api.filesystem.IWritableMount}, it will mounted using mountWritable() * @see IMount * @see dan200.computercraft.api.filesystem.IWritableMount * @see dan200.computercraft.api.ComputerCraftAPI#createSaveDirMount(Level, String, long) diff --git a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java index 023e4d12c..04ec9f9d6 100644 --- a/src/main/java/dan200/computercraft/api/media/IMediaProvider.java +++ b/src/main/java/dan200/computercraft/api/media/IMediaProvider.java @@ -3,7 +3,6 @@ * 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; import net.minecraft.world.item.ItemStack; diff --git a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java index b897717c6..277150156 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketNetwork.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; @@ -38,8 +37,8 @@ public interface IPacketNetwork boolean isWireless(); /** - * Submit a packet for transmitting across the network. This will route the packet through the network, sending it to all receivers within range (or any - * interdimensional ones). + * Submit a packet for transmitting across the network. This will route the packet through the network, sending it + * to all receivers within range (or any interdimensional ones). * * @param packet The packet to send. * @param range The maximum distance this packet will be sent. @@ -49,8 +48,8 @@ public interface IPacketNetwork void transmitSameDimension( @Nonnull Packet packet, double range ); /** - * Submit a packet for transmitting across the network. This will route the packet through the network, sending it to all receivers across all - * dimensions. + * Submit a packet for transmitting across the network. This will route the packet through the network, sending it + * to all receivers across all dimensions. * * @param packet The packet to send. * @see #transmitSameDimension(Packet, double) diff --git a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java index ccea2630f..b8a639828 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketReceiver.java @@ -3,7 +3,6 @@ * 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; import net.minecraft.world.level.Level; @@ -22,7 +21,7 @@ public interface IPacketReceiver * @return The receivers's world. */ @Nonnull - Level getWorld(); + Level getLevel(); /** * Get the position in the world at which this receiver exists. @@ -35,8 +34,9 @@ public interface IPacketReceiver /** * Get the maximum distance this receiver can send and receive messages. * - * When determining whether a receiver can receive a message, the largest distance of the packet and receiver is used - ensuring it is within range. If - * the packet or receiver is inter-dimensional, then the packet will always be received. + * When determining whether a receiver can receive a message, the largest distance of the packet and receiver is + * used - ensuring it is within range. If the packet or receiver is inter-dimensional, then the packet will always + * be received. * * @return The maximum distance this device can send and receive messages. * @see #isInterdimensional() @@ -60,8 +60,8 @@ public interface IPacketReceiver /** * Receive a network packet from the same dimension. * - * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, if so, queue the appropriate - * modem event. + * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, + * if so, queue the appropriate modem event. * @param distance The distance this packet has travelled from the source. * @see Packet * @see #getRange() @@ -73,8 +73,8 @@ public interface IPacketReceiver /** * Receive a network packet from a different dimension. * - * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, if so, queue the appropriate - * modem event. + * @param packet The packet to receive. Generally you should check that you are listening on the given channel and, + * if so, queue the appropriate modem event. * @see Packet * @see IPacketNetwork#transmitInterdimensional(Packet) * @see IPacketNetwork#transmitSameDimension(Packet, double) diff --git a/src/main/java/dan200/computercraft/api/network/IPacketSender.java b/src/main/java/dan200/computercraft/api/network/IPacketSender.java index 310dd92d1..b6346952a 100644 --- a/src/main/java/dan200/computercraft/api/network/IPacketSender.java +++ b/src/main/java/dan200/computercraft/api/network/IPacketSender.java @@ -3,7 +3,6 @@ * 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; import net.minecraft.world.level.Level; @@ -22,7 +21,7 @@ public interface IPacketSender * @return The sender's world. */ @Nonnull - Level getWorld(); + Level getLevel(); /** * Get the position in the world at which this sender exists. @@ -33,8 +32,8 @@ public interface IPacketSender Vec3 getPosition(); /** - * Get some sort of identification string for this sender. This does not strictly need to be unique, but you should be able to extract some identifiable - * information from it. + * Get some sort of identification string for this sender. This does not strictly need to be unique, but you + * should be able to extract some identifiable information from it. * * @return This device's id. */ diff --git a/src/main/java/dan200/computercraft/api/network/Packet.java b/src/main/java/dan200/computercraft/api/network/Packet.java index 34b2bd41f..5d1854120 100644 --- a/src/main/java/dan200/computercraft/api/network/Packet.java +++ b/src/main/java/dan200/computercraft/api/network/Packet.java @@ -3,128 +3,28 @@ * 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; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; - /** * Represents a packet which may be sent across a {@link IPacketNetwork}. * + * @param channel The channel to send the packet along. Receiving devices should only process packets from on + * channels they are listening to. + * @param replyChannel The channel to reply on. + * @param payload The contents of this packet. This should be a "valid" Lua object, safe for queuing as an + * event or returning from a peripheral call. + * @param sender The object which sent this packet. * @see IPacketSender * @see IPacketNetwork#transmitSameDimension(Packet, double) * @see IPacketNetwork#transmitInterdimensional(Packet) * @see IPacketReceiver#receiveDifferentDimension(Packet) * @see IPacketReceiver#receiveSameDimension(Packet, double) */ -public class Packet +public record Packet( + int channel, + int replyChannel, + Object payload, + IPacketSender sender +) { - private final int channel; - private final int replyChannel; - private final Object payload; - - private final IPacketSender sender; - - /** - * Create a new packet, ready for transmitting across the network. - * - * @param channel The channel to send the packet along. Receiving devices should only process packets from on channels they are listening to. - * @param replyChannel The channel to reply on. - * @param payload The contents of this packet. This should be a "valid" Lua object, safe for queuing as an event or returning from a peripheral - * call. - * @param sender The object which sent this packet. - */ - public Packet( int channel, int replyChannel, @Nullable Object payload, @Nonnull IPacketSender sender ) - { - Objects.requireNonNull( sender, "sender cannot be null" ); - - this.channel = channel; - this.replyChannel = replyChannel; - this.payload = payload; - this.sender = sender; - } - - /** - * Get the channel this packet is sent along. Receivers should generally only process packets from on channels they are listening to. - * - * @return This packet's channel. - */ - public int getChannel() - { - return channel; - } - - /** - * The channel to reply on. Objects which will reply should send it along this channel. - * - * @return This channel to reply on. - */ - public int getReplyChannel() - { - return replyChannel; - } - - /** - * The actual data of this packet. This should be a "valid" Lua object, safe for queuing as an event or returning from a peripheral call. - * - * @return The packet's payload - */ - @Nullable - public Object getPayload() - { - return payload; - } - - /** - * The object which sent this message. - * - * @return The sending object. - */ - @Nonnull - public IPacketSender getSender() - { - return sender; - } - - @Override - public int hashCode() - { - int result; - result = channel; - result = 31 * result + replyChannel; - result = 31 * result + (payload != null ? payload.hashCode() : 0); - result = 31 * result + sender.hashCode(); - return result; - } - - @Override - public boolean equals( Object o ) - { - if( this == o ) - { - return true; - } - if( o == null || getClass() != o.getClass() ) - { - return false; - } - - Packet packet = (Packet) o; - - if( channel != packet.channel ) - { - return false; - } - if( replyChannel != packet.replyChannel ) - { - return false; - } - if( !Objects.equals( payload, packet.payload ) ) - { - return false; - } - return sender.equals( packet.sender ); - } } 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 5ca0ddb9f..390bd91e9 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredElement.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; @@ -13,16 +12,18 @@ import javax.annotation.Nonnull; /** * An object which may be part of a wired network. * - * Elements should construct a node using {@link ComputerCraftAPI#createWiredNodeForElement(IWiredElement)}. This acts as a proxy for all network objects. - * Whilst the node may change networks, an element's node should remain constant for its lifespan. + * Elements should construct a node using {@link ComputerCraftAPI#createWiredNodeForElement(IWiredElement)}. This acts + * as a proxy for all network objects. Whilst the node may change networks, an element's node should remain constant + * for its lifespan. * - * Elements are generally tied to a block or tile entity in world. In such as case, one should provide the {@link IWiredElement} capability for the - * appropriate sides. + * Elements are generally tied to a block or tile entity in world. In such as case, one should provide the + * {@link IWiredElement} capability for the appropriate sides. */ public interface IWiredElement extends IWiredSender { /** - * Called when objects on the network change. This may occur when network nodes are added or removed, or when peripherals change. + * Called when objects on the network change. This may occur when network nodes are added or removed, or when + * peripherals change. * * @param change The change which occurred. * @see IWiredNetworkChange 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 fa44c4d1b..ae18cb691 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetwork.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.peripheral.IPeripheral; @@ -12,14 +11,16 @@ import javax.annotation.Nonnull; import java.util.Map; /** - * A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series of peripherals. + * A wired network is composed of one of more {@link IWiredNode}s, a set of connections between them, and a series + * of peripherals. * - * Networks from a connected graph. This means there is some path between all nodes on the network. Further more, if there is some path between two nodes - * then they must be on the same network. {@link IWiredNetwork} will automatically handle the merging and splitting of networks (and thus changing of - * available nodes and peripherals) as connections change. + * Networks from a connected graph. This means there is some path between all nodes on the network. Further more, if + * there is some path between two nodes then they must be on the same network. {@link IWiredNetwork} will automatically + * handle the merging and splitting of networks (and thus changing of available nodes and peripherals) as connections + * change. * - * This does mean one can not rely on the network remaining consistent between subsequent operations. Consequently, it is generally preferred to use the - * methods provided by {@link IWiredNode}. + * This does mean one can not rely on the network remaining consistent between subsequent operations. Consequently, + * it is generally preferred to use the methods provided by {@link IWiredNode}. * * @see IWiredNode#getNetwork() */ @@ -58,10 +59,12 @@ public interface IWiredNetwork /** * Sever all connections this node has, removing it from this network. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * * @param node The node to remove - * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the only element. + * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the + * only element. * @throws IllegalArgumentException If the node is not in the network. * @see IWiredNode#remove() */ @@ -70,7 +73,8 @@ public interface IWiredNetwork /** * Update the peripherals a node provides. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * * @param node The node to attach peripherals for. * @param peripherals The new peripherals for this node. 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 bef4b1048..0663509a6 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNetworkChange.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.peripheral.IPeripheral; @@ -19,8 +18,8 @@ import java.util.Map; public interface IWiredNetworkChange { /** - * A set of peripherals which have been removed. Note that there may be entries with the same name in the added and removed set, but with a different - * peripheral. + * A set of peripherals which have been removed. Note that there may be entries with the same name + * in the added and removed set, but with a different peripheral. * * @return The set of removed peripherals. */ @@ -28,8 +27,8 @@ public interface IWiredNetworkChange Map peripheralsRemoved(); /** - * A set of peripherals which have been added. Note that there may be entries with the same name in the added and removed set, but with a different - * peripheral. + * A set of peripherals which have been added. Note that there may be entries with the same name + * in the added and removed set, but with a different peripheral. * * @return The set of added peripherals. */ 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 73afe2fd7..e72f25a62 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredNode.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.network.IPacketNetwork; @@ -15,14 +14,15 @@ import java.util.Map; /** * Wired nodes act as a layer between {@link IWiredElement}s and {@link IWiredNetwork}s. * - * Firstly, a node acts as a packet network, capable of sending and receiving modem messages to connected nodes. These methods may be safely used on any - * thread. + * Firstly, a node acts as a packet network, capable of sending and receiving modem messages to connected nodes. These + * methods may be safely used on any thread. * - * When sending a packet, the system will attempt to find the shortest path between the two nodes based on their element's position. Note that packet - * senders and receivers can have different locations from their associated element: the distance between the two will be added to the total packet's - * distance. + * When sending a packet, the system will attempt to find the shortest path between the two nodes based on their + * element's position. Note that packet senders and receivers can have different locations from their associated + * element: the distance between the two will be added to the total packet's distance. * - * Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever be used on the main server thread. + * Wired nodes also provide several convenience methods for interacting with a wired network. These should only ever + * be used on the main server thread. */ public interface IWiredNode extends IPacketNetwork { @@ -34,6 +34,17 @@ public interface IWiredNode extends IPacketNetwork @Nonnull IWiredElement getElement(); + /** + * The network this node is currently connected to. Note that this may change + * after any network operation, so it should not be cached. + * + * This should only be used on the server thread. + * + * @return This node's network. + */ + @Nonnull + IWiredNetwork getNetwork(); + /** * Create a connection from this node to another. * @@ -49,16 +60,6 @@ public interface IWiredNode extends IPacketNetwork return getNetwork().connect( this, node ); } - /** - * The network this node is currently connected to. Note that this may change after any network operation, so it should not be cached. - * - * This should only be used on the server thread. - * - * @return This node's network. - */ - @Nonnull - IWiredNetwork getNetwork(); - /** * Destroy a connection between this node and another. * @@ -78,9 +79,11 @@ public interface IWiredNode extends IPacketNetwork /** * Sever all connections this node has, removing it from this network. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * - * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the only element. + * @return Whether this node was removed from the network. One cannot remove a node from a network where it is the + * only element. * @throws IllegalArgumentException If the node is not in the network. * @see IWiredNetwork#remove(IWiredNode) */ @@ -92,7 +95,8 @@ public interface IWiredNode extends IPacketNetwork /** * Mark this node's peripherals as having changed. * - * This should only be used on the server thread. You should only call this on nodes that your network element owns. + * This should only be used on the server thread. You should only call this on nodes + * that your network element owns. * * @param peripherals The new peripherals for this node. * @see IWiredNetwork#updatePeripherals(IWiredNode, Map) 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 c306b0a6b..f2795eced 100644 --- a/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java +++ b/src/main/java/dan200/computercraft/api/network/wired/IWiredSender.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.network.IPacketSender; @@ -13,14 +12,16 @@ import javax.annotation.Nonnull; /** * An object on a {@link IWiredNetwork} capable of sending packets. * - * Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to to send the packet from. + * Unlike a regular {@link IPacketSender}, this must be associated with the node you are attempting to + * to send the packet from. */ public interface IWiredSender extends IPacketSender { /** * The node in the network representing this object. * - * This should be used as a proxy for the main network. One should send packets and register receivers through this object. + * This should be used as a proxy for the main network. One should send packets + * and register receivers through this object. * * @return The node for this element. */ diff --git a/src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java new file mode 100644 index 000000000..15988b3d3 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/GenericPeripheral.java @@ -0,0 +1,45 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * 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; + +import dan200.computercraft.api.lua.GenericSource; +import net.minecraft.world.Container; +import net.minecraft.world.level.block.entity.BlockEntity; + +import javax.annotation.Nonnull; + +/** + * A {@link GenericSource} which provides methods for a peripheral. + * + * Unlike a {@link GenericSource}, all methods should target the same type, for instance a + * {@link BlockEntity} subclass or a capability interface. This is not currently enforced. + */ +public interface GenericPeripheral extends GenericSource +{ + /** + * Get the type of the exposed peripheral. + * + * Unlike normal {@link IPeripheral}s, {@link GenericPeripheral} do not have to have a type. By default, the + * resulting peripheral uses the resource name of the wrapped {@link BlockEntity} (for instance {@literal minecraft:chest}). + * + * However, in some cases it may be more appropriate to specify a more readable name. Overriding this method allows + * you to do so. + * + * When multiple {@link GenericPeripheral}s return a non-empty peripheral type for a single tile entity, the + * lexicographically smallest will be chosen. In order to avoid this conflict, this method should only be + * implemented when your peripheral targets a single tile entity AND it's likely that you're the + * only mod to do so. Similarly this should NOT be implemented when your methods target an + * interface (i.e. {@link Container}). + * + * @return The type of this peripheral or {@link PeripheralType#untyped()}. + * @see IPeripheral#getType() + */ + @Nonnull + default PeripheralType getType() + { + return PeripheralType.untyped(); + } +} diff --git a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java index 7012b482e..11c9dec1a 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IComputerAccess.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; @@ -20,8 +19,9 @@ import javax.annotation.Nullable; import java.util.Map; /** - * The interface passed to peripherals by computers or turtles, providing methods that they can call. This should not be implemented by your classes. Do not - * interact with computers except via this interface. + * The interface passed to peripherals by computers or turtles, providing methods + * that they can call. This should not be implemented by your classes. Do not interact + * with computers except via this interface. */ public interface IComputerAccess { @@ -30,8 +30,8 @@ public interface IComputerAccess * * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @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. + * @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 NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -52,8 +52,8 @@ public interface IComputerAccess * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @param mount The mount object to mount on the computer. * @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. + * @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 NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -65,24 +65,13 @@ public interface IComputerAccess @Nullable String mount( @Nonnull String desiredLocation, @Nonnull IMount mount, @Nonnull String driveName ); - /** - * Get a string, unique to the computer, by which the computer refers to this peripheral. For directly attached peripherals this will be - * "left","right","front","back",etc, but for peripherals attached remotely it will be different. It is good practice to supply this string when raising - * events to the computer, so that the computer knows from which peripheral the event came. - * - * @return A string unique to the computer, but not globally. - * @throws NotAttachedException If the peripheral has been detached. - */ - @Nonnull - String getAttachmentName(); - /** * Mount a mount onto the computer's file system in a writable mode. * * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @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. + * @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 NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -102,8 +91,8 @@ public interface IComputerAccess * @param desiredLocation The location on the computer's file system where you would like the mount to be mounted. * @param mount The mount object to mount on the computer. * @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. + * @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 NotAttachedException If the peripheral has been detached. * @see ComputerCraftAPI#createSaveDirMount(Level, String, long) * @see ComputerCraftAPI#createResourceMount(String, String) @@ -114,16 +103,18 @@ public interface IComputerAccess String mountWritable( @Nonnull String desiredLocation, @Nonnull IWritableMount mount, @Nonnull String driveName ); /** - * Unmounts a directory previously mounted onto the computers file system by {@link #mount(String, IMount)} or {@link #mountWritable(String, - * IWritableMount)}. + * Unmounts a directory previously mounted onto the computers file system by {@link #mount(String, IMount)} + * or {@link #mountWritable(String, IWritableMount)}. * - * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be able to access it. All directories - * mounted by a mount or mountWritable are automatically unmounted when the peripheral is attached if they have not been explicitly unmounted. + * When a directory is unmounted, it will disappear from the computers file system, and the user will no longer be + * able to access it. All directories mounted by a mount or mountWritable are automatically unmounted when the + * peripheral is attached if they have not been explicitly unmounted. * * Note that you cannot unmount another peripheral's mounts. * - * @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. + * @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 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) @@ -134,22 +125,26 @@ public interface IComputerAccess /** * Returns the numerical ID of this computer. * - * This is the same number obtained by calling {@code os.getComputerID()} or running the "id" program from lua, and is guaranteed unique. This number - * will be positive. + * This is the same number obtained by calling {@code os.getComputerID()} or running the "id" program from lua, + * and is guaranteed unique. This number will be positive. * * @return The identifier. */ int getID(); /** - * Causes an event to be raised on this computer, which the computer can respond to by calling {@code os.pullEvent()}. This can be used to notify the - * computer when things happen in the world or to this peripheral. + * Causes an event to be raised on this computer, which the computer can respond to by calling + * {@code os.pullEvent()}. This can be used to notify the computer when things happen in the world or to + * this peripheral. * - * @param event A string identifying the type of event that has occurred, this will be returned as the first value from {@code os.pullEvent()}. It - * is recommended that you you choose a name that is unique, and recognisable as originating from your peripheral. eg: If your peripheral type is - * "button", a suitable event would be "button_pressed". - * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will be supplied as extra return values to - * os.pullEvent(). Objects in the array will be converted to lua data types in the same fashion as the return values of IPeripheral.callMethod(). + * @param event A string identifying the type of event that has occurred, this will be + * returned as the first value from {@code os.pullEvent()}. It is recommended that you + * you choose a name that is unique, and recognisable as originating from your + * peripheral. eg: If your peripheral type is "button", a suitable event would be + * "button_pressed". + * @param arguments In addition to a name, you may pass an array of extra arguments to the event, that will + * be supplied as extra return values to os.pullEvent(). Objects in the array will be converted + * 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 NotAttachedException If the peripheral has been detached. @@ -157,6 +152,19 @@ public interface IComputerAccess */ void queueEvent( @Nonnull String event, @Nullable Object... arguments ); + /** + * Get a string, unique to the computer, by which the computer refers to this peripheral. + * For directly attached peripherals this will be "left","right","front","back",etc, but + * for peripherals attached remotely it will be different. It is good practice to supply + * this string when raising events to the computer, so that the computer knows from + * which peripheral the event came. + * + * @return A string unique to the computer, but not globally. + * @throws NotAttachedException If the peripheral has been detached. + */ + @Nonnull + String getAttachmentName(); + /** * Get a set of peripherals that this computer access can "see", along with their attachment name. * @@ -171,8 +179,8 @@ public interface IComputerAccess Map getAvailablePeripherals(); /** - * Get a reachable peripheral with the given attachment name. This is a equivalent to {@link #getAvailablePeripherals()}{@code .get(name)}, though may - * be more efficient. + * Get a reachable peripheral with the given attachment name. This is a equivalent to + * {@link #getAvailablePeripherals()}{@code .get(name)}, though may be more efficient. * * @param name The peripheral's attached name * @return The reachable peripheral, or {@code null} if none can be found. @@ -184,11 +192,13 @@ public interface IComputerAccess /** * Get a {@link IWorkMonitor} for tasks your peripheral might execute on the main (server) thread. * - * This should be used to ensure your peripheral integrates with ComputerCraft's monitoring and limiting of how much server time each computer consumes. - * You should not need to use this if you use {@link ILuaContext#issueMainThreadTask(ILuaTask)} - this is intended for mods with their own system for - * running work on the main thread. + * This should be used to ensure your peripheral integrates with ComputerCraft's monitoring and limiting of how much + * server time each computer consumes. You should not need to use this if you use + * {@link ILuaContext#issueMainThreadTask(ILuaTask)} - this is intended for mods with their own system for running + * work on the main thread. * - * Please note that the returned implementation is not thread-safe, and should only be used from the main thread. + * Please note that the returned implementation is not thread-safe, and should only be used from the main + * 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. diff --git a/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java index e06c14096..695680b94 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IDynamicPeripheral.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.lua.*; @@ -13,14 +12,14 @@ 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. + * 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. + * 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 @@ -29,19 +28,24 @@ public interface IDynamicPeripheral extends IPeripheral 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()}. + * 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. + * 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 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. + * @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 diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java index 09a63c64d..eddc30861 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheral.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.lua.LuaFunction; @@ -17,12 +16,14 @@ import javax.annotation.Nullable; * In order to expose a peripheral for your block or tile entity, you 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}. + * Peripherals should provide a series of methods to the user, either using {@link LuaFunction} or by implementing + * {@link IDynamicPeripheral}. */ public interface IPeripheral { /** - * Should return a string that uniquely identifies this type of peripheral. This can be queried from lua by calling {@code peripheral.getType()} + * Should return a string that uniquely identifies this type of peripheral. + * This can be queried from lua by calling {@code peripheral.getType()} * * @return A string identifying the type of peripheral. */ @@ -32,15 +33,19 @@ public interface IPeripheral /** * Is called when when a computer is attaching to the peripheral. * - * This will occur when a peripheral is placed next to an active computer, when a computer is turned on next to a peripheral, when a turtle travels into - * a square next to a peripheral, or when a wired modem adjacent to this peripheral is does any of the above. + * This will occur when a peripheral is placed next to an active computer, when a computer is turned on next to a + * peripheral, when a turtle travels into a square next to a peripheral, or when a wired modem adjacent to this + * peripheral is does any of the above. * - * Between calls to attach and {@link #detach}, the attached computer can make method calls on the peripheral using {@code peripheral.call()}. This - * method can be used to keep track of which computers are attached to the peripheral, or to take action when attachment occurs. + * Between calls to attach and {@link #detach}, the attached computer can make method calls on the peripheral using + * {@code peripheral.call()}. This method can be used to keep track of which computers are attached to the + * peripheral, or to take action when attachment occurs. * - * Be aware that will be called from both the server thread and ComputerCraft Lua thread, and so must be thread-safe and reentrant. + * Be aware that will be called from both the server thread and ComputerCraft Lua thread, and so must be thread-safe + * and reentrant. * - * @param computer The interface to the computer that is being attached. Remember that multiple computers can be attached to a peripheral at once. + * @param computer The interface to the computer that is being attached. Remember that multiple computers can be + * attached to a peripheral at once. * @see #detach */ default void attach( @Nonnull IComputerAccess computer ) @@ -50,14 +55,18 @@ public interface IPeripheral /** * Called when a computer is detaching from the peripheral. * - * This will occur when a computer shuts down, when the peripheral is removed while attached to computers, when a turtle moves away from a block - * attached to a peripheral, or when a wired modem adjacent to this peripheral is detached. + * This will occur when a computer shuts down, when the peripheral is removed while attached to computers, when a + * turtle moves away from a block attached to a peripheral, or when a wired modem adjacent to this peripheral is + * detached. * - * This method can be used to keep track of which computers are attached to the peripheral, or to take action when detachment occurs. + * This method can be used to keep track of which computers are attached to the peripheral, or to take action when + * detachment occurs. * - * Be aware that this will be called from both the server and ComputerCraft Lua thread, and must be thread-safe and reentrant. + * Be aware that this will be called from both the server and ComputerCraft Lua thread, and must be thread-safe + * and reentrant. * - * @param computer The interface to the computer that is being detached. Remember that multiple computers can be attached to a peripheral at once. + * @param computer The interface to the computer that is being detached. Remember that multiple computers can be + * attached to a peripheral at once. * @see #attach */ default void detach( @Nonnull IComputerAccess computer ) @@ -65,7 +74,8 @@ public interface IPeripheral } /** - * Get the object that this peripheral provides methods for. This will generally be the tile entity or block, but may be an inventory, entity, etc... + * Get the object that this peripheral provides methods for. This will generally be the tile entity + * or block, but may be an inventory, entity, etc... * * @return The object this peripheral targets */ @@ -78,8 +88,8 @@ public interface IPeripheral /** * Determine whether this peripheral is equivalent to another one. * - * The minimal example should at least check whether they are the same object. However, you may wish to check if they point to the same block or tile - * entity. + * The minimal example should at least check whether they are the same object. However, you may wish to check if + * they point to the same block or tile entity. * * @param other The peripheral to compare against. This may be {@code null}. * @return Whether these peripherals are equivalent. diff --git a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java index 20e8e416f..98e97d628 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IPeripheralProvider.java @@ -3,22 +3,18 @@ * 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; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.entity.BlockEntity; import javax.annotation.Nonnull; -import java.util.Optional; +import javax.annotation.Nullable; /** * This interface is used to create peripheral implementations for blocks. * - * If you have a {@link BlockEntity} which acts as a peripheral, you may alternatively expose the {@link IPeripheral} capability. - * * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ @FunctionalInterface @@ -30,9 +26,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 {@link Optional#empty()} if there is not a peripheral here you'd like to handle. + * @return A peripheral or {@literal null} if there is not a peripheral here you'd like to handle. * @see dan200.computercraft.api.ComputerCraftAPI#registerPeripheralProvider(IPeripheralProvider) */ - @Nonnull + @Nullable IPeripheral getPeripheral( @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull Direction side ); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java index 21ae59438..2ec3f3df9 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java +++ b/src/main/java/dan200/computercraft/api/peripheral/IWorkMonitor.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; @@ -11,14 +10,15 @@ import java.util.Objects; import java.util.concurrent.TimeUnit; /** - * Monitors "work" associated with a computer, keeping track of how much a computer has done, and ensuring every computer receives a fair share of any - * processing time. + * Monitors "work" associated with a computer, keeping track of how much a computer has done, and ensuring every + * computer receives a fair share of any processing time. * - * This is primarily intended for work done by peripherals on the main thread (such as on a tile entity's tick), but could be used for other purposes (such - * as complex computations done on another thread). + * This is primarily intended for work done by peripherals on the main thread (such as on a tile entity's tick), but + * could be used for other purposes (such as complex computations done on another thread). * - * Before running a task, one should call {@link #canWork()} to determine if the computer is currently allowed to execute work. If that returns true, you - * should execute the task and use {@link #trackWork(long, TimeUnit)} to inform the monitor how long that task took. + * Before running a task, one should call {@link #canWork()} to determine if the computer is currently allowed to + * execute work. If that returns true, you should execute the task and use {@link #trackWork(long, TimeUnit)} to inform + * the monitor how long that task took. * * Alternatively, use {@link #runWork(Runnable)} to run and keep track of work. * @@ -26,16 +26,31 @@ import java.util.concurrent.TimeUnit; */ public interface IWorkMonitor { + /** + * If the owning computer is currently allowed to execute work. + * + * @return If we can execute work right now. + */ + boolean canWork(); + /** * If the owning computer is currently allowed to execute work, and has ample time to do so. * - * This is effectively a more restrictive form of {@link #canWork()}. One should use that in order to determine if you may do an initial piece of work, - * and shouldWork to determine if any additional task may be performed. + * This is effectively a more restrictive form of {@link #canWork()}. One should use that in order to determine if + * you may do an initial piece of work, and shouldWork to determine if any additional task may be performed. * * @return If we should execute work right now. */ boolean shouldWork(); + /** + * Inform the monitor how long some piece of work took to execute. + * + * @param time The time some task took to run + * @param unit The unit that {@code time} was measured in. + */ + void trackWork( long time, @Nonnull TimeUnit unit ); + /** * Run a task if possible, and inform the monitor of how long it took. * @@ -45,10 +60,7 @@ public interface IWorkMonitor default boolean runWork( @Nonnull Runnable runnable ) { Objects.requireNonNull( runnable, "runnable should not be null" ); - if( !canWork() ) - { - return false; - } + if( !canWork() ) return false; long start = System.nanoTime(); try @@ -62,19 +74,4 @@ public interface IWorkMonitor return true; } - - /** - * If the owning computer is currently allowed to execute work. - * - * @return If we can execute work right now. - */ - boolean canWork(); - - /** - * Inform the monitor how long some piece of work took to execute. - * - * @param time The time some task took to run - * @param unit The unit that {@code time} was measured in. - */ - void trackWork( long time, @Nonnull TimeUnit unit ); } diff --git a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java index 335841cfb..96ebd11ac 100644 --- a/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java +++ b/src/main/java/dan200/computercraft/api/peripheral/NotAttachedException.java @@ -3,11 +3,11 @@ * 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; /** - * Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to the computer. + * Thrown when performing operations on {@link IComputerAccess} when the current peripheral is no longer attached to + * the computer. */ public class NotAttachedException extends IllegalStateException { diff --git a/src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java b/src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java new file mode 100644 index 000000000..2780534c2 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/peripheral/PeripheralType.java @@ -0,0 +1,62 @@ +/* + * This file is part of the public ComputerCraft API - http://www.computercraft.info + * 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; + +import com.google.common.base.Strings; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * The type of a {@link GenericPeripheral}. + * + * When determining the final type of the resulting peripheral, the union of all types is taken, with the + * lexicographically smallest non-empty name being chosen. + */ +public final class PeripheralType +{ + private static final PeripheralType UNTYPED = new PeripheralType( null ); + + private final String type; + + public PeripheralType( String type ) + { + this.type = type; + } + + /** + * An empty peripheral type, used when a {@link GenericPeripheral} does not have an explicit type. + * + * @return The empty peripheral type. + */ + public static PeripheralType untyped() + { + return UNTYPED; + } + + /** + * Create a new non-empty peripheral type. + * + * @param type The name of the type. + * @return The constructed peripheral type. + */ + public static PeripheralType ofType( @Nonnull String type ) + { + if( Strings.isNullOrEmpty( type ) ) throw new IllegalArgumentException( "type cannot be null or empty" ); + return new PeripheralType( type ); + } + + /** + * Get the name of this peripheral type. This may be {@literal null}. + * + * @return The type of this peripheral. + */ + @Nullable + public String getPrimaryType() + { + return type; + } +} diff --git a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java index cd8a2f55e..ccb68d834 100644 --- a/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/AbstractPocketUpgrade.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.shared.util.NonNullSupplier; diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java index f8ee4010b..2fa939153 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketAccess.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.peripheral.IPeripheral; @@ -33,7 +32,8 @@ public interface IPocketAccess /** * Get the colour of this pocket computer as a RGB number. * - * @return The colour this pocket computer is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 if it has no colour. + * @return The colour this pocket computer is. This will be a RGB colour between {@code 0x000000} and + * {@code 0xFFFFFF} or -1 if it has no colour. * @see #setColour(int) */ int getColour(); @@ -41,8 +41,8 @@ public interface IPocketAccess /** * Set the colour of the pocket computer to a RGB number. * - * @param colour The colour this pocket computer should be changed to. This should be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or - * -1 to reset to the default colour. + * @param colour The colour this pocket computer should be changed to. This should be a RGB colour between + * {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour. * @see #getColour() */ void setColour( int colour ); @@ -50,7 +50,8 @@ public interface IPocketAccess /** * Get the colour of this pocket computer's light as a RGB number. * - * @return The colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 if it has no colour. + * @return The colour this light is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or + * -1 if it has no colour. * @see #setLight(int) */ int getLight(); @@ -58,8 +59,8 @@ public interface IPocketAccess /** * Set the colour of the pocket computer's light to a RGB number. * - * @param colour The colour this modem's light will be changed to. This should be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 - * to reset to the default colour. + * @param colour The colour this modem's light will be changed to. This should be a RGB colour between + * {@code 0x000000} and {@code 0xFFFFFF} or -1 to reset to the default colour. * @see #getLight() */ void setLight( int colour ); diff --git a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java index d81e59d51..4e39f0b38 100644 --- a/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java +++ b/src/main/java/dan200/computercraft/api/pocket/IPocketUpgrade.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; @@ -24,8 +23,9 @@ public interface IPocketUpgrade extends IUpgradeBase /** * Creates a peripheral for the pocket computer. * - * The peripheral created will be stored for the lifetime of the upgrade, will be passed an argument to {@link #update(IPocketAccess, IPeripheral)} and - * will be attached, detached and have methods called in the same manner as an ordinary peripheral. + * The peripheral created will be stored for the lifetime of the upgrade, will be passed an argument to + * {@link #update(IPocketAccess, IPeripheral)} and will be attached, detached and have methods called in the same + * manner as an ordinary peripheral. * * @param access The access object for the pocket item stack. * @return The newly created peripheral. @@ -51,8 +51,9 @@ public interface IPocketUpgrade extends IUpgradeBase * @param world The world the computer is in. * @param access The access object for the pocket item stack. * @param peripheral The peripheral for this upgrade. - * @return {@code true} to stop the GUI from opening, otherwise false. You should always provide some code path which returns {@code false}, such as - * requiring the player to be sneaking - otherwise they will be unable to access the GUI. + * @return {@code true} to stop the GUI from opening, otherwise false. You should always provide some code path + * which returns {@code false}, such as requiring the player to be sneaking - otherwise they will be unable to + * access the GUI. * @see #createPeripheral(IPocketAccess) */ default boolean onRightClick( @Nonnull Level world, @Nonnull IPocketAccess access, @Nullable IPeripheral peripheral ) diff --git a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java index 092f79d51..1f2f4f4ad 100644 --- a/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java +++ b/src/main/java/dan200/computercraft/api/redstone/IBundledRedstoneProvider.java @@ -3,7 +3,6 @@ * 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; import net.minecraft.core.BlockPos; @@ -26,7 +25,8 @@ public interface IBundledRedstoneProvider * @param world The world this block is in. * @param pos The position this block is at. * @param side The side to extract the bundled redstone output from. - * @return A number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to handle this block. + * @return A number in the range 0-65535 to indicate this block is providing output, or -1 if you do not wish to + * handle this block. * @see dan200.computercraft.api.ComputerCraftAPI#registerBundledRedstoneProvider(IBundledRedstoneProvider) */ int getBundledRedstoneOutput( @Nonnull Level 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 0f876f109..d9de8062a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleAccess.java @@ -3,7 +3,6 @@ * 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; import com.mojang.authlib.GameProfile; @@ -24,7 +23,8 @@ import javax.annotation.Nullable; /** * The interface passed to turtle by turtles, providing methods that they can call. * - * This should not be implemented by your classes. Do not interact with turtles except via this interface and {@link ITurtleUpgrade}. + * This should not be implemented by your classes. Do not interact with turtles except via this interface and + * {@link ITurtleUpgrade}. */ public interface ITurtleAccess { @@ -34,7 +34,7 @@ public interface ITurtleAccess * @return the world in which the turtle resides. */ @Nonnull - Level getWorld(); + Level getLevel(); /** * Returns a vector containing the integer co-ordinates at which the turtle resides. @@ -47,18 +47,20 @@ public interface ITurtleAccess /** * Attempt to move this turtle to a new position. * - * This will preserve the turtle's internal state, such as it's inventory, computer and upgrades. It should be used before playing a movement animation - * using {@link #playAnimation(TurtleAnimation)}. + * This will preserve the turtle's internal state, such as it's inventory, computer and upgrades. It should + * be used before playing a movement animation using {@link #playAnimation(TurtleAnimation)}. * * @param world The new world to move it to * @param pos The new position to move it to. - * @return Whether the movement was successful. It may fail if the block was not loaded or the block placement was cancelled. + * @return Whether the movement was successful. It may fail if the block was not loaded or the block placement + * was cancelled. * @throws UnsupportedOperationException When attempting to teleport on the client side. */ boolean teleportTo( @Nonnull Level world, @Nonnull BlockPos pos ); /** - * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. This will shift when the turtle is moving. + * Returns a vector containing the floating point co-ordinates at which the turtle is rendered. + * This will shift when the turtle is moving. * * @param f The subframe fraction. * @return A vector containing the floating point co-ordinates at which the turtle resides. @@ -86,8 +88,8 @@ public interface ITurtleAccess Direction getDirection(); /** - * Set the direction the turtle is facing. Note that this will not play a rotation animation, you will also need to call {@link - * #playAnimation(TurtleAnimation)} to do so. + * Set the direction the turtle is facing. Note that this will not play a rotation animation, you will also need to + * call {@link #playAnimation(TurtleAnimation)} to do so. * * @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() @@ -106,30 +108,32 @@ public interface ITurtleAccess /** * Set the currently selected slot in the turtle's inventory. * - * @param slot The slot to set. This must be greater or equal to 0 and less than the inventory size. Otherwise no action will be taken. + * @param slot The slot to set. This must be greater or equal to 0 and less than the inventory size. Otherwise no + * action will be taken. * @throws UnsupportedOperationException When attempting to change the slot on the client side. * @see #getInventory() * @see #getSelectedSlot() */ void setSelectedSlot( int slot ); - /** - * Get the colour of this turtle as a RGB number. - * - * @return The colour this turtle is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 if it has no colour. - * @see #setColour(int) - */ - int getColour(); - /** * Set the colour of the turtle to a RGB number. * - * @param colour The colour this turtle should be changed to. This should be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or -1 to - * reset to the default colour. + * @param colour The colour this turtle should be changed to. This should be a RGB colour between {@code 0x000000} + * and {@code 0xFFFFFF} or -1 to reset to the default colour. * @see #getColour() */ void setColour( int colour ); + /** + * Get the colour of this turtle as a RGB number. + * + * @return The colour this turtle is. This will be a RGB colour between {@code 0x000000} and {@code 0xFFFFFF} or + * -1 if it has no colour. + * @see #setColour(int) + */ + int getColour(); + /** * Get the player who owns this turtle, namely whoever placed it. * @@ -138,6 +142,32 @@ public interface ITurtleAccess @Nullable GameProfile getOwningPlayer(); + /** + * 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() + */ + @Nonnull + Container getInventory(); + + /** + * Get the inventory of this turtle as an {@link ItemStorage}. + * + * Note: this inventory should only be accessed and modified on the server thread. + * + * @return This turtle's inventory + * @see #getInventory() + * @see ItemStorage + */ + @Nonnull + default ItemStorage getItemHandler() + { + return ItemStorage.wrap( getInventory() ); + } + /** * Determine whether this turtle will require fuel when performing actions. * @@ -157,7 +187,8 @@ public interface ITurtleAccess int getFuelLevel(); /** - * Set the fuel level to a new value. It is generally preferred to use {@link #consumeFuel(int)}} or {@link #addFuel(int)} instead. + * Set the fuel level to a new value. It is generally preferred to use {@link #consumeFuel(int)}} or {@link #addFuel(int)} + * instead. * * @param fuel The new amount of fuel. This must be between 0 and the fuel limit. * @see #getFuelLevel() @@ -178,8 +209,8 @@ public interface ITurtleAccess * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle. * * @param fuel The amount of fuel to consume. - * @return Whether the turtle was able to consume the amount of fuel specified. Will return false if you supply a number greater than the current fuel - * level of the turtle. No fuel will be consumed if {@code false} is returned. + * @return Whether the turtle was able to consume the amount of fuel specified. Will return false if you supply a number + * greater than the current fuel level of the turtle. No fuel will be consumed if {@code false} is returned. * @throws UnsupportedOperationException When attempting to consume fuel on the client side. */ boolean consumeFuel( int fuel ); @@ -193,13 +224,15 @@ public interface ITurtleAccess void addFuel( int fuel ); /** - * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed on the main thread, so are - * guaranteed to be able to access Minecraft objects safely, and will be queued up with the turtles standard movement and tool commands. An issued - * command will return an unique integer, which will 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. + * Adds a custom command to the turtles command queue. Unlike peripheral methods, these custom commands will be executed + * on the main thread, so are guaranteed to be able to access Minecraft objects safely, and will be queued up + * with the turtles standard movement and tool commands. An issued command will return an unique integer, which will + * 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 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. + * @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. * @see ITurtleCommand * @see MethodResult#pullEvent(String, ILuaCallback) @@ -208,7 +241,8 @@ public interface ITurtleAccess MethodResult executeCommand( @Nonnull ITurtleCommand command ); /** - * Start playing a specific animation. This will prevent other turtle commands from executing until it is finished. + * Start playing a specific animation. This will prevent other turtle commands from executing until + * it is finished. * * @param animation The animation to play. * @throws UnsupportedOperationException When attempting to execute play an animation on the client side. @@ -247,8 +281,8 @@ public interface ITurtleAccess /** * Get an upgrade-specific NBT compound, which can be used to store arbitrary data. * - * This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You must call {@link - * #updateUpgradeNBTData(TurtleSide)} after modifying it. + * This will be persisted across turtle restarts and chunk loads, as well as being synced to the client. You must + * call {@link #updateUpgradeNBTData(TurtleSide)} after modifying it. * * @param side The side to get the upgrade data for. * @return The upgrade-specific data. @@ -258,25 +292,11 @@ public interface ITurtleAccess CompoundTag 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 client and persisted. + * Mark the upgrade-specific data as dirty on a specific side. This is required for the data to be synced to the + * client and persisted. * * @param side The side to mark dirty. * @see #updateUpgradeNBTData(TurtleSide) */ void updateUpgradeNBTData( @Nonnull TurtleSide side ); - - default ItemStorage getItemHandler() - { - return ItemStorage.wrap( getInventory() ); - } - - /** - * Get the inventory of this turtle. - * - * Note: this inventory should only be accessed and modified on the server thread. - * - * @return This turtle's inventory - */ - @Nonnull - Container getInventory(); } diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java index 134bb346d..e7300a02c 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleCommand.java @@ -3,7 +3,6 @@ * 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; import javax.annotation.Nonnull; @@ -19,8 +18,8 @@ public interface ITurtleCommand /** * Will be called by the turtle on the main thread when it is time to execute the custom command. * - * The handler should either perform the work of the command, and return success, or return failure with an error message to indicate the command cannot - * be executed at this time. + * The handler should either perform the work of the command, and return success, or return + * failure with an error message to indicate the command cannot be executed at this time. * * @param turtle Access to the turtle for whom the command was issued. * @return A result, indicating whether this action succeeded or not. diff --git a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java index 4fc3d69f9..52acab992 100644 --- a/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java +++ b/src/main/java/dan200/computercraft/api/turtle/ITurtleUpgrade.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.ComputerCraftAPI; @@ -18,7 +17,8 @@ import javax.annotation.Nonnull; import javax.annotation.Nullable; /** - * The primary interface for defining an update for Turtles. A turtle update can either be a new tool, or a new peripheral. + * The primary interface for defining an update for Turtles. A turtle update + * can either be a new tool, or a new peripheral. * * @see ComputerCraftAPI#registerTurtleUpgrade(ITurtleUpgrade) */ @@ -36,12 +36,14 @@ public interface ITurtleUpgrade extends IUpgradeBase /** * Will only be called for peripheral upgrades. Creates a peripheral for a turtle being placed using this upgrade. * - * The peripheral created will be stored for the lifetime of the upgrade and will be passed as an argument to {@link #update(ITurtleAccess, - * TurtleSide)}. It will be attached, detached and have methods called in the same manner as a Computer peripheral. + * The peripheral created will be stored for the lifetime of the upgrade and will be passed as an argument to + * {@link #update(ITurtleAccess, TurtleSide)}. It will be attached, detached and have methods called in the same + * manner as a Computer peripheral. * * @param turtle Access to the turtle that the peripheral is being created for. * @param side Which side of the turtle (left or right) that the upgrade resides on. - * @return The newly created peripheral. You may return {@code null} if this upgrade is a Tool and this method is not expected to be called. + * @return The newly created peripheral. You may return {@code null} if this upgrade is a Tool + * and this method is not expected to be called. */ @Nullable default IPeripheral createPeripheral( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) @@ -50,16 +52,19 @@ public interface ITurtleUpgrade extends IUpgradeBase } /** - * 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. + * 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. * * @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. * @param verb Which action (dig or attack) the turtle is being called on to perform. - * @param direction Which world direction the action should be performed in, relative to the turtles position. This will either be up, down, or the - * direction the turtle is facing, depending on whether dig, digUp or digDown was called. - * @return Whether the turtle was able to perform the action, and hence whether the {@code turtle.dig()} or {@code turtle.attack()} lua method should - * return true. If true is returned, the tool will perform a swinging animation. You may return {@code null} if this turtle is a Peripheral and - * this method is not expected to be called. + * @param direction Which world direction the action should be performed in, relative to the turtles + * position. This will either be up, down, or the direction the turtle is facing, depending on + * whether dig, digUp or digDown was called. + * @return Whether the turtle was able to perform the action, and hence whether the {@code turtle.dig()} + * or {@code turtle.attack()} lua method should return true. If true is returned, the tool will perform + * a swinging animation. You may return {@code null} if this turtle is a Peripheral and this method is not expected + * to be called. */ @Nonnull default TurtleCommandResult useTool( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side, @Nonnull TurtleVerb verb, @Nonnull Direction direction ) @@ -70,6 +75,10 @@ public interface ITurtleUpgrade extends IUpgradeBase /** * Called to obtain the model to be used when rendering a turtle peripheral. * + * This can be obtained from {@link net.minecraft.client.renderer.ItemModelShaper#getItemModel(ItemStack)}, + * {@link net.minecraft.client.resources.model.ModelManager#getModel(ModelResourceLocation)} or any other + * source. + * * @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. diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java index f4468b5c9..dd67a044a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleAnimation.java @@ -3,7 +3,6 @@ * 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; /** @@ -24,34 +23,38 @@ public enum TurtleAnimation NONE, /** - * Make the turtle move forward. Note that the animation starts from the block behind it, and moves into this one. + * Make the turtle move forward. Note that the animation starts from the block behind it, and + * moves into this one. */ MOVE_FORWARD, /** - * Make the turtle move backwards. Note that the animation starts from the block in front it, and moves into this one. + * Make the turtle move backwards. Note that the animation starts from the block in front it, and + * moves into this one. */ MOVE_BACK, /** - * Make the turtle move backwards. Note that the animation starts from the block above it, and moves into this one. + * Make the turtle move backwards. Note that the animation starts from the block above it, and + * moves into this one. */ MOVE_UP, /** - * Make the turtle move backwards. Note that the animation starts from the block below it, and moves into this one. + * Make the turtle move backwards. Note that the animation starts from the block below it, and + * moves into this one. */ 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. + * 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. */ 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. + * 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. */ TURN_RIGHT, diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java index 17f42bb85..eccd976e5 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleCommandResult.java @@ -3,9 +3,10 @@ * 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; +import net.minecraft.core.Direction; + import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -19,16 +20,6 @@ public final class TurtleCommandResult { private static final TurtleCommandResult EMPTY_SUCCESS = new TurtleCommandResult( true, null, null ); private static final TurtleCommandResult EMPTY_FAILURE = new TurtleCommandResult( false, null, null ); - private final boolean success; - private final String errorMessage; - private final Object[] results; - - private TurtleCommandResult( boolean success, String errorMessage, Object[] results ) - { - this.success = success; - this.errorMessage = errorMessage; - this.results = results; - } /** * Create a successful command result with no result. @@ -50,10 +41,7 @@ public final class TurtleCommandResult @Nonnull public static TurtleCommandResult success( @Nullable Object[] results ) { - if( results == null || results.length == 0 ) - { - return EMPTY_SUCCESS; - } + if( results == null || results.length == 0 ) return EMPTY_SUCCESS; return new TurtleCommandResult( true, null, results ); } @@ -77,13 +65,21 @@ public final class TurtleCommandResult @Nonnull public static TurtleCommandResult failure( @Nullable String errorMessage ) { - if( errorMessage == null ) - { - return EMPTY_FAILURE; - } + if( errorMessage == null ) return EMPTY_FAILURE; return new TurtleCommandResult( false, errorMessage, null ); } + private final boolean success; + private final String errorMessage; + private final Object[] results; + + private TurtleCommandResult( boolean success, String errorMessage, Object[] results ) + { + this.success = success; + this.errorMessage = errorMessage; + this.results = results; + } + /** * Determine whether the command executed successfully. * diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java index 86edade62..e944cfe43 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleSide.java @@ -3,7 +3,6 @@ * 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 a6c6fede4..daa036a8a 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleUpgradeType.java @@ -3,7 +3,6 @@ * 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; /** @@ -14,20 +13,21 @@ package dan200.computercraft.api.turtle; 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). + * 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, /** - * 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). + * 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, /** - * 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. + * 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; diff --git a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java index d4622b1a0..53a2b0ceb 100644 --- a/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java +++ b/src/main/java/dan200/computercraft/api/turtle/TurtleVerb.java @@ -3,11 +3,13 @@ * 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; +import net.minecraft.core.Direction; + /** - * An enum representing the different actions that an {@link ITurtleUpgrade} of type Tool may be called on to perform by a turtle. + * 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, Direction) diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java deleted file mode 100644 index ca5ccecf6..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAction.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * 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; - -/** - * A basic action that a turtle may perform, as accessed by the {@code turtle} API. - * - * @see TurtleActionEvent - */ -public enum TurtleAction -{ - /** - * A turtle moves to a new position. - * - * @see TurtleBlockEvent.Move - */ - MOVE, - - /** - * A turtle turns in a specific direction. - */ - TURN, - - /** - * A turtle attempts to dig a block. - * - * @see TurtleBlockEvent.Dig - */ - DIG, - - /** - * A turtle attempts to place a block or item in the world. - * - * @see TurtleBlockEvent.Place - */ - PLACE, - - /** - * A turtle attempts to attack an entity. - * - * @see TurtleActionEvent - */ - ATTACK, - - /** - * Drop an item into an inventory/the world. - * - * @see TurtleInventoryEvent.Drop - */ - DROP, - - /** - * Suck an item from an inventory or the world. - * - * @see TurtleInventoryEvent.Suck - */ - SUCK, - - /** - * Refuel the turtle's fuel levels. - */ - REFUEL, - - /** - * Equip or unequip an item. - */ - EQUIP, - - /** - * Inspect a block in world. - * - * @see TurtleBlockEvent.Inspect - */ - INSPECT, - - /** - * Gather metdata about an item in the turtle's inventory. - */ - INSPECT_ITEM, -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java deleted file mode 100644 index b6c129855..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleActionEvent.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * 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; - -import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.api.turtle.TurtleCommandResult; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; - -/** - * An event fired when a turtle is performing a known action. - */ -public class TurtleActionEvent extends TurtleEvent -{ - private final TurtleAction action; - private String failureMessage; - private boolean cancelled = false; - - public TurtleActionEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action ) - { - super( turtle ); - - Objects.requireNonNull( action, "action cannot be null" ); - this.action = action; - } - - public TurtleAction getAction() - { - return action; - } - - /** - * Sets the cancellation state of this action. - * - * If {@code cancel} is {@code true}, this action will not be carried out. - * - * @param cancel The new canceled value. - * @see TurtleCommandResult#failure() - * @deprecated Use {@link #setCanceled(boolean, String)} instead. - */ - @Deprecated - public void setCanceled( boolean cancel ) - { - setCanceled( cancel, null ); - } - - /** - * Set the cancellation state of this action, setting a failure message if required. - * - * If {@code cancel} is {@code true}, this action will not be carried out. - * - * @param cancel The new canceled value. - * @param failureMessage The message to return to the user explaining the failure. - * @see TurtleCommandResult#failure(String) - */ - public void setCanceled( boolean cancel, @Nullable String failureMessage ) - { - cancelled = true; - this.failureMessage = cancel ? failureMessage : null; - } - - /** - * Get the message with which this will fail. - * - * @return The failure message. - * @see TurtleCommandResult#failure() - * @see #setCanceled(boolean, String) - */ - @Nullable - public String getFailureMessage() - { - return failureMessage; - } - - public boolean isCancelled() - { - return cancelled; - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java deleted file mode 100644 index 64126aa39..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleAttackEvent.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * 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; - -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import net.minecraft.world.entity.Entity; - -import javax.annotation.Nonnull; -import java.util.Objects; - -/** - * Fired when a turtle attempts to attack an entity. - * - * @see TurtleAction#ATTACK - */ -public class TurtleAttackEvent extends TurtlePlayerEvent -{ - private final Entity target; - private final ITurtleUpgrade upgrade; - private final TurtleSide side; - - public TurtleAttackEvent( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Entity target, @Nonnull ITurtleUpgrade upgrade, - @Nonnull TurtleSide side ) - { - super( turtle, TurtleAction.ATTACK, player ); - Objects.requireNonNull( target, "target cannot be null" ); - Objects.requireNonNull( upgrade, "upgrade cannot be null" ); - Objects.requireNonNull( side, "side cannot be null" ); - this.target = target; - this.upgrade = upgrade; - this.side = side; - } - - /** - * Get the entity being attacked by this turtle. - * - * @return The entity being attacked. - */ - @Nonnull - public Entity getTarget() - { - return target; - } - - /** - * Get the upgrade responsible for attacking. - * - * @return The upgrade responsible for attacking. - */ - @Nonnull - public ITurtleUpgrade getUpgrade() - { - return upgrade; - } - - /** - * Get the side the attacking upgrade is on. - * - * @return The upgrade's side. - */ - @Nonnull - public TurtleSide getSide() - { - return side; - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java deleted file mode 100644 index ca757dd7d..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleBlockEvent.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * 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; - -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; -import dan200.computercraft.api.turtle.ITurtleUpgrade; -import dan200.computercraft.api.turtle.TurtleSide; -import net.minecraft.core.BlockPos; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; - -import javax.annotation.Nonnull; -import java.util.Map; -import java.util.Objects; - -/** - * A general event for when a turtle interacts with a block or region. - * - * You should generally listen to one of the sub-events instead, cancelling them where appropriate. - * - * Note that you are not guaranteed to receive this event, if it has been cancelled by other mechanisms, such as block protection systems. - * - * Be aware that some events (such as {@link TurtleInventoryEvent}) do not necessarily interact with a block, simply objects within that block space. - */ -public abstract class TurtleBlockEvent extends TurtlePlayerEvent -{ - private final Level world; - private final BlockPos pos; - - protected TurtleBlockEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull Level world, - @Nonnull BlockPos pos ) - { - super( turtle, action, player ); - - Objects.requireNonNull( world, "world cannot be null" ); - Objects.requireNonNull( pos, "pos cannot be null" ); - this.world = world; - this.pos = pos; - } - - /** - * Get the world the turtle is interacting in. - * - * @return The world the turtle is interacting in. - */ - public Level getWorld() - { - return world; - } - - /** - * Get the position the turtle is interacting with. Note that this is different to {@link ITurtleAccess#getPosition()}. - * - * @return The position the turtle is interacting with. - */ - public BlockPos getPos() - { - return pos; - } - - /** - * Fired when a turtle attempts to dig a block. - * - * @see TurtleAction#DIG - */ - public static class Dig extends TurtleBlockEvent - { - private final BlockState block; - private final ITurtleUpgrade upgrade; - private final TurtleSide side; - - public Dig( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState block, - @Nonnull ITurtleUpgrade upgrade, @Nonnull TurtleSide side ) - { - super( turtle, TurtleAction.DIG, player, world, pos ); - - Objects.requireNonNull( block, "block cannot be null" ); - Objects.requireNonNull( upgrade, "upgrade cannot be null" ); - Objects.requireNonNull( side, "side cannot be null" ); - this.block = block; - this.upgrade = upgrade; - this.side = side; - } - - /** - * Get the block which is about to be broken. - * - * @return The block which is going to be broken. - */ - @Nonnull - public BlockState getBlock() - { - return block; - } - - /** - * Get the upgrade doing the digging. - * - * @return The upgrade doing the digging. - */ - @Nonnull - public ITurtleUpgrade getUpgrade() - { - return upgrade; - } - - /** - * Get the side the upgrade doing the digging is on. - * - * @return The upgrade's side. - */ - @Nonnull - public TurtleSide getSide() - { - return side; - } - } - - /** - * Fired when a turtle attempts to move into a block. - * - * @see TurtleAction#MOVE - */ - public static class Move extends TurtleBlockEvent - { - public Move( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos ) - { - super( turtle, TurtleAction.MOVE, player, world, pos ); - } - } - - /** - * Fired when a turtle attempts to place a block in the world. - * - * @see TurtleAction#PLACE - */ - public static class Place extends TurtleBlockEvent - { - private final ItemStack stack; - - public Place( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull ItemStack stack ) - { - super( turtle, TurtleAction.PLACE, player, world, pos ); - - Objects.requireNonNull( stack, "stack cannot be null" ); - this.stack = stack; - } - - /** - * Get the item stack that will be placed. This should not be modified. - * - * @return The item stack to be placed. - */ - @Nonnull - public ItemStack getStack() - { - return stack; - } - } - - /** - * Fired when a turtle gathers data on a block in world. - * - * You may prevent blocks being inspected, or add additional information to the result. - * - * @see TurtleAction#INSPECT - */ - public static class Inspect extends TurtleBlockEvent - { - private final BlockState state; - private final Map data; - - public Inspect( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nonnull BlockState state, - @Nonnull Map data ) - { - super( turtle, TurtleAction.INSPECT, player, world, pos ); - - Objects.requireNonNull( state, "state cannot be null" ); - Objects.requireNonNull( data, "data cannot be null" ); - this.data = data; - this.state = state; - } - - /** - * Get the block state which is being inspected. - * - * @return The inspected block state. - */ - @Nonnull - public BlockState getState() - { - return state; - } - - /** - * Get the "inspection data" from this block, which will be returned to the user. - * - * @return This block's inspection data. - */ - @Nonnull - public Map getData() - { - return data; - } - - /** - * 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 MethodResult#of(Object)}). - */ - public void addData( @Nonnull Map newData ) - { - Objects.requireNonNull( newData, "newData cannot be null" ); - data.putAll( newData ); - } - } -} 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 726a059ae..6557efc12 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleEvent.java @@ -3,7 +3,6 @@ * 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; import com.google.common.eventbus.EventBus; @@ -13,12 +12,10 @@ import javax.annotation.Nonnull; import java.util.Objects; /** - * A base class for all events concerning a turtle. This will only ever constructed and fired on the server side, so sever specific methods on {@link - * ITurtleAccess} are safe to use. + * A base class for all events concerning a turtle. This will only ever constructed and fired on the server side, + * so sever specific methods on {@link ITurtleAccess} are safe to use. * * You should generally not need to subscribe to this event, preferring one of the more specific classes. - * - * @see TurtleActionEvent */ public abstract class TurtleEvent { @@ -32,12 +29,6 @@ public abstract class TurtleEvent this.turtle = turtle; } - public static boolean post( TurtleActionEvent event ) - { - EVENT_BUS.post( event ); - return event.isCancelled(); - } - /** * Get the turtle which is performing this action. * @@ -48,5 +39,4 @@ public abstract class TurtleEvent { return turtle; } - } diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java deleted file mode 100644 index 14a5e20aa..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInspectItemEvent.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * 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; - -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.world.item.ItemStack; - -import javax.annotation.Nonnull; -import java.util.Map; -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 may be fired on the computer thread, and so any - * operations on it must be thread safe. - * - * @see TurtleAction#INSPECT_ITEM - */ -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 ); - - Objects.requireNonNull( stack, "stack cannot be null" ); - Objects.requireNonNull( data, "data cannot be null" ); - this.stack = stack; - this.data = data; - this.mainThread = mainThread; - } - - /** - * The item which is currently being inspected. - * - * @return The item stack which is being inspected. This should not be modified. - */ - @Nonnull - public ItemStack getStack() - { - return stack; - } - - /** - * Get the "inspection data" from this item, which will be returned to the user. - * - * @return This items's inspection data. - */ - @Nonnull - public Map getData() - { - 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. - * - * @param newData The data to add. Note all values should be convertible to Lua (see {@link MethodResult#of(Object)}). - */ - public void addData( @Nonnull Map newData ) - { - Objects.requireNonNull( newData, "newData cannot be null" ); - data.putAll( newData ); - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java deleted file mode 100644 index 83033a513..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleInventoryEvent.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * 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; - -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; -import net.minecraft.core.BlockPos; -import net.minecraft.world.Container; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.level.Level; - -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import java.util.Objects; - -/** - * Fired when a turtle attempts to interact with an inventory. - */ -public abstract class TurtleInventoryEvent extends TurtleBlockEvent -{ - private final Container handler; - - protected TurtleInventoryEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player, @Nonnull Level world, - @Nonnull BlockPos pos, @Nullable Container handler ) - { - super( turtle, action, player, world, pos ); - this.handler = handler; - } - - /** - * 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. - */ - @Nullable - public Container getItemHandler() - { - return handler; - } - - /** - * Fired when a turtle attempts to suck from an inventory. - * - * @see TurtleAction#SUCK - */ - public static class Suck extends TurtleInventoryEvent - { - public Suck( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nullable Container handler ) - { - super( turtle, TurtleAction.SUCK, player, world, pos, handler ); - } - } - - /** - * Fired when a turtle attempts to drop an item into an inventory. - * - * @see TurtleAction#DROP - */ - public static class Drop extends TurtleInventoryEvent - { - private final ItemStack stack; - - public Drop( @Nonnull ITurtleAccess turtle, @Nonnull FakePlayer player, @Nonnull Level world, @Nonnull BlockPos pos, @Nullable Container handler, - @Nonnull ItemStack stack ) - { - super( turtle, TurtleAction.DROP, player, world, pos, handler ); - - Objects.requireNonNull( stack, "stack cannot be null" ); - this.stack = stack; - } - - /** - * The item which will be inserted into the inventory/dropped on the ground. - * - * @return The item stack which will be dropped. This should not be modified. - */ - @Nonnull - public ItemStack getStack() - { - return stack; - } - } -} diff --git a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java b/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java deleted file mode 100644 index 463a6602c..000000000 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtlePlayerEvent.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * This file is part of the public ComputerCraft API - http://www.computercraft.info - * 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; - -import dan200.computercraft.api.turtle.FakePlayer; -import dan200.computercraft.api.turtle.ITurtleAccess; - -import javax.annotation.Nonnull; -import java.util.Objects; - -/** - * An action done by a turtle which is normally done by a player. - * - * {@link #getPlayer()} may be used to modify the player's attributes or perform permission checks. - */ -public abstract class TurtlePlayerEvent extends TurtleActionEvent -{ - private final FakePlayer player; - - protected TurtlePlayerEvent( @Nonnull ITurtleAccess turtle, @Nonnull TurtleAction action, @Nonnull FakePlayer player ) - { - super( turtle, action ); - - Objects.requireNonNull( player, "player cannot be null" ); - this.player = player; - } - - /** - * A fake player, representing this turtle. - * - * This may be used for triggering permission checks. - * - * @return A {@link FakePlayer} representing this turtle. - */ - @Nonnull - public FakePlayer getPlayer() - { - return player; - } -} 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 47327afee..ec7f41244 100644 --- a/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java +++ b/src/main/java/dan200/computercraft/api/turtle/event/TurtleRefuelEvent.java @@ -3,7 +3,6 @@ * 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; import dan200.computercraft.api.turtle.ITurtleAccess; @@ -16,17 +15,16 @@ import java.util.Objects; /** * Fired when a turtle attempts to refuel from an item. * - * One may use {@link #setCanceled(boolean, String)} to prevent refueling from this specific item. Additionally, you may use {@link #setHandler(Handler)} to - * register a custom fuel provider. + * One may use {@link #setHandler(Handler)} to register a custom fuel provider for a given item. */ -public class TurtleRefuelEvent extends TurtleActionEvent +public class TurtleRefuelEvent extends TurtleEvent { private final ItemStack stack; private Handler handler; public TurtleRefuelEvent( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack ) { - super( turtle, TurtleAction.REFUEL ); + super( turtle ); Objects.requireNonNull( turtle, "turtle cannot be null" ); this.stack = stack; @@ -59,7 +57,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent /** * Set the refuel handler for this stack. * - * You should call this if you can actually refuel from this item, and ideally only if there are no existing handlers. + * You should call this if you can actually refuel from this item, and ideally only if there are no existing + * handlers. * * @param handler The new refuel handler. * @see #getHandler() @@ -81,7 +80,8 @@ public class TurtleRefuelEvent extends TurtleActionEvent * @param turtle The turtle to refuel. * @param stack The stack to refuel with. * @param slot The slot the stack resides within. This may be used to modify the inventory afterwards. - * @param limit The maximum number of refuel operations to perform. This will often correspond to the number of items to consume. + * @param limit The maximum number of refuel operations to perform. This will often correspond to the number of + * items to consume. * @return The amount of fuel gained. */ int refuel( @Nonnull ITurtleAccess turtle, @Nonnull ItemStack stack, int slot, int limit ); diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java index 77203c656..fdf68c141 100644 --- a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -35,6 +35,7 @@ public abstract class ComputerAccess implements IComputerAccess { ComputerCraft.log.warn( "Peripheral or API called mount but did not call unmount for {}", mounts ); } + for( String mount : mounts ) { fileSystem.unmount( mount ); diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 6d1e5f2f6..9e1059545 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -68,6 +68,13 @@ public class FSAPI implements ILuaAPI * @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. + * @cc.usage List all files under {@code /rom/} + *
    {@code
    +     * local files = fs.list("/rom/")
    +     * for i = 1, #files do
    +     *   print(files[i])
    +     * end
    +     * }
    */ @LuaFunction public final String[] list( String path ) throws LuaException @@ -92,6 +99,12 @@ public class FSAPI implements ILuaAPI * @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. + * @cc.changed 1.95.0 Now supports multiple arguments. + * @cc.usage Combine several file paths together + *
    {@code
    +     * fs.combine("/rom/programs", "../apis", "parallel.lua")
    +     * -- => rom/apis/parallel.lua
    +     * }
    */ @LuaFunction public final String combine( IArguments arguments ) throws LuaException @@ -114,6 +127,12 @@ public class FSAPI implements ILuaAPI * * @param path The path to get the name from. * @return The final part of the path (the file name). + * @cc.since 1.2 + * @cc.usage Get the file name of {@code rom/startup.lua} + *
    {@code
    +     * fs.getName("rom/startup.lua")
    +     * -- => startup.lua
    +     * }
    */ @LuaFunction public final String getName( String path ) @@ -126,6 +145,12 @@ public class FSAPI implements ILuaAPI * * @param path The path to get the directory from. * @return The path with the final part removed (the parent directory). + * @cc.since 1.63 + * @cc.usage Get the directory name of {@code rom/startup.lua} + *
    {@code
    +     * fs.getDir("rom/startup.lua")
    +     * -- => rom
    +     * }
    */ @LuaFunction public final String getDir( String path ) @@ -139,6 +164,7 @@ public class FSAPI implements ILuaAPI * @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. + * @cc.since 1.3 */ @LuaFunction public final long getSize( String path ) throws LuaException @@ -304,10 +330,15 @@ public class FSAPI implements ILuaAPI /** * 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. + * The {@code mode} string can be any of the following: + *
      + *
    • "r": Read mode
    • + *
    • "w": Write 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. * * @param path The path to the file to open. * @param mode The mode to open the file with. @@ -316,6 +347,37 @@ public class FSAPI implements ILuaAPI * @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. + * @cc.usage Read the contents of a file. + *
    {@code
    +     * local file = fs.open("/rom/help/intro.txt", "r")
    +     * local contents = file.readAll()
    +     * file.close()
    +     *
    +     * print(contents)
    +     * }
    + * @cc.usage Open a file and read all lines into a table. @{io.lines} offers an alternative way to do this. + *
    {@code
    +     * local file = fs.open("/rom/motd.txt", "r")
    +     * local lines = {}
    +     * while true do
    +     *   local line = file.readLine()
    +     *
    +     *   -- If line is nil then we've reached the end of the file and should stop
    +     *   if not line then break end
    +     *
    +     *   lines[#lines + 1] = line
    +     * end
    +     *
    +     * file.close()
    +     *
    +     * print(lines[math.random(#lines)]) -- Pick a random line and print it.
    +     * }
    + * @cc.usage Open a file and write some text to it. You can run {@code edit out.txt} to see the written text. + *
    {@code
    +     * local file = fs.open("out.txt", "w")
    +     * file.write("Just testing some code")
    +     * file.close() -- Remember to call close, otherwise changes may not be written!
    +     * }
    */ @LuaFunction public final Object[] open( String path, String mode ) throws LuaException @@ -344,9 +406,11 @@ public class FSAPI implements ILuaAPI 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 @@ -354,9 +418,11 @@ public class FSAPI implements ILuaAPI 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" ); } @@ -396,6 +462,8 @@ public class FSAPI implements ILuaAPI * @return The amount of free space available, in bytes. * @throws LuaException If the path doesn't exist. * @cc.treturn number|"unlimited" The amount of free space available, in bytes, or "unlimited". + * @cc.since 1.4 + * @see #getCapacity To get the capacity of this drive. */ @LuaFunction public final Object getFreeSpace( String path ) throws LuaException @@ -422,6 +490,7 @@ public class FSAPI implements ILuaAPI * @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. + * @cc.since 1.6 */ @LuaFunction public final String[] find( String path ) throws LuaException @@ -438,17 +507,15 @@ 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. + * Returns the capacity of the drive the path is located on. * * @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. + * @cc.since 1.87.0 + * @see #getFreeSpace To get the free space available on this drive. */ @LuaFunction public final Object getCapacity( String path ) throws LuaException @@ -477,6 +544,9 @@ public class FSAPI implements ILuaAPI * @return The resulting attributes. * @throws LuaException If the path does not exist. * @cc.treturn { size = number, isDir = boolean, isReadOnly = boolean, created = number, modified = number } The resulting attributes. + * @cc.since 1.87.0 + * @cc.changed 1.91.0 Renamed `modification` field to `modified`. + * @cc.changed 1.95.2 Added `isReadOnly` to 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. */ diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 0ef4899bc..3140326d7 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -204,14 +204,15 @@ public class OSAPI implements ILuaAPI } /** - * Sets an alarm that will fire at the specified world time. When it fires, - * an {@code alarm} event will be added to the event queue with the ID - * returned from this function as the first parameter. + * Sets an alarm that will fire at the specified in-game time. When it + * fires, * 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 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. + * @cc.since 1.2 * @see #cancelAlarm To cancel an alarm. */ @LuaFunction @@ -232,6 +233,7 @@ public class OSAPI implements ILuaAPI * alarm from firing. * * @param token The ID of the alarm to cancel. + * @cc.since 1.2 * @see #setAlarm To set an alarm. */ @LuaFunction @@ -277,6 +279,7 @@ public class OSAPI implements ILuaAPI * * @return The label of the computer. * @cc.treturn string The label of the computer. + * @cc.since 1.3 */ @LuaFunction( { "getComputerLabel", "computerLabel" } ) public final Object[] getComputerLabel() @@ -289,6 +292,7 @@ public class OSAPI implements ILuaAPI * Set the label of this computer. * * @param label The new label. May be {@code nil} in order to clear it. + * @cc.since 1.3 */ @LuaFunction public final void setComputerLabel( Optional label ) @@ -300,6 +304,7 @@ public class OSAPI implements ILuaAPI * Returns the number of seconds that the computer has been running. * * @return The computer's uptime. + * @cc.since 1.2 */ @LuaFunction public final double clock() @@ -311,7 +316,7 @@ public class OSAPI implements ILuaAPI * 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. + * * If called with {@code dan200.computercraft.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 @@ -321,10 +326,19 @@ public class OSAPI implements ILuaAPI * 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. + * @param args The locale of the time, or a table filled by {@code os.date("*t")} to decode. Defaults to {@code dan200.computercraft.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. + * @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 dan200.computercraft.ingame} locale if not specified. + * @cc.see textutils.formatTime To convert times into a user-readable string. + * @cc.usage Print the current in-game time. + *
    {@code
    +     * textutils.formatTime(os.time())
    +     * }
    + * @cc.since 1.2 + * @cc.changed 1.80pr1 Add support for getting the local local and UTC time. + * @cc.changed 1.82.0 Arguments are now case insensitive. + * @cc.changed 1.83.0 {@link #time(IArguments)} now accepts table arguments and converts them to UNIX timestamps. * @see #date To get a date table that can be converted with this function. */ @LuaFunction @@ -333,14 +347,14 @@ public class OSAPI implements ILuaAPI Object value = args.get( 0 ); if( value instanceof Map ) return LuaDateTime.fromTable( (Map) value ); - String param = args.optString( 0, "ingame" ); + String param = args.optString( 0, "dan200.computercraft.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 + case "dan200.computercraft.ingame": // Get in-game hour return time; default: throw new LuaException( "Unsupported operation" ); @@ -350,27 +364,29 @@ 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 + * * If called with {@code dan200.computercraft.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. + * @param args The locale to get the day for. Defaults to {@code dan200.computercraft.ingame} if not set. * @return The day depending on the selected locale. * @throws LuaException If an invalid locale is passed. + * @cc.since 1.48 + * @cc.changed 1.82.0 Arguments are now case insensitive. */ @LuaFunction public final int day( Optional args ) throws LuaException { - switch( args.orElse( "ingame" ).toLowerCase( Locale.ROOT ) ) + switch( args.orElse( "dan200.computercraft.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 + case "dan200.computercraft.ingame":// Get game day return day; default: throw new LuaException( "Unsupported operation" ); @@ -380,21 +396,29 @@ 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 + * * If called with {@code dan200.computercraft.ingame}, returns the number of milliseconds since the * 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. * * 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 milliseconds for. Defaults to {@code ingame} if not set. + * @param args The locale to get the milliseconds for. Defaults to {@code dan200.computercraft.ingame} if not set. * @return The milliseconds since the epoch depending on the selected locale. * @throws LuaException If an invalid locale is passed. + * @cc.since 1.80pr1 + * @cc.usage Get the current time and use {@link #date} to convert it to a table. + *
    {@code
    +     * -- Dividing by 1000 converts it from milliseconds to seconds.
    +     * local time = os.epoch("local") / 1000
    +     * local time_table = os.date("*t", time)
    +     * print(textutils.serialize(time_table))
    +     * }
    */ @LuaFunction public final long epoch( Optional args ) throws LuaException { - switch( args.orElse( "ingame" ).toLowerCase( Locale.ROOT ) ) + switch( args.orElse( "dan200.computercraft.ingame" ).toLowerCase( Locale.ROOT ) ) { case "utc": { @@ -403,10 +427,12 @@ public class OSAPI implements ILuaAPI return getEpochForCalendar( c ); } case "local": + { // Get local epoch Calendar c = Calendar.getInstance(); return getEpochForCalendar( c ); - case "ingame": + } + case "dan200.computercraft.ingame": // Get in-game epoch synchronized( alarms ) { @@ -436,6 +462,11 @@ public class OSAPI implements ILuaAPI * @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. + * @cc.since 1.83.0 + * @cc.usage Print the current date in a user-friendly string. + *
    {@code
    +     * os.date("%A %d %B %Y") -- See the reference above!
    +     * }
    */ @LuaFunction public final Object date( Optional formatA, Optional timeA ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index 186199302..3fc1285d4 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -30,15 +30,15 @@ import dan200.computercraft.core.computer.ComputerSide; * * @cc.usage Toggle the redstone signal above the computer every 0.5 seconds. * - *
    + * 
    {@code
      * while true do
      *   redstone.setOutput("top", not redstone.getOutput("top"))
      *   sleep(0.5)
      * end
    - * 
    + * }
    * @cc.usage Mimic a redstone comparator in [subtraction mode][comparator]. * - *
    + * 
    {@code
      * while true do
      *   local rear = rs.getAnalogueInput("back")
      *   local sides = math.max(rs.getAnalogueInput("left"), rs.getAnalogueInput("right"))
    @@ -46,7 +46,7 @@ import dan200.computercraft.core.computer.ComputerSide;
      *
      *   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." @@ -72,6 +72,7 @@ public class RedstoneAPI implements ILuaAPI * "back". * * @return A table of valid sides. + * @cc.since 1.2 */ @LuaFunction public final String[] getSides() @@ -122,6 +123,7 @@ public class RedstoneAPI implements ILuaAPI * @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. + * @cc.since 1.51 */ @LuaFunction( { "setAnalogOutput", "setAnalogueOutput" } ) public final void setAnalogOutput( ComputerSide side, int value ) throws LuaException @@ -135,6 +137,7 @@ public class RedstoneAPI implements ILuaAPI * * @param side The side to get. * @return The output signal strength, between 0 and 15. + * @cc.since 1.51 * @see #setAnalogOutput */ @LuaFunction( { "getAnalogOutput", "getAnalogueOutput" } ) @@ -148,6 +151,7 @@ public class RedstoneAPI implements ILuaAPI * * @param side The side to get. * @return The input signal strength, between 0 and 15. + * @cc.since 1.51 */ @LuaFunction( { "getAnalogInput", "getAnalogueInput" } ) public final int getAnalogInput( ComputerSide side ) @@ -201,9 +205,9 @@ public class RedstoneAPI implements ILuaAPI * @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. - *
    +     * 
    {@code
          * print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black)))
    -     * 
    + * }
    * @see #getBundledInput */ @LuaFunction diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 6b1816096..d0fa42ff1 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -46,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. + * @cc.since 1.81.0 * @see TermMethods#setPaletteColour(IArguments) To change the palette colour. */ @LuaFunction( { "nativePaletteColour", "nativePaletteColor" } ) diff --git a/src/main/java/dan200/computercraft/core/apis/TermMethods.java b/src/main/java/dan200/computercraft/core/apis/TermMethods.java index ce5545124..420c8fc95 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermMethods.java +++ b/src/main/java/dan200/computercraft/core/apis/TermMethods.java @@ -112,6 +112,7 @@ public abstract class TermMethods * * @return If the cursor is blinking. * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.since 1.80pr1.9 */ @LuaFunction public final boolean getCursorBlink() throws LuaException @@ -179,6 +180,7 @@ public abstract class TermMethods * @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. + * @cc.since 1.74 */ @LuaFunction( { "getTextColour", "getTextColor" } ) public final int getTextColour() throws LuaException @@ -192,6 +194,8 @@ public abstract class TermMethods * @param colourArg The new text colour. * @throws LuaException (hidden) If the terminal cannot be found. * @cc.see colors For a list of colour constants. + * @cc.since 1.45 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. */ @LuaFunction( { "setTextColour", "setTextColor" } ) public final void setTextColour( int colourArg ) throws LuaException @@ -211,6 +215,7 @@ public abstract class TermMethods * @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. + * @cc.since 1.74 */ @LuaFunction( { "getBackgroundColour", "getBackgroundColor" } ) public final int getBackgroundColour() throws LuaException @@ -225,6 +230,8 @@ public abstract class TermMethods * @param colourArg The new background colour. * @throws LuaException (hidden) If the terminal cannot be found. * @cc.see colors For a list of colour constants. + * @cc.since 1.45 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. */ @LuaFunction( { "setBackgroundColour", "setBackgroundColor" } ) public final void setBackgroundColour( int colourArg ) throws LuaException @@ -245,6 +252,7 @@ public abstract class TermMethods * * @return Whether this terminal supports colour. * @throws LuaException (hidden) If the terminal cannot be found. + * @cc.since 1.45 */ @LuaFunction( { "isColour", "isColor" } ) public final boolean getIsColour() throws LuaException @@ -267,6 +275,8 @@ public abstract class TermMethods * @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.since 1.74 + * @cc.changed 1.80pr1 Standard computers can now use all 16 colors, being changed to grayscale on screen. * @cc.usage Prints "Hello, world!" in rainbow text. *
    {@code
          * term.blit("Hello, world!","01234456789ab","0000000000000")
    @@ -319,6 +329,7 @@ public abstract class TermMethods
          * }
    * @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. + * @cc.since 1.80pr1 */ @LuaFunction( { "setPaletteColour", "setPaletteColor" } ) public final void setPaletteColour( IArguments args ) throws LuaException @@ -348,6 +359,7 @@ public abstract class TermMethods * @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. + * @cc.since 1.80pr1 */ @LuaFunction( { "getPaletteColour", "getPaletteColor" } ) public final Object[] getPaletteColour( int colourArg ) throws LuaException 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 4477dde92..b026aa750 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryReadableHandle.java @@ -61,6 +61,7 @@ public class BinaryReadableHandle extends HandleGeneric * @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. + * @cc.changed 1.80pr1 Now accepts an integer argument to read multiple bytes, returning a string instead of a number. */ @LuaFunction public final Object[] read( Optional countArg ) throws LuaException @@ -145,6 +146,7 @@ public class BinaryReadableHandle extends HandleGeneric * @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. + * @cc.since 1.80pr1 */ @LuaFunction public final Object[] readAll() throws LuaException @@ -182,6 +184,8 @@ public class BinaryReadableHandle extends HandleGeneric * @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. + * @cc.since 1.80pr1.9 + * @cc.changed 1.81.0 `\r` is now stripped. */ @LuaFunction public final Object[] readLine( Optional withTrailingArg ) throws LuaException @@ -259,6 +263,7 @@ public class BinaryReadableHandle extends HandleGeneric * @cc.treturn [1] number The new position. * @cc.treturn [2] nil If seeking failed. * @cc.treturn string The reason seeking failed. + * @cc.since 1.80pr1.9 */ @LuaFunction public final Object[] seek( Optional whence, Optional offset ) throws LuaException 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 796582855..39e234648 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/BinaryWritableHandle.java @@ -55,6 +55,7 @@ public class BinaryWritableHandle extends HandleGeneric * @throws LuaException If the file has been closed. * @cc.tparam [1] number The byte to write. * @cc.tparam [2] string The string to write. + * @cc.changed 1.80pr1 Now accepts a string to write multiple bytes. */ @LuaFunction public final void write( IArguments arguments ) throws LuaException @@ -130,6 +131,7 @@ public class BinaryWritableHandle extends HandleGeneric * @cc.treturn [1] number The new position. * @cc.treturn [2] nil If seeking failed. * @cc.treturn string The reason seeking failed. + * @cc.since 1.80pr1.9 */ @LuaFunction public final Object[] seek( Optional whence, Optional offset ) throws LuaException 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 28576f70d..27e1b7083 100644 --- a/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java +++ b/src/main/java/dan200/computercraft/core/apis/handles/EncodedReadableHandle.java @@ -50,6 +50,7 @@ public class EncodedReadableHandle extends HandleGeneric * @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. + * @cc.changed 1.81.0 Added option to return trailing newline. */ @LuaFunction public final Object[] readLine( Optional withTrailingArg ) throws LuaException @@ -116,6 +117,7 @@ public class EncodedReadableHandle extends HandleGeneric * @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. + * @cc.since 1.80pr1.4 */ @LuaFunction public final Object[] read( Optional countA ) throws LuaException 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 ffd895b0b..d5b1b18f2 100644 --- a/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java +++ b/src/main/java/dan200/computercraft/core/apis/http/NetworkUtils.java @@ -201,7 +201,7 @@ public final class NetworkUtils { return "Timed out"; } - else if( cause instanceof SSLHandshakeException || cause instanceof DecoderException && cause.getCause() instanceof SSLHandshakeException ) + else if( cause instanceof SSLHandshakeException || (cause instanceof DecoderException && cause.getCause() instanceof SSLHandshakeException) ) { return "Could not create a secure connection"; } 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 13365b453..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 @@ -75,7 +75,7 @@ public final class AddressRule if( this.port != null && this.port != port ) return false; return predicate.matches( domain ) || predicate.matches( address ) - || ipv4Address != null && predicate.matches( ipv4Address ); + || (ipv4Address != null && predicate.matches( ipv4Address )); } public static Options apply( Iterable rules, String domain, InetSocketAddress socketAddress ) 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 c5d72134b..4dcd82c9b 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 @@ -46,6 +46,7 @@ public class HttpResponseHandle implements ObjectSource * @return The response code and message. * @cc.treturn number The response code (i.e. 200) * @cc.treturn string The response message (i.e. "OK") + * @cc.changed 1.80pr1.13 Added response message return value. */ @LuaFunction public final Object[] getResponseCode() 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 0c74c0c9f..0901cc25e 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 @@ -55,6 +55,8 @@ public class WebsocketHandle implements Closeable * @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. + * @cc.changed 1.80pr1.13 Added return value indicating whether the message was binary. + * @cc.changed 1.87.0 Added timeout argument. */ @LuaFunction public final MethodResult receive( Optional timeout ) throws LuaException @@ -74,6 +76,7 @@ public class WebsocketHandle implements Closeable * @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. + * @cc.changed 1.81.0 Added argument for binary mode. */ @LuaFunction public final void send( Object message, Optional binary ) throws LuaException diff --git a/src/main/java/dan200/computercraft/core/asm/Generator.java b/src/main/java/dan200/computercraft/core/asm/Generator.java index e68732f95..4cd2d66cf 100644 --- a/src/main/java/dan200/computercraft/core/asm/Generator.java +++ b/src/main/java/dan200/computercraft/core/asm/Generator.java @@ -15,6 +15,7 @@ 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 dan200.computercraft.api.peripheral.PeripheralType; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Type; @@ -108,7 +109,7 @@ public final class Generator if( instance == null ) continue; if( methods == null ) methods = new ArrayList<>(); - addMethod( methods, method, annotation, instance ); + addMethod( methods, method, annotation, null, instance ); } for( GenericMethod method : GenericMethod.all() ) @@ -119,7 +120,7 @@ public final class Generator if( instance == null ) continue; if( methods == null ) methods = new ArrayList<>(); - addMethod( methods, method.method, method.annotation, instance ); + addMethod( methods, method.method, method.annotation, method.peripheralType, instance ); } if( methods == null ) return Collections.emptyList(); @@ -127,7 +128,7 @@ public final class Generator return Collections.unmodifiableList( methods ); } - private void addMethod( List> methods, Method method, LuaFunction annotation, T instance ) + private void addMethod( List> methods, Method method, LuaFunction annotation, PeripheralType genericType, T instance ) { if( annotation.mainThread() ) instance = wrap.apply( instance ); @@ -135,13 +136,13 @@ public final class Generator boolean isSimple = method.getReturnType() != MethodResult.class && !annotation.mainThread(); if( names.length == 0 ) { - methods.add( new NamedMethod<>( method.getName(), instance, isSimple ) ); + methods.add( new NamedMethod<>( method.getName(), instance, isSimple, genericType ) ); } else { for( String name : names ) { - methods.add( new NamedMethod<>( name, instance, isSimple ) ); + methods.add( new NamedMethod<>( name, instance, isSimple, genericType ) ); } } } diff --git a/src/main/java/dan200/computercraft/core/asm/GenericMethod.java b/src/main/java/dan200/computercraft/core/asm/GenericMethod.java index e0c916c2e..691d9b742 100644 --- a/src/main/java/dan200/computercraft/core/asm/GenericMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/GenericMethod.java @@ -8,6 +8,8 @@ package dan200.computercraft.core.asm; import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.GenericSource; import dan200.computercraft.api.lua.LuaFunction; +import dan200.computercraft.api.peripheral.GenericPeripheral; +import dan200.computercraft.api.peripheral.PeripheralType; import javax.annotation.Nonnull; import java.lang.reflect.Method; @@ -18,6 +20,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * A generic method is a method belonging to a {@link GenericSource} with a known target. @@ -27,15 +30,17 @@ public class GenericMethod final Method method; final LuaFunction annotation; final Class target; + final PeripheralType peripheralType; private static final List sources = new ArrayList<>(); private static List cache; - GenericMethod( Method method, LuaFunction annotation, Class target ) + GenericMethod( Method method, LuaFunction annotation, Class target, PeripheralType peripheralType ) { this.method = method; this.annotation = annotation; this.target = target; + this.peripheralType = peripheralType; } /** @@ -46,10 +51,28 @@ public class GenericMethod static List all() { if( cache != null ) return cache; - return cache = sources.stream() - .flatMap( x -> Arrays.stream( x.getClass().getDeclaredMethods() ) ) - .map( method -> - { + return cache = sources.stream().flatMap( GenericMethod::getMethods ).collect( Collectors.toList() ); + } + + public static synchronized void register( @Nonnull GenericSource source ) + { + Objects.requireNonNull( source, "Source cannot be null" ); + + if( cache != null ) + { + ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache ); + } + + sources.add( source ); + } + + private static Stream getMethods( GenericSource source ) + { + Class klass = source.getClass(); + PeripheralType type = source instanceof GenericPeripheral ? ((GenericPeripheral) source).getType() : null; + + return Arrays.stream( klass.getDeclaredMethods() ) + .map( method -> { LuaFunction annotation = method.getAnnotation( LuaFunction.class ); if( annotation == null ) return null; @@ -69,22 +92,8 @@ public class GenericMethod Class target = Reflect.getRawType( method, types[0], false ); if( target == null ) return null; - return new GenericMethod( method, annotation, target ); + return new GenericMethod( method, annotation, target, type ); } ) - .filter( Objects::nonNull ) - .collect( Collectors.toList() ); - } - - - public static synchronized void register( @Nonnull GenericSource source ) - { - Objects.requireNonNull( source, "Source cannot be null" ); - - if( cache != null ) - { - ComputerCraft.log.warn( "Registering a generic source {} after cache has been built. This source will be ignored.", cache ); - } - - sources.add( source ); + .filter( Objects::nonNull ); } } diff --git a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java index b0562835c..281ab9c56 100644 --- a/src/main/java/dan200/computercraft/core/asm/LuaMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/LuaMethod.java @@ -13,7 +13,7 @@ import java.util.Collections; public interface LuaMethod { Generator GENERATOR = new Generator<>( LuaMethod.class, Collections.singletonList( ILuaContext.class ), - m -> ( target, context, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, args ) ) ) + m -> ( target, context, args ) -> context.executeMainThreadTask( () -> ResultHelpers.checkNormalResult( m.apply( target, context, args ) ) ) ); IntCache DYNAMIC = new IntCache<>( diff --git a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java index ea72bb7a4..35d9c0a77 100644 --- a/src/main/java/dan200/computercraft/core/asm/NamedMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/NamedMethod.java @@ -5,7 +5,10 @@ */ package dan200.computercraft.core.asm; +import dan200.computercraft.api.peripheral.PeripheralType; + import javax.annotation.Nonnull; +import javax.annotation.Nullable; public final class NamedMethod { @@ -13,11 +16,14 @@ public final class NamedMethod private final T method; private final boolean nonYielding; - NamedMethod( String name, T method, boolean nonYielding ) + private final PeripheralType genericType; + + NamedMethod( String name, T method, boolean nonYielding, PeripheralType genericType ) { this.name = name; this.method = method; this.nonYielding = nonYielding; + this.genericType = genericType; } @Nonnull @@ -36,4 +42,10 @@ public final class NamedMethod { return nonYielding; } + + @Nullable + public PeripheralType getGenericType() + { + return genericType; + } } diff --git a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java index 38618442f..146896b04 100644 --- a/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java +++ b/src/main/java/dan200/computercraft/core/asm/PeripheralMethod.java @@ -18,7 +18,7 @@ import java.util.Arrays; public interface PeripheralMethod { Generator GENERATOR = new Generator<>( PeripheralMethod.class, Arrays.asList( ILuaContext.class, IComputerAccess.class ), - m -> ( target, context, computer, args ) -> TaskCallback.make( context, () -> TaskCallback.checkUnwrap( m.apply( target, context, computer, args ) ) ) + m -> ( target, context, computer, args ) -> context.executeMainThreadTask( () -> ResultHelpers.checkNormalResult( m.apply( target, context, computer, args ) ) ) ); IntCache DYNAMIC = new IntCache<>( diff --git a/src/main/java/dan200/computercraft/core/asm/ResultHelpers.java b/src/main/java/dan200/computercraft/core/asm/ResultHelpers.java new file mode 100644 index 000000000..7b9b464b2 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/asm/ResultHelpers.java @@ -0,0 +1,27 @@ +/* + * 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.asm; + +import dan200.computercraft.api.lua.MethodResult; + +final class ResultHelpers +{ + private ResultHelpers() + { + } + + static Object[] checkNormalResult( MethodResult result ) + { + 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( "Must return MethodResult.of from mainThread function." ); + } + + return result.getResult(); + } +} diff --git a/src/main/java/dan200/computercraft/core/computer/Environment.java b/src/main/java/dan200/computercraft/core/computer/Environment.java index ecc8aea80..3931629f1 100644 --- a/src/main/java/dan200/computercraft/core/computer/Environment.java +++ b/src/main/java/dan200/computercraft/core/computer/Environment.java @@ -309,9 +309,9 @@ public final class Environment implements IAPIEnvironment { int index = side.ordinal(); IPeripheral existing = peripherals[index]; - if( existing == null && peripheral != null || - existing != null && peripheral == null || - existing != null && !existing.equals( peripheral ) ) + if( (existing == null && peripheral != null) || + (existing != null && peripheral == null) || + (existing != null && !existing.equals( peripheral )) ) { peripherals[index] = peripheral; if( peripheralListener != null ) peripheralListener.onPeripheralChanged( side, peripheral ); diff --git a/src/main/java/dan200/computercraft/core/computer/MainThread.java b/src/main/java/dan200/computercraft/core/computer/MainThread.java index 8f53541e2..1c77e3692 100644 --- a/src/main/java/dan200/computercraft/core/computer/MainThread.java +++ b/src/main/java/dan200/computercraft/core/computer/MainThread.java @@ -93,7 +93,7 @@ public final class MainThread executor.updateTime(); // We're not currently on the queue, so update its current execution time to - // ensure its at least as high as the minimum. + // ensure it's at least as high as the minimum. long newRuntime = minimumTime; // Slow down new computers a little bit. diff --git a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java index 90566970e..d31757cda 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java +++ b/src/main/java/dan200/computercraft/core/filesystem/ResourceMount.java @@ -7,7 +7,6 @@ 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; @@ -15,10 +14,11 @@ import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.shared.util.IoUtil; import net.minecraft.ResourceLocationException; import net.minecraft.resources.ResourceLocation; -import net.minecraft.server.packs.resources.ReloadableResourceManager; +import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; -import net.minecraft.server.packs.resources.ResourceManagerReloadListener; +import net.minecraft.server.packs.resources.SimplePreparableReloadListener; +import net.minecraft.util.profiling.ProfilerFiller; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -27,7 +27,9 @@ import java.io.IOException; import java.io.InputStream; import java.nio.channels.Channels; import java.nio.channels.ReadableByteChannel; -import java.util.*; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; public final class ResourceMount implements IMount @@ -56,50 +58,37 @@ public final 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 static final Map MOUNT_CACHE = new HashMap<>( 2 ); private final String namespace; private final String subPath; - private final ReloadableResourceManager manager; + private ResourceManager manager; @Nullable private FileEntry root; - public static ResourceMount get( String namespace, String subPath, ReloadableResourceManager manager ) + public static ResourceMount get( String namespace, String subPath, ResourceManager manager ) { - Map cache; - + ResourceLocation path = new ResourceLocation( namespace, subPath ); 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 ) ); + ResourceMount mount = MOUNT_CACHE.get( path ); + if( mount == null ) MOUNT_CACHE.put( path, mount = new ResourceMount( namespace, subPath, manager ) ); return mount; } } - private ResourceMount( String namespace, String subPath, ReloadableResourceManager manager ) + private ResourceMount( String namespace, String subPath, ResourceManager manager ) { this.namespace = namespace; this.subPath = subPath; - this.manager = manager; - - Listener.INSTANCE.add( manager, this ); - if( root == null ) load(); + load( manager ); } - private void load() + private void load( ResourceManager manager ) { boolean hasAny = false; String existingNamespace = null; @@ -117,6 +106,7 @@ public final class ResourceMount implements IMount hasAny = true; } + this.manager = manager; root = hasAny ? newRoot : null; if( !hasAny ) @@ -292,28 +282,30 @@ public final class ResourceMount implements IMount } /** - * A {@link ResourceReloader} which reloads any associated mounts. - * - * While people should really be keeping a permanent reference to this, some people construct it every - * method call, so let's make this as small as possible. + * A {@link PreparableReloadListener} which reloads any associated mounts and correctly updates the resource manager + * they point to. */ - static class Listener implements ResourceManagerReloadListener + public static final SimplePreparableReloadListener RELOAD_LISTENER = new SimplePreparableReloadListener<>() { - private static final Listener INSTANCE = new Listener(); - - private final Set mounts = Collections.newSetFromMap( new WeakHashMap<>() ); - private final Set managers = Collections.newSetFromMap( new WeakHashMap<>() ); + @Nonnull + @Override + protected Void prepare( @Nonnull ResourceManager manager, @Nonnull ProfilerFiller profiler ) + { + profiler.push( "Reloading ComputerCraft mounts" ); + try + { + for( ResourceMount mount : MOUNT_CACHE.values() ) mount.load( manager ); + } + finally + { + profiler.pop(); + } + return null; + } @Override - public void onResourceManagerReload( @Nonnull ResourceManager manager ) + protected void apply( @Nonnull Void result, @Nonnull ResourceManager manager, @Nonnull ProfilerFiller profiler ) { - for( ResourceMount mount : mounts ) mount.load(); } - - synchronized void add( ReloadableResourceManager manager, ResourceMount mount ) - { - if( managers.add( manager ) ) manager.registerReloadListener( this ); - mounts.add( mount ); - } - } + }; } diff --git a/src/main/java/dan200/computercraft/core/lua/LuaContext.java b/src/main/java/dan200/computercraft/core/lua/LuaContext.java index 0e5c792c8..626d15fad 100644 --- a/src/main/java/dan200/computercraft/core/lua/LuaContext.java +++ b/src/main/java/dan200/computercraft/core/lua/LuaContext.java @@ -9,8 +9,6 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.lua.MethodResult; -import dan200.computercraft.core.asm.TaskCallback; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.MainThread; @@ -68,11 +66,4 @@ class LuaContext implements ILuaContext throw new LuaException( "Task limit exceeded" ); } } - - @Nonnull - @Override - public MethodResult executeMainThreadTask( @Nonnull ILuaTask task ) throws LuaException - { - return TaskCallback.make( this, task ); - } } diff --git a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java index 495d1a2d1..b2cbb021c 100644 --- a/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java +++ b/src/main/java/dan200/computercraft/core/lua/ResultInterpreterFunction.java @@ -24,7 +24,7 @@ class ResultInterpreterFunction extends ResumableVarArgFunction SKIP = new HashSet<>( Arrays.asList( + TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME, + TrackingField.SERVER_COUNT, TrackingField.SERVER_TIME + ) ); + + private static ComputerMBean instance; + + private final Map attributes = new HashMap<>(); + private final Map values = new HashMap<>(); + private final MBeanInfo info; + + private ComputerMBean() + { + List attributes = new ArrayList<>(); + for( Map.Entry field : TrackingField.fields().entrySet() ) + { + if( SKIP.contains( field.getValue() ) ) continue; + + String name = CaseFormat.LOWER_UNDERSCORE.to( CaseFormat.LOWER_CAMEL, field.getKey() ); + add( name, field.getValue(), attributes, null ); + } + + add( "task", TrackingField.TOTAL_TIME, attributes, TrackingField.TASKS ); + add( "serverTask", TrackingField.SERVER_TIME, attributes, TrackingField.SERVER_COUNT ); + + info = new MBeanInfo( + ComputerMBean.class.getSimpleName(), + "metrics about all computers on the server", + attributes.toArray( new MBeanAttributeInfo[0] ), null, null, null + ); + } + + public static void register() + { + try + { + ManagementFactory.getPlatformMBeanServer().registerMBean( instance = new ComputerMBean(), new ObjectName( "dan200.computercraft:type=Computers" ) ); + } + catch( InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException | MalformedObjectNameException e ) + { + ComputerCraft.log.warn( "Failed to register JMX bean", e ); + } + } + + public static void registerTracker() + { + if( instance != null ) Tracking.add( instance ); + } + + @Override + public Object getAttribute( String attribute ) throws AttributeNotFoundException + { + LongSupplier value = attributes.get( attribute ); + if( value == null ) throw new AttributeNotFoundException(); + return value.getAsLong(); + } + + @Override + public void setAttribute( Attribute attribute ) throws InvalidAttributeValueException + { + throw new InvalidAttributeValueException( "Cannot set attribute" ); + } + + @Override + public AttributeList getAttributes( String[] attributes ) + { + return null; + } + + @Override + public AttributeList setAttributes( AttributeList attributes ) + { + return new AttributeList(); + } + + @Override + public Object invoke( String actionName, Object[] params, String[] signature ) + { + return null; + } + + @Override + @Nonnull + public MBeanInfo getMBeanInfo() + { + return info; + } + + @Override + public void addTaskTiming( Computer computer, long time ) + { + addValue( computer, TrackingField.TOTAL_TIME, time ); + } + + @Override + public void addServerTiming( Computer computer, long time ) + { + addValue( computer, TrackingField.SERVER_TIME, time ); + } + + @Override + public void addValue( Computer computer, TrackingField field, long change ) + { + Counter counter = values.get( field ); + counter.value.addAndGet( change ); + counter.count.incrementAndGet(); + } + + private MBeanAttributeInfo addAttribute( String name, String description, LongSupplier value ) + { + attributes.put( name, value ); + return new MBeanAttributeInfo( name, "long", description, true, false, false ); + } + + private void add( String name, TrackingField field, List attributes, TrackingField count ) + { + Counter counter = new Counter(); + values.put( field, counter ); + + String prettyName = Language.getInstance().getOrDefault( field.translationKey() ); + attributes.add( addAttribute( name, prettyName, counter.value::longValue ) ); + if( count != null ) + { + String countName = Language.getInstance().getOrDefault( count.translationKey() ); + attributes.add( addAttribute( name + "Count", countName, counter.count::longValue ) ); + } + } + + private static class Counter + { + final AtomicLong value = new AtomicLong(); + final AtomicLong count = new AtomicLong(); + } +} 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 fec0609ae..e312c43ff 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/modem/ModemPeripheral.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem; import dan200.computercraft.api.lua.LuaException; @@ -28,9 +27,9 @@ import java.util.Set; */ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPacketReceiver { + private IPacketNetwork network; private final Set computers = new HashSet<>( 1 ); private final ModemState state; - private IPacketNetwork network; protected ModemPeripheral( ModemState state ) { @@ -42,6 +41,20 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return state; } + private synchronized void setNetwork( IPacketNetwork network ) + { + if( this.network == network ) return; + + // Leave old network + if( this.network != null ) this.network.removeReceiver( this ); + + // Set new network + this.network = network; + + // Join new network + if( this.network != null ) this.network.addReceiver( this ); + } + public void destroy() { setNetwork( null ); @@ -50,21 +63,14 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @Override public void receiveSameDimension( @Nonnull Packet packet, double distance ) { - if( packet.getSender() == this || !state.isOpen( packet.getChannel() ) ) - { - return; - } + if( packet.sender() == this || !state.isOpen( packet.channel() ) ) return; synchronized( computers ) { for( IComputerAccess computer : computers ) { computer.queueEvent( "modem_message", - computer.getAttachmentName(), - packet.getChannel(), - packet.getReplyChannel(), - packet.getPayload(), - distance ); + computer.getAttachmentName(), packet.channel(), packet.replyChannel(), packet.payload(), distance ); } } } @@ -72,20 +78,20 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa @Override public void receiveDifferentDimension( @Nonnull Packet packet ) { - if( packet.getSender() == this || !state.isOpen( packet.getChannel() ) ) - { - return; - } + if( packet.sender() == this || !state.isOpen( packet.channel() ) ) return; synchronized( computers ) { for( IComputerAccess computer : computers ) { - computer.queueEvent( "modem_message", computer.getAttachmentName(), packet.getChannel(), packet.getReplyChannel(), packet.getPayload() ); + computer.queueEvent( "modem_message", + computer.getAttachmentName(), packet.channel(), packet.replyChannel(), packet.payload() ); } } } + protected abstract IPacketNetwork getNetwork(); + @Nonnull @Override public String getType() @@ -93,60 +99,15 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return "modem"; } - @Override - public synchronized void attach( @Nonnull IComputerAccess computer ) + private static int parseChannel( int channel ) throws LuaException { - synchronized( computers ) - { - computers.add( computer ); - } - - setNetwork( getNetwork() ); - } - - protected abstract IPacketNetwork getNetwork(); - - private synchronized void setNetwork( IPacketNetwork network ) - { - if( this.network == network ) - { - return; - } - - // Leave old network - if( this.network != null ) - { - this.network.removeReceiver( this ); - } - - // Set new network - this.network = network; - - // Join new network - if( this.network != null ) - { - this.network.addReceiver( this ); - } - } - - @Override - public synchronized void detach( @Nonnull IComputerAccess computer ) - { - boolean empty; - synchronized( computers ) - { - computers.remove( computer ); - empty = computers.isEmpty(); - } - - if( empty ) - { - setNetwork( null ); - } + if( channel < 0 || channel > 65535 ) throw new LuaException( "Expected number in range 0-65535" ); + 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. + * 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. @@ -158,15 +119,6 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa state.open( parseChannel( channel ) ); } - private static int parseChannel( int channel ) throws LuaException - { - if( channel < 0 || channel > 65535 ) - { - throw new LuaException( "Expected number in range 0-65535" ); - } - return channel; - } - /** * Check if a channel is open. * @@ -202,13 +154,14 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa } /** - * Sends a modem message on a certain channel. Modems listening on the channel will queue a {@code modem_message} event on adjacent computers. + * 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. + * @param payload The object to send. This can be a boolean, string, number, or table. * @throws LuaException If the channel is out of range. */ @LuaFunction @@ -217,14 +170,11 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa parseChannel( channel ); parseChannel( replyChannel ); - Level world = getWorld(); + Level world = getLevel(); Vec3 position = getPosition(); IPacketNetwork network = this.network; - if( world == null || position == null || network == null ) - { - return; - } + if( world == null || position == null || network == null ) return; Packet packet = new Packet( channel, replyChannel, payload, this ); if( isInterdimensional() ) @@ -240,7 +190,8 @@ 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. + * 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. */ @@ -251,6 +202,30 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa return network != null && network.isWireless(); } + @Override + public synchronized void attach( @Nonnull IComputerAccess computer ) + { + synchronized( computers ) + { + computers.add( computer ); + } + + setNetwork( getNetwork() ); + } + + @Override + public synchronized void detach( @Nonnull IComputerAccess computer ) + { + boolean empty; + synchronized( computers ) + { + computers.remove( computer ); + empty = computers.isEmpty(); + } + + if( empty ) setNetwork( null ); + } + @Nonnull @Override public String getSenderID() @@ -263,8 +238,7 @@ public abstract class ModemPeripheral implements IPeripheral, IPacketSender, IPa } else { - IComputerAccess computer = 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 fefdf28c3..4c8c7ebb5 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 @@ -419,7 +419,7 @@ public class TileCable extends TileGeneric implements IPeripheralTile { @Nonnull @Override - public Level getWorld() + public Level getLevel() { return TileCable.this.getLevel(); } 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 11dd6ebfe..37de3790b 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 @@ -430,7 +430,7 @@ public class TileWiredModemFull extends TileGeneric implements IPeripheralTile @Nonnull @Override - public Level getWorld() + public Level getLevel() { return entity.getLevel(); } 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 aae60b894..6cf699655 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 @@ -122,9 +122,9 @@ public abstract class WiredModemPeripheral extends ModemPeripheral implements IW @Nonnull @Override - public Level getWorld() + public Level getLevel() { - return modem.getWorld(); + return modem.getLevel(); } /** 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 b1a3379e8..809fa0761 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 @@ -121,7 +121,7 @@ public class TileWirelessModem extends TileGeneric implements IPeripheralTile @Nonnull @Override - public Level getWorld() + public Level getLevel() { return entity.getLevel(); } 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 3f0ca47aa..07f685542 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 @@ -32,7 +32,7 @@ public abstract class WirelessModemPeripheral extends ModemPeripheral } else { - Level world = getWorld(); + Level world = getLevel(); if( world != null ) { Vec3 position = getPosition(); 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 7f3dcb35f..c1f06c922 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 @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.peripheral.modem.wireless; import dan200.computercraft.api.network.IPacketNetwork; @@ -20,14 +19,10 @@ import java.util.concurrent.ConcurrentHashMap; public class WirelessNetwork implements IPacketNetwork { private static WirelessNetwork universalNetwork = null; - private final Set receivers = Collections.newSetFromMap( new ConcurrentHashMap<>() ); public static WirelessNetwork getUniversal() { - if( universalNetwork == null ) - { - universalNetwork = new WirelessNetwork(); - } + if( universalNetwork == null ) universalNetwork = new WirelessNetwork(); return universalNetwork; } @@ -36,6 +31,8 @@ public class WirelessNetwork implements IPacketNetwork universalNetwork = null; } + private final Set receivers = Collections.newSetFromMap( new ConcurrentHashMap<>() ); + @Override public void addReceiver( @Nonnull IPacketReceiver receiver ) { @@ -50,40 +47,27 @@ public class WirelessNetwork implements IPacketNetwork receivers.remove( receiver ); } - @Override - public boolean isWireless() - { - return true; - } - @Override public void transmitSameDimension( @Nonnull Packet packet, double range ) { Objects.requireNonNull( packet, "packet cannot be null" ); - for( IPacketReceiver device : 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 : 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 ) { - IPacketSender sender = packet.getSender(); - if( receiver.getWorld() == sender.getWorld() ) + IPacketSender sender = packet.sender(); + if( receiver.getLevel() == sender.getLevel() ) { double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical - double distanceSq = receiver.getPosition() - .distanceToSqr( sender.getPosition() ); + double distanceSq = receiver.getPosition().distanceToSqr( sender.getPosition() ); if( interdimensional || receiver.isInterdimensional() || distanceSq <= receiveRange * receiveRange ) { receiver.receiveSameDimension( packet, Math.sqrt( distanceSq ) ); @@ -97,4 +81,10 @@ public class WirelessNetwork implements IPacketNetwork } } } + + @Override + public boolean isWireless() + { + return true; + } } 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 f13b41927..f31a7d14d 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java +++ b/src/main/java/dan200/computercraft/shared/pocket/peripherals/PocketModemPeripheral.java @@ -32,7 +32,7 @@ public class PocketModemPeripheral extends WirelessModemPeripheral @Nonnull @Override - public Level getWorld() + public Level getLevel() { return world; } diff --git a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java index 27de26e94..5e875d045 100644 --- a/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java +++ b/src/main/java/dan200/computercraft/shared/proxy/ComputerCraftProxyCommon.java @@ -28,7 +28,6 @@ import dan200.computercraft.shared.peripheral.generic.methods.InventoryMethods; import dan200.computercraft.shared.peripheral.modem.wired.BlockCable; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import dan200.computercraft.shared.turtle.FurnaceRefuelHandler; -import dan200.computercraft.shared.turtle.SignInspectHandler; import dan200.computercraft.shared.util.Config; import dan200.computercraft.shared.util.TickScheduler; import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; @@ -139,7 +138,6 @@ public final class ComputerCraftProxyCommon TurtleEvent.EVENT_BUS.register( FurnaceRefuelHandler.INSTANCE ); TurtleEvent.EVENT_BUS.register( new TurtlePermissions() ); - TurtleEvent.EVENT_BUS.register( new SignInspectHandler() ); } public static void registerLoot() diff --git a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java index ab02d655a..c8f3ad0a0 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java +++ b/src/main/java/dan200/computercraft/shared/turtle/FurnaceRefuelHandler.java @@ -51,7 +51,7 @@ public final class FurnaceRefuelHandler implements TurtleRefuelEvent.Handler if( !remainder.isEmpty() ) { WorldUtil.dropItemStack( remainder, - turtle.getWorld(), + turtle.getLevel(), turtle.getPosition(), turtle.getDirection() .getOpposite() ); diff --git a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java b/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java deleted file mode 100644 index 574274d97..000000000 --- a/src/main/java/dan200/computercraft/shared/turtle/SignInspectHandler.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.shared.turtle; - -import com.google.common.eventbus.Subscribe; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.SignBlockEntity; - -import java.util.HashMap; -import java.util.Map; - -public class SignInspectHandler -{ - @Subscribe - public void onTurtleInspect( TurtleBlockEvent.Inspect event ) - { - BlockEntity be = event.getWorld().getBlockEntity( event.getPos() ); - if( be instanceof SignBlockEntity ) - { - SignBlockEntity sbe = (SignBlockEntity) be; - Map textTable = new HashMap<>(); - for( int k = 0; k < 4; k++ ) - { - textTable.put( k + 1, sbe.getMessage( k, true ).getString() ); - } - event.getData().put( "text", textTable ); - } - } -} 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 79438be47..3da20374e 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -11,9 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleCommandResult; import dan200.computercraft.api.turtle.TurtleSide; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; -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; @@ -774,12 +771,6 @@ public class TurtleAPI implements ILuaAPI ? ItemData.fill( new HashMap<>(), stack ) : ItemData.fillBasicSafe( new HashMap<>(), stack ); - TurtleActionEvent event = new TurtleInspectItemEvent( turtle, stack, table, detailed ); - if( TurtleEvent.post( event ) ) - { - return new Object[] { false, event.getFailureMessage() }; - } - return new Object[] { table }; } } 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 d00fbdd03..57f7c76e5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -160,7 +160,7 @@ public class TurtleBrain implements ITurtleAccess public void update() { - Level world = getWorld(); + Level world = getLevel(); if( !world.isClientSide ) { // Advance movement @@ -187,7 +187,7 @@ public class TurtleBrain implements ITurtleAccess @Nonnull @Override - public Level getWorld() + public Level getLevel() { return owner.getLevel(); } @@ -202,13 +202,13 @@ public class TurtleBrain implements ITurtleAccess @Override public boolean teleportTo( @Nonnull Level world, @Nonnull BlockPos pos ) { - if( world.isClientSide || getWorld().isClientSide ) + if( world.isClientSide || getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot teleport on the client" ); } // Cache info about the old turtle (so we don't access this after we delete ourselves) - Level oldWorld = getWorld(); + Level oldWorld = getLevel(); TileTurtle oldOwner = owner; BlockPos oldPos = owner.getBlockPos(); BlockState oldBlock = owner.getBlockState(); @@ -341,7 +341,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void setSelectedSlot( int slot ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot set the slot on the client" ); } @@ -419,7 +419,7 @@ public class TurtleBrain implements ITurtleAccess @Override public boolean consumeFuel( int fuel ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot consume fuel on the client" ); } @@ -441,7 +441,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void addFuel( int fuel ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot add fuel on the client" ); } @@ -454,7 +454,7 @@ public class TurtleBrain implements ITurtleAccess @Override public MethodResult executeCommand( @Nonnull ITurtleCommand command ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot run commands on the client" ); } @@ -474,7 +474,7 @@ public class TurtleBrain implements ITurtleAccess @Override public void playAnimation( @Nonnull TurtleAnimation animation ) { - if( getWorld().isClientSide ) + if( getLevel().isClientSide ) { throw new UnsupportedOperationException( "Cannot play animations on the client" ); } @@ -646,7 +646,7 @@ public class TurtleBrain implements ITurtleAccess { if( animation != TurtleAnimation.NONE ) { - Level world = getWorld(); + Level world = getLevel(); if( ComputerCraft.turtlesCanPush ) { 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 c18fe8b44..d5acdc3d2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCompareCommand.java @@ -41,7 +41,7 @@ public class TurtleCompareCommand implements ITurtleCommand .getItem( turtle.getSelectedSlot() ); // Get stack representing thing in front - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); 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 80af2ff7e..ac7e7652d 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleCraftCommand.java @@ -33,7 +33,7 @@ public class TurtleCraftCommand implements ITurtleCommand { // Craft the item TurtleInventoryCrafting crafting = new TurtleInventoryCrafting( turtle ); - List results = crafting.doCrafting( turtle.getWorld(), limit ); + List results = crafting.doCrafting( turtle.getLevel(), limit ); if( results == null ) { return TurtleCommandResult.failure( "No matching recipes" ); @@ -45,7 +45,7 @@ public class TurtleCraftCommand implements ITurtleCommand ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); if( !remainder.isEmpty() ) { - WorldUtil.dropItemStack( remainder, turtle.getWorld(), turtle.getPosition(), turtle.getDirection() ); + WorldUtil.dropItemStack( remainder, turtle.getLevel(), turtle.getPosition(), turtle.getDirection() ); } } 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 b35416964..e422cbdb2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDetectCommand.java @@ -33,7 +33,7 @@ public class TurtleDetectCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); 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 81fc98340..a035ba148 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleDropCommand.java @@ -10,8 +10,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleEvent; -import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import dan200.computercraft.shared.util.WorldUtil; @@ -56,22 +54,13 @@ public class TurtleDropCommand implements ITurtleCommand } // Get inventory for thing in front - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); Direction side = direction.getOpposite(); Container inventory = InventoryUtil.getInventory( world, newPosition, side ); - // Fire the event, restoring the inventory and exiting if it is cancelled. - TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, oldPosition, direction ); - TurtleInventoryEvent.Drop event = new TurtleInventoryEvent.Drop( turtle, player, world, newPosition, inventory, stack ); - if( TurtleEvent.post( event ) ) - { - InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - if( inventory != null ) { // Drop the item into the inventory 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 e2bc8f065..b87bc201f 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleEquipCommand.java @@ -7,9 +7,6 @@ package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.*; -import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtleUpgrades; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; @@ -66,12 +63,6 @@ public class TurtleEquipCommand implements ITurtleCommand oldUpgradeStack = null; } - TurtleActionEvent event = new TurtleActionEvent( turtle, TurtleAction.EQUIP ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - // Do the swapping: if( newUpgradeStack != null ) { @@ -86,7 +77,7 @@ public class TurtleEquipCommand implements ITurtleCommand { // If there's no room for the items, drop them BlockPos position = turtle.getPosition(); - WorldUtil.dropItemStack( remainder, turtle.getWorld(), position, turtle.getDirection() ); + WorldUtil.dropItemStack( remainder, turtle.getLevel(), position, turtle.getDirection() ); } } turtle.setUpgrade( side, newUpgrade ); 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 f65811149..1dee94820 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleInspectCommand.java @@ -9,8 +9,6 @@ package dan200.computercraft.shared.turtle.core; 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 dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.peripheral.generic.data.BlockData; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; @@ -39,7 +37,7 @@ public class TurtleInspectCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if thing in front is air or not - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); @@ -51,14 +49,6 @@ public class TurtleInspectCommand implements ITurtleCommand Map table = BlockData.fill( new HashMap<>(), state ); - // 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 ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - return TurtleCommandResult.success( new Object[] { table } ); } 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 4d7092230..0d6956fae 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleMoveCommand.java @@ -11,8 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.core.BlockPos; @@ -45,7 +43,7 @@ public class TurtleMoveCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Check if we can move - Level oldWorld = turtle.getWorld(); + Level oldWorld = turtle.getLevel(); BlockPos oldPosition = turtle.getPosition(); BlockPos newPosition = oldPosition.relative( direction ); @@ -88,12 +86,6 @@ public class TurtleMoveCommand implements ITurtleCommand } } - TurtleBlockEvent.Move moveEvent = new TurtleBlockEvent.Move( turtle, turtlePlayer, oldWorld, newPosition ); - if( TurtleEvent.post( moveEvent ) ) - { - return TurtleCommandResult.failure( moveEvent.getFailureMessage() ); - } - // Check fuel level if( turtle.isFuelNeeded() && turtle.getFuelLevel() < 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 2d92ddd14..edf5d8181 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlaceCommand.java @@ -11,8 +11,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleBlockEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.DropConsumer; @@ -83,12 +81,6 @@ public class TurtlePlaceCommand implements ITurtleCommand .relative( direction ); TurtlePlayer turtlePlayer = createPlayer( turtle, playerPosition, direction ); - TurtleBlockEvent.Place place = new TurtleBlockEvent.Place( turtle, turtlePlayer, turtle.getWorld(), coordinates, stack ); - if( TurtleEvent.post( place ) ) - { - return TurtleCommandResult.failure( place.getFailureMessage() ); - } - // Do the deploying String[] errorMessage = new String[1]; ItemStack remainder = deploy( stack, turtle, turtlePlayer, direction, extraArguments, errorMessage ); @@ -221,7 +213,7 @@ public class TurtlePlaceCommand implements ITurtleCommand Object[] extraArguments, String[] outErrorMessage ) { // See if there is an entity present - final Level world = turtle.getWorld(); + final Level world = turtle.getLevel(); final BlockPos position = turtle.getPosition(); Vec3 turtlePos = turtlePlayer.position(); Vec3 rayDir = turtlePlayer.getViewVector( 1.0f ); @@ -324,7 +316,7 @@ public class TurtlePlaceCommand implements ITurtleCommand // Do the deploying (put everything in the players inventory) boolean placed = false; - BlockEntity existingTile = turtle.getWorld() + BlockEntity existingTile = turtle.getLevel() .getBlockEntity( position ); if( stackCopy.useOn( context ).consumesAction() ) @@ -335,7 +327,7 @@ public class TurtlePlaceCommand implements ITurtleCommand if( !placed && (item instanceof BucketItem || item instanceof BoatItem || item instanceof WaterLilyBlockItem || item instanceof BottleItem) ) { - InteractionResultHolder result = stackCopy.use( turtle.getWorld(), turtlePlayer, InteractionHand.MAIN_HAND ); + InteractionResultHolder result = stackCopy.use( turtle.getLevel(), turtlePlayer, InteractionHand.MAIN_HAND ); if( result.getResult() .consumesAction() && !ItemStack.matches( stack, result.getObject() ) ) { @@ -349,7 +341,7 @@ public class TurtlePlaceCommand implements ITurtleCommand { if( extraArguments != null && extraArguments.length >= 1 && extraArguments[0] instanceof String ) { - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockEntity tile = world.getBlockEntity( position ); if( tile == null || tile == existingTile ) { @@ -404,7 +396,7 @@ public class TurtlePlaceCommand implements ITurtleCommand private static boolean canDeployOnBlock( @Nonnull BlockPlaceContext context, ITurtleAccess turtle, TurtlePlayer player, BlockPos position, Direction side, boolean allowReplaceable, String[] outErrorMessage ) { - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); if( !world.isInWorldBounds( position ) || world.isEmptyBlock( position ) || (context.getItemInHand() .getItem() instanceof BlockItem && WorldUtil.isLiquidBlock( world, position )) ) 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 bb00bbedd..fc7830834 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtlePlayer.java @@ -48,7 +48,7 @@ public final class TurtlePlayer extends FakePlayer private static TurtlePlayer create( ITurtleAccess turtle ) { - ServerLevel world = (ServerLevel) turtle.getWorld(); + ServerLevel world = (ServerLevel) turtle.getLevel(); GameProfile profile = turtle.getOwningPlayer(); TurtlePlayer player = new TurtlePlayer( world, getProfile( profile ) ); @@ -96,7 +96,7 @@ public final class TurtlePlayer extends FakePlayer TurtleBrain brain = (TurtleBrain) access; TurtlePlayer player = brain.cachedPlayer; - if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getCommandSenderWorld() != access.getWorld() ) + if( player == null || player.getGameProfile() != getProfile( access.getOwningPlayer() ) || player.getCommandSenderWorld() != access.getLevel() ) { player = brain.cachedPlayer = create( brain ); } @@ -133,7 +133,7 @@ public final class TurtlePlayer extends FakePlayer ItemStack remainder = InventoryUtil.storeItems( stack, turtle.getItemHandler(), turtle.getSelectedSlot() ); if( !remainder.isEmpty() ) { - WorldUtil.dropItemStack( remainder, turtle.getWorld(), dropPosition, dropDirection ); + WorldUtil.dropItemStack( remainder, turtle.getLevel(), dropPosition, dropDirection ); } getInventory().setItem( i, ItemStack.EMPTY ); } 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 51a71febf..7a913666a 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleRefuelCommand.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.turtle.core; import dan200.computercraft.api.turtle.ITurtleAccess; @@ -30,27 +29,16 @@ public class TurtleRefuelCommand implements ITurtleCommand public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { int slot = turtle.getSelectedSlot(); - ItemStack stack = turtle.getInventory() - .getItem( slot ); - if( stack.isEmpty() ) - { - return TurtleCommandResult.failure( "No items to combust" ); - } + ItemStack stack = turtle.getInventory().getItem( slot ); + if( stack.isEmpty() ) return TurtleCommandResult.failure( "No items to combust" ); TurtleRefuelEvent event = new TurtleRefuelEvent( turtle, stack ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - if( event.getHandler() == null ) - { - return TurtleCommandResult.failure( "Items not combustible" ); - } + TurtleEvent.EVENT_BUS.post( event ); + if( event.getHandler() == null ) return TurtleCommandResult.failure( "Items not combustible" ); if( limit != 0 ) { - turtle.addFuel( event.getHandler() - .refuel( turtle, stack, slot, limit ) ); + turtle.addFuel( event.getHandler().refuel( turtle, stack, slot, limit ) ); turtle.playAnimation( TurtleAnimation.WAIT ); } 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 be448c095..54138dc99 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleSuckCommand.java @@ -10,8 +10,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleEvent; -import dan200.computercraft.api.turtle.event.TurtleInventoryEvent; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.ItemStorage; import net.minecraft.core.BlockPos; @@ -52,21 +50,13 @@ public class TurtleSuckCommand implements ITurtleCommand Direction direction = this.direction.toWorldDir( turtle ); // Get inventory for thing in front - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos turtlePosition = turtle.getPosition(); BlockPos blockPosition = turtlePosition.relative( direction ); Direction side = direction.getOpposite(); Container inventory = InventoryUtil.getInventory( world, blockPosition, side ); - // Fire the event, exiting if it is cancelled. - TurtlePlayer player = TurtlePlaceCommand.createPlayer( turtle, turtlePosition, direction ); - TurtleInventoryEvent.Suck event = new TurtleInventoryEvent.Suck( turtle, player, world, blockPosition, inventory ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - if( inventory != null ) { // Take from inventory of thing in front 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 add8d1fec..78c27ecf3 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleTurnCommand.java @@ -10,9 +10,6 @@ import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleAnimation; import dan200.computercraft.api.turtle.TurtleCommandResult; -import dan200.computercraft.api.turtle.event.TurtleAction; -import dan200.computercraft.api.turtle.event.TurtleActionEvent; -import dan200.computercraft.api.turtle.event.TurtleEvent; import javax.annotation.Nonnull; @@ -29,12 +26,6 @@ public class TurtleTurnCommand implements ITurtleCommand @Override public TurtleCommandResult execute( @Nonnull ITurtleAccess turtle ) { - TurtleActionEvent event = new TurtleActionEvent( turtle, TurtleAction.TURN ); - if( TurtleEvent.post( event ) ) - { - return TurtleCommandResult.failure( event.getFailureMessage() ); - } - switch( direction ) { case LEFT: 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 1c2d0189b..bfc6a5c00 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleInventoryCrafting.java @@ -3,7 +3,6 @@ * 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.turtle.ITurtleAccess; @@ -27,8 +26,8 @@ import java.util.List; public class TurtleInventoryCrafting extends CraftingContainer { private final ITurtleAccess turtle; - private int xStart; - private int yStart; + private int xStart = 0; + private int yStart = 0; @SuppressWarnings( "ConstantConditions" ) public TurtleInventoryCrafting( ITurtleAccess turtle ) @@ -37,8 +36,6 @@ public class TurtleInventoryCrafting extends CraftingContainer // avoid throwing any NPEs. super( null, 0, 0 ); this.turtle = turtle; - xStart = 0; - yStart = 0; } @Nullable @@ -52,11 +49,10 @@ public class TurtleInventoryCrafting extends CraftingContainer { for( int y = 0; y < TileTurtle.INVENTORY_HEIGHT; y++ ) { - if( x < this.xStart || x >= this.xStart + 3 || y < this.yStart || y >= this.yStart + 3 ) + if( x < this.xStart || x >= this.xStart + 3 || + y < this.yStart || y >= this.yStart + 3 ) { - if( !turtle.getInventory() - .getItem( x + y * TileTurtle.INVENTORY_WIDTH ) - .isEmpty() ) + if( !turtle.getInventory().getItem( x + y * TileTurtle.INVENTORY_WIDTH ).isEmpty() ) { return null; } @@ -65,44 +61,23 @@ public class TurtleInventoryCrafting extends CraftingContainer } // Check the actual crafting - return turtle.getWorld() - .getRecipeManager() - .getRecipeFor( RecipeType.CRAFTING, this, turtle.getWorld() ) - .orElse( null ); + return turtle.getLevel().getRecipeManager().getRecipeFor( RecipeType.CRAFTING, this, turtle.getLevel() ).orElse( null ); } @Nullable public List doCrafting( Level world, int maxCount ) { - if( world.isClientSide || !(world instanceof ServerLevel) ) - { - return null; - } + if( world.isClientSide || !(world instanceof ServerLevel) ) return null; // Find out what we can craft Recipe 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 ); - } - if( recipe == null ) - { - return null; - } + if( recipe == null ) recipe = tryCrafting( 0, 1 ); + if( recipe == null ) recipe = tryCrafting( 1, 0 ); + if( recipe == null ) recipe = tryCrafting( 1, 1 ); + if( recipe == null ) return null; // Special case: craft(0) just returns an empty list if crafting was possible - if( maxCount == 0 ) - { - return Collections.emptyList(); - } + if( maxCount == 0 ) return Collections.emptyList(); TurtlePlayer player = TurtlePlayer.get( turtle ); @@ -110,13 +85,11 @@ public class TurtleInventoryCrafting extends CraftingContainer for( int i = 0; i < maxCount && recipe.matches( this, world ); i++ ) { ItemStack result = recipe.assemble( this ); - if( result.isEmpty() ) - { - break; - } + if( result.isEmpty() ) break; results.add( result ); result.onCraftedBy( world, player, result.getCount() ); + NonNullList remainders = recipe.getRemainingItems( this ); for( int slot = 0; slot < remainders.size(); slot++ ) @@ -130,10 +103,7 @@ public class TurtleInventoryCrafting extends CraftingContainer existing = getItem( slot ); } - if( remainder.isEmpty() ) - { - continue; - } + if( remainder.isEmpty() ) continue; // Either update the current stack or add it to the remainder list (to be inserted into the inventory // afterwards). @@ -156,27 +126,12 @@ public class TurtleInventoryCrafting extends CraftingContainer return results; } - @Override - public int getMaxStackSize() - { - return turtle.getInventory() - .getMaxStackSize(); - } - @Override public int getWidth() { return 3; } - @Override - public boolean canPlaceItem( int i, @Nonnull ItemStack stack ) - { - i = modifyIndex( i ); - return turtle.getInventory() - .canPlaceItem( i, stack ); - } - @Override public int getHeight() { @@ -187,7 +142,9 @@ public class TurtleInventoryCrafting extends CraftingContainer { 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; + return x >= 0 && x < TileTurtle.INVENTORY_WIDTH && y >= 0 && y < TileTurtle.INVENTORY_HEIGHT + ? x + y * TileTurtle.INVENTORY_WIDTH + : -1; } // IInventory implementation @@ -203,8 +160,7 @@ public class TurtleInventoryCrafting extends CraftingContainer public ItemStack getItem( int i ) { i = modifyIndex( i ); - return turtle.getInventory() - .getItem( i ); + return turtle.getInventory().getItem( i ); } @Nonnull @@ -212,8 +168,7 @@ public class TurtleInventoryCrafting extends CraftingContainer public ItemStack removeItemNoUpdate( int i ) { i = modifyIndex( i ); - return turtle.getInventory() - .removeItemNoUpdate( i ); + return turtle.getInventory().removeItemNoUpdate( i ); } @Nonnull @@ -221,24 +176,26 @@ public class TurtleInventoryCrafting extends CraftingContainer public ItemStack removeItem( int i, int size ) { i = modifyIndex( i ); - return turtle.getInventory() - .removeItem( i, size ); + return turtle.getInventory().removeItem( i, size ); } @Override public void setItem( int i, @Nonnull ItemStack stack ) { i = modifyIndex( i ); - turtle.getInventory() - .setItem( i, stack ); + turtle.getInventory().setItem( i, stack ); } + @Override + public int getMaxStackSize() + { + return turtle.getInventory().getMaxStackSize(); + } @Override public void setChanged() { - turtle.getInventory() - .setChanged(); + turtle.getInventory().setChanged(); } @Override @@ -247,6 +204,12 @@ public class TurtleInventoryCrafting extends CraftingContainer return true; } + @Override + public boolean canPlaceItem( int i, @Nonnull ItemStack stack ) + { + i = modifyIndex( i ); + return turtle.getInventory().canPlaceItem( i, stack ); + } @Override public void clearContent() @@ -254,8 +217,7 @@ public class TurtleInventoryCrafting extends CraftingContainer for( int i = 0; i < getContainerSize(); i++ ) { int j = modifyIndex( i ); - 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 97a0851c9..74edc1935 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleModem.java @@ -100,7 +100,7 @@ public class TurtleModem extends AbstractTurtleUpgrade public void update( @Nonnull ITurtleAccess turtle, @Nonnull TurtleSide side ) { // Advance the modem - if( !turtle.getWorld().isClientSide ) + if( !turtle.getLevel().isClientSide ) { IPeripheral peripheral = turtle.getPeripheral( side ); if( peripheral instanceof Peripheral ) @@ -128,9 +128,9 @@ public class TurtleModem extends AbstractTurtleUpgrade @Nonnull @Override - public Level getWorld() + public Level getLevel() { - return turtle.getWorld(); + return turtle.getLevel(); } @Nonnull 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 bd35ecd90..e31884bed 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleSpeaker.java @@ -83,7 +83,7 @@ public class TurtleSpeaker extends AbstractTurtleUpgrade @Override public Level getWorld() { - return turtle.getWorld(); + return turtle.getLevel(); } @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 c25d9dbef..d18ff84a5 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java +++ b/src/main/java/dan200/computercraft/shared/turtle/upgrades/TurtleTool.java @@ -11,9 +11,6 @@ import com.mojang.math.Transformation; import dan200.computercraft.ComputerCraft; 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; -import dan200.computercraft.api.turtle.event.TurtleEvent; import dan200.computercraft.fabric.mixininterface.IMatrix4f; import dan200.computercraft.shared.TurtlePermissions; import dan200.computercraft.shared.turtle.core.TurtleBrain; @@ -114,7 +111,7 @@ public class TurtleTool extends AbstractTurtleUpgrade private TurtleCommandResult attack( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Create a fake player, and orient it appropriately - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos position = turtle.getPosition(); BlockEntity turtleBlock = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( position ); if( turtleBlock == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); @@ -144,12 +141,6 @@ public class TurtleTool extends AbstractTurtleUpgrade return TurtleCommandResult.failure( "Nothing to attack here" ); } - TurtleAttackEvent attackEvent = new TurtleAttackEvent( turtle, turtlePlayer, hitEntity, this, side ); - if( TurtleEvent.post( attackEvent ) ) - { - return TurtleCommandResult.failure( attackEvent.getFailureMessage() ); - } - // Start claiming entity drops DropConsumer.set( hitEntity, turtleDropConsumer( turtleBlock, turtle ) ); @@ -199,7 +190,7 @@ public class TurtleTool extends AbstractTurtleUpgrade private TurtleCommandResult dig( ITurtleAccess turtle, Direction direction, TurtleSide side ) { // Get ready to dig - Level world = turtle.getWorld(); + Level world = turtle.getLevel(); BlockPos turtlePosition = turtle.getPosition(); BlockEntity turtleBlock = turtle instanceof TurtleBrain ? ((TurtleBrain) turtle).getOwner() : world.getBlockEntity( turtlePosition ); if( turtleBlock == null ) return TurtleCommandResult.failure( "Turtle has vanished from existence." ); @@ -231,13 +222,6 @@ public class TurtleTool extends AbstractTurtleUpgrade return TurtleCommandResult.failure( "Unbreakable block detected" ); } - // Fire the dig event, checking whether it was cancelled. - TurtleBlockEvent.Dig digEvent = new TurtleBlockEvent.Dig( turtle, turtlePlayer, world, blockPosition, state, this, side ); - if( TurtleEvent.post( digEvent ) ) - { - return TurtleCommandResult.failure( digEvent.getFailureMessage() ); - } - if( !PlayerBlockBreakEvents.BEFORE.invoker().beforeBlockBreak( world, turtlePlayer, blockPosition, state, null ) ) { return TurtleCommandResult.failure( "Break cancelled" ); @@ -291,7 +275,7 @@ public class TurtleTool extends AbstractTurtleUpgrade for( ItemStack remainder : extra ) { WorldUtil.dropItemStack( remainder, - turtle.getWorld(), + turtle.getLevel(), turtle.getPosition(), direction ); } diff --git a/src/main/java/dan200/computercraft/shared/util/Config.java b/src/main/java/dan200/computercraft/shared/util/Config.java index 0fc7fc4a6..1f46afc71 100644 --- a/src/main/java/dan200/computercraft/shared/util/Config.java +++ b/src/main/java/dan200/computercraft/shared/util/Config.java @@ -13,7 +13,6 @@ import com.electronwill.nightconfig.core.file.FileNotFoundAction; 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.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRuleConfig; import dan200.computercraft.fabric.mixin.LevelResourceAccess; @@ -25,7 +24,10 @@ import net.minecraft.world.level.storage.LevelResource; import java.nio.file.Files; import java.nio.file.Path; -import java.util.*; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -208,10 +210,6 @@ public final class Config serverSpec.comment( "turtle.can_push", "If set to true, Turtles will push entities out of the way instead of stopping if there is space to do so" ); serverSpec.define( "turtle.can_push", ComputerCraft.turtlesCanPush ); - - serverSpec.comment( "turtle.disabled_actions", - "A list of turtle actions which are disabled." ); - serverSpec.defineList( "turtle.disabled_actions", Collections.emptyList(), x -> x instanceof String && getAction( (String) x ) != null ); } { // Terminal sizes @@ -372,12 +370,6 @@ public final class Config ComputerCraft.turtlesObeyBlockProtection = serverConfig.get( "turtle.obey_block_protection" ); ComputerCraft.turtlesCanPush = serverConfig.get( "turtle.can_push" ); - ComputerCraft.turtleDisabledActions.clear(); - for( String value : serverConfig.>get( "turtle.disabled_actions" ) ) - { - ComputerCraft.turtleDisabledActions.add( getAction( value ) ); - } - // Terminal Size ComputerCraft.computerTermWidth = serverConfig.get( "term_sizes.computer.width" ); ComputerCraft.computerTermHeight = serverConfig.get( "term_sizes.computer.height" ); @@ -397,16 +389,4 @@ public final class Config } private static final Converter converter = CaseFormat.LOWER_CAMEL.converterTo( CaseFormat.UPPER_UNDERSCORE ); - - private static TurtleAction getAction( String value ) - { - try - { - return TurtleAction.valueOf( converter.convert( value ) ); - } - catch( IllegalArgumentException e ) - { - return null; - } - } } diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java index 558de86ca..34db6a87f 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNetwork.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import com.google.common.collect.ImmutableMap; @@ -36,21 +35,299 @@ public final class WiredNetwork implements IWiredNetwork this.nodes = nodes; } + @Override + public boolean connect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) + { + WiredNode wiredU = checkNode( nodeU ); + WiredNode wiredV = checkNode( nodeV ); + if( nodeU == nodeV ) throw new IllegalArgumentException( "Cannot add a connection to oneself." ); + + lock.writeLock().lock(); + try + { + if( nodes == null ) throw new IllegalStateException( "Cannot add a connection to an empty network." ); + + boolean hasU = wiredU.network == this; + boolean hasV = wiredV.network == this; + if( !hasU && !hasV ) throw new IllegalArgumentException( "Neither node is in the network." ); + + // We're going to assimilate a node. Copy across all edges and vertices. + if( !hasU || !hasV ) + { + WiredNetwork other = hasU ? wiredV.network : wiredU.network; + other.lock.writeLock().lock(); + try + { + // Cache several properties for iterating over later + Map otherPeripherals = other.peripherals; + Map thisPeripherals = otherPeripherals.isEmpty() ? peripherals : new HashMap<>( peripherals ); + + Collection thisNodes = otherPeripherals.isEmpty() ? nodes : new ArrayList<>( nodes ); + Collection otherNodes = other.nodes; + + // Move all nodes across into this network, destroying the original nodes. + nodes.addAll( otherNodes ); + for( WiredNode node : otherNodes ) node.network = this; + other.nodes = null; + + // Move all peripherals across, + other.peripherals = null; + peripherals.putAll( otherPeripherals ); + + if( !thisPeripherals.isEmpty() ) + { + WiredNetworkChange.added( thisPeripherals ).broadcast( otherNodes ); + } + + if( !otherPeripherals.isEmpty() ) + { + WiredNetworkChange.added( otherPeripherals ).broadcast( thisNodes ); + } + } + finally + { + other.lock.writeLock().unlock(); + } + } + + boolean added = wiredU.neighbours.add( wiredV ); + if( added ) wiredV.neighbours.add( wiredU ); + + InvariantChecker.checkNetwork( this ); + InvariantChecker.checkNode( wiredU ); + InvariantChecker.checkNode( wiredV ); + + return added; + } + finally + { + lock.writeLock().unlock(); + } + } + + @Override + public boolean disconnect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) + { + WiredNode wiredU = checkNode( nodeU ); + WiredNode wiredV = checkNode( nodeV ); + if( nodeU == nodeV ) throw new IllegalArgumentException( "Cannot remove a connection to oneself." ); + + lock.writeLock().lock(); + try + { + boolean hasU = wiredU.network == this; + boolean hasV = wiredV.network == this; + if( !hasU || !hasV ) throw new IllegalArgumentException( "One node is not in the network." ); + + // If there was no connection to remove then split. + if( !wiredU.neighbours.remove( wiredV ) ) return false; + wiredV.neighbours.remove( wiredU ); + + // Determine if there is still some connection from u to v. + // Note this is an inlining of reachableNodes which short-circuits + // if all nodes are reachable. + Queue enqueued = new ArrayDeque<>(); + HashSet reachableU = new HashSet<>(); + + reachableU.add( wiredU ); + enqueued.add( wiredU ); + + while( !enqueued.isEmpty() ) + { + WiredNode node = enqueued.remove(); + for( WiredNode neighbour : node.neighbours ) + { + // If we can reach wiredV from wiredU then abort. + if( neighbour == wiredV ) return true; + + // Otherwise attempt to enqueue this neighbour as well. + if( reachableU.add( neighbour ) ) enqueued.add( neighbour ); + } + } + + // Create a new network with all U-reachable nodes/edges and remove them + // from the existing graph. + WiredNetwork networkU = new WiredNetwork( reachableU ); + networkU.lock.writeLock().lock(); + try + { + // Remove nodes from this network + nodes.removeAll( reachableU ); + + // Set network and transfer peripherals + for( WiredNode node : reachableU ) + { + node.network = networkU; + networkU.peripherals.putAll( node.peripherals ); + peripherals.keySet().removeAll( node.peripherals.keySet() ); + } + + // Broadcast changes + if( !peripherals.isEmpty() ) WiredNetworkChange.removed( peripherals ).broadcast( networkU.nodes ); + if( !networkU.peripherals.isEmpty() ) + { + WiredNetworkChange.removed( networkU.peripherals ).broadcast( nodes ); + } + + InvariantChecker.checkNetwork( this ); + InvariantChecker.checkNetwork( networkU ); + InvariantChecker.checkNode( wiredU ); + InvariantChecker.checkNode( wiredV ); + + return true; + } + finally + { + networkU.lock.writeLock().unlock(); + } + } + finally + { + lock.writeLock().unlock(); + } + } + + @Override + public boolean remove( @Nonnull IWiredNode node ) + { + WiredNode wired = checkNode( node ); + + lock.writeLock().lock(); + try + { + // If we're the empty graph then just abort: nodes must have _some_ network. + if( nodes == null ) return false; + if( nodes.size() <= 1 ) return false; + if( wired.network != this ) return false; + + HashSet neighbours = wired.neighbours; + + // Remove this node and move into a separate network. + nodes.remove( wired ); + for( WiredNode neighbour : neighbours ) neighbour.neighbours.remove( wired ); + + WiredNetwork wiredNetwork = new WiredNetwork( wired ); + + // If we're a leaf node in the graph (only one neighbour) then we don't need to + // check for network splitting + if( neighbours.size() == 1 ) + { + // Broadcast our simple peripheral changes + removeSingleNode( wired, wiredNetwork ); + InvariantChecker.checkNode( wired ); + InvariantChecker.checkNetwork( wiredNetwork ); + return true; + } + + HashSet reachable = reachableNodes( neighbours.iterator().next() ); + + // If all nodes are reachable then exit. + if( reachable.size() == nodes.size() ) + { + // Broadcast our simple peripheral changes + removeSingleNode( wired, wiredNetwork ); + InvariantChecker.checkNode( wired ); + InvariantChecker.checkNetwork( wiredNetwork ); + return true; + } + + // A split may cause 2..neighbours.size() separate networks, so we + // iterate through our neighbour list, generating child networks. + neighbours.removeAll( reachable ); + ArrayList maximals = new ArrayList<>( neighbours.size() + 1 ); + maximals.add( wiredNetwork ); + maximals.add( new WiredNetwork( reachable ) ); + + while( !neighbours.isEmpty() ) + { + reachable = reachableNodes( neighbours.iterator().next() ); + neighbours.removeAll( reachable ); + maximals.add( new WiredNetwork( reachable ) ); + } + + for( WiredNetwork network : maximals ) network.lock.writeLock().lock(); + + try + { + // We special case the original node: detaching all peripherals when needed. + wired.network = wiredNetwork; + wired.peripherals = Collections.emptyMap(); + + // Ensure every network is finalised + for( WiredNetwork network : maximals ) + { + for( WiredNode child : network.nodes ) + { + child.network = network; + network.peripherals.putAll( child.peripherals ); + } + } + + for( WiredNetwork network : maximals ) InvariantChecker.checkNetwork( network ); + InvariantChecker.checkNode( wired ); + + // Then broadcast network changes once all nodes are finalised + for( WiredNetwork network : maximals ) + { + WiredNetworkChange.changeOf( peripherals, network.peripherals ).broadcast( network.nodes ); + } + } + finally + { + for( WiredNetwork network : maximals ) network.lock.writeLock().unlock(); + } + + nodes.clear(); + peripherals.clear(); + + return true; + } + finally + { + lock.writeLock().unlock(); + } + } + + @Override + public void updatePeripherals( @Nonnull IWiredNode node, @Nonnull Map newPeripherals ) + { + WiredNode wired = checkNode( node ); + Objects.requireNonNull( peripherals, "peripherals cannot be null" ); + + lock.writeLock().lock(); + try + { + if( wired.network != this ) throw new IllegalStateException( "Node is not on this network" ); + + Map oldPeripherals = wired.peripherals; + WiredNetworkChange change = WiredNetworkChange.changeOf( oldPeripherals, newPeripherals ); + if( change.isEmpty() ) return; + + wired.peripherals = ImmutableMap.copyOf( newPeripherals ); + + // Detach the old peripherals then remove them. + peripherals.keySet().removeAll( change.peripheralsRemoved().keySet() ); + + // Add the new peripherals and attach them + peripherals.putAll( change.peripheralsAdded() ); + + change.broadcast( nodes ); + } + finally + { + lock.writeLock().unlock(); + } + } + static void transmitPacket( WiredNode start, Packet packet, double range, boolean interdimensional ) { Map points = new HashMap<>(); TreeSet transmitTo = new TreeSet<>(); { - TransmitPoint startEntry = start.element.getWorld() != packet.getSender() - .getWorld() ? new TransmitPoint( start, - Double.POSITIVE_INFINITY, - true ) : new TransmitPoint( start, - start.element.getPosition() - .distanceTo( - packet.getSender() - .getPosition() ), - false ); + TransmitPoint startEntry = start.element.getLevel() != packet.sender().getLevel() + ? new TransmitPoint( start, Double.POSITIVE_INFINITY, true ) + : new TransmitPoint( start, start.element.getPosition().distanceTo( packet.sender().getPosition() ), false ); points.put( start, startEntry ); transmitTo.add( startEntry ); } @@ -59,7 +336,7 @@ public final class WiredNetwork implements IWiredNetwork TransmitPoint point; while( (point = transmitTo.pollFirst()) != null ) { - Level world = point.node.element.getWorld(); + Level world = point.node.element.getLevel(); Vec3 position = point.node.element.getPosition(); for( WiredNode neighbour : point.node.neighbours ) { @@ -67,7 +344,7 @@ public final class WiredNetwork implements IWiredNetwork boolean newInterdimensional; double newDistance; - if( world != neighbour.element.getWorld() ) + if( world != neighbour.element.getLevel() ) { newInterdimensional = true; newDistance = Double.POSITIVE_INFINITY; @@ -101,378 +378,9 @@ public final class WiredNetwork implements IWiredNetwork } } - @Override - public boolean connect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) - { - WiredNode wiredU = checkNode( nodeU ); - WiredNode wiredV = checkNode( nodeV ); - if( nodeU == nodeV ) - { - throw new IllegalArgumentException( "Cannot add a connection to oneself." ); - } - - lock.writeLock() - .lock(); - try - { - if( nodes == null ) - { - throw new IllegalStateException( "Cannot add a connection to an empty network." ); - } - - boolean hasU = wiredU.network == this; - boolean hasV = wiredV.network == this; - if( !hasU && !hasV ) - { - throw new IllegalArgumentException( "Neither node is in the network." ); - } - - // We're going to assimilate a node. Copy across all edges and vertices. - if( !hasU || !hasV ) - { - WiredNetwork other = hasU ? wiredV.network : wiredU.network; - other.lock.writeLock() - .lock(); - try - { - // Cache several properties for iterating over later - Map otherPeripherals = other.peripherals; - Map thisPeripherals = otherPeripherals.isEmpty() ? peripherals : new HashMap<>( peripherals ); - - Collection thisNodes = otherPeripherals.isEmpty() ? nodes : new ArrayList<>( nodes ); - Collection otherNodes = other.nodes; - - // Move all nodes across into this network, destroying the original nodes. - nodes.addAll( otherNodes ); - for( WiredNode node : otherNodes ) - { - node.network = this; - } - other.nodes = null; - - // Move all peripherals across, - other.peripherals = null; - peripherals.putAll( otherPeripherals ); - - if( !thisPeripherals.isEmpty() ) - { - WiredNetworkChange.added( thisPeripherals ) - .broadcast( otherNodes ); - } - - if( !otherPeripherals.isEmpty() ) - { - WiredNetworkChange.added( otherPeripherals ) - .broadcast( thisNodes ); - } - } - finally - { - other.lock.writeLock() - .unlock(); - } - } - - boolean added = wiredU.neighbours.add( wiredV ); - if( added ) - { - wiredV.neighbours.add( wiredU ); - } - - InvariantChecker.checkNetwork( this ); - InvariantChecker.checkNode( wiredU ); - InvariantChecker.checkNode( wiredV ); - - return added; - } - finally - { - lock.writeLock() - .unlock(); - } - } - - @Override - public boolean disconnect( @Nonnull IWiredNode nodeU, @Nonnull IWiredNode nodeV ) - { - WiredNode wiredU = checkNode( nodeU ); - WiredNode wiredV = checkNode( nodeV ); - if( nodeU == nodeV ) - { - throw new IllegalArgumentException( "Cannot remove a connection to oneself." ); - } - - lock.writeLock() - .lock(); - try - { - boolean hasU = wiredU.network == this; - boolean hasV = wiredV.network == this; - if( !hasU || !hasV ) - { - throw new IllegalArgumentException( "One node is not in the network." ); - } - - // If there was no connection to remove then split. - if( !wiredU.neighbours.remove( wiredV ) ) - { - return false; - } - wiredV.neighbours.remove( wiredU ); - - // Determine if there is still some connection from u to v. - // Note this is an inlining of reachableNodes which short-circuits - // if all nodes are reachable. - Queue enqueued = new ArrayDeque<>(); - HashSet reachableU = new HashSet<>(); - - reachableU.add( wiredU ); - enqueued.add( wiredU ); - - while( !enqueued.isEmpty() ) - { - WiredNode node = enqueued.remove(); - for( WiredNode neighbour : node.neighbours ) - { - // If we can reach wiredV from wiredU then abort. - if( neighbour == wiredV ) - { - return true; - } - - // Otherwise attempt to enqueue this neighbour as well. - if( reachableU.add( neighbour ) ) - { - enqueued.add( neighbour ); - } - } - } - - // Create a new network with all U-reachable nodes/edges and remove them - // from the existing graph. - WiredNetwork networkU = new WiredNetwork( reachableU ); - networkU.lock.writeLock() - .lock(); - try - { - // Remove nodes from this network - nodes.removeAll( reachableU ); - - // Set network and transfer peripherals - for( WiredNode node : reachableU ) - { - node.network = networkU; - networkU.peripherals.putAll( node.peripherals ); - peripherals.keySet() - .removeAll( node.peripherals.keySet() ); - } - - // Broadcast changes - if( !peripherals.isEmpty() ) - { - WiredNetworkChange.removed( peripherals ) - .broadcast( networkU.nodes ); - } - if( !networkU.peripherals.isEmpty() ) - { - WiredNetworkChange.removed( networkU.peripherals ) - .broadcast( nodes ); - } - - InvariantChecker.checkNetwork( this ); - InvariantChecker.checkNetwork( networkU ); - InvariantChecker.checkNode( wiredU ); - InvariantChecker.checkNode( wiredV ); - - return true; - } - finally - { - networkU.lock.writeLock() - .unlock(); - } - } - finally - { - lock.writeLock() - .unlock(); - } - } - - @Override - public boolean remove( @Nonnull IWiredNode node ) - { - WiredNode wired = checkNode( node ); - - lock.writeLock() - .lock(); - try - { - // If we're the empty graph then just abort: nodes must have _some_ network. - if( nodes == null ) - { - return false; - } - if( nodes.size() <= 1 ) - { - return false; - } - if( wired.network != this ) - { - return false; - } - - HashSet neighbours = wired.neighbours; - - // Remove this node and move into a separate network. - nodes.remove( wired ); - for( WiredNode neighbour : neighbours ) - { - neighbour.neighbours.remove( wired ); - } - - WiredNetwork wiredNetwork = new WiredNetwork( wired ); - - // If we're a leaf node in the graph (only one neighbour) then we don't need to - // check for network splitting - if( neighbours.size() == 1 ) - { - // Broadcast our simple peripheral changes - removeSingleNode( wired, wiredNetwork ); - InvariantChecker.checkNode( wired ); - InvariantChecker.checkNetwork( wiredNetwork ); - return true; - } - - HashSet reachable = reachableNodes( neighbours.iterator() - .next() ); - - // If all nodes are reachable then exit. - if( reachable.size() == nodes.size() ) - { - // Broadcast our simple peripheral changes - removeSingleNode( wired, wiredNetwork ); - InvariantChecker.checkNode( wired ); - InvariantChecker.checkNetwork( wiredNetwork ); - return true; - } - - // A split may cause 2..neighbours.size() separate networks, so we - // iterate through our neighbour list, generating child networks. - neighbours.removeAll( reachable ); - ArrayList maximals = new ArrayList<>( neighbours.size() + 1 ); - maximals.add( wiredNetwork ); - maximals.add( new WiredNetwork( reachable ) ); - - while( !neighbours.isEmpty() ) - { - reachable = reachableNodes( neighbours.iterator() - .next() ); - neighbours.removeAll( reachable ); - maximals.add( new WiredNetwork( reachable ) ); - } - - for( WiredNetwork network : maximals ) - { - network.lock.writeLock() - .lock(); - } - - try - { - // We special case the original node: detaching all peripherals when needed. - wired.network = wiredNetwork; - wired.peripherals = Collections.emptyMap(); - - // Ensure every network is finalised - for( WiredNetwork network : maximals ) - { - for( WiredNode child : network.nodes ) - { - child.network = network; - network.peripherals.putAll( child.peripherals ); - } - } - - for( WiredNetwork network : maximals ) - { - InvariantChecker.checkNetwork( network ); - } - InvariantChecker.checkNode( wired ); - - // Then broadcast network changes once all nodes are finalised - for( WiredNetwork network : maximals ) - { - WiredNetworkChange.changeOf( peripherals, network.peripherals ) - .broadcast( network.nodes ); - } - } - finally - { - for( WiredNetwork network : maximals ) - { - network.lock.writeLock() - .unlock(); - } - } - - nodes.clear(); - peripherals.clear(); - - return true; - } - finally - { - lock.writeLock() - .unlock(); - } - } - - @Override - public void updatePeripherals( @Nonnull IWiredNode node, @Nonnull Map newPeripherals ) - { - WiredNode wired = checkNode( node ); - Objects.requireNonNull( peripherals, "peripherals cannot be null" ); - - lock.writeLock() - .lock(); - try - { - if( wired.network != this ) - { - throw new IllegalStateException( "Node is not on this network" ); - } - - Map oldPeripherals = wired.peripherals; - WiredNetworkChange change = WiredNetworkChange.changeOf( oldPeripherals, newPeripherals ); - if( change.isEmpty() ) - { - return; - } - - wired.peripherals = ImmutableMap.copyOf( newPeripherals ); - - // Detach the old peripherals then remove them. - peripherals.keySet() - .removeAll( change.peripheralsRemoved() - .keySet() ); - - // Add the new peripherals and attach them - peripherals.putAll( change.peripheralsAdded() ); - - change.broadcast( nodes ); - } - finally - { - lock.writeLock() - .unlock(); - } - } - private void removeSingleNode( WiredNode wired, WiredNetwork wiredNetwork ) { - wiredNetwork.lock.writeLock() - .lock(); + wiredNetwork.lock.writeLock().lock(); try { // Cache all the old nodes. @@ -485,62 +393,16 @@ public final class WiredNetwork implements IWiredNetwork wired.peripherals = Collections.emptyMap(); // Broadcast the change - if( !peripherals.isEmpty() ) - { - WiredNetworkChange.removed( peripherals ) - .broadcast( wired ); - } + if( !peripherals.isEmpty() ) WiredNetworkChange.removed( peripherals ).broadcast( wired ); // Now remove all peripherals from this network and broadcast the change. - peripherals.keySet() - .removeAll( wiredPeripherals.keySet() ); - if( !wiredPeripherals.isEmpty() ) - { - WiredNetworkChange.removed( wiredPeripherals ) - .broadcast( nodes ); - } + peripherals.keySet().removeAll( wiredPeripherals.keySet() ); + if( !wiredPeripherals.isEmpty() ) WiredNetworkChange.removed( wiredPeripherals ).broadcast( nodes ); } finally { - wiredNetwork.lock.writeLock() - .unlock(); - } - } - - private static HashSet reachableNodes( WiredNode start ) - { - Queue enqueued = new ArrayDeque<>(); - HashSet reachable = new HashSet<>(); - - reachable.add( start ); - enqueued.add( start ); - - WiredNode node; - while( (node = enqueued.poll()) != null ) - { - for( WiredNode neighbour : node.neighbours ) - { - // Otherwise attempt to enqueue this neighbour as well. - if( reachable.add( neighbour ) ) - { - enqueued.add( neighbour ); - } - } - } - - return reachable; - } - - private static WiredNode checkNode( IWiredNode node ) - { - if( node instanceof WiredNode ) - { - return (WiredNode) node; - } - else - { - throw new IllegalArgumentException( "Unknown implementation of IWiredNode: " + node ); + wiredNetwork.lock.writeLock().unlock(); } } @@ -561,7 +423,42 @@ public final class WiredNetwork implements IWiredNetwork public int compareTo( @Nonnull TransmitPoint o ) { // Objects with the same distance are not the same object, so we must add an additional layer of ordering. - return distance == o.distance ? Integer.compare( node.hashCode(), o.node.hashCode() ) : Double.compare( distance, o.distance ); + return distance == o.distance + ? Integer.compare( node.hashCode(), o.node.hashCode() ) + : Double.compare( distance, o.distance ); } } + + private static WiredNode checkNode( IWiredNode node ) + { + if( node instanceof WiredNode ) + { + return (WiredNode) node; + } + else + { + throw new IllegalArgumentException( "Unknown implementation of IWiredNode: " + node ); + } + } + + private static HashSet reachableNodes( WiredNode start ) + { + Queue enqueued = new ArrayDeque<>(); + HashSet reachable = new HashSet<>(); + + reachable.add( start ); + enqueued.add( start ); + + WiredNode node; + while( (node = enqueued.poll()) != null ) + { + for( WiredNode neighbour : node.neighbours ) + { + // Otherwise attempt to enqueue this neighbour as well. + if( reachable.add( neighbour ) ) enqueued.add( neighbour ); + } + } + + return reachable; + } } diff --git a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java index 03cd63820..c6426ca18 100644 --- a/src/main/java/dan200/computercraft/shared/wired/WiredNode.java +++ b/src/main/java/dan200/computercraft/shared/wired/WiredNode.java @@ -3,7 +3,6 @@ * Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ - package dan200.computercraft.shared.wired; import dan200.computercraft.api.network.IPacketReceiver; @@ -20,12 +19,14 @@ import java.util.concurrent.locks.Lock; public final class WiredNode implements IWiredNode { - final IWiredElement element; - final HashSet neighbours = new HashSet<>(); - Map peripherals = Collections.emptyMap(); - volatile WiredNetwork network; private Set receivers; + final IWiredElement element; + Map peripherals = Collections.emptyMap(); + + final HashSet neighbours = new HashSet<>(); + volatile WiredNetwork network; + public WiredNode( IWiredElement element ) { this.element = element; @@ -35,19 +36,37 @@ public final class WiredNode implements IWiredNode @Override public synchronized void addReceiver( @Nonnull IPacketReceiver receiver ) { - if( receivers == null ) - { - receivers = new HashSet<>(); - } + if( receivers == null ) receivers = new HashSet<>(); receivers.add( receiver ); } @Override public synchronized void removeReceiver( @Nonnull IPacketReceiver receiver ) { - if( receivers != null ) + if( receivers != null ) receivers.remove( receiver ); + } + + synchronized void tryTransmit( Packet packet, double packetDistance, boolean packetInterdimensional, double range, boolean interdimensional ) + { + if( receivers == null ) return; + + for( IPacketReceiver receiver : receivers ) { - receivers.remove( receiver ); + if( !packetInterdimensional ) + { + double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical + if( interdimensional || receiver.isInterdimensional() || packetDistance < receiveRange ) + { + receiver.receiveSameDimension( packet, packetDistance + element.getPosition().distanceTo( receiver.getPosition() ) ); + } + } + else + { + if( interdimensional || receiver.isInterdimensional() ) + { + receiver.receiveDifferentDimension( packet ); + } + } } } @@ -61,7 +80,7 @@ public final class WiredNode implements IWiredNode public void transmitSameDimension( @Nonnull Packet packet, double range ) { Objects.requireNonNull( packet, "packet cannot be null" ); - if( !(packet.getSender() instanceof IWiredSender) || ((IWiredSender) packet.getSender()).getNode() != this ) + if( !(packet.sender() instanceof IWiredSender) || ((IWiredSender) packet.sender()).getNode() != this ) { throw new IllegalArgumentException( "Sender is not in the network" ); } @@ -73,8 +92,7 @@ public final class WiredNode implements IWiredNode } finally { - network.lock.readLock() - .unlock(); + network.lock.readLock().unlock(); } } @@ -82,7 +100,7 @@ public final class WiredNode implements IWiredNode public void transmitInterdimensional( @Nonnull Packet packet ) { Objects.requireNonNull( packet, "packet cannot be null" ); - if( !(packet.getSender() instanceof IWiredSender) || ((IWiredSender) packet.getSender()).getNode() != this ) + if( !(packet.sender() instanceof IWiredSender) || ((IWiredSender) packet.sender()).getNode() != this ) { throw new IllegalArgumentException( "Sender is not in the network" ); } @@ -94,54 +112,7 @@ public final class WiredNode implements IWiredNode } finally { - network.lock.readLock() - .unlock(); - } - } - - private void acquireReadLock() - { - WiredNetwork currentNetwork = network; - while( true ) - { - Lock lock = currentNetwork.lock.readLock(); - lock.lock(); - if( currentNetwork == network ) - { - return; - } - - - lock.unlock(); - } - } - - synchronized void tryTransmit( Packet packet, double packetDistance, boolean packetInterdimensional, double range, boolean interdimensional ) - { - if( receivers == null ) - { - return; - } - - for( IPacketReceiver receiver : receivers ) - { - if( !packetInterdimensional ) - { - double receiveRange = Math.max( range, receiver.getRange() ); // Ensure range is symmetrical - if( interdimensional || receiver.isInterdimensional() || packetDistance < receiveRange ) - { - receiver.receiveSameDimension( packet, - packetDistance + element.getPosition() - .distanceTo( receiver.getPosition() ) ); - } - } - else - { - if( interdimensional || receiver.isInterdimensional() ) - { - receiver.receiveDifferentDimension( packet ); - } - } + network.lock.readLock().unlock(); } } @@ -162,7 +133,20 @@ public final class WiredNode implements IWiredNode @Override public String toString() { - return "WiredNode{@" + element.getPosition() + " (" + element.getClass() - .getSimpleName() + ")}"; + return "WiredNode{@" + element.getPosition() + " (" + element.getClass().getSimpleName() + ")}"; + } + + private void acquireReadLock() + { + WiredNetwork currentNetwork = network; + while( true ) + { + Lock lock = currentNetwork.lock.readLock(); + lock.lock(); + if( currentNetwork == network ) return; + + + lock.unlock(); + } } } diff --git a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua index 3f42b6510..83f4bb6ad 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/rednet.lua @@ -25,9 +25,17 @@ CHANNEL_BROADCAST = 65535 --- The channel used by the Rednet API to repeat messages. CHANNEL_REPEAT = 65533 +--- The number of channels rednet reserves for computer IDs. Computers with IDs +-- greater or equal to this limit wrap around to 0. +MAX_ID_CHANNELS = 65500 + local tReceivedMessages = {} -local tReceivedMessageTimeouts = {} local tHostnames = {} +local nClearTimer + +local function id_as_channel(id) + return (id or os.getComputerID()) % MAX_ID_CHANNELS +end --[[- Opens a modem with the given @{peripheral} name, allowing it to send and receive messages over rednet. @@ -47,7 +55,7 @@ function open(modem) if peripheral.getType(modem) ~= "modem" then error("No such modem: " .. modem, 2) end - peripheral.call(modem, "open", os.getComputerID()) + peripheral.call(modem, "open", id_as_channel()) peripheral.call(modem, "open", CHANNEL_BROADCAST) end @@ -64,7 +72,7 @@ function close(modem) if peripheral.getType(modem) ~= "modem" then error("No such modem: " .. modem, 2) end - peripheral.call(modem, "close", os.getComputerID()) + peripheral.call(modem, "close", id_as_channel()) peripheral.call(modem, "close", CHANNEL_BROADCAST) else -- Close all modems @@ -87,7 +95,7 @@ function isOpen(modem) 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) + return peripheral.call(modem, "isOpen", id_as_channel()) and peripheral.call(modem, "isOpen", CHANNEL_BROADCAST) end else -- Check if any modem is open @@ -130,14 +138,15 @@ function send(nRecipient, message, sProtocol) -- 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 + tReceivedMessages[nMessageID] = os.clock() + 9.5 + if not nClearTimer then nClearTimer = os.startTimer(10) end -- Create the message - local nReplyChannel = os.getComputerID() + local nReplyChannel = id_as_channel() local tMessage = { nMessageID = nMessageID, nRecipient = nRecipient, + nSender = os.getComputerID(), message = message, sProtocol = sProtocol, } @@ -145,10 +154,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", os.getComputerID(), message, sProtocol) sent = true else -- Send on all open modems, to the target and to repeaters + if nRecipient ~= CHANNEL_BROADCAST then + nRecipient = id_as_channel(nRecipient) + end + for _, sModem in ipairs(peripheral.getNames()) do if isOpen(sModem) then peripheral.call(sModem, "transmit", nRecipient, nReplyChannel, tMessage) @@ -390,13 +403,15 @@ 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 nChannel == id_as_channel() or nChannel == CHANNEL_BROADCAST then if type(tMessage) == "table" and type(tMessage.nMessageID) == "number" and tMessage.nMessageID == tMessage.nMessageID and not tReceivedMessages[tMessage.nMessageID] + and ((tMessage.nRecipient and tMessage.nRecipient == os.getComputerID()) or nChannel == CHANNEL_BROADCAST) + and isOpen(sModem) then - tReceivedMessages[tMessage.nMessageID] = true - tReceivedMessageTimeouts[os.startTimer(30)] = tMessage.nMessageID - os.queueEvent("rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol) + tReceivedMessages[tMessage.nMessageID] = os.clock() + 9.5 + if not nClearTimer then nClearTimer = os.startTimer(10) end + os.queueEvent("rednet_message", tMessage.nSender or nReplyChannel, tMessage.message, tMessage.sProtocol) end end @@ -414,14 +429,15 @@ function run() end end - elseif sEvent == "timer" then + elseif sEvent == "timer" and p1 == nClearTimer then -- Got a timer event, use it to clear the event queue - local nTimer = p1 - local nMessage = tReceivedMessageTimeouts[nTimer] - if nMessage then - tReceivedMessageTimeouts[nTimer] = nil - tReceivedMessages[nMessage] = nil + nClearTimer = nil + local nNow, bHasMore = os.clock(), nil + for nMessageID, nDeadline in pairs(tReceivedMessages) do + if nDeadline <= nNow then tReceivedMessages[nMessageID] = nil + else bHasMore = true end end + nClearTimer = bHasMore and os.startTimer(10) end end end 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 feafa00c2..724cda155 100644 --- a/src/main/resources/data/computercraft/lua/rom/apis/window.lua +++ b/src/main/resources/data/computercraft/lua/rom/apis/window.lua @@ -265,6 +265,8 @@ function create(parent, nX, nY, nWidth, nHeight, bStartVisible) if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then error("Arguments must be the same length", 2) end + sTextColor = sTextColor:lower() + sBackgroundColor = sBackgroundColor:lower() internalBlit(sText, sTextColor, sBackgroundColor) end diff --git a/src/main/resources/data/computercraft/lua/rom/help/changelog.txt b/src/main/resources/data/computercraft/lua/rom/help/changelog.md similarity index 100% rename from src/main/resources/data/computercraft/lua/rom/help/changelog.txt rename to src/main/resources/data/computercraft/lua/rom/help/changelog.md diff --git a/src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt b/src/main/resources/data/computercraft/lua/rom/help/whatsnew.md similarity index 100% rename from src/main/resources/data/computercraft/lua/rom/help/whatsnew.txt rename to src/main/resources/data/computercraft/lua/rom/help/whatsnew.md diff --git a/src/main/resources/data/computercraft/lua/rom/programs/about.lua b/src/main/resources/data/computercraft/lua/rom/programs/about.lua new file mode 100644 index 000000000..37a0e2901 --- /dev/null +++ b/src/main/resources/data/computercraft/lua/rom/programs/about.lua @@ -0,0 +1,4 @@ +-- Prints information about CraftOS +term.setTextColor(colors.yellow) +print(os.version() .. " on " .. _HOST) +term.setTextColor(colors.white) 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 57ab7b916..5a2e78b83 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/motd.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/motd.lua @@ -5,6 +5,8 @@ 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!") +elseif date.month == 4 and date.day == 28 then + print("Ed Balls") else local tMotd = {} diff --git a/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua b/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua index dfd9ca907..c5ed89984 100644 --- a/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua +++ b/src/main/resources/data/computercraft/lua/rom/programs/rednet/repeat.lua @@ -14,6 +14,10 @@ else print(#tModems .. " modems found.") end +local function idAsChannel(id) + return (id or os.getComputerID()) % rednet.MAX_ID_CHANNELS +end + local function open(nChannel) for n = 1, #tModems do local sModem = tModems[n] @@ -53,7 +57,7 @@ local ok, error = pcall(function() 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", idAsChannel(tMessage.nRecipient), nReplyChannel, tMessage) end -- Log the event