diff --git a/src/dan200/computer/api/ComputerCraftAPI.java b/src/dan200/computer/api/ComputerCraftAPI.java new file mode 100644 index 00000000..714ea587 --- /dev/null +++ b/src/dan200/computer/api/ComputerCraftAPI.java @@ -0,0 +1,86 @@ + +package dan200.computer.api; +import java.lang.reflect.Method; + +/** + * The static entry point to the ComputerCraft API. + * Members in this class must be called after mod_ComputerCraft has been initialised, + * but may be called before it is fully loaded. + */ +public class ComputerCraftAPI +{ + /** + * Get the creative mode tab that ComputerCraft items can be found on. + * Use this to add your peripherals to ComputerCraft's tab. + */ + public static net.minecraft.creativetab.CreativeTabs getCreativeTab() + { + findCC(); + if (computerCraft_getCreativeTab != null) + { + try { + return (net.minecraft.creativetab.CreativeTabs)( computerCraft_getCreativeTab.invoke(null) ); + } catch (Exception e){ + // It failed + } + } + return null; + } + + /** + * Registers a peripheral handler for a TileEntity that you do not have access to. Only + * use this if you want to expose IPeripheral on a TileEntity from another mod. For your own + * mod, just implement IPeripheral on the TileEntity directly. + * @see IPeripheral + * @see IPeripheralHandler + */ + public static void registerExternalPeripheral( Class clazz, IPeripheralHandler handler ) + { + findCC(); + if (computerCraft_registerExternalPeripheral != null) + { + try { + computerCraft_registerExternalPeripheral.invoke(null, clazz, handler); + } catch (Exception e){ + // It failed + } + } + } + + // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. + // Reflection is used here so you can develop your mod in MCP without decompiling ComputerCraft and including + // it in your solution. + + private static void findCC() + { + if( !ccSearched ) { + try { + computerCraft = Class.forName( "dan200.ComputerCraft" ); + computerCraft_getCreativeTab = findCCMethod( "getCreativeTab", new Class[] { } ); + computerCraft_registerExternalPeripheral = findCCMethod( "registerExternalPeripheral", new Class[] { + Class.class, IPeripheralHandler.class + } ); + } catch( Exception e ) { + System.out.println("ComputerCraftAPI: ComputerCraft not found."); + } finally { + ccSearched = true; + } + } + } + + private static Method findCCMethod( String name, Class[] args ) + { + try { + return computerCraft.getMethod( name, args ); + + } catch( NoSuchMethodException e ) { + System.out.println("ComputerCraftAPI: ComputerCraft method " + name + " not found."); + return null; + } + } + + private static boolean ccSearched = false; + private static Class computerCraft = null; + private static Method computerCraft_registerExternalPeripheral = null; + private static Method computerCraft_getCreativeTab = null; +} diff --git a/src/dan200/computer/api/IComputerAccess.java b/src/dan200/computer/api/IComputerAccess.java new file mode 100644 index 00000000..c9150530 --- /dev/null +++ b/src/dan200/computer/api/IComputerAccess.java @@ -0,0 +1,127 @@ + +package dan200.computer.api; + +/** + * 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 +{ + /** + * Creates a new numbered directory in a subPath of the users game save, and return that number. To be used with mountSaveDir.
+ * For example: n = createNewSaveDir( "computer/cdrom" ), will create a new + * numbered folder in the "computer/cdrom" subdirectory of the users save file, and return that number. + * mountSaveDir( "computer/rom", n ) could then be used to mount that folder onto the computers directory + * structure, and the value n could be saved out and used again in future to give the peripheral + * persistant storage. + * @param subPath A relative file path from the users world save, where the directory should be located. + * @return The numeric represenation of the name of the folder created. Will be positive. + * @see #mountSaveDir(String, String, int, boolean, long) + */ + public int createNewSaveDir( String subPath ); + + /** + * Mounts a directory into the computers file system, from a real directory a subPath of the users game save, + * with a numerical name. To be used with createNewSaveDir.
+ * For example: n = createNewSaveDir( "computer/cdrom" ), will create a new + * numbered folder in the "computer/cdrom" subdirectory of the users save file, and return that number. + * mountSaveDir( "computer/rom", n ) could then be used to mount that folder onto the computers directory + * structure, and the value n can be saved out by the peripheral and used again, to give the peripheral + * persistant storage.
+ * When a directory is mounted, it will appear in the computers file system, and the user will be + * able to use file operation to read from and write to the directory (unless readOnly, then only writes will be allowed). + * @param desiredLocation The desired location in the computers file system where you would like the directory to appear. + * If this location already exists, a number will be appended until a free name is found, and the + * actual location will be returned. eg: "cdrom" can become "cdrom2" if two peripherals attempt to + * mount "cdrom", or a "cdrom" folder already exists. + * @param subPath The real relative file path from the users world save, where the directory to mount can be located. + * @param id The numerical name of the folder to mount from the subPath: ex: mountSaveDir( "cdrom", "computer/cdrom", 7 ) + * will mount the directory "computer/cdrom/7". Use createNewSaveDir to obtain a unique directory id. + * @param readOnly Whether the computer will be disallowed from making changes to the mounted directory and modifing or creating files therin. + * @param spaceLimit The size limit of the mount, in bytes. Specify 0 to have unlimited capacity. + * @return The location in the computers file system where the directory was mounted. This may differ from "desiredLocation", so the + * return value should be kept track of so the folder can be unmounted later. + * @see #createNewSaveDir(String) + * @see #mountFixedDir(String, String, boolean, long) + * @see #unmount(String) + */ + public String mountSaveDir( String desiredLocation, String subPath, int id, boolean readOnly, long spaceLimit ); + + /** + * Mounts a directory into the computers file system, from a real directory in the Minecraft install folder.
+ * For example: mountFixedDir( "stuff", "mods/mymod/lua/stuff", true ), will mount the "lua/stuff" folder from + * your mod's directory into the computers filesystem at the location "stuff", with readonly permission, giving the + * computer access to those files.
+ * When a directory is mounted, it will appear in the computers file system, and the user will be + * able to use file operation to read from and write to the directory (unless readOnly, then only writes will be allowed).
+ * mountFixedDir can also be used to mount files, for example: mountFixedDir( "rom/apis/myapi", "mods/mymod/lua/myapi.lua", true ) can + * be used to have the peripheral install an API onto the computer it attaches to. + * @param desiredLocation The desired location in the computers file system where you would like the directory to appear. + * If this location already exists, a number will be appended until a free name is found, and the + * actual location will be returned. eg: "cdrom" can become "cdrom2" if two peripherals attempt to + * mount "cdrom", or a "cdrom" folder already exists. + * @param subPath The real relative file path from the minecraft install root, where the directory to mount can be located. + * @param readOnly Whether the computer will be disallowed from making changes to the mounted directory and modifing or creating files therin. + * @param spaceLimit The size limit of the mount, in bytes. Specify 0 to have unlimited capacity. + * @return The location in the computers file system where the directory was mounted. This may differ from "desiredLocation", so the + * return value should be kept track of so the folder can be unmounted later. + * @see #mountSaveDir(String, String, int, boolean, long) + * @see #unmount(String) + */ + public String mountFixedDir( String desiredLocation, String path, boolean readOnly, long spaceLimit ); + + /** + * Unmounts a directory previously mounted onto the computers file system by mountSaveDir or mountFixedDir.
+ * 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 mountFixedDir or mountSaveDir are automatically unmounted when the peripheral + * is attached if they have not been explicitly unmounted. + * @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 mountFixedDir() or mountSaveDir(), as + * indicated by their return value. + * @see #mountSaveDir(String, String, int, boolean, long) + * @see #mountFixedDir(String, String, boolean, long) + */ + public void unmount( String location ); + + /** + * Returns the numerical ID of this computer.
+ * This is the same number obtained by calling os.getComputerID() or running the "id" program from lua, + * and is guarunteed unique. This number will be positive. + * @return The identifier. + */ + public int getID(); + + /** + * Equivalent to queueEvent( String event, Object[] arguments ) with an empty arguments array. + * @see #queueEvent(String, Object[]) + */ + public void queueEvent( String event ); + + /** + * Causes an event to be raised on this computer, which the computer can respond to by calling + * 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 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 null to indicate that no arguments are to be supplied. + * @see IPeripheral#callMethod + */ + public void queueEvent( String event, Object[] arguments ); + + /** + * Get a string indicating which "side" of the computer the IComputerAccess this peripheral + * has been created for is attached to, relative to the computers orientation. This can be used to + * uniquely identify the peripheral when raising events or returning values to the computer. + * The value returned by this function will be different for the IComputerAccess for each of + * the peripherals attached to the computer. + * @return One of "top", "bottom", "left", "right", "front" or "back" + */ + public String getAttachmentSide(); +} diff --git a/src/dan200/computer/api/IHostedPeripheral.java b/src/dan200/computer/api/IHostedPeripheral.java new file mode 100644 index 00000000..b4ac9fa6 --- /dev/null +++ b/src/dan200/computer/api/IHostedPeripheral.java @@ -0,0 +1,39 @@ + +package dan200.computer.api; +import dan200.computer.api.IPeripheral; + +/** + * A subclass of IPeripheral specifically for peripherals + * created by ITurtleUpgrade's of type Peripheral. When an + * IHostedPeripheral is created, its IPeripheral methods will be called + * just as if the peripheral was a seperate adjacent block in the world, + * and update() will be called once per tick. + * @see ITurtleUpgrade + */ +public interface IHostedPeripheral extends IPeripheral +{ + /** + * A method called on each hosted peripheral once per tick, on the main thread + * over the lifetime of the turtle or block. May be used to update the state + * of the peripheral, and may interact with IComputerAccess or ITurtleAccess + * however it likes at this time. + */ + public void update(); + + /** + * A method called whenever data is read from the Turtle's NBTTag, + * over the lifetime of the turtle. You should only use this for + * reading data you want to stay with the peripheral. + * @param nbttagcompound The peripheral's NBTTag + */ + public void readFromNBT( net.minecraft.nbt.NBTTagCompound nbttagcompound ); + + /** + * A method called whenever data is written to the Turtle's NBTTag, + * over the lifetime of the turtle. You should only use this for + * writing data you want to stay with the peripheral. + * @param nbttagcompound The peripheral's NBTTag. + * @param ID The turtle's ID. + */ + public void writeToNBT( net.minecraft.nbt.NBTTagCompound nbttagcompound ); +} diff --git a/src/dan200/computer/api/IMedia.java b/src/dan200/computer/api/IMedia.java new file mode 100644 index 00000000..9147b94f --- /dev/null +++ b/src/dan200/computer/api/IMedia.java @@ -0,0 +1,16 @@ + +package dan200.computer.api; + +/** + * TODO: Document me + */ +public interface IMedia +{ + public String getLabel( net.minecraft.item.ItemStack stack ); + public boolean setLabel( net.minecraft.item.ItemStack stack, String label ); + + public String getAudioTitle( net.minecraft.item.ItemStack stack ); + public String getAudioRecordName( net.minecraft.item.ItemStack stack ); + + public String mountData( net.minecraft.item.ItemStack stack, IComputerAccess computer ); +} diff --git a/src/dan200/computer/api/IPeripheral.java b/src/dan200/computer/api/IPeripheral.java new file mode 100644 index 00000000..9d565133 --- /dev/null +++ b/src/dan200/computer/api/IPeripheral.java @@ -0,0 +1,99 @@ + +package dan200.computer.api; + +/** + * The interface that defines a peripheral. This should be implemented by the + * TileEntity of any block that you wish to be interacted with by + * computer or turtle. + */ +public interface IPeripheral +{ + /** + * Should return a string that uniquely identifies this type of peripheral. + * This can be queried from lua by calling peripheral.getType() + * @return A string identifying the type of peripheral. + */ + public String getType(); + + /** + * Should return an array of strings that identify the methods that this + * peripheral exposes to Lua. This will be called once before each attachment, + * and should not change when called multiple times. + * @return An array of strings representing method names. + * @see #callMethod + */ + public String[] getMethodNames(); + + /** + * This is called when a lua program on an attached computer calls peripheral.call() with + * one of the methods exposed by getMethodNames().
+ *
+ * Be aware that this will be called from the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computer that is making the call. Remember that multiple + * computers can be attached to a peripheral at once. + * @param method An integer identifying which of the methods from getMethodNames() the computer + * wishes to call. The integer indicates the index into the getMethodNames() table + * that corresponds to the string passed into peripheral.call() + * @param arguments An array of objects, representing the arguments passed into peripheral.call().
+ * Lua values of type "string" will be represented by Object type String.
+ * Lua values of type "number" will be represented by Object type Double.
+ * Lua values of type "boolean" will be represented by Object type Boolean.
+ * Lua values of any other type will be represented by a null object.
+ * This array will be empty if no arguments are passed. + * @return An array of objects, representing values you wish to return to the lua program.
+ * Integers, Doubles, Floats, Strings, Booleans and null be converted to their corresponding lua type.
+ * All other types will be converted to nil.
+ * You may return null to indicate no values should be returned. + * @throws Exception 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 + */ + public Object[] callMethod( IComputerAccess computer, int method, Object[] arguments ) throws Exception; + + /** + * Is called before the computer attempts to attach to the peripheral, and should return whether to allow + * the attachment. Use this to restrict the number of computers that can attach, or to limit attachments to + * certain world directions.
+ * If true is returned, attach() will be called shortly afterwards, and the computer will be able to make method calls. + * If false is returned, attach() will not be called, and the peripheral will be invisible to the computer. + * @param side The world direction (0=bottom, 1=top, etc) that the computer lies relative to the peripheral. + * @return Whether to allow the attachment, as a boolean. + * @see #attach + */ + public boolean canAttachToSide( int side ); + + /** + * Is called when canAttachToSide has returned true, and 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, + * or when a turtle travels into a square next to a peripheral. + * Between calls to attach() and detach(), the attached computer can make method calls on the peripheral using 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 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 being attached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #canAttachToSide + * @see #detach + */ + public void attach( IComputerAccess computer ); + + /** + * Is 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, + * or when a turtle moves away from a square attached to a peripheral. + * 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 the ComputerCraft Lua thread, and must be thread-safe + * when interacting with minecraft objects. + * @param computer The interface to the computer that is being detached. Remember that multiple + * computers can be attached to a peripheral at once. + * @see #canAttachToSide + * @see #detach + */ + public void detach( IComputerAccess computer ); +} diff --git a/src/dan200/computer/api/IPeripheralHandler.java b/src/dan200/computer/api/IPeripheralHandler.java new file mode 100644 index 00000000..ef32ea00 --- /dev/null +++ b/src/dan200/computer/api/IPeripheralHandler.java @@ -0,0 +1,9 @@ +package dan200.computer.api; + +/** + * TODO: Document me + */ +public interface IPeripheralHandler +{ + public IHostedPeripheral getPeripheral( net.minecraft.tileentity.TileEntity tile ); +} diff --git a/src/dan200/turtle/api/ITurtleAccess.java b/src/dan200/turtle/api/ITurtleAccess.java new file mode 100644 index 00000000..1a83cdbe --- /dev/null +++ b/src/dan200/turtle/api/ITurtleAccess.java @@ -0,0 +1,145 @@ + +package dan200.turtle.api; +import dan200.computer.api.*; + +/** + * The interface passed to upgrades 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 ITurtleUpgrade. + */ +public interface ITurtleAccess +{ + /** + * Returns the world in which the turtle resides. + * @return the world in which the turtle resides. + */ + public net.minecraft.world.World getWorld(); + + /** + * Returns a vector containing the integer block co-ordinates at which the turtle resides. + * @return a vector containing the integer block co-ordinates at which the turtle resides. + */ + public net.minecraft.util.Vec3 getPosition(); + + /** + * Returns the world direction the turtle is currently facing. + * @return the world direction the turtle is currently facing. + */ + public int getFacingDir(); + + /** + * Returns the size of the turtles inventory, in number of slots. This will currently always be 16. + * @return the size of the turtles inventory, in number of slots. This will currently always be 16. + */ + public int getInventorySize(); + + /** + * Returns which slot the turtle currently has selected in its inventory using turtle.select(). + * Unlike the 1-based lua representation, this will be between 0 and getInventorySize() - 1. + * @return which slot the turtle currently has selected in its inventory + */ + public int getSelectedSlot(); + + /** + * Returns the item stack that the turtle has in one of its inventory slots. + * @param index which inventory slot to retreive, should be between 0 and getInventorySize() - 1 + * @return the item stack that the turtle has in one of its inventory slots. May be null. + */ + public net.minecraft.item.ItemStack getSlotContents( int index ); + + /** + * Changes the item stack that the turtle has in one of its inventory slots. + * @param index which inventory slot to change, should be between 0 and getInventorySize() - 1 + * @param stack an item stack to put in the slot. May be null. + */ + public void setSlotContents( int index, net.minecraft.item.ItemStack stack ); + + /** + * Tries to store an item stack into the turtles current inventory, starting from the turtles + * currently selected inventory slot. + * @param stack The item stack to try and store. + * @return true if the stack was completely stored in the inventory, false if + * it was only partially stored, or could not fit at all. If false is returned + * and the stack was partially stored, the ItemStack passed into "stack" will now + * represent the stack of items that is left over. + */ + public boolean storeItemStack( net.minecraft.item.ItemStack stack ); + + /** + * Drops an item stack from the turtle onto the floor, or into an inventory is there is one + * adjacent to the turtle in the direction specified. + * @param stack The item stack to drop. + * @param dir The world direction to drop the item + * @return true if the stack was dropped, or completely stored in the adjacent inventory, false if + * it was only partially stored in the adjacent inventory, or could not fit at all. If false is returned + * and the stack was partially stored, the ItemStack passed into "stack" will now + * represent the stack of items that is left over. + */ + public boolean dropItemStack( net.minecraft.item.ItemStack stack, int dir ); + + /** + * "Deploys" an item stack in the direction specified. This simulates a player right clicking, and calls onItemUse() on the Item class. + * Will return true if some kind of deployment happened, and may modify the item stack. For block item types, this can be + * used to place blocks. Some kinds of items (such as shears when facing a sheep) may modify the turtles inventory during this call. + * @param stack The item stack to deploy + * @param dir The world direction to deploy the item + * @return true if the stack was deployed, false if it was not. + */ + public boolean deployWithItemStack( net.minecraft.item.ItemStack stack, int dir ); + + /** + * Tries to "attack" entities with an item stack in the direction specified. This simulates a player left clicking, but will + * not affect blocks. If an entity is attacked and killed during this call, its dropped items will end up in the turtles + * inventory. + * @param stack The item stack to attack with + * @param dir The world direction to attack with the item + * @return true if something was attacked, false if it was not + */ + public boolean attackWithItemStack( net.minecraft.item.ItemStack stack, int dir, float damageMultiplier ); + + /** + * Returns the current fuel level of the turtle, this is the same integer returned by turtle.getFuelLevel(), + * that decreases by 1 every time the turtle moves. Can be used to have your tool or peripheral require or supply + * fuel to the turtle. + * @return the fuel level + */ + public int getFuelLevel(); + + /** + * Tries to increase the fuel level of a turtle by burning an item stack. If the item passed in is a fuel source, fuel + * will increase and true will be returned. Otherwise, nothing will happen and false will be returned. + * @param stack The stack to try to refuel with + * @return Whether the turtle was refueled + */ + public boolean refuelWithItemStack( net.minecraft.item.ItemStack stack ); + + /** + * Removes some fuel from the turtles fuel supply. Negative numbers can be passed in to INCREASE the fuel level of the turtle. + * @return Whether the turtle was able to consume the ammount of fuel specified. Will return false if you supply a number + * greater than the current fuel level of the turtle. + */ + public boolean consumeFuel( 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. + * @param handler an object which will execute the custom command when its point in the queue is reached + * @return the unique command identifier described above + * @see ITurtleCommandHandler + */ + public int issueCommand( ITurtleCommandHandler handler ); + + /** + * Returns the upgrade on the specified side of the turtle, if there is one. + * @return the upgrade on the specified side of the turtle, if there is one. + */ + public ITurtleUpgrade getUpgrade( TurtleSide side ); + + /** + * Returns the peripheral created by the upgrade on the specified side of the turtle, if there is one. + * @return the peripheral created by the upgrade on the specified side of the turtle, if there is one. + */ + public IHostedPeripheral getPeripheral( TurtleSide side ); +} diff --git a/src/dan200/turtle/api/ITurtleCommandHandler.java b/src/dan200/turtle/api/ITurtleCommandHandler.java new file mode 100644 index 00000000..5d397c87 --- /dev/null +++ b/src/dan200/turtle/api/ITurtleCommandHandler.java @@ -0,0 +1,20 @@ + +package dan200.turtle.api; + +/** + * An interface for objects executing custom turtle commands, used with ITurtleAccess.issueCommand + * @see ITurtleAccess#issueCommand( ITurtleCommandHandler ) + */ +public interface ITurtleCommandHandler +{ + /** + * 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 true for success, or return + * false to indicate failure if the command cannot be executed at this time. + * @param turtle access to the turtle for whom the command was issued + * @return true for success, false for failure. If true is returned, the turtle will wait 0.4 seconds + * before executing the next command in its queue, as it does for the standard turtle commands. + * @see ITurtleAccess#issueCommand( ITurtleCommandHandler ) + */ + public boolean handleCommand( ITurtleAccess turtle ); +} diff --git a/src/dan200/turtle/api/ITurtleUpgrade.java b/src/dan200/turtle/api/ITurtleUpgrade.java new file mode 100644 index 00000000..673205a4 --- /dev/null +++ b/src/dan200/turtle/api/ITurtleUpgrade.java @@ -0,0 +1,98 @@ + +package dan200.turtle.api; +import dan200.computer.api.*; + +/** + * The primary interface for defining an upgrade for Turtles. A turtle upgrade + * can either be a new tool, or a new peripheral. + * @see TurtleAPI#registerUpgrade( ITurtleUpgrade ) + */ +public interface ITurtleUpgrade +{ + /** + * Gets a unique numerical identifier representing this type of turtle upgrade. + * Like Minecraft block and item IDs, you should strive to make this number unique + * among all turtle upgrades that have been released for ComputerCraft. + * The ID must be in the range 64 to 255, as the ID is stored as an 8-bit value, + * and 0-64 is reserved for future use by ComputerCraft. The upgrade will + * fail registration if an already used ID is specified. + * @see TurtleAPI#registerUpgrade( ITurtleUpgrade ) + */ + public int getUpgradeID(); + + /** + * Return a String to describe this type of upgrade in turtle item names. + * Examples of built-in adjectives are "Wireless", "Mining" and "Crafty". + */ + public String getAdjective(); + + /** + * Return whether this upgrade adds a tool or a peripheral to the turtle. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + * @see TurtleUpgradeType for the differences between the two. + */ + public TurtleUpgradeType getType(); + + /** + * Return an item stack representing the type of item that a turtle must be crafted + * with to create a turtle which holds this upgrade. + * Currently, turtle crafting is restricted to one tool & one peripheral per turtle. + */ + public net.minecraft.item.ItemStack getCraftingItem(); + + /** + * Return whether this turtle upgrade is an easter egg, and should be attempted to be hidden + * from the creative mode inventory and recipe book plugins. + */ + public boolean isSecret(); + + /** + * Return which texture file should be used to render this upgrade when rendering a turtle + * in the world or as an item. + * @param turtle Access to the turtle that is being rendered, this will be null when + * the method is being called to render the turtle as an Item. For turtles in the world, + * this can be used to have the upgrade change appearance based on state. + * @param side Which side of the turtle (left or right) that the upgrade being rendered resides on. + * @see #getIconIndex + */ + public String getIconTexture( ITurtleAccess turtle, TurtleSide side ); + + /** + * Return which icon index should be used to render this upgrade when rendering a turtle + * in the world or as an item. + * @param turtle Access to the turtle that is being rendered, this will be null when + * the method is being called to render the turtle as an Item. For turtles in the world, + * this can be used to have the upgrade change appearance based on state. + * @param side Which side of the turtle (left or right) that the upgrade being rendered resides on. + * @see #getIconTexture + */ + public int getIconIndex( ITurtleAccess turtle, TurtleSide side ); + + /** + * 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 turtle, will have update() called once-per-tick, and will be + * attach'd detach'd 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. + * @returns The newly created peripheral. You may return null if this upgrade is a Tool + * and this method is not expected to be called. + */ + public IHostedPeripheral createPeripheral( ITurtleAccess turtle, TurtleSide side ); + + /** + * Will only be called for Tool upgrades. 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 turtle.dig() + * or turtle.attack() lua method should return true. If true is returned, the tool will perform + * a swinging animation. You may return false if this upgrade is a Peripheral + * and this method is not expected to be called. + */ + public boolean useTool( ITurtleAccess turtle, TurtleSide side, TurtleVerb verb, int direction ); +} diff --git a/src/dan200/turtle/api/TurtleAPI.java b/src/dan200/turtle/api/TurtleAPI.java new file mode 100644 index 00000000..f802ddd6 --- /dev/null +++ b/src/dan200/turtle/api/TurtleAPI.java @@ -0,0 +1,73 @@ + +package dan200.turtle.api; +import java.lang.reflect.Method; + +/** + * The static entry point to the ComputerCraft Turtle Upgrade API. + * Members in this class must be called after mod_CCTurtle has been initialised, + * but may be called before it is fully loaded. + */ +public class TurtleAPI +{ + /** + * Registers a new turtle upgrade for use in ComputerCraft. After calling this, + * users should be able to craft Turtles with your new upgrade. It is recommended to call + * this during the load() method of your mod. + * @throws Exception if you try to register an upgrade with an already used or reserved upgradeID + * @see ITurtleUpgrade + */ + public static void registerUpgrade( ITurtleUpgrade upgrade ) + { + if( upgrade != null ) + { + findCCTurtle(); + if( ccTurtle_registerTurtleUpgrade != null ) + { + try { + ccTurtle_registerTurtleUpgrade.invoke( null, new Object[]{ upgrade } ); + } catch( Exception e ) { + // It failed + } + } + } + } + + // The functions below here are private, and are used to interface with the non-API ComputerCraft classes. + // Reflection is used here so you can develop your mod in MCP without decompiling ComputerCraft and including + // it in your solution. + + private static void findCCTurtle() + { + if( !ccTurtleSearched ) { + // Search for CCTurtle + try { + ccTurtle = Class.forName( "dan200.CCTurtle" ); + ccTurtle_registerTurtleUpgrade = findCCTurtleMethod( "registerTurtleUpgrade", new Class[] { + ITurtleUpgrade.class + } ); + + } catch( ClassNotFoundException e ) { + System.out.println("ComputerCraftAPI: CCTurtle not found."); + + } finally { + ccTurtleSearched = true; + + } + } + } + + private static Method findCCTurtleMethod( String name, Class[] args ) + { + try { + return ccTurtle.getMethod( name, args ); + + } catch( NoSuchMethodException e ) { + System.out.println("ComputerCraftAPI: CCTurtle method " + name + " not found."); + return null; + } + } + + private static boolean ccTurtleSearched = false; + private static Class ccTurtle = null; + private static Method ccTurtle_registerTurtleUpgrade = null; +} diff --git a/src/dan200/turtle/api/TurtleSide.java b/src/dan200/turtle/api/TurtleSide.java new file mode 100644 index 00000000..bc64f711 --- /dev/null +++ b/src/dan200/turtle/api/TurtleSide.java @@ -0,0 +1,18 @@ + +package dan200.turtle.api; + +/** + * An enum representing the two sides of the turtle that a turtle upgrade might reside. + */ +public enum TurtleSide +{ + /** + * The turtles left side (where the pickaxe usually is on a Wireless Mining Turtle) + */ + Left, + + /** + * The turtles right side (where the modem usually is on a Wireless Mining Turtle) + */ + Right, +} diff --git a/src/dan200/turtle/api/TurtleUpgradeType.java b/src/dan200/turtle/api/TurtleUpgradeType.java new file mode 100644 index 00000000..d1b69499 --- /dev/null +++ b/src/dan200/turtle/api/TurtleUpgradeType.java @@ -0,0 +1,22 @@ + +package dan200.turtle.api; + +/** + * An enum representing the two different types of upgrades that an ITurtleUpgrade + * implementation can add to a turtle. + * @see ITurtleUpgrade + */ +public enum TurtleUpgradeType +{ + /** + * A tool is rendered as an item on the side of the turtle, and responds to the turtle.dig() + * and 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 peripheral API (Such as the modem on Wireless Turtles). + */ + Peripheral, +} diff --git a/src/dan200/turtle/api/TurtleVerb.java b/src/dan200/turtle/api/TurtleVerb.java new file mode 100644 index 00000000..4da83c6c --- /dev/null +++ b/src/dan200/turtle/api/TurtleVerb.java @@ -0,0 +1,21 @@ + +package dan200.turtle.api; + +/** + * An enum representing the two different actions that an ITurtleUpgrade of type + * Tool may be called on to perform by a turtle. + * @see ITurtleUpgrade + * @see ITurtleUpgrade#useTool + */ +public enum TurtleVerb +{ + /** + * The turtle called turtle.dig(), turtle.digUp() or turtle.digDown() + */ + Dig, + + /** + * The turtle called turtle.attack(), turtle.attackUp() or turtle.attackDown() + */ + Attack, +} diff --git a/src/dan200/turtle/api/events/TurtleEvent.java b/src/dan200/turtle/api/events/TurtleEvent.java new file mode 100644 index 00000000..d5264ca3 --- /dev/null +++ b/src/dan200/turtle/api/events/TurtleEvent.java @@ -0,0 +1,16 @@ +package dan200.turtle.api.events; + +import dan200.turtle.api.ITurtleAccess; +import net.minecraftforge.event.Event; + +public class TurtleEvent extends Event +{ + + public final ITurtleAccess turtle; + + public TurtleEvent (ITurtleAccess turtle) + { + this.turtle = turtle; + } + +} diff --git a/src/dan200/turtle/api/events/TurtleRefuel.java b/src/dan200/turtle/api/events/TurtleRefuel.java new file mode 100644 index 00000000..31fd30e2 --- /dev/null +++ b/src/dan200/turtle/api/events/TurtleRefuel.java @@ -0,0 +1,30 @@ +package dan200.turtle.api.events; + +import dan200.turtle.api.ITurtleAccess; +import net.minecraft.item.ItemStack; +import net.minecraftforge.event.Cancelable; + +@Cancelable +public class TurtleRefuel extends TurtleEvent +{ + public ItemStack itemstack; + public int refuelAmount; + private boolean handled = false; + + public TurtleRefuel (ITurtleAccess turtle, ItemStack itemstack, int fuelToGive ) + { + super(turtle); + this.itemstack = itemstack; + this.refuelAmount = fuelToGive; + } + + public boolean isHandled() + { + return handled; + } + + public void setHandled() + { + handled = true; + } +}