diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index af1438236b..9505b8dc70 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -9,6 +9,7 @@ import com.google.common.base.CaseFormat; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMediaProvider; import dan200.computercraft.api.network.IPacketNetwork; @@ -81,10 +82,7 @@ import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -244,6 +242,7 @@ public static class Config { private static List mediaProviders = new ArrayList<>(); private static List permissionProviders = new ArrayList<>(); private static final Map pocketUpgrades = new HashMap<>(); + private static final Set apiFactories = new LinkedHashSet<>(); // Implementation @Mod.Instance( value = ComputerCraft.MOD_ID ) @@ -644,6 +643,14 @@ public static void registerMediaProvider( IMediaProvider provider ) } } + public static void registerAPIFactory( ILuaAPIFactory provider ) + { + if( provider != null ) + { + apiFactories.add( provider ); + } + } + public static IPeripheral getPeripheralAt( World world, BlockPos pos, EnumFacing side ) { // Try the handlers in order: @@ -771,6 +778,11 @@ public IPacketNetwork getWirelessNetwork() return WirelessNetwork.getUniversal(); } + public static Iterable getAPIFactories() + { + return apiFactories; + } + public static int createUniqueNumberedSaveDir( World world, String parentSubPath ) { return IDAssigner.getNextIDFromDirectory(new File(getWorldDir(world), parentSubPath)); diff --git a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java index f1a33b15dc..88dd4bcde0 100644 --- a/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java +++ b/src/main/java/dan200/computercraft/api/ComputerCraftAPI.java @@ -8,6 +8,7 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.ILuaAPIFactory; import dan200.computercraft.api.media.IMedia; import dan200.computercraft.api.media.IMediaProvider; import dan200.computercraft.api.network.IPacketNetwork; @@ -311,6 +312,22 @@ public static IPacketNetwork getWirelessNetwork() return null; } + public static void registerAPIFactory( @Nonnull ILuaAPIFactory upgrade ) + { + findCC(); + if( computerCraft_registerAPIFactory != null ) + { + try + { + computerCraft_registerAPIFactory.invoke( null, 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 without decompiling ComputerCraft and including // it in your solution, and so your mod won't crash if ComputerCraft is installed. @@ -354,6 +371,9 @@ private static void findCC() } ); computerCraft_getWirelessNetwork = findCCMethod( "getWirelessNetwork", new Class[] { } ); + computerCraft_registerAPIFactory = findCCMethod( "registerAPIFactory", new Class[] { + ILuaAPIFactory.class + } ); } catch( Exception e ) { System.out.println( "ComputerCraftAPI: ComputerCraft not found." ); } finally { @@ -390,4 +410,5 @@ private static Method findCCMethod( String name, Class[] args ) private static Method computerCraft_registerPermissionProvider = null; private static Method computerCraft_registerPocketUpgrade = null; private static Method computerCraft_getWirelessNetwork = null; + private static Method computerCraft_registerAPIFactory = null; } diff --git a/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java new file mode 100644 index 0000000000..414911d419 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/filesystem/IFileSystem.java @@ -0,0 +1,38 @@ +package dan200.computercraft.api.filesystem; + +import java.io.IOException; + +/** + * Provides a mount of the entire computer's file system. + * + * This exists for use by various APIs - one should not attempt to mount it. + */ +public interface IFileSystem extends IWritableMount +{ + /** + * Combine two paths together, reducing them into a normalised form. + * + * @param path The main path. + * @param child The path to append. + * @return The combined, normalised path. + */ + String combine( String path, String child ); + + /** + * Copy files from one location to another. + * + * @param from The location to copy from. + * @param to The location to copy to. This should not exist. + * @throws IOException If the copy failed. + */ + void copy( String from, String to ) throws IOException; + + /** + * Move files from one location to another. + * + * @param from The location to move from. + * @param to The location to move to. This should not exist. + * @throws IOException If the move failed. + */ + void move( String from, String to ) throws IOException; +} diff --git a/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java new file mode 100644 index 0000000000..a892a027b2 --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/IComputerSystem.java @@ -0,0 +1,29 @@ +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.filesystem.IFileSystem; +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. + */ +public interface IComputerSystem extends IComputerAccess +{ + /** + * Get the file system for this computer. + * + * @return The computer's file system, or {@code null} if it is not initialised. + */ + @Nullable + IFileSystem getFileSystem(); + + /** + * Get the label for this computer + * + * @return This computer's label, or {@code null} if it is not set. + */ + @Nullable + String getLabel(); +} diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java new file mode 100644 index 0000000000..7eaa589abb --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPI.java @@ -0,0 +1,47 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2016. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ + +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.ComputerCraftAPI; + +/** + * Represents a {@link ILuaObject} which is stored as a global variable on computer startup. + * + * 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) + */ +public interface ILuaAPI extends ILuaObject +{ + /** + * Get the globals this API will be assigned to. This will override any other global, so you should + * + * @return A list of globals this API will be assigned to. + */ + String[] getNames(); + + /** + * Called when the computer is turned on. + * + * One should only interact with the file system. + */ + default void startup() { } + + /** + * Called every time the computer is ticked. This can be used to process various. + */ + default void update() { } + + /** + * Called when the computer is turned off or unloaded. + * + * This should reset the state of the object, disposing any remaining file handles, or other resources. + */ + default void shutdown() { } +} diff --git a/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java new file mode 100644 index 0000000000..558c51d4ac --- /dev/null +++ b/src/main/java/dan200/computercraft/api/lua/ILuaAPIFactory.java @@ -0,0 +1,24 @@ +package dan200.computercraft.api.lua; + +import dan200.computercraft.api.ComputerCraftAPI; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Construct an {@link ILuaAPI} for a specific computer. + * + * @see ILuaAPI + * @see ComputerCraftAPI#registerAPIFactory(ILuaAPIFactory) + */ +public interface ILuaAPIFactory +{ + /** + * Create a new API instance for a given computer. + * + * @param computer The computer this API is for. + * @return The created API, or {@code null} if one should not be injected. + */ + @Nullable + ILuaAPI create( @Nonnull IComputerSystem computer ); +} diff --git a/src/main/java/dan200/computercraft/core/apis/BitAPI.java b/src/main/java/dan200/computercraft/core/apis/BitAPI.java index 8d4021b2c4..c7de069d5c 100644 --- a/src/main/java/dan200/computercraft/core/apis/BitAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/BitAPI.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; @@ -37,21 +38,6 @@ public String[] getNames() "bit" }; } - - @Override - public void startup( ) - { - } - - @Override - public void advance( double _dt ) - { - } - - @Override - public void shutdown( ) - { - } @Nonnull @Override diff --git a/src/main/java/dan200/computercraft/core/apis/BufferAPI.java b/src/main/java/dan200/computercraft/core/apis/BufferAPI.java index 3035ef763e..ec842e4f9a 100644 --- a/src/main/java/dan200/computercraft/core/apis/BufferAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/BufferAPI.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.ILuaObject; import dan200.computercraft.api.lua.LuaException; @@ -100,21 +101,6 @@ public String[] getNames() }; } - @Override - public void startup() - { - } - - @Override - public void advance( double _dt ) - { - } - - @Override - public void shutdown() - { - } - @Nonnull @Override public String[] getMethodNames() diff --git a/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java new file mode 100644 index 0000000000..1f82ec3bb5 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/apis/ComputerAccess.java @@ -0,0 +1,155 @@ +package dan200.computercraft.core.apis; + +import dan200.computercraft.api.filesystem.IMount; +import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.peripheral.IComputerAccess; +import dan200.computercraft.core.filesystem.FileSystem; +import dan200.computercraft.core.filesystem.FileSystemException; + +import javax.annotation.Nonnull; +import java.util.HashSet; +import java.util.Set; + +public abstract class ComputerAccess implements IComputerAccess +{ + private final IAPIEnvironment m_environment; + private final Set m_mounts = new HashSet<>(); + + protected ComputerAccess( IAPIEnvironment m_environment ) + { + this.m_environment = m_environment; + } + + public void unmountAll() + { + FileSystem fileSystem = m_environment.getFileSystem(); + for( String m_mount : m_mounts ) + { + fileSystem.unmount( m_mount ); + } + m_mounts.clear(); + } + + @Override + public String mount( @Nonnull String desiredLoc, @Nonnull IMount mount ) + { + return mount( desiredLoc, mount, getAttachmentName() ); + } + + @Override + public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName ) + { + // Mount the location + String location; + FileSystem fileSystem = m_environment.getFileSystem(); + if( fileSystem == null ) + { + throw new IllegalStateException( "File system has not been created" ); + } + + synchronized( fileSystem ) + { + location = findFreeLocation( desiredLoc ); + if( location != null ) + { + try + { + fileSystem.mount( driveName, location, mount ); + } + catch( FileSystemException ignored ) + { + } + } + } + if( location != null ) + { + m_mounts.add( location ); + } + return location; + } + + @Override + public String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount ) + { + return mountWritable( desiredLoc, mount, getAttachmentName() ); + } + + @Override + public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount, @Nonnull String driveName ) + { + // Mount the location + String location; + FileSystem fileSystem = m_environment.getFileSystem(); + if( fileSystem == null ) + { + throw new IllegalStateException( "File system has not been created" ); + } + + synchronized( fileSystem ) + { + location = findFreeLocation( desiredLoc ); + if( location != null ) + { + try + { + fileSystem.mountWritable( driveName, location, mount ); + } + catch( FileSystemException ignored ) + { + } + } + } + if( location != null ) + { + m_mounts.add( location ); + } + return location; + } + + @Override + public synchronized void unmount( String location ) + { + if( location != null ) + { + if( !m_mounts.contains( location ) ) + { + throw new RuntimeException( "You didn't mount this location" ); + } + + m_environment.getFileSystem().unmount( location ); + m_mounts.remove( location ); + } + } + + @Override + public synchronized int getID() + { + return m_environment.getComputerID(); + } + + @Override + public synchronized void queueEvent( @Nonnull final String event, final Object[] arguments ) + { + m_environment.queueEvent( event, arguments ); + } + + private String findFreeLocation( String desiredLoc ) + { + try + { + FileSystem fileSystem = m_environment.getFileSystem(); + if( !fileSystem.exists( desiredLoc ) ) + { + return desiredLoc; + } + + // We used to check foo2,foo3,foo4,etc here + // but the disk drive does this itself now + return null; + } + catch( FileSystemException e ) + { + return null; + } + } +} diff --git a/src/main/java/dan200/computercraft/core/apis/FSAPI.java b/src/main/java/dan200/computercraft/core/apis/FSAPI.java index 7cf8bdc309..4f955a2660 100644 --- a/src/main/java/dan200/computercraft/core/apis/FSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/FSAPI.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.core.apis.handles.BinaryInputHandle; @@ -48,11 +49,6 @@ public void startup( ) m_fileSystem = m_env.getFileSystem(); } - @Override - public void advance( double _dt ) - { - } - @Override public void shutdown( ) { diff --git a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java index 67ccc4413a..e44ae75710 100644 --- a/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/HTTPAPI.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.core.apis.http.HTTPCheck; @@ -38,12 +39,7 @@ public String[] getNames() } @Override - public void startup( ) - { - } - - @Override - public void advance( double _dt ) + public void update() { // Wait for all of our http requests synchronized( m_httpTasks ) diff --git a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java b/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java deleted file mode 100644 index f8d4915440..0000000000 --- a/src/main/java/dan200/computercraft/core/apis/ILuaAPI.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ - -package dan200.computercraft.core.apis; -import dan200.computercraft.api.lua.ILuaObject; - -public interface ILuaAPI extends ILuaObject -{ - String[] getNames(); - - void startup(); // LT - void advance( double _dt ); // MT - void shutdown(); // LT -} diff --git a/src/main/java/dan200/computercraft/core/apis/OSAPI.java b/src/main/java/dan200/computercraft/core/apis/OSAPI.java index 7ec4b6878c..ae091c6451 100644 --- a/src/main/java/dan200/computercraft/core/apis/OSAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/OSAPI.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.shared.util.StringUtil; @@ -102,7 +103,7 @@ public void startup() } @Override - public void advance( double dt ) + public void update() { synchronized( m_timers ) { diff --git a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java index 390bd5563e..459a743db7 100644 --- a/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/PeripheralAPI.java @@ -8,24 +8,25 @@ import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.ComputerThread; import dan200.computercraft.core.computer.ITask; import dan200.computercraft.core.filesystem.FileSystem; -import dan200.computercraft.core.filesystem.FileSystemException; import javax.annotation.Nonnull; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import static dan200.computercraft.core.apis.ArgumentHelper.getString; public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener { - private class PeripheralWrapper implements IComputerAccess + private class PeripheralWrapper extends ComputerAccess { private final String m_side; private final IPeripheral m_peripheral; @@ -35,10 +36,9 @@ private class PeripheralWrapper implements IComputerAccess private Map m_methodMap; private boolean m_attached; - private Set m_mounts; - public PeripheralWrapper( IPeripheral peripheral, String side ) { + super(m_environment); m_side = side; m_peripheral = peripheral; m_attached = false; @@ -54,8 +54,6 @@ public PeripheralWrapper( IPeripheral peripheral, String side ) m_methodMap.put( m_methods[i], i ); } } - - m_mounts = new HashSet<>(); } public IPeripheral getPeripheral() @@ -89,13 +87,9 @@ public synchronized void detach() // Call detach m_peripheral.detach( this ); m_attached = false; - + // Unmount everything the detach function forgot to do - for( String m_mount : m_mounts ) - { - m_fileSystem.unmount( m_mount ); - } - m_mounts.clear(); + unmountAll(); } public Object[] call( ILuaContext context, String methodName, Object[] arguments ) throws LuaException, InterruptedException @@ -119,13 +113,6 @@ public Object[] call( ILuaContext context, String methodName, Object[] arguments } // IComputerAccess implementation - - @Override - public String mount( @Nonnull String desiredLoc, @Nonnull IMount mount ) - { - return mount( desiredLoc, mount, m_side ); - } - @Override public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mount, @Nonnull String driveName ) { @@ -133,32 +120,8 @@ public synchronized String mount( @Nonnull String desiredLoc, @Nonnull IMount mo { throw new RuntimeException( "You are not attached to this Computer" ); } - - // Mount the location - String location; - synchronized( m_fileSystem ) - { - location = findFreeLocation( desiredLoc ); - if( location != null ) - { - try { - m_fileSystem.mount( driveName, location, mount ); - } catch( FileSystemException e ) { - // fail and return null - } - } - } - if( location != null ) - { - m_mounts.add( location ); - } - return location; - } - @Override - public String mountWritable( @Nonnull String desiredLoc, @Nonnull IWritableMount mount ) - { - return mountWritable( desiredLoc, mount, m_side ); + return super.mount( desiredLoc, mount, driveName ); } @Override @@ -168,69 +131,47 @@ public synchronized String mountWritable( @Nonnull String desiredLoc, @Nonnull I { throw new RuntimeException( "You are not attached to this Computer" ); } - - // Mount the location - String location; - synchronized( m_fileSystem ) - { - location = findFreeLocation( desiredLoc ); - if( location != null ) - { - try { - m_fileSystem.mountWritable( driveName, location, mount ); - } catch( FileSystemException e ) { - // fail and return null - } - } - } - if( location != null ) - { - m_mounts.add( location ); - } - return location; + + return super.mountWritable( desiredLoc, mount, driveName ); } - + @Override public synchronized void unmount( String location ) { - if( !m_attached ) { - throw new RuntimeException( "You are not attached to this Computer" ); - } - - if( location != null ) + if( !m_attached ) { - if( !m_mounts.contains( location ) ) { - throw new RuntimeException( "You didn't mount this location" ); - } - - m_fileSystem.unmount( location ); - m_mounts.remove( location ); + throw new RuntimeException( "You are not attached to this Computer" ); } + + super.unmount( location ); } - + @Override public synchronized int getID() { - if( !m_attached ) { + if( !m_attached ) + { throw new RuntimeException( "You are not attached to this Computer" ); } - return m_environment.getComputerID(); + return super.getID(); } - + @Override public synchronized void queueEvent( @Nonnull final String event, final Object[] arguments ) { - if( !m_attached ) { + if( !m_attached ) + { throw new RuntimeException( "You are not attached to this Computer" ); - } - m_environment.queueEvent( event, arguments ); + } + super.queueEvent( event, arguments ); } - + @Nonnull @Override public synchronized String getAttachmentName() { - if( !m_attached ) { + if( !m_attached ) + { throw new RuntimeException( "You are not attached to this Computer" ); } return m_side; @@ -353,11 +294,6 @@ public void startup( ) } } - @Override - public void advance( double _dt ) - { - } - @Override public void shutdown( ) { @@ -506,25 +442,4 @@ private int parseSide( Object[] args ) throws LuaException } return -1; } - - private String findFreeLocation( String desiredLoc ) - { - try - { - synchronized( m_fileSystem ) - { - if( !m_fileSystem.exists( desiredLoc ) ) - { - return desiredLoc; - } - // We used to check foo2,foo3,foo4,etc here - // but the disk drive does this itself now - return null; - } - } - catch( FileSystemException e ) - { - return null; - } - } } diff --git a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java index a856ed3df8..7230f17af8 100644 --- a/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/RedstoneAPI.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.core.computer.Computer; @@ -33,21 +34,6 @@ public String[] getNames() }; } - @Override - public void startup( ) - { - } - - @Override - public void advance( double _dt ) - { - } - - @Override - public void shutdown( ) - { - } - @Nonnull @Override public String[] getMethodNames() diff --git a/src/main/java/dan200/computercraft/core/apis/TermAPI.java b/src/main/java/dan200/computercraft/core/apis/TermAPI.java index 38a64b059d..07dcc58c5c 100644 --- a/src/main/java/dan200/computercraft/core/apis/TermAPI.java +++ b/src/main/java/dan200/computercraft/core/apis/TermAPI.java @@ -6,6 +6,7 @@ package dan200.computercraft.core.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.core.computer.IComputerEnvironment; @@ -36,21 +37,6 @@ public String[] getNames() }; } - @Override - public void startup( ) - { - } - - @Override - public void advance( double _dt ) - { - } - - @Override - public void shutdown( ) - { - } - @Nonnull @Override public String[] getMethodNames() diff --git a/src/main/java/dan200/computercraft/core/computer/Computer.java b/src/main/java/dan200/computercraft/core/computer/Computer.java index 18e3751f8f..6014cf5089 100644 --- a/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -8,8 +8,10 @@ import com.google.common.base.Objects; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; +import dan200.computercraft.api.lua.*; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.apis.*; import dan200.computercraft.core.filesystem.FileSystem; @@ -18,6 +20,8 @@ import dan200.computercraft.core.lua.LuaJLuaMachine; import dan200.computercraft.core.terminal.Terminal; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; @@ -173,7 +177,91 @@ public void onPeripheralChanged( int side, IPeripheral peripheral ) } } } - + + private static class ComputerSystem extends ComputerAccess implements IComputerSystem + { + private final IAPIEnvironment m_environment; + + private ComputerSystem( IAPIEnvironment m_environment ) + { + super( m_environment ); + this.m_environment = m_environment; + } + + @Nonnull + @Override + public String getAttachmentName() + { + return "computer"; + } + + @Nullable + @Override + public IFileSystem getFileSystem() + { + FileSystem fs = m_environment.getFileSystem(); + return fs == null ? null : fs.getMountWrapper(); + } + + @Nullable + @Override + public String getLabel() + { + return m_environment.getLabel(); + } + } + + private static class APIWrapper implements ILuaAPI + { + private final ILuaAPI delegate; + private final ComputerSystem system; + + private APIWrapper( ILuaAPI delegate, ComputerSystem system ) + { + this.delegate = delegate; + this.system = system; + } + + @Override + public String[] getNames() + { + return delegate.getNames(); + } + + @Override + public void startup() + { + delegate.startup(); + } + + @Override + public void update() + { + delegate.update(); + } + + @Override + public void shutdown() + { + delegate.shutdown(); + system.unmountAll(); + } + + @Nonnull + @Override + public String[] getMethodNames() + { + return delegate.getMethodNames(); + } + + @Nullable + @Override + public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException + { + return delegate.callMethod( context, method, arguments ); + } + } + private static IMount s_romMount = null; private int m_id; @@ -371,7 +459,7 @@ public void advance( double _dt ) { for(ILuaAPI api : m_apis) { - api.advance( _dt ); + api.update(); } } } @@ -617,6 +705,16 @@ private void createAPIs() { m_apis.add( new HTTPAPI( m_apiEnvironment ) ); } + + for( ILuaAPIFactory factory : ComputerCraft.getAPIFactories() ) + { + ComputerSystem system = new ComputerSystem( m_apiEnvironment ); + ILuaAPI api = factory.create( system ); + if( api != null ) + { + m_apis.add( api ); + } + } } private void initLua() @@ -789,7 +887,7 @@ public void execute() // Shutdown our APIs synchronized( m_apis ) { - for(ILuaAPI api : m_apis) + for( ILuaAPI api : m_apis ) { api.shutdown(); } diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java index 0662ab4c87..9f3696e4c4 100644 --- a/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystem.java @@ -7,6 +7,7 @@ package dan200.computercraft.core.filesystem; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.filesystem.IFileSystem; import dan200.computercraft.api.filesystem.IMount; import dan200.computercraft.api.filesystem.IWritableMount; @@ -290,6 +291,7 @@ private String toLocal( String path ) } } + private final FileSystemMount m_wrapper = new FileSystemMount( this ); private final Map m_mounts = new HashMap<>(); private final Set m_openFiles = Collections.newSetFromMap( new WeakHashMap() ); @@ -734,6 +736,11 @@ private MountWrapper getMount( String path ) throws FileSystemException return match; } + public IFileSystem getMountWrapper() + { + return m_wrapper; + } + private static String sanitizePath( String path ) { return sanitizePath( path, false ); diff --git a/src/main/java/dan200/computercraft/core/filesystem/FileSystemMount.java b/src/main/java/dan200/computercraft/core/filesystem/FileSystemMount.java new file mode 100644 index 0000000000..1face43130 --- /dev/null +++ b/src/main/java/dan200/computercraft/core/filesystem/FileSystemMount.java @@ -0,0 +1,185 @@ +package dan200.computercraft.core.filesystem; + +import dan200.computercraft.api.filesystem.IFileSystem; + +import javax.annotation.Nonnull; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collections; +import java.util.List; + +public class FileSystemMount implements IFileSystem +{ + private final FileSystem m_filesystem; + + public FileSystemMount( FileSystem m_filesystem ) + { + this.m_filesystem = m_filesystem; + } + + @Override + public void makeDirectory( @Nonnull String path ) throws IOException + { + try + { + m_filesystem.makeDir( path ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public void delete( @Nonnull String path ) throws IOException + { + try + { + m_filesystem.delete( path ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Nonnull + @Override + public OutputStream openForWrite( @Nonnull String path ) throws IOException + { + try + { + return m_filesystem.openForWrite( path, false ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Nonnull + @Override + public OutputStream openForAppend( @Nonnull String path ) throws IOException + { + try + { + return m_filesystem.openForWrite( path, true ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public long getRemainingSpace() throws IOException + { + try + { + return m_filesystem.getFreeSpace( "/" ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public boolean exists( @Nonnull String path ) throws IOException + { + try + { + return m_filesystem.exists( path ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public boolean isDirectory( @Nonnull String path ) throws IOException + { + try + { + return m_filesystem.exists( path ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public void list( @Nonnull String path, @Nonnull List contents ) throws IOException + { + try + { + Collections.addAll( contents, m_filesystem.list( path ) ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public long getSize( @Nonnull String path ) throws IOException + { + try + { + return m_filesystem.getSize( path ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Nonnull + @Override + public InputStream openForRead( @Nonnull String path ) throws IOException + { + try + { + return m_filesystem.openForRead( path ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public String combine( String path, String child ) + { + return m_filesystem.combine( path, child ); + } + + @Override + public void copy( String from, String to ) throws IOException + { + try + { + m_filesystem.copy( from, to ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } + + @Override + public void move( String from, String to ) throws IOException + { + try + { + m_filesystem.move( from, to ); + } + catch( FileSystemException e ) + { + throw new IOException( e.getMessage() ); + } + } +} diff --git a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java index 4ebba572b0..754982bae0 100644 --- a/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/ILuaMachine.java @@ -5,7 +5,7 @@ */ package dan200.computercraft.core.lua; -import dan200.computercraft.core.apis.ILuaAPI; +import dan200.computercraft.api.lua.ILuaAPI; import java.io.InputStream; import java.io.OutputStream; diff --git a/src/main/java/dan200/computercraft/core/lua/LuaJLuaMachine.java b/src/main/java/dan200/computercraft/core/lua/LuaJLuaMachine.java index abd7453f34..40d3a92af8 100644 --- a/src/main/java/dan200/computercraft/core/lua/LuaJLuaMachine.java +++ b/src/main/java/dan200/computercraft/core/lua/LuaJLuaMachine.java @@ -11,7 +11,7 @@ import dan200.computercraft.api.lua.ILuaObject; import dan200.computercraft.api.lua.ILuaTask; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.core.apis.ILuaAPI; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.ITask; import dan200.computercraft.core.computer.MainThread; diff --git a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java index 2c8b234530..6e693fced1 100644 --- a/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java +++ b/src/main/java/dan200/computercraft/shared/computer/apis/CommandAPI.java @@ -8,9 +8,9 @@ import com.google.common.collect.ImmutableMap; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; -import dan200.computercraft.core.apis.ILuaAPI; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.block.Block; @@ -49,21 +49,6 @@ public String[] getNames() }; } - @Override - public void startup() - { - } - - @Override - public void advance( double dt ) - { - } - - @Override - public void shutdown() - { - } - @Nonnull @Override public String[] getMethodNames() diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 4d7c3ed555..a7863c29ec 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -12,7 +12,7 @@ import dan200.computercraft.api.filesystem.IWritableMount; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.apis.IAPIEnvironment; -import dan200.computercraft.core.apis.ILuaAPI; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.IComputerEnvironment; import dan200.computercraft.shared.common.ServerTerminal; diff --git a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java index 46377e98ec..96a79791df 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java +++ b/src/main/java/dan200/computercraft/shared/pocket/apis/PocketAPI.java @@ -7,10 +7,10 @@ package dan200.computercraft.shared.pocket.apis; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.pocket.IPocketUpgrade; -import dan200.computercraft.core.apis.ILuaAPI; import dan200.computercraft.shared.pocket.core.PocketServerComputer; import dan200.computercraft.shared.util.InventoryUtil; import dan200.computercraft.shared.util.WorldUtil; @@ -39,21 +39,6 @@ public String[] getNames() }; } - @Override - public void startup() - { - } - - @Override - public void advance( double dt ) - { - } - - @Override - public void shutdown() - { - } - @Nonnull @Override public String[] getMethodNames() 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 1d5b6083f1..276e260a87 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java +++ b/src/main/java/dan200/computercraft/shared/turtle/apis/TurtleAPI.java @@ -6,13 +6,13 @@ package dan200.computercraft.shared.turtle.apis; +import dan200.computercraft.api.lua.ILuaAPI; import dan200.computercraft.api.lua.ILuaContext; import dan200.computercraft.api.lua.LuaException; import dan200.computercraft.api.turtle.ITurtleAccess; import dan200.computercraft.api.turtle.ITurtleCommand; import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.core.apis.IAPIEnvironment; -import dan200.computercraft.core.apis.ILuaAPI; import dan200.computercraft.shared.turtle.core.*; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; @@ -44,21 +44,6 @@ public String[] getNames() "turtle" }; } - - @Override - public void startup( ) - { - } - - @Override - public void advance( double _dt ) - { - } - - @Override - public void shutdown( ) - { - } @Nonnull @Override