mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2024-12-13 19:50:31 +00:00
commit
592c0c9341
2
LICENSE
2
LICENSE
@ -36,7 +36,7 @@ This mod is provided 'as is' with no warranties, implied or otherwise. The owner
|
|||||||
of this mod takes no responsibility for any damages incurred from the use of
|
of this mod takes no responsibility for any damages incurred from the use of
|
||||||
this mod. This mod alters fundamental parts of the Minecraft game, parts of
|
this mod. This mod alters fundamental parts of the Minecraft game, parts of
|
||||||
Minecraft may not work with this mod installed. All damages caused from the use
|
Minecraft may not work with this mod installed. All damages caused from the use
|
||||||
or misuse of this mad fall on the user.
|
or misuse of this mod fall on the user.
|
||||||
|
|
||||||
3. Play rights
|
3. Play rights
|
||||||
--------------
|
--------------
|
||||||
|
20
build.gradle
20
build.gradle
@ -31,7 +31,7 @@ minecraft {
|
|||||||
version = "1.9.4-12.17.0.1959"
|
version = "1.9.4-12.17.0.1959"
|
||||||
runDir = "run"
|
runDir = "run"
|
||||||
replace '${version}', project.version
|
replace '${version}', project.version
|
||||||
|
|
||||||
// the mappings can be changed at any time, and must be in the following format.
|
// the mappings can be changed at any time, and must be in the following format.
|
||||||
// snapshot_YYYYMMDD snapshot are built nightly.
|
// snapshot_YYYYMMDD snapshot are built nightly.
|
||||||
// stable_# stables are built at the discretion of the MCP team.
|
// stable_# stables are built at the discretion of the MCP team.
|
||||||
@ -46,7 +46,7 @@ dependencies {
|
|||||||
// or you may define them like so..
|
// or you may define them like so..
|
||||||
//compile "some.group:artifact:version:classifier"
|
//compile "some.group:artifact:version:classifier"
|
||||||
//compile "some.group:artifact:version"
|
//compile "some.group:artifact:version"
|
||||||
|
|
||||||
// real examples
|
// real examples
|
||||||
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
|
//compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
|
||||||
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
|
//compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
|
||||||
@ -78,23 +78,25 @@ processResources {
|
|||||||
inputs.property "mcversion", project.minecraft.version
|
inputs.property "mcversion", project.minecraft.version
|
||||||
|
|
||||||
def grgit = Grgit.open(dir: '.')
|
def grgit = Grgit.open(dir: '.')
|
||||||
inputs.property "commithash", grgit.log(maxCommits: 1)[0].id
|
inputs.property "commithash", grgit.head().id
|
||||||
|
|
||||||
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
|
def blacklist = ['GitHub', 'dan200', 'Daniel Ratcliffe']
|
||||||
Set<String> contributors = []
|
Set<String> contributors = []
|
||||||
|
|
||||||
grgit.log().each {
|
grgit.log().each {
|
||||||
if (!blacklist.contains(it.committer.name))
|
if (!blacklist.contains(it.author.name)) contributors.add(it.author.name)
|
||||||
contributors.add(it.committer.name)
|
if (!blacklist.contains(it.committer.name)) contributors.add(it.committer.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
from(sourceSets.main.resources.srcDirs) {
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
include 'mcmod.info'
|
include 'mcmod.info'
|
||||||
include 'assets/computercraft/lua/rom/help/credits.txt'
|
include 'assets/computercraft/lua/rom/help/credits.txt'
|
||||||
|
|
||||||
expand 'version':project.version, 'mcversion':project.minecraft.version, 'gitcontributors':contributors.sort().join('\n')
|
expand 'version':project.version,
|
||||||
}
|
'mcversion':project.minecraft.version,
|
||||||
|
'gitcontributors':contributors.sort(false, String.CASE_INSENSITIVE_ORDER).join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
from(sourceSets.main.resources.srcDirs) {
|
from(sourceSets.main.resources.srcDirs) {
|
||||||
exclude 'mcmod.info'
|
exclude 'mcmod.info'
|
||||||
exclude 'assets/computercraft/lua/rom/help/credits.txt'
|
exclude 'assets/computercraft/lua/rom/help/credits.txt'
|
||||||
|
@ -18,6 +18,7 @@ import dan200.computercraft.api.permissions.ITurtlePermissionProvider;
|
|||||||
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
import dan200.computercraft.api.pocket.IPocketUpgrade;
|
||||||
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
import dan200.computercraft.api.redstone.IBundledRedstoneProvider;
|
||||||
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
import dan200.computercraft.api.turtle.ITurtleUpgrade;
|
||||||
|
import dan200.computercraft.core.apis.AddressPredicate;
|
||||||
import dan200.computercraft.core.filesystem.ComboMount;
|
import dan200.computercraft.core.filesystem.ComboMount;
|
||||||
import dan200.computercraft.core.filesystem.FileMount;
|
import dan200.computercraft.core.filesystem.FileMount;
|
||||||
import dan200.computercraft.core.filesystem.JarMount;
|
import dan200.computercraft.core.filesystem.JarMount;
|
||||||
@ -60,6 +61,7 @@ import net.minecraft.util.EnumHand;
|
|||||||
import net.minecraft.util.SoundEvent;
|
import net.minecraft.util.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
import net.minecraftforge.common.config.ConfigCategory;
|
||||||
import net.minecraftforge.common.config.Configuration;
|
import net.minecraftforge.common.config.Configuration;
|
||||||
import net.minecraftforge.common.config.Property;
|
import net.minecraftforge.common.config.Property;
|
||||||
import net.minecraftforge.fml.common.FMLCommonHandler;
|
import net.minecraftforge.fml.common.FMLCommonHandler;
|
||||||
@ -105,8 +107,18 @@ public class ComputerCraft
|
|||||||
public static final int pocketComputerGUIID = 106;
|
public static final int pocketComputerGUIID = 106;
|
||||||
|
|
||||||
// Configuration options
|
// Configuration options
|
||||||
|
private static final String[] DEFAULT_HTTP_WHITELIST = new String[] { "*" };
|
||||||
|
private static final String[] DEFAULT_HTTP_BLACKLIST = new String[] {
|
||||||
|
"127.0.0.0/8",
|
||||||
|
"10.0.0.0/8",
|
||||||
|
"172.16.0.0/12",
|
||||||
|
"192.168.0.0/16",
|
||||||
|
"fd00::/8",
|
||||||
|
};
|
||||||
|
|
||||||
public static boolean http_enable = true;
|
public static boolean http_enable = true;
|
||||||
public static String http_whitelist = "*";
|
public static AddressPredicate http_whitelist = new AddressPredicate( DEFAULT_HTTP_WHITELIST );
|
||||||
|
public static AddressPredicate http_blacklist = new AddressPredicate( DEFAULT_HTTP_BLACKLIST );
|
||||||
public static boolean disable_lua51_features = false;
|
public static boolean disable_lua51_features = false;
|
||||||
public static String default_computer_settings = "";
|
public static String default_computer_settings = "";
|
||||||
public static boolean logPeripheralErrors = false;
|
public static boolean logPeripheralErrors = false;
|
||||||
@ -185,6 +197,7 @@ public class ComputerCraft
|
|||||||
|
|
||||||
public static Property http_enable;
|
public static Property http_enable;
|
||||||
public static Property http_whitelist;
|
public static Property http_whitelist;
|
||||||
|
public static Property http_blacklist;
|
||||||
public static Property disable_lua51_features;
|
public static Property disable_lua51_features;
|
||||||
public static Property default_computer_settings;
|
public static Property default_computer_settings;
|
||||||
public static Property logPeripheralErrors;
|
public static Property logPeripheralErrors;
|
||||||
@ -252,10 +265,28 @@ public class ComputerCraft
|
|||||||
Config.config.load();
|
Config.config.load();
|
||||||
|
|
||||||
Config.http_enable = Config.config.get( Configuration.CATEGORY_GENERAL, "http_enable", http_enable );
|
Config.http_enable = Config.config.get( Configuration.CATEGORY_GENERAL, "http_enable", http_enable );
|
||||||
Config.http_enable.setComment( "Enable the \"http\" API on Computers (see \"http_whitelist\" for more fine grained control than this)" );
|
Config.http_enable.setComment( "Enable the \"http\" API on Computers (see \"http_whitelist\" and \"http_blacklist\" for more fine grained control than this)" );
|
||||||
|
|
||||||
Config.http_whitelist = Config.config.get( Configuration.CATEGORY_GENERAL, "http_whitelist", http_whitelist );
|
{
|
||||||
Config.http_whitelist.setComment( "A semicolon limited list of wildcards for domains that can be accessed through the \"http\" API on Computers. Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com;*.github.com;*.computercraft.info\" will restrict access to just those 3 domains." );
|
ConfigCategory category = Config.config.getCategory( Configuration.CATEGORY_GENERAL );
|
||||||
|
Property currentProperty = category.get( "http_whitelist" );
|
||||||
|
if( currentProperty != null && !currentProperty.isList() ) category.remove( "http_whitelist" );
|
||||||
|
|
||||||
|
Config.http_whitelist = Config.config.get( Configuration.CATEGORY_GENERAL, "http_whitelist", DEFAULT_HTTP_WHITELIST );
|
||||||
|
|
||||||
|
if( currentProperty != null && !currentProperty.isList() )
|
||||||
|
{
|
||||||
|
Config.http_whitelist.setValues( currentProperty.getString().split( ";" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Config.http_whitelist.setComment( "A list of wildcards for domains or IP ranges that can be accessed through the \"http\" API on Computers.\n" +
|
||||||
|
"Set this to \"*\" to access to the entire internet. Example: \"*.pastebin.com\" will restrict access to just subdomains of pastebin.com.\n" +
|
||||||
|
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." );
|
||||||
|
|
||||||
|
Config.http_blacklist = Config.config.get( Configuration.CATEGORY_GENERAL, "http_blacklist", DEFAULT_HTTP_BLACKLIST );
|
||||||
|
Config.http_blacklist.setComment( "A list of wildcards for domains or IP ranges that cannot be accessed through the \"http\" API on Computers.\n" +
|
||||||
|
"If this is empty then all whitelisted domains will be accessible. Example: \"*.github.com\" will block access to all subdomains of github.com.\n" +
|
||||||
|
"You can use domain names (\"pastebin.com\"), wilcards (\"*.pastebin.com\") or CIDR notation (\"127.0.0.0/8\")." );
|
||||||
|
|
||||||
Config.disable_lua51_features = Config.config.get( Configuration.CATEGORY_GENERAL, "disable_lua51_features", disable_lua51_features );
|
Config.disable_lua51_features = Config.config.get( Configuration.CATEGORY_GENERAL, "disable_lua51_features", disable_lua51_features );
|
||||||
Config.disable_lua51_features.setComment( "Set this to true to disable Lua 5.1 functions that will be removed in a future update. Useful for ensuring forward compatibility of your programs now." );
|
Config.disable_lua51_features.setComment( "Set this to true to disable Lua 5.1 functions that will be removed in a future update. Useful for ensuring forward compatibility of your programs now." );
|
||||||
@ -327,7 +358,8 @@ public class ComputerCraft
|
|||||||
public static void syncConfig() {
|
public static void syncConfig() {
|
||||||
|
|
||||||
http_enable = Config.http_enable.getBoolean();
|
http_enable = Config.http_enable.getBoolean();
|
||||||
http_whitelist = Config.http_whitelist.getString();
|
http_whitelist = new AddressPredicate( Config.http_whitelist.getStringList() );
|
||||||
|
http_blacklist = new AddressPredicate( Config.http_blacklist.getStringList() );
|
||||||
disable_lua51_features = Config.disable_lua51_features.getBoolean();
|
disable_lua51_features = Config.disable_lua51_features.getBoolean();
|
||||||
default_computer_settings = Config.default_computer_settings.getString();
|
default_computer_settings = Config.default_computer_settings.getString();
|
||||||
|
|
||||||
|
@ -0,0 +1,168 @@
|
|||||||
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import com.google.common.net.InetAddresses;
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
|
||||||
|
import java.net.Inet6Address;
|
||||||
|
import java.net.InetAddress;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to determine whether a domain or IP address matches a series of patterns.
|
||||||
|
*/
|
||||||
|
public class AddressPredicate
|
||||||
|
{
|
||||||
|
private static class HostRange
|
||||||
|
{
|
||||||
|
private final byte[] min;
|
||||||
|
private final byte[] max;
|
||||||
|
|
||||||
|
private HostRange( byte[] min, byte[] max )
|
||||||
|
{
|
||||||
|
this.min = min;
|
||||||
|
this.max = max;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains( InetAddress address )
|
||||||
|
{
|
||||||
|
byte[] entry = address.getAddress();
|
||||||
|
if( entry.length != min.length ) return false;
|
||||||
|
|
||||||
|
for( int i = 0; i < entry.length; i++ )
|
||||||
|
{
|
||||||
|
int value = 0xFF & entry[ i ];
|
||||||
|
if( value < (0xFF & min[ i ]) || value > (0xFF & max[ i ]) ) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final List<Pattern> wildcards;
|
||||||
|
private final List<HostRange> ranges;
|
||||||
|
|
||||||
|
public AddressPredicate( String... filters )
|
||||||
|
{
|
||||||
|
List<Pattern> wildcards = this.wildcards = new ArrayList<Pattern>();
|
||||||
|
List<HostRange> ranges = this.ranges = new ArrayList<HostRange>();
|
||||||
|
|
||||||
|
for( String filter : filters )
|
||||||
|
{
|
||||||
|
int cidr = filter.indexOf( '/' );
|
||||||
|
if( cidr >= 0 )
|
||||||
|
{
|
||||||
|
String addressStr = filter.substring( 0, cidr );
|
||||||
|
String prefixSizeStr = filter.substring( cidr + 1 );
|
||||||
|
|
||||||
|
int prefixSize;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
prefixSize = Integer.parseInt( prefixSizeStr );
|
||||||
|
}
|
||||||
|
catch( NumberFormatException e )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.warn( "Cannot parse CIDR size from {} ({})", filter, prefixSizeStr );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
InetAddress address;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
address = InetAddresses.forString( addressStr );
|
||||||
|
}
|
||||||
|
catch( IllegalArgumentException e )
|
||||||
|
{
|
||||||
|
ComputerCraft.log.warn( "Cannot parse IP address from {} ({})", filter, addressStr );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask the bytes of the IP address.
|
||||||
|
byte[] minBytes = address.getAddress(), maxBytes = address.getAddress();
|
||||||
|
int size = prefixSize;
|
||||||
|
for( int i = 0; i < minBytes.length; i++ )
|
||||||
|
{
|
||||||
|
if( size <= 0 )
|
||||||
|
{
|
||||||
|
minBytes[ i ] &= 0;
|
||||||
|
maxBytes[ i ] |= 0xFF;
|
||||||
|
}
|
||||||
|
else if( size < 8 )
|
||||||
|
{
|
||||||
|
minBytes[ i ] &= 0xFF << (8 - size);
|
||||||
|
maxBytes[ i ] |= ~(0xFF << (8 - size));
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
ranges.add( new HostRange( minBytes, maxBytes ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wildcards.add( Pattern.compile( "^\\Q" + filter.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether a host name matches a series of patterns.
|
||||||
|
*
|
||||||
|
* This is intended to allow early exiting, before one has to look up the IP address. You should use
|
||||||
|
* {@link #matches(InetAddress)} instead of/in addition to this one.
|
||||||
|
*
|
||||||
|
* @param domain The domain to match.
|
||||||
|
* @return Whether the patterns were matched.
|
||||||
|
*/
|
||||||
|
public boolean matches( String domain )
|
||||||
|
{
|
||||||
|
for( Pattern domainPattern : wildcards )
|
||||||
|
{
|
||||||
|
if( domainPattern.matcher( domain ).matches() ) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesAddress( InetAddress address )
|
||||||
|
{
|
||||||
|
String addressString = address.getHostAddress();
|
||||||
|
for( Pattern domainPattern : wildcards )
|
||||||
|
{
|
||||||
|
if( domainPattern.matcher( addressString ).matches() ) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for( HostRange range : ranges )
|
||||||
|
{
|
||||||
|
if( range.contains( address ) ) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the given address matches a series of patterns
|
||||||
|
*
|
||||||
|
* @param address The address to check.
|
||||||
|
* @return Whether it matches any of these patterns.
|
||||||
|
*/
|
||||||
|
public boolean matches( InetAddress address )
|
||||||
|
{
|
||||||
|
// Match the host name
|
||||||
|
String host = address.getHostName();
|
||||||
|
if( host != null && matches( host ) ) return true;
|
||||||
|
|
||||||
|
// Match the normal address
|
||||||
|
if( matchesAddress( address ) ) return true;
|
||||||
|
|
||||||
|
// If we're an IPv4 address in disguise then let's check that.
|
||||||
|
if( address instanceof Inet6Address && InetAddresses.is6to4Address( (Inet6Address) address )
|
||||||
|
&& matchesAddress( InetAddresses.get6to4IPv4Address( (Inet6Address) address ) ) )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
246
src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java
Normal file
246
src/main/java/dan200/computercraft/core/apis/ArgumentHelper.java
Normal file
@ -0,0 +1,246 @@
|
|||||||
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Various helpers for arguments
|
||||||
|
*/
|
||||||
|
public final class ArgumentHelper
|
||||||
|
{
|
||||||
|
private ArgumentHelper()
|
||||||
|
{
|
||||||
|
throw new IllegalStateException( "Cannot instantiate singleton " + getClass().getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static String getType( @Nullable Object type )
|
||||||
|
{
|
||||||
|
if( type == null ) return "nil";
|
||||||
|
if( type instanceof String ) return "string";
|
||||||
|
if( type instanceof Boolean ) return "boolean";
|
||||||
|
if( type instanceof Number ) return "number";
|
||||||
|
if( type instanceof Map ) return "table";
|
||||||
|
|
||||||
|
Class<?> klass = type.getClass();
|
||||||
|
if( klass.isArray() )
|
||||||
|
{
|
||||||
|
StringBuilder name = new StringBuilder();
|
||||||
|
while( klass.isArray() )
|
||||||
|
{
|
||||||
|
name.append( "[]" );
|
||||||
|
klass = klass.getComponentType();
|
||||||
|
}
|
||||||
|
name.insert( 0, klass.getName() );
|
||||||
|
return name.toString();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return klass.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static LuaException badArgument( int index, @Nonnull String expected, @Nullable Object actual )
|
||||||
|
{
|
||||||
|
return badArgument( index, expected, getType( actual ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static LuaException badArgument( int index, @Nonnull String expected, @Nonnull String actual )
|
||||||
|
{
|
||||||
|
return new LuaException( "bad argument #" + (index + 1) + " (" + expected + " expected, got " + actual + ")" );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getNumber( @Nonnull Object[] args, int index ) throws LuaException
|
||||||
|
{
|
||||||
|
if( index >= args.length ) throw badArgument( index, "number", "nil" );
|
||||||
|
Object value = args[ index ];
|
||||||
|
if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return ((Number) value).doubleValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getInt( @Nonnull Object[] args, int index ) throws LuaException
|
||||||
|
{
|
||||||
|
if( index >= args.length ) throw badArgument( index, "number", "nil" );
|
||||||
|
Object value = args[ index ];
|
||||||
|
if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return (int) ((Number) value).longValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double getReal( @Nonnull Object[] args, int index ) throws LuaException
|
||||||
|
{
|
||||||
|
return checkReal( index, getNumber( args, index ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean getBoolean( @Nonnull Object[] args, int index ) throws LuaException
|
||||||
|
{
|
||||||
|
if( index >= args.length ) throw badArgument( index, "boolean", "nil" );
|
||||||
|
Object value = args[ index ];
|
||||||
|
if( value instanceof Boolean )
|
||||||
|
{
|
||||||
|
return (Boolean) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "boolean", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
public static String getString( @Nonnull Object[] args, int index ) throws LuaException
|
||||||
|
{
|
||||||
|
if( index >= args.length ) throw badArgument( index, "string", "nil" );
|
||||||
|
Object value = args[ index ];
|
||||||
|
if( value instanceof String )
|
||||||
|
{
|
||||||
|
return (String) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "string", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Nonnull
|
||||||
|
public static Map<Object, Object> getTable( @Nonnull Object[] args, int index ) throws LuaException
|
||||||
|
{
|
||||||
|
if( index >= args.length ) throw badArgument( index, "table", "nil" );
|
||||||
|
Object value = args[ index ];
|
||||||
|
if( value instanceof Map )
|
||||||
|
{
|
||||||
|
return (Map<Object, Object>) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "table", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double optNumber( @Nonnull Object[] args, int index, double def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = index < args.length ? args[ index ] : null;
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return ((Number) value).doubleValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int optInt( @Nonnull Object[] args, int index, int def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = index < args.length ? args[ index ] : null;
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Number )
|
||||||
|
{
|
||||||
|
return (int) ((Number) value).longValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "number", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static double optReal( @Nonnull Object[] args, int index, double def ) throws LuaException
|
||||||
|
{
|
||||||
|
return checkReal( index, optNumber( args, index, def ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean optBoolean( @Nonnull Object[] args, int index, boolean def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = index < args.length ? args[ index ] : null;
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Boolean )
|
||||||
|
{
|
||||||
|
return (Boolean) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "boolean", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String optString( @Nonnull Object[] args, int index, String def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = index < args.length ? args[ index ] : null;
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof String )
|
||||||
|
{
|
||||||
|
return (String) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "string", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public static Map<Object, Object> optTable( @Nonnull Object[] args, int index, Map<Object, Object> def ) throws LuaException
|
||||||
|
{
|
||||||
|
Object value = index < args.length ? args[ index ] : null;
|
||||||
|
if( value == null )
|
||||||
|
{
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
else if( value instanceof Map )
|
||||||
|
{
|
||||||
|
return (Map<Object, Object>) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw badArgument( index, "table", value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static double checkReal( int index, double value ) throws LuaException
|
||||||
|
{
|
||||||
|
if( Double.isNaN( value ) )
|
||||||
|
{
|
||||||
|
throw badArgument( index, "number", "nan" );
|
||||||
|
}
|
||||||
|
else if( value == Double.POSITIVE_INFINITY )
|
||||||
|
{
|
||||||
|
throw badArgument( index, "number", "inf" );
|
||||||
|
}
|
||||||
|
else if( value == Double.NEGATIVE_INFINITY )
|
||||||
|
{
|
||||||
|
throw badArgument( index, "number", "-inf" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,8 @@ import dan200.computercraft.api.lua.LuaException;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
||||||
|
|
||||||
// Contributed by Nia
|
// Contributed by Nia
|
||||||
// Based on LuaBit (http://luaforge.net/projects/bit)
|
// Based on LuaBit (http://luaforge.net/projects/bit)
|
||||||
|
|
||||||
@ -23,25 +25,6 @@ public class BitAPI implements ILuaAPI
|
|||||||
private static final int BRSHIFT = 4;
|
private static final int BRSHIFT = 4;
|
||||||
private static final int BLSHIFT = 5;
|
private static final int BLSHIFT = 5;
|
||||||
private static final int BLOGIC_RSHIFT = 6;
|
private static final int BLOGIC_RSHIFT = 6;
|
||||||
|
|
||||||
private static int checkInt( Object o, int count ) throws LuaException
|
|
||||||
{
|
|
||||||
if( o instanceof Number )
|
|
||||||
{
|
|
||||||
return (int)(((Number)o).longValue());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if( count == 2 )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number, number" );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BitAPI( IAPIEnvironment _environment )
|
public BitAPI( IAPIEnvironment _environment )
|
||||||
{
|
{
|
||||||
@ -82,31 +65,28 @@ public class BitAPI implements ILuaAPI
|
|||||||
@Override
|
@Override
|
||||||
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
|
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException
|
||||||
{
|
{
|
||||||
Object a = args.length>0?args[0]:null;
|
|
||||||
Object b = args.length>1?args[1]:null;
|
|
||||||
|
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
switch(method) {
|
switch(method) {
|
||||||
case BNOT:
|
case BNOT:
|
||||||
ret = ~checkInt(a, 1);
|
ret = ~getInt( args, 0 );
|
||||||
break;
|
break;
|
||||||
case BAND:
|
case BAND:
|
||||||
ret = checkInt(a, 2) & checkInt(b, 2);
|
ret = getInt( args, 0 ) & getInt( args, 1 );
|
||||||
break;
|
break;
|
||||||
case BOR:
|
case BOR:
|
||||||
ret = checkInt(a, 2) | checkInt(b, 2);
|
ret = getInt( args, 0 ) | getInt( args, 1 );
|
||||||
break;
|
break;
|
||||||
case BXOR:
|
case BXOR:
|
||||||
ret = checkInt(a, 2) ^ checkInt(b, 2);
|
ret = getInt( args, 0 ) ^ getInt( args, 1 );
|
||||||
break;
|
break;
|
||||||
case BRSHIFT:
|
case BRSHIFT:
|
||||||
ret = checkInt(a, 2) >> checkInt(b, 2);
|
ret = getInt( args, 0 ) >> getInt( args, 1 );
|
||||||
break;
|
break;
|
||||||
case BLSHIFT:
|
case BLSHIFT:
|
||||||
ret = checkInt(a, 2) << checkInt(b, 2);
|
ret = getInt( args, 0 ) << getInt( args, 1 );
|
||||||
break;
|
break;
|
||||||
case BLOGIC_RSHIFT:
|
case BLOGIC_RSHIFT:
|
||||||
ret = checkInt(a, 2) >>> checkInt(b, 2);
|
ret = getInt( args, 0 ) >>> getInt( args, 1 );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,9 @@ import dan200.computercraft.core.terminal.TextBuffer;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.optInt;
|
||||||
|
|
||||||
public class BufferAPI implements ILuaAPI
|
public class BufferAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private static class BufferLuaObject implements ILuaObject
|
private static class BufferLuaObject implements ILuaObject
|
||||||
@ -55,81 +58,25 @@ public class BufferAPI implements ILuaAPI
|
|||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// read
|
// read
|
||||||
int start = 0;
|
int start = optInt( arguments, 0, 0 );
|
||||||
if( arguments.length >= 1 && (arguments[0] != null) )
|
int end = optInt( arguments, 1, m_buffer.length() );
|
||||||
{
|
|
||||||
if( !(arguments[0] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
start = ((Number)arguments[1]).intValue() - 1;
|
|
||||||
}
|
|
||||||
int end = m_buffer.length();
|
|
||||||
if( arguments.length >= 2 && (arguments[1] != null) )
|
|
||||||
{
|
|
||||||
if( !(arguments[1] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number, number" );
|
|
||||||
}
|
|
||||||
end = ((Number)arguments[1]).intValue();
|
|
||||||
}
|
|
||||||
return new Object[] { m_buffer.read( start, end ) };
|
return new Object[] { m_buffer.read( start, end ) };
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// write
|
// write
|
||||||
if( arguments.length < 1 || !(arguments[0] instanceof String) )
|
String text = getString( arguments, 0 );
|
||||||
{
|
int start = optInt( arguments, 1, 0 );
|
||||||
throw new LuaException( "Expected string" );
|
int end = optInt( arguments, 2, start + text.length() );
|
||||||
}
|
|
||||||
String text = (String)(arguments[0]);
|
|
||||||
int start = 0;
|
|
||||||
if( arguments.length >= 2 && (arguments[1] != null) )
|
|
||||||
{
|
|
||||||
if( !(arguments[1] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number" );
|
|
||||||
}
|
|
||||||
start = ((Number)arguments[1]).intValue() - 1;
|
|
||||||
}
|
|
||||||
int end = start + text.length();
|
|
||||||
if( arguments.length >= 3 && (arguments[2] != null) )
|
|
||||||
{
|
|
||||||
if( !(arguments[2] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number, number" );
|
|
||||||
}
|
|
||||||
end = ((Number)arguments[2]).intValue();
|
|
||||||
}
|
|
||||||
m_buffer.write( text, start, end );
|
m_buffer.write( text, start, end );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
// fill
|
// fill
|
||||||
if( arguments.length < 1 || !(arguments[0] instanceof String) )
|
String text = getString( arguments, 0 );
|
||||||
{
|
int start = optInt( arguments, 1, 0 );
|
||||||
throw new LuaException( "Expected string" );
|
int end = optInt( arguments, 2, m_buffer.length() );
|
||||||
}
|
|
||||||
String text = (String)(arguments[0]);
|
|
||||||
int start = 0;
|
|
||||||
if( arguments.length >= 2 && (arguments[1] != null) )
|
|
||||||
{
|
|
||||||
if( !(arguments[1] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number" );
|
|
||||||
}
|
|
||||||
start = ((Number)arguments[1]).intValue() - 1;
|
|
||||||
}
|
|
||||||
int end = m_buffer.length();
|
|
||||||
if( arguments.length >= 3 && (arguments[2] != null) )
|
|
||||||
{
|
|
||||||
if( !(arguments[2] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number, number" );
|
|
||||||
}
|
|
||||||
end = ((Number)arguments[2]).intValue();
|
|
||||||
}
|
|
||||||
m_buffer.fill( text, start, end );
|
m_buffer.fill( text, start, end );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -184,23 +131,11 @@ public class BufferAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
if( arguments.length < 1 || !(arguments[0] instanceof String) )
|
String text = getString( arguments, 0 );
|
||||||
|
int repetitions = optInt( arguments, 1, 1 );
|
||||||
|
if( repetitions < 0 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Expected string" );
|
throw ArgumentHelper.badArgument( 1, "positive number", Integer.toString( repetitions ) );
|
||||||
}
|
|
||||||
String text = (String)(arguments[0]);
|
|
||||||
int repetitions = 1;
|
|
||||||
if( arguments.length >= 2 && arguments[1] != null )
|
|
||||||
{
|
|
||||||
if( !(arguments[1] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number" );
|
|
||||||
}
|
|
||||||
repetitions = ((Number)arguments[1]).intValue();
|
|
||||||
if( repetitions < 0 )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected positive number" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
TextBuffer buffer = new TextBuffer( text, repetitions );
|
TextBuffer buffer = new TextBuffer( text, repetitions );
|
||||||
return new Object[] { new BufferLuaObject( buffer ) };
|
return new Object[] { new BufferLuaObject( buffer ) };
|
||||||
|
@ -21,6 +21,8 @@ import java.io.OutputStream;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
public class FSAPI implements ILuaAPI
|
public class FSAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private IAPIEnvironment m_env;
|
private IAPIEnvironment m_env;
|
||||||
@ -89,11 +91,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// list
|
// list
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
String[] results = m_fileSystem.list( path );
|
String[] results = m_fileSystem.list( path );
|
||||||
Map<Object,Object> table = new HashMap<Object,Object>();
|
Map<Object,Object> table = new HashMap<Object,Object>();
|
||||||
@ -110,32 +108,20 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// combine
|
// combine
|
||||||
if( args.length != 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) )
|
String pathA = getString( args, 0 );
|
||||||
{
|
String pathB = getString( args, 1 );
|
||||||
throw new LuaException( "Expected string, string" );
|
|
||||||
}
|
|
||||||
String pathA = (String)args[0];
|
|
||||||
String pathB = (String)args[1];
|
|
||||||
return new Object[] { m_fileSystem.combine( pathA, pathB ) };
|
return new Object[] { m_fileSystem.combine( pathA, pathB ) };
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// getName
|
// getName
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
return new Object[]{ FileSystem.getName( path ) };
|
return new Object[]{ FileSystem.getName( path ) };
|
||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// getSize
|
// getSize
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
return new Object[]{ m_fileSystem.getSize( path ) };
|
return new Object[]{ m_fileSystem.getSize( path ) };
|
||||||
@ -148,11 +134,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
// exists
|
// exists
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
return new Object[]{ m_fileSystem.exists( path ) };
|
return new Object[]{ m_fileSystem.exists( path ) };
|
||||||
} catch( FileSystemException e ) {
|
} catch( FileSystemException e ) {
|
||||||
@ -162,11 +144,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 5:
|
case 5:
|
||||||
{
|
{
|
||||||
// isDir
|
// isDir
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
return new Object[]{ m_fileSystem.isDir( path ) };
|
return new Object[]{ m_fileSystem.isDir( path ) };
|
||||||
} catch( FileSystemException e ) {
|
} catch( FileSystemException e ) {
|
||||||
@ -176,11 +154,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 6:
|
case 6:
|
||||||
{
|
{
|
||||||
// isReadOnly
|
// isReadOnly
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
return new Object[]{ m_fileSystem.isReadOnly( path ) };
|
return new Object[]{ m_fileSystem.isReadOnly( path ) };
|
||||||
} catch( FileSystemException e ) {
|
} catch( FileSystemException e ) {
|
||||||
@ -190,11 +164,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 7:
|
case 7:
|
||||||
{
|
{
|
||||||
// makeDir
|
// makeDir
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
m_fileSystem.makeDir( path );
|
m_fileSystem.makeDir( path );
|
||||||
return null;
|
return null;
|
||||||
@ -205,12 +175,8 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 8:
|
case 8:
|
||||||
{
|
{
|
||||||
// move
|
// move
|
||||||
if( args.length != 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
String dest = getString( args, 1 );
|
||||||
throw new LuaException( "Expected string, string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
String dest = (String)args[1];
|
|
||||||
try {
|
try {
|
||||||
m_fileSystem.move( path, dest );
|
m_fileSystem.move( path, dest );
|
||||||
return null;
|
return null;
|
||||||
@ -221,12 +187,8 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 9:
|
case 9:
|
||||||
{
|
{
|
||||||
// copy
|
// copy
|
||||||
if( args.length != 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
String dest = getString( args, 1 );
|
||||||
throw new LuaException( "Expected string, string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
String dest = (String)args[1];
|
|
||||||
try {
|
try {
|
||||||
m_fileSystem.copy( path, dest );
|
m_fileSystem.copy( path, dest );
|
||||||
return null;
|
return null;
|
||||||
@ -237,11 +199,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 10:
|
case 10:
|
||||||
{
|
{
|
||||||
// delete
|
// delete
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
m_fileSystem.delete( path );
|
m_fileSystem.delete( path );
|
||||||
return null;
|
return null;
|
||||||
@ -252,12 +210,8 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 11:
|
case 11:
|
||||||
{
|
{
|
||||||
// open
|
// open
|
||||||
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
String mode = getString( args, 1 );
|
||||||
throw new LuaException( "Expected string, string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
String mode = (String)args[1];
|
|
||||||
try {
|
try {
|
||||||
if( mode.equals( "r" ) ) {
|
if( mode.equals( "r" ) ) {
|
||||||
// Open the file for reading, then create a wrapper around the reader
|
// Open the file for reading, then create a wrapper around the reader
|
||||||
@ -300,11 +254,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 12:
|
case 12:
|
||||||
{
|
{
|
||||||
// getDrive
|
// getDrive
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
if( !m_fileSystem.exists( path ) )
|
if( !m_fileSystem.exists( path ) )
|
||||||
{
|
{
|
||||||
@ -318,11 +268,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 13:
|
case 13:
|
||||||
{
|
{
|
||||||
// getFreeSpace
|
// getFreeSpace
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
long freeSpace = m_fileSystem.getFreeSpace( path );
|
long freeSpace = m_fileSystem.getFreeSpace( path );
|
||||||
if( freeSpace >= 0 )
|
if( freeSpace >= 0 )
|
||||||
@ -337,11 +283,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 14:
|
case 14:
|
||||||
{
|
{
|
||||||
// find
|
// find
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
try {
|
try {
|
||||||
String[] results = m_fileSystem.find( path );
|
String[] results = m_fileSystem.find( path );
|
||||||
Map<Object,Object> table = new HashMap<Object,Object>();
|
Map<Object,Object> table = new HashMap<Object,Object>();
|
||||||
@ -356,11 +298,7 @@ public class FSAPI implements ILuaAPI
|
|||||||
case 15:
|
case 15:
|
||||||
{
|
{
|
||||||
// getDir
|
// getDir
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof String) )
|
String path = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String path = (String)args[0];
|
|
||||||
return new Object[]{ FileSystem.getDirectory( path ) };
|
return new Object[]{ FileSystem.getDirectory( path ) };
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
@ -7,24 +7,26 @@
|
|||||||
package dan200.computercraft.core.apis;
|
package dan200.computercraft.core.apis;
|
||||||
|
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.ILuaObject;
|
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
|
import dan200.computercraft.core.apis.http.HTTPCheck;
|
||||||
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
|
import dan200.computercraft.core.apis.http.HTTPRequest;
|
||||||
|
import dan200.computercraft.core.apis.http.HTTPTask;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.InputStream;
|
import java.net.URL;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||||
|
|
||||||
public class HTTPAPI implements ILuaAPI
|
public class HTTPAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private final IAPIEnvironment m_apiEnvironment;
|
private final IAPIEnvironment m_apiEnvironment;
|
||||||
private final List<HTTPRequest> m_httpRequests;
|
private final List<HTTPTask> m_httpTasks;
|
||||||
|
|
||||||
public HTTPAPI( IAPIEnvironment environment )
|
public HTTPAPI( IAPIEnvironment environment )
|
||||||
{
|
{
|
||||||
m_apiEnvironment = environment;
|
m_apiEnvironment = environment;
|
||||||
m_httpRequests = new ArrayList<HTTPRequest>();
|
m_httpTasks = new ArrayList<HTTPTask>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -44,95 +46,31 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
public void advance( double _dt )
|
public void advance( double _dt )
|
||||||
{
|
{
|
||||||
// Wait for all of our http requests
|
// Wait for all of our http requests
|
||||||
synchronized( m_httpRequests )
|
synchronized( m_httpTasks )
|
||||||
{
|
{
|
||||||
Iterator<HTTPRequest> it = m_httpRequests.iterator();
|
Iterator<HTTPTask> it = m_httpTasks.iterator();
|
||||||
while( it.hasNext() ) {
|
while( it.hasNext() )
|
||||||
final HTTPRequest h = it.next();
|
{
|
||||||
if( h.isComplete() ) {
|
final HTTPTask h = it.next();
|
||||||
final String url = h.getURL();
|
if( h.isFinished() )
|
||||||
if( h.wasSuccessful() ) {
|
{
|
||||||
// Queue the "http_success" event
|
h.whenFinished( m_apiEnvironment );
|
||||||
InputStream contents = h.getContents();
|
|
||||||
Object result = wrapStream(
|
|
||||||
h.isBinary() ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, h.getEncoding() ),
|
|
||||||
h.getResponseCode(), h.getResponseHeaders()
|
|
||||||
);
|
|
||||||
m_apiEnvironment.queueEvent( "http_success", new Object[] { url, result } );
|
|
||||||
} else {
|
|
||||||
// Queue the "http_failure" event
|
|
||||||
InputStream contents = h.getContents();
|
|
||||||
Object result = null;
|
|
||||||
if( contents != null ) {
|
|
||||||
result = wrapStream(
|
|
||||||
h.isBinary() ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, h.getEncoding() ),
|
|
||||||
h.getResponseCode(), h.getResponseHeaders()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
m_apiEnvironment.queueEvent( "http_failure", new Object[]{ url, "Could not connect", result } );
|
|
||||||
}
|
|
||||||
it.remove();
|
it.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ILuaObject wrapStream( final ILuaObject reader, final int responseCode, final Map<String, String> responseHeaders )
|
|
||||||
{
|
|
||||||
String[] oldMethods = reader.getMethodNames();
|
|
||||||
final int methodOffset = oldMethods.length;
|
|
||||||
|
|
||||||
final String[] newMethods = Arrays.copyOf( oldMethods, oldMethods.length + 2 );
|
|
||||||
newMethods[ methodOffset + 0 ] = "getResponseCode";
|
|
||||||
newMethods[ methodOffset + 1 ] = "getResponseHeaders";
|
|
||||||
|
|
||||||
return new ILuaObject()
|
|
||||||
{
|
|
||||||
@Nonnull
|
|
||||||
@Override
|
|
||||||
public String[] getMethodNames()
|
|
||||||
{
|
|
||||||
return newMethods;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
|
|
||||||
{
|
|
||||||
if( method < methodOffset )
|
|
||||||
{
|
|
||||||
return reader.callMethod( context, method, args );
|
|
||||||
}
|
|
||||||
switch( method - methodOffset )
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
{
|
|
||||||
// getResponseCode
|
|
||||||
return new Object[] { responseCode };
|
|
||||||
}
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
// getResponseHeaders
|
|
||||||
return new Object[] { responseHeaders };
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void shutdown( )
|
public void shutdown( )
|
||||||
{
|
{
|
||||||
synchronized( m_httpRequests )
|
synchronized( m_httpTasks )
|
||||||
{
|
{
|
||||||
for( HTTPRequest r : m_httpRequests )
|
for( HTTPTask r : m_httpTasks )
|
||||||
{
|
{
|
||||||
r.cancel();
|
r.cancel();
|
||||||
}
|
}
|
||||||
m_httpRequests.clear();
|
m_httpTasks.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,24 +93,16 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
// request
|
// request
|
||||||
// Get URL
|
// Get URL
|
||||||
if( args.length < 1 || !(args[0] instanceof String) )
|
String urlString = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String urlString = args[0].toString();
|
|
||||||
|
|
||||||
// Get POST
|
// Get POST
|
||||||
String postString = null;
|
String postString = optString( args, 1, null );
|
||||||
if( args.length >= 2 && args[1] instanceof String )
|
|
||||||
{
|
|
||||||
postString = args[1].toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Headers
|
// Get Headers
|
||||||
Map<String, String> headers = null;
|
Map<String, String> headers = null;
|
||||||
if( args.length >= 3 && args[2] instanceof Map )
|
Map<Object, Object> table = optTable( args, 2, null );
|
||||||
|
if( table != null )
|
||||||
{
|
{
|
||||||
Map<?, ?> table = (Map<?, ?>)args[2];
|
|
||||||
headers = new HashMap<String, String>( table.size() );
|
headers = new HashMap<String, String>( table.size() );
|
||||||
for( Object key : table.keySet() )
|
for( Object key : table.keySet() )
|
||||||
{
|
{
|
||||||
@ -194,10 +124,11 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
// Make the request
|
// Make the request
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HTTPRequest request = new HTTPRequest( urlString, postString, headers, binary );
|
URL url = HTTPRequest.checkURL( urlString );
|
||||||
synchronized( m_httpRequests )
|
HTTPRequest request = new HTTPRequest( urlString, url, postString, headers, binary );
|
||||||
|
synchronized( m_httpTasks )
|
||||||
{
|
{
|
||||||
m_httpRequests.add( request );
|
m_httpTasks.add( HTTPTask.submit( request ) );
|
||||||
}
|
}
|
||||||
return new Object[] { true };
|
return new Object[] { true };
|
||||||
}
|
}
|
||||||
@ -210,16 +141,16 @@ public class HTTPAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
// checkURL
|
// checkURL
|
||||||
// Get URL
|
// Get URL
|
||||||
if( args.length < 1 || !(args[0] instanceof String) )
|
String urlString = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String urlString = args[0].toString();
|
|
||||||
|
|
||||||
// Check URL
|
// Check URL
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HTTPRequest.checkURL( urlString );
|
URL url = HTTPRequest.checkURL( urlString );
|
||||||
|
HTTPCheck check = new HTTPCheck( urlString, url );
|
||||||
|
synchronized( m_httpTasks ) {
|
||||||
|
m_httpTasks.add( HTTPTask.submit( check ) );
|
||||||
|
}
|
||||||
return new Object[] { true };
|
return new Object[] { true };
|
||||||
}
|
}
|
||||||
catch( HTTPRequestException e )
|
catch( HTTPRequestException e )
|
||||||
|
@ -1,261 +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 com.google.common.base.Joiner;
|
|
||||||
import com.google.common.io.ByteStreams;
|
|
||||||
import dan200.computercraft.ComputerCraft;
|
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.net.HttpURLConnection;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class HTTPRequest
|
|
||||||
{
|
|
||||||
public static URL checkURL( String urlString ) throws HTTPRequestException
|
|
||||||
{
|
|
||||||
URL url;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
url = new URL( urlString );
|
|
||||||
}
|
|
||||||
catch( MalformedURLException e )
|
|
||||||
{
|
|
||||||
throw new HTTPRequestException( "URL malformed" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate the URL
|
|
||||||
String protocol = url.getProtocol().toLowerCase();
|
|
||||||
if( !protocol.equals("http") && !protocol.equals("https") )
|
|
||||||
{
|
|
||||||
throw new HTTPRequestException( "URL not http" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare the URL to the whitelist
|
|
||||||
boolean allowed = false;
|
|
||||||
String whitelistString = ComputerCraft.http_whitelist;
|
|
||||||
String[] allowedURLs = whitelistString.split( ";" );
|
|
||||||
for( String allowedURL : allowedURLs )
|
|
||||||
{
|
|
||||||
Pattern allowedURLPattern = Pattern.compile( "^\\Q" + allowedURL.replaceAll( "\\*", "\\\\E.*\\\\Q" ) + "\\E$" );
|
|
||||||
if( allowedURLPattern.matcher( url.getHost() ).matches() )
|
|
||||||
{
|
|
||||||
allowed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if( !allowed )
|
|
||||||
{
|
|
||||||
throw new HTTPRequestException( "Domain not permitted" );
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HTTPRequest( String url, final String postText, final Map<String, String> headers, boolean binary ) throws HTTPRequestException
|
|
||||||
{
|
|
||||||
// Parse the URL
|
|
||||||
m_urlString = url;
|
|
||||||
m_url = checkURL( m_urlString );
|
|
||||||
m_binary = binary;
|
|
||||||
|
|
||||||
// Start the thread
|
|
||||||
m_cancelled = false;
|
|
||||||
m_complete = false;
|
|
||||||
m_success = false;
|
|
||||||
m_result = null;
|
|
||||||
m_responseCode = -1;
|
|
||||||
|
|
||||||
Thread thread = new Thread( new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Connect to the URL
|
|
||||||
HttpURLConnection connection = (HttpURLConnection)m_url.openConnection();
|
|
||||||
|
|
||||||
if( postText != null )
|
|
||||||
{
|
|
||||||
connection.setRequestMethod( "POST" );
|
|
||||||
connection.setDoOutput( true );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
connection.setRequestMethod( "GET" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set headers
|
|
||||||
connection.setRequestProperty( "accept-charset", "UTF-8" );
|
|
||||||
if( postText != null )
|
|
||||||
{
|
|
||||||
connection.setRequestProperty( "content-type", "application/x-www-form-urlencoded; charset=utf-8" );
|
|
||||||
connection.setRequestProperty( "content-encoding", "UTF-8" );
|
|
||||||
}
|
|
||||||
if( headers != null )
|
|
||||||
{
|
|
||||||
for( Map.Entry<String, String> header : headers.entrySet() )
|
|
||||||
{
|
|
||||||
connection.setRequestProperty( header.getKey(), header.getValue() );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send POST text
|
|
||||||
if( postText != null )
|
|
||||||
{
|
|
||||||
OutputStream os = connection.getOutputStream();
|
|
||||||
OutputStreamWriter osw;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
osw = new OutputStreamWriter( os, "UTF-8" );
|
|
||||||
}
|
|
||||||
catch( UnsupportedEncodingException e )
|
|
||||||
{
|
|
||||||
osw = new OutputStreamWriter( os );
|
|
||||||
}
|
|
||||||
BufferedWriter writer = new BufferedWriter( osw );
|
|
||||||
writer.write( postText, 0, postText.length() );
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read response
|
|
||||||
InputStream is;
|
|
||||||
int code = connection.getResponseCode();
|
|
||||||
boolean responseSuccess;
|
|
||||||
if (code >= 200 && code < 400) {
|
|
||||||
is = connection.getInputStream();
|
|
||||||
responseSuccess = true;
|
|
||||||
} else {
|
|
||||||
is = connection.getErrorStream();
|
|
||||||
responseSuccess = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
byte[] result = ByteStreams.toByteArray( is );
|
|
||||||
is.close();
|
|
||||||
|
|
||||||
synchronized( m_lock )
|
|
||||||
{
|
|
||||||
if( m_cancelled )
|
|
||||||
{
|
|
||||||
// We cancelled
|
|
||||||
m_complete = true;
|
|
||||||
m_success = false;
|
|
||||||
m_result = null;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// We completed
|
|
||||||
m_complete = true;
|
|
||||||
m_success = responseSuccess;
|
|
||||||
m_result = result;
|
|
||||||
m_responseCode = connection.getResponseCode();
|
|
||||||
m_encoding = connection.getContentEncoding();
|
|
||||||
|
|
||||||
Joiner joiner = Joiner.on( ',' );
|
|
||||||
Map<String, String> headers = m_responseHeaders = new HashMap<String, String>();
|
|
||||||
for (Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet()) {
|
|
||||||
headers.put(header.getKey(), joiner.join( header.getValue() ));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
connection.disconnect(); // disconnect
|
|
||||||
|
|
||||||
}
|
|
||||||
catch( IOException e )
|
|
||||||
{
|
|
||||||
synchronized( m_lock )
|
|
||||||
{
|
|
||||||
// There was an error
|
|
||||||
m_complete = true;
|
|
||||||
m_success = false;
|
|
||||||
m_result = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
thread.setDaemon(true);
|
|
||||||
thread.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getURL() {
|
|
||||||
return m_urlString;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void cancel()
|
|
||||||
{
|
|
||||||
synchronized(m_lock) {
|
|
||||||
m_cancelled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isComplete()
|
|
||||||
{
|
|
||||||
synchronized(m_lock) {
|
|
||||||
return m_complete;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getResponseCode() {
|
|
||||||
synchronized(m_lock) {
|
|
||||||
return m_responseCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Map<String, String> getResponseHeaders() {
|
|
||||||
synchronized (m_lock) {
|
|
||||||
return m_responseHeaders;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean wasSuccessful()
|
|
||||||
{
|
|
||||||
synchronized(m_lock) {
|
|
||||||
return m_success;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isBinary()
|
|
||||||
{
|
|
||||||
return m_binary;
|
|
||||||
}
|
|
||||||
|
|
||||||
public InputStream getContents()
|
|
||||||
{
|
|
||||||
byte[] result;
|
|
||||||
synchronized(m_lock) {
|
|
||||||
result = m_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( result != null ) {
|
|
||||||
return new ByteArrayInputStream( result );
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getEncoding() {
|
|
||||||
return m_encoding;
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Object m_lock = new Object();
|
|
||||||
private final URL m_url;
|
|
||||||
private final String m_urlString;
|
|
||||||
|
|
||||||
private boolean m_complete;
|
|
||||||
private boolean m_cancelled;
|
|
||||||
private boolean m_success;
|
|
||||||
private String m_encoding;
|
|
||||||
private byte[] m_result;
|
|
||||||
private boolean m_binary;
|
|
||||||
private int m_responseCode;
|
|
||||||
private Map<String, String> m_responseHeaders;
|
|
||||||
}
|
|
@ -13,6 +13,8 @@ import dan200.computercraft.shared.util.StringUtil;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||||
|
|
||||||
public class OSAPI implements ILuaAPI
|
public class OSAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private IAPIEnvironment m_apiEnvironment;
|
private IAPIEnvironment m_apiEnvironment;
|
||||||
@ -225,21 +227,13 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// queueEvent
|
// queueEvent
|
||||||
if( args.length == 0 || args[0] == null || !(args[0] instanceof String) )
|
queueLuaEvent( getString( args, 0 ), trimArray( args, 1 ) );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
queueLuaEvent( (String)args[0], trimArray( args, 1 ) );
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// startTimer
|
// startTimer
|
||||||
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) )
|
double timer = getReal( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
double timer = ((Number)args[0]).doubleValue();
|
|
||||||
synchronized( m_timers )
|
synchronized( m_timers )
|
||||||
{
|
{
|
||||||
m_timers.put( m_nextTimerToken, new Timer( (int)Math.round( timer / 0.05 ) ) );
|
m_timers.put( m_nextTimerToken, new Timer( (int)Math.round( timer / 0.05 ) ) );
|
||||||
@ -249,11 +243,7 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// setAlarm
|
// setAlarm
|
||||||
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) )
|
double time = getReal( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
double time = ((Number)args[0]).doubleValue();
|
|
||||||
if( time < 0.0 || time >= 24.0 )
|
if( time < 0.0 || time >= 24.0 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Number out of range" );
|
throw new LuaException( "Number out of range" );
|
||||||
@ -286,16 +276,8 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 7:
|
case 7:
|
||||||
{
|
{
|
||||||
// setComputerLabel
|
// setComputerLabel
|
||||||
String label = null;
|
String label = optString( args, 0, null );
|
||||||
if( args.length > 0 && args[0] != null )
|
m_apiEnvironment.setLabel( StringUtil.normaliseLabel( label ) );
|
||||||
{
|
|
||||||
if(!(args[0] instanceof String))
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string or nil" );
|
|
||||||
}
|
|
||||||
label = StringUtil.normaliseLabel( (String) args[0] );
|
|
||||||
}
|
|
||||||
m_apiEnvironment.setLabel( label );
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 8:
|
case 8:
|
||||||
@ -320,13 +302,7 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 11:
|
case 11:
|
||||||
{
|
{
|
||||||
// time
|
// time
|
||||||
String param = "ingame";
|
String param = optString( args, 0, "ingame" );
|
||||||
if (args.length > 0 && args[0] != null) {
|
|
||||||
if (!(args[0] instanceof String)) {
|
|
||||||
throw new LuaException("Expected string");
|
|
||||||
}
|
|
||||||
param = (String)args[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (param.equals("utc")) {
|
if (param.equals("utc")) {
|
||||||
// Get Hour of day (UTC)
|
// Get Hour of day (UTC)
|
||||||
@ -351,13 +327,7 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 12:
|
case 12:
|
||||||
{
|
{
|
||||||
// day
|
// day
|
||||||
String param = "ingame";
|
String param = optString( args, 0, "ingame" );
|
||||||
if (args.length > 0 && args[0] != null) {
|
|
||||||
if (!(args[0] instanceof String)) {
|
|
||||||
throw new LuaException("Expected string");
|
|
||||||
}
|
|
||||||
param = (String)args[0];
|
|
||||||
}
|
|
||||||
if (param.equals("utc")) {
|
if (param.equals("utc")) {
|
||||||
// Get numbers of days since 1970-01-01 (utc)
|
// Get numbers of days since 1970-01-01 (utc)
|
||||||
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||||
@ -381,11 +351,7 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 13:
|
case 13:
|
||||||
{
|
{
|
||||||
// cancelTimer
|
// cancelTimer
|
||||||
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) )
|
int token = getInt( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
int token = ((Number)args[0]).intValue();
|
|
||||||
synchronized( m_timers )
|
synchronized( m_timers )
|
||||||
{
|
{
|
||||||
if( m_timers.containsKey( token ) )
|
if( m_timers.containsKey( token ) )
|
||||||
@ -398,11 +364,7 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 14:
|
case 14:
|
||||||
{
|
{
|
||||||
// cancelAlarm
|
// cancelAlarm
|
||||||
if( args.length < 1 || args[0] == null || !(args[0] instanceof Number) )
|
int token = getInt( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
int token = ((Number)args[0]).intValue();
|
|
||||||
synchronized( m_alarms )
|
synchronized( m_alarms )
|
||||||
{
|
{
|
||||||
if( m_alarms.containsKey( token ) )
|
if( m_alarms.containsKey( token ) )
|
||||||
@ -415,13 +377,7 @@ public class OSAPI implements ILuaAPI
|
|||||||
case 15:
|
case 15:
|
||||||
{
|
{
|
||||||
// epoch
|
// epoch
|
||||||
String param = "ingame";
|
String param = optString( args, 0, "ingame" );
|
||||||
if (args.length > 0 && args[0] != null) {
|
|
||||||
if (!(args[0] instanceof String)) {
|
|
||||||
throw new LuaException("Expected string");
|
|
||||||
}
|
|
||||||
param = (String)args[0];
|
|
||||||
}
|
|
||||||
if (param.equals("utc")) {
|
if (param.equals("utc")) {
|
||||||
// Get utc epoch
|
// Get utc epoch
|
||||||
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
Calendar c = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
|
||||||
|
@ -21,6 +21,8 @@ import dan200.computercraft.core.filesystem.FileSystemException;
|
|||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener
|
public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChangeListener
|
||||||
{
|
{
|
||||||
private class PeripheralWrapper implements IComputerAccess
|
private class PeripheralWrapper implements IComputerAccess
|
||||||
@ -460,14 +462,10 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// call
|
// call
|
||||||
if( args.length < 2 || args[1] == null || !(args[1] instanceof String) )
|
int side = parseSide( args );
|
||||||
{
|
String methodName = getString( args, 1 );
|
||||||
throw new LuaException( "Expected string, string" );
|
|
||||||
}
|
|
||||||
String methodName = (String)args[1];
|
|
||||||
Object[] methodArgs = trimArray( args, 2 );
|
Object[] methodArgs = trimArray( args, 2 );
|
||||||
|
|
||||||
int side = parseSide( args );
|
|
||||||
if( side >= 0 )
|
if( side >= 0 )
|
||||||
{
|
{
|
||||||
PeripheralWrapper p;
|
PeripheralWrapper p;
|
||||||
@ -498,11 +496,7 @@ public class PeripheralAPI implements ILuaAPI, IAPIEnvironment.IPeripheralChange
|
|||||||
|
|
||||||
private int parseSide( Object[] args ) throws LuaException
|
private int parseSide( Object[] args ) throws LuaException
|
||||||
{
|
{
|
||||||
if( args.length < 1 || args[0] == null || !(args[0] instanceof String) )
|
String side = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String side = (String)args[0];
|
|
||||||
for( int n=0; n<Computer.s_sideNames.length; ++n )
|
for( int n=0; n<Computer.s_sideNames.length; ++n )
|
||||||
{
|
{
|
||||||
if( side.equals( Computer.s_sideNames[n] ) )
|
if( side.equals( Computer.s_sideNames[n] ) )
|
||||||
|
@ -14,6 +14,8 @@ import javax.annotation.Nonnull;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||||
|
|
||||||
public class RedstoneAPI implements ILuaAPI
|
public class RedstoneAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private IAPIEnvironment m_environment;
|
private IAPIEnvironment m_environment;
|
||||||
@ -86,12 +88,8 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// setOutput
|
// setOutput
|
||||||
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Boolean) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, boolean" );
|
|
||||||
}
|
|
||||||
int side = parseSide( args );
|
int side = parseSide( args );
|
||||||
boolean output = (Boolean) args[ 1 ];
|
boolean output = getBoolean( args, 1 );
|
||||||
m_environment.setOutput( side, output ? 15 : 0 );
|
m_environment.setOutput( side, output ? 15 : 0 );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -110,12 +108,8 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
// setBundledOutput
|
// setBundledOutput
|
||||||
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Double) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number" );
|
|
||||||
}
|
|
||||||
int side = parseSide( args );
|
int side = parseSide( args );
|
||||||
int output = ((Double)args[1]).intValue();
|
int output = getInt( args, 1 );
|
||||||
m_environment.setBundledOutput( side, output );
|
m_environment.setBundledOutput( side, output );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -134,12 +128,8 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
case 7:
|
case 7:
|
||||||
{
|
{
|
||||||
// testBundledInput
|
// testBundledInput
|
||||||
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Double) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number" );
|
|
||||||
}
|
|
||||||
int side = parseSide( args );
|
int side = parseSide( args );
|
||||||
int mask = ((Double)args[1]).intValue();
|
int mask = getInt( args, 1 );
|
||||||
int input = m_environment.getBundledInput( side );
|
int input = m_environment.getBundledInput( side );
|
||||||
return new Object[] { ((input & mask) == mask) };
|
return new Object[] { ((input & mask) == mask) };
|
||||||
}
|
}
|
||||||
@ -147,12 +137,8 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
case 9:
|
case 9:
|
||||||
{
|
{
|
||||||
// setAnalogOutput/setAnalogueOutput
|
// setAnalogOutput/setAnalogueOutput
|
||||||
if( args.length < 2 || args[0] == null || !(args[0] instanceof String) || args[1] == null || !(args[1] instanceof Double) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number" );
|
|
||||||
}
|
|
||||||
int side = parseSide( args );
|
int side = parseSide( args );
|
||||||
int output = ((Double)args[1]).intValue();
|
int output = getInt( args, 1 );
|
||||||
if( output < 0 || output > 15 )
|
if( output < 0 || output > 15 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Expected number in range 0-15" );
|
throw new LuaException( "Expected number in range 0-15" );
|
||||||
@ -183,11 +169,7 @@ public class RedstoneAPI implements ILuaAPI
|
|||||||
|
|
||||||
private int parseSide( Object[] args ) throws LuaException
|
private int parseSide( Object[] args ) throws LuaException
|
||||||
{
|
{
|
||||||
if( args.length < 1 || args[0] == null || !(args[0] instanceof String) )
|
String side = getString( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
String side = (String)args[0];
|
|
||||||
for( int n=0; n<Computer.s_sideNames.length; ++n )
|
for( int n=0; n<Computer.s_sideNames.length; ++n )
|
||||||
{
|
{
|
||||||
if( side.equals( Computer.s_sideNames[n] ) )
|
if( side.equals( Computer.s_sideNames[n] ) )
|
||||||
|
@ -13,12 +13,10 @@ import dan200.computercraft.core.terminal.Terminal;
|
|||||||
import dan200.computercraft.shared.util.Palette;
|
import dan200.computercraft.shared.util.Palette;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||||
|
|
||||||
public class TermAPI implements ILuaAPI
|
public class TermAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private final Terminal m_terminal;
|
private final Terminal m_terminal;
|
||||||
@ -86,11 +84,7 @@ public class TermAPI implements ILuaAPI
|
|||||||
|
|
||||||
public static int parseColour( Object[] args ) throws LuaException
|
public static int parseColour( Object[] args ) throws LuaException
|
||||||
{
|
{
|
||||||
if( args.length < 1 || args[0] == null || !(args[0] instanceof Double) )
|
int colour = getInt( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
int colour = (int)((Double)args[0]).doubleValue();
|
|
||||||
if( colour <= 0 )
|
if( colour <= 0 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Colour out of range" );
|
throw new LuaException( "Colour out of range" );
|
||||||
@ -144,12 +138,7 @@ public class TermAPI implements ILuaAPI
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// scroll
|
// scroll
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof Double) )
|
int y = getInt( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int y = (int)((Double)args[0]).doubleValue();
|
|
||||||
synchronized( m_terminal )
|
synchronized( m_terminal )
|
||||||
{
|
{
|
||||||
m_terminal.scroll(y);
|
m_terminal.scroll(y);
|
||||||
@ -159,12 +148,8 @@ public class TermAPI implements ILuaAPI
|
|||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// setCursorPos
|
// setCursorPos
|
||||||
if( args.length != 2 || args[0] == null || !(args[0] instanceof Double) || args[1] == null || !(args[1] instanceof Double) )
|
int x = getInt( args, 0 ) - 1;
|
||||||
{
|
int y = getInt( args, 1 ) - 1;
|
||||||
throw new LuaException( "Expected number, number" );
|
|
||||||
}
|
|
||||||
int x = (int)((Double)args[0]).doubleValue() - 1;
|
|
||||||
int y = (int)((Double)args[1]).doubleValue() - 1;
|
|
||||||
synchronized( m_terminal )
|
synchronized( m_terminal )
|
||||||
{
|
{
|
||||||
m_terminal.setCursorPos( x, y );
|
m_terminal.setCursorPos( x, y );
|
||||||
@ -174,11 +159,7 @@ public class TermAPI implements ILuaAPI
|
|||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// setCursorBlink
|
// setCursorBlink
|
||||||
if( args.length != 1 || args[0] == null || !(args[0] instanceof Boolean) )
|
boolean b = getBoolean( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected boolean" );
|
|
||||||
}
|
|
||||||
boolean b = (Boolean) args[ 0 ];
|
|
||||||
synchronized( m_terminal )
|
synchronized( m_terminal )
|
||||||
{
|
{
|
||||||
m_terminal.setCursorBlink( b );
|
m_terminal.setCursorBlink( b );
|
||||||
@ -268,14 +249,9 @@ public class TermAPI implements ILuaAPI
|
|||||||
case 18:
|
case 18:
|
||||||
{
|
{
|
||||||
// blit
|
// blit
|
||||||
if( args.length < 3 || !(args[0] instanceof String) || !(args[1] instanceof String) || !(args[2] instanceof String) )
|
String text = getString( args, 0 );
|
||||||
{
|
String textColour = getString( args, 1 );
|
||||||
throw new LuaException( "Expected string, string, string" );
|
String backgroundColour = getString( args, 2 );
|
||||||
}
|
|
||||||
|
|
||||||
String text = (String)args[0];
|
|
||||||
String textColour = (String)args[1];
|
|
||||||
String backgroundColour = (String)args[2];
|
|
||||||
if( textColour.length() != text.length() || backgroundColour.length() != text.length() )
|
if( textColour.length() != text.length() || backgroundColour.length() != text.length() )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Arguments must be the same length" );
|
throw new LuaException( "Arguments must be the same length" );
|
||||||
@ -292,36 +268,26 @@ public class TermAPI implements ILuaAPI
|
|||||||
case 20:
|
case 20:
|
||||||
{
|
{
|
||||||
// setPaletteColour/setPaletteColor
|
// setPaletteColour/setPaletteColor
|
||||||
if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double)
|
int colour = 15 - parseColour( args );
|
||||||
|
if( args.length == 2 )
|
||||||
{
|
{
|
||||||
int colour = 15 - parseColour( args );
|
int hex = getInt( args, 1 );
|
||||||
int hex = ((Double)args[1]).intValue();
|
|
||||||
double[] rgb = Palette.decodeRGB8( hex );
|
double[] rgb = Palette.decodeRGB8( hex );
|
||||||
setColour( m_terminal, colour, rgb[0], rgb[1], rgb[2] );
|
setColour( m_terminal, colour, rgb[ 0 ], rgb[ 1 ], rgb[ 2 ] );
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if(args.length >= 4 && args[0] instanceof Double && args[1] instanceof Double && args[2] instanceof Double && args[3] instanceof Double)
|
|
||||||
{
|
{
|
||||||
int colour = 15 - parseColour( args );
|
double r = getReal( args, 1 );
|
||||||
double r = (Double)args[1];
|
double g = getReal( args, 2 );
|
||||||
double g = (Double)args[2];
|
double b = getReal( args, 3 );
|
||||||
double b = (Double)args[3];
|
|
||||||
setColour( m_terminal, colour, r, g, b );
|
setColour( m_terminal, colour, r, g, b );
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
throw new LuaException( "Expected number, number or number, number, number, number" );
|
|
||||||
}
|
}
|
||||||
case 21:
|
case 21:
|
||||||
case 22:
|
case 22:
|
||||||
{
|
{
|
||||||
// getPaletteColour/getPaletteColor
|
// getPaletteColour/getPaletteColor
|
||||||
if(args.length < 1 || !(args[0] instanceof Double))
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int colour = 15 - parseColour( args );
|
int colour = 15 - parseColour( args );
|
||||||
synchronized( m_terminal )
|
synchronized( m_terminal )
|
||||||
{
|
{
|
||||||
|
@ -9,6 +9,8 @@ import java.io.IOException;
|
|||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
||||||
|
|
||||||
public class BinaryInputHandle extends HandleGeneric
|
public class BinaryInputHandle extends HandleGeneric
|
||||||
{
|
{
|
||||||
private final InputStream m_stream;
|
private final InputStream m_stream;
|
||||||
@ -42,13 +44,7 @@ public class BinaryInputHandle extends HandleGeneric
|
|||||||
{
|
{
|
||||||
if( args.length > 0 && args[ 0 ] != null )
|
if( args.length > 0 && args[ 0 ] != null )
|
||||||
{
|
{
|
||||||
if( !(args[ 0 ] instanceof Number) )
|
int count = getInt( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int count = ((Number) args[ 0 ]).intValue();
|
|
||||||
|
|
||||||
if( count <= 0 || count >= 1024 * 16 )
|
if( count <= 0 || count >= 1024 * 16 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Count out of range" );
|
throw new LuaException( "Count out of range" );
|
||||||
|
@ -2,6 +2,7 @@ package dan200.computercraft.core.apis.handles;
|
|||||||
|
|
||||||
import dan200.computercraft.api.lua.ILuaContext;
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
import dan200.computercraft.core.apis.ArgumentHelper;
|
||||||
import dan200.computercraft.shared.util.StringUtil;
|
import dan200.computercraft.shared.util.StringUtil;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -51,7 +52,7 @@ public class BinaryOutputHandle extends HandleGeneric
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new LuaException( "Expected number" );
|
throw ArgumentHelper.badArgument( 0, "string or number", args.length > 0 ? args[ 0 ] : null );
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
package dan200.computercraft.core.apis.http;
|
||||||
|
|
||||||
|
import dan200.computercraft.core.apis.HTTPRequestException;
|
||||||
|
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
|
||||||
|
public class HTTPCheck implements HTTPTask.IHTTPTask
|
||||||
|
{
|
||||||
|
private final String urlString;
|
||||||
|
private final URL url;
|
||||||
|
private String error;
|
||||||
|
|
||||||
|
public HTTPCheck( String urlString, URL url )
|
||||||
|
{
|
||||||
|
this.urlString = urlString;
|
||||||
|
this.url = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HTTPRequest.checkHost( url );
|
||||||
|
}
|
||||||
|
catch( HTTPRequestException e )
|
||||||
|
{
|
||||||
|
error = e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void whenFinished( IAPIEnvironment environment )
|
||||||
|
{
|
||||||
|
if( error == null )
|
||||||
|
{
|
||||||
|
environment.queueEvent( "http_check", new Object[] { urlString, true } );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
environment.queueEvent( "http_check", new Object[] { urlString, false, error } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,290 @@
|
|||||||
|
/*
|
||||||
|
* 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.http;
|
||||||
|
|
||||||
|
import com.google.common.base.Joiner;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
import dan200.computercraft.ComputerCraft;
|
||||||
|
import dan200.computercraft.api.lua.ILuaContext;
|
||||||
|
import dan200.computercraft.api.lua.ILuaObject;
|
||||||
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
|
import dan200.computercraft.core.apis.HTTPRequestException;
|
||||||
|
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||||
|
import dan200.computercraft.core.apis.handles.BinaryInputHandle;
|
||||||
|
import dan200.computercraft.core.apis.handles.EncodedInputHandle;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.*;
|
||||||
|
import java.net.*;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HTTPRequest implements HTTPTask.IHTTPTask
|
||||||
|
{
|
||||||
|
public static URL checkURL( String urlString ) throws HTTPRequestException
|
||||||
|
{
|
||||||
|
URL url;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
url = new URL( urlString );
|
||||||
|
}
|
||||||
|
catch( MalformedURLException e )
|
||||||
|
{
|
||||||
|
throw new HTTPRequestException( "URL malformed" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate the URL
|
||||||
|
String protocol = url.getProtocol().toLowerCase();
|
||||||
|
if( !protocol.equals( "http" ) && !protocol.equals( "https" ) )
|
||||||
|
{
|
||||||
|
throw new HTTPRequestException( "URL not http" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare the URL to the whitelist
|
||||||
|
if( !ComputerCraft.http_whitelist.matches( url.getHost() ) || ComputerCraft.http_blacklist.matches( url.getHost() ) )
|
||||||
|
{
|
||||||
|
throw new HTTPRequestException( "Domain not permitted" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InetAddress checkHost( URL url ) throws HTTPRequestException
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InetAddress resolved = InetAddress.getByName( url.getHost() );
|
||||||
|
if( !ComputerCraft.http_whitelist.matches( resolved ) || ComputerCraft.http_blacklist.matches( resolved ) )
|
||||||
|
{
|
||||||
|
throw new HTTPRequestException( "Domain not permitted" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
catch( UnknownHostException e )
|
||||||
|
{
|
||||||
|
throw new HTTPRequestException( "Unknown host" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final URL m_url;
|
||||||
|
private final String m_urlString;
|
||||||
|
private final String m_postText;
|
||||||
|
private final Map<String, String> m_headers;
|
||||||
|
|
||||||
|
private boolean m_success = false;
|
||||||
|
private String m_encoding;
|
||||||
|
private byte[] m_result;
|
||||||
|
private boolean m_binary;
|
||||||
|
private int m_responseCode = -1;
|
||||||
|
private Map<String, String> m_responseHeaders;
|
||||||
|
private String m_errorMessage;
|
||||||
|
|
||||||
|
public HTTPRequest( String urlString, URL url, final String postText, final Map<String, String> headers, boolean binary ) throws HTTPRequestException
|
||||||
|
{
|
||||||
|
// Parse the URL
|
||||||
|
m_urlString = urlString;
|
||||||
|
m_url = url;
|
||||||
|
m_binary = binary;
|
||||||
|
m_postText = postText;
|
||||||
|
m_headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InputStream getContents()
|
||||||
|
{
|
||||||
|
byte[] result = m_result;
|
||||||
|
if( result != null )
|
||||||
|
{
|
||||||
|
return new ByteArrayInputStream( result );
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
// First verify the address is allowed.
|
||||||
|
try
|
||||||
|
{
|
||||||
|
checkHost( m_url );
|
||||||
|
}
|
||||||
|
catch( HTTPRequestException e )
|
||||||
|
{
|
||||||
|
m_success = false;
|
||||||
|
m_errorMessage = e.getMessage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Connect to the URL
|
||||||
|
HttpURLConnection connection = (HttpURLConnection) m_url.openConnection();
|
||||||
|
|
||||||
|
if( m_postText != null )
|
||||||
|
{
|
||||||
|
connection.setRequestMethod( "POST" );
|
||||||
|
connection.setDoOutput( true );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
connection.setRequestMethod( "GET" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set headers
|
||||||
|
connection.setRequestProperty( "accept-charset", "UTF-8" );
|
||||||
|
if( m_postText != null )
|
||||||
|
{
|
||||||
|
connection.setRequestProperty( "content-type", "application/x-www-form-urlencoded; charset=utf-8" );
|
||||||
|
connection.setRequestProperty( "content-encoding", "UTF-8" );
|
||||||
|
}
|
||||||
|
if( m_postText != null )
|
||||||
|
{
|
||||||
|
for( Map.Entry<String, String> header : m_headers.entrySet() )
|
||||||
|
{
|
||||||
|
connection.setRequestProperty( header.getKey(), header.getValue() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send POST text
|
||||||
|
if( m_postText != null )
|
||||||
|
{
|
||||||
|
OutputStream os = connection.getOutputStream();
|
||||||
|
OutputStreamWriter osw;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
osw = new OutputStreamWriter( os, "UTF-8" );
|
||||||
|
}
|
||||||
|
catch( UnsupportedEncodingException e )
|
||||||
|
{
|
||||||
|
osw = new OutputStreamWriter( os );
|
||||||
|
}
|
||||||
|
BufferedWriter writer = new BufferedWriter( osw );
|
||||||
|
writer.write( m_postText, 0, m_postText.length() );
|
||||||
|
writer.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read response
|
||||||
|
InputStream is;
|
||||||
|
int code = connection.getResponseCode();
|
||||||
|
boolean responseSuccess;
|
||||||
|
if( code >= 200 && code < 400 )
|
||||||
|
{
|
||||||
|
is = connection.getInputStream();
|
||||||
|
responseSuccess = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
is = connection.getErrorStream();
|
||||||
|
responseSuccess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] result = ByteStreams.toByteArray( is );
|
||||||
|
is.close();
|
||||||
|
|
||||||
|
// We completed
|
||||||
|
m_success = responseSuccess;
|
||||||
|
m_result = result;
|
||||||
|
m_responseCode = connection.getResponseCode();
|
||||||
|
m_encoding = connection.getContentEncoding();
|
||||||
|
|
||||||
|
Joiner joiner = Joiner.on( ',' );
|
||||||
|
Map<String, String> headers = m_responseHeaders = new HashMap<String, String>();
|
||||||
|
for( Map.Entry<String, List<String>> header : connection.getHeaderFields().entrySet() )
|
||||||
|
{
|
||||||
|
headers.put( header.getKey(), joiner.join( header.getValue() ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
connection.disconnect(); // disconnect
|
||||||
|
}
|
||||||
|
catch( IOException e )
|
||||||
|
{
|
||||||
|
// There was an error
|
||||||
|
m_success = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void whenFinished( IAPIEnvironment environment )
|
||||||
|
{
|
||||||
|
final String url = m_urlString;
|
||||||
|
if( m_success )
|
||||||
|
{
|
||||||
|
// Queue the "http_success" event
|
||||||
|
InputStream contents = getContents();
|
||||||
|
Object result = wrapStream(
|
||||||
|
m_binary ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, m_encoding ),
|
||||||
|
m_responseCode, m_responseHeaders
|
||||||
|
);
|
||||||
|
environment.queueEvent( "http_success", new Object[] { url, result } );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Queue the "http_failure" event
|
||||||
|
String error = "Could not connect";
|
||||||
|
if( m_errorMessage != null ) error = m_errorMessage;
|
||||||
|
|
||||||
|
InputStream contents = getContents();
|
||||||
|
Object result = null;
|
||||||
|
if( contents != null )
|
||||||
|
{
|
||||||
|
result = wrapStream(
|
||||||
|
m_binary ? new BinaryInputHandle( contents ) : new EncodedInputHandle( contents, m_encoding ),
|
||||||
|
m_responseCode, m_responseHeaders
|
||||||
|
);
|
||||||
|
}
|
||||||
|
environment.queueEvent( "http_failure", new Object[] { url, error, result } );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ILuaObject wrapStream( final ILuaObject reader, final int responseCode, final Map<String, String> responseHeaders )
|
||||||
|
{
|
||||||
|
String[] oldMethods = reader.getMethodNames();
|
||||||
|
final int methodOffset = oldMethods.length;
|
||||||
|
|
||||||
|
final String[] newMethods = Arrays.copyOf( oldMethods, oldMethods.length + 2 );
|
||||||
|
newMethods[ methodOffset + 0 ] = "getResponseCode";
|
||||||
|
newMethods[ methodOffset + 1 ] = "getResponseHeaders";
|
||||||
|
|
||||||
|
return new ILuaObject()
|
||||||
|
{
|
||||||
|
@Nonnull
|
||||||
|
@Override
|
||||||
|
public String[] getMethodNames()
|
||||||
|
{
|
||||||
|
return newMethods;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] args ) throws LuaException, InterruptedException
|
||||||
|
{
|
||||||
|
if( method < methodOffset )
|
||||||
|
{
|
||||||
|
return reader.callMethod( context, method, args );
|
||||||
|
}
|
||||||
|
switch( method - methodOffset )
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
// getResponseCode
|
||||||
|
return new Object[] { responseCode };
|
||||||
|
}
|
||||||
|
case 1:
|
||||||
|
{
|
||||||
|
// getResponseHeaders
|
||||||
|
return new Object[] { responseHeaders };
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,61 @@
|
|||||||
|
package dan200.computercraft.core.apis.http;
|
||||||
|
|
||||||
|
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||||
|
import dan200.computercraft.core.apis.IAPIEnvironment;
|
||||||
|
|
||||||
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task which executes asynchronously on a new thread.
|
||||||
|
*
|
||||||
|
* This functions very similarly to a {@link Future}, but with an additional
|
||||||
|
* method which is called on the main thread when the task is completed.
|
||||||
|
*/
|
||||||
|
public class HTTPTask
|
||||||
|
{
|
||||||
|
public interface IHTTPTask extends Runnable
|
||||||
|
{
|
||||||
|
void whenFinished( IAPIEnvironment environment );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final ExecutorService httpThreads = new ThreadPoolExecutor(
|
||||||
|
4, Integer.MAX_VALUE,
|
||||||
|
60L, TimeUnit.SECONDS,
|
||||||
|
new SynchronousQueue<Runnable>(),
|
||||||
|
new ThreadFactoryBuilder()
|
||||||
|
.setDaemon( true )
|
||||||
|
.setPriority( Thread.MIN_PRIORITY + (Thread.NORM_PRIORITY - Thread.MIN_PRIORITY) / 2 )
|
||||||
|
.setNameFormat( "ComputerCraft-HTTP-%d" )
|
||||||
|
.build()
|
||||||
|
);
|
||||||
|
|
||||||
|
private final Future<?> future;
|
||||||
|
private final IHTTPTask task;
|
||||||
|
|
||||||
|
private HTTPTask( Future<?> future, IHTTPTask task )
|
||||||
|
{
|
||||||
|
this.future = future;
|
||||||
|
this.task = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static HTTPTask submit( IHTTPTask task )
|
||||||
|
{
|
||||||
|
Future<?> future = httpThreads.submit( task );
|
||||||
|
return new HTTPTask( future, task );
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cancel()
|
||||||
|
{
|
||||||
|
future.cancel( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished()
|
||||||
|
{
|
||||||
|
return future.isDone();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void whenFinished( IAPIEnvironment environment )
|
||||||
|
{
|
||||||
|
task.whenFinished( environment );
|
||||||
|
}
|
||||||
|
}
|
@ -172,7 +172,7 @@ public class FileSystem
|
|||||||
{
|
{
|
||||||
if( m_writableMount == null )
|
if( m_writableMount == null )
|
||||||
{
|
{
|
||||||
throw new FileSystemException( "Access Denied" );
|
throw new FileSystemException( "Access denied" );
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -199,7 +199,7 @@ public class FileSystem
|
|||||||
{
|
{
|
||||||
if( m_writableMount == null )
|
if( m_writableMount == null )
|
||||||
{
|
{
|
||||||
throw new FileSystemException( "Access Denied" );
|
throw new FileSystemException( "Access denied" );
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -219,7 +219,7 @@ public class FileSystem
|
|||||||
{
|
{
|
||||||
if( m_writableMount == null )
|
if( m_writableMount == null )
|
||||||
{
|
{
|
||||||
throw new FileSystemException( "Access Denied" );
|
throw new FileSystemException( "Access denied" );
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -251,7 +251,7 @@ public class FileSystem
|
|||||||
{
|
{
|
||||||
if( m_writableMount == null )
|
if( m_writableMount == null )
|
||||||
{
|
{
|
||||||
throw new FileSystemException( "Access Denied" );
|
throw new FileSystemException( "Access denied" );
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -28,6 +28,9 @@ import javax.annotation.Nonnull;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
public class CommandAPI implements ILuaAPI
|
public class CommandAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private TileCommandComputer m_computer;
|
private TileCommandComputer m_computer;
|
||||||
@ -151,11 +154,7 @@ public class CommandAPI implements ILuaAPI
|
|||||||
case 0:
|
case 0:
|
||||||
{
|
{
|
||||||
// exec
|
// exec
|
||||||
if( arguments.length < 1 || !(arguments[0] instanceof String) )
|
final String command = getString( arguments, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
final String command = (String)arguments[0];
|
|
||||||
return context.executeMainThreadTask( new ILuaTask()
|
return context.executeMainThreadTask( new ILuaTask()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@ -168,11 +167,7 @@ public class CommandAPI implements ILuaAPI
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// execAsync
|
// execAsync
|
||||||
if( arguments.length < 1 || !(arguments[0] instanceof String) )
|
final String command = getString( arguments, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
final String command = (String)arguments[0];
|
|
||||||
long taskID = context.issueMainThreadTask( new ILuaTask()
|
long taskID = context.issueMainThreadTask( new ILuaTask()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@ -234,22 +229,12 @@ public class CommandAPI implements ILuaAPI
|
|||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
// getBlockInfos
|
// getBlockInfos
|
||||||
if( arguments.length < 6 ||
|
final int minx = getInt( arguments, 0 );
|
||||||
!(arguments[0] instanceof Number) ||
|
final int miny = getInt( arguments, 1 );
|
||||||
!(arguments[1] instanceof Number) ||
|
final int minz = getInt( arguments, 2 );
|
||||||
!(arguments[2] instanceof Number) ||
|
final int maxx = getInt( arguments, 3 );
|
||||||
!(arguments[3] instanceof Number) ||
|
final int maxy = getInt( arguments, 4 );
|
||||||
!(arguments[4] instanceof Number) ||
|
final int maxz = getInt( arguments, 5 );
|
||||||
!(arguments[5] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number, number, number, number, number, number" );
|
|
||||||
}
|
|
||||||
final int minx = ((Number)arguments[0]).intValue();
|
|
||||||
final int miny = ((Number)arguments[1]).intValue();
|
|
||||||
final int minz = ((Number)arguments[2]).intValue();
|
|
||||||
final int maxx = ((Number)arguments[3]).intValue();
|
|
||||||
final int maxy = ((Number)arguments[4]).intValue();
|
|
||||||
final int maxz = ((Number)arguments[5]).intValue();
|
|
||||||
return context.executeMainThreadTask( new ILuaTask()
|
return context.executeMainThreadTask( new ILuaTask()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@ -295,16 +280,9 @@ public class CommandAPI implements ILuaAPI
|
|||||||
case 5:
|
case 5:
|
||||||
{
|
{
|
||||||
// getBlockInfo
|
// getBlockInfo
|
||||||
if( arguments.length < 3 ||
|
final int x = getInt( arguments, 0 );
|
||||||
!(arguments[0] instanceof Number) ||
|
final int y = getInt( arguments, 1 );
|
||||||
!(arguments[1] instanceof Number) ||
|
final int z = getInt( arguments, 2 );
|
||||||
!(arguments[2] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number, number, number" );
|
|
||||||
}
|
|
||||||
final int x = ((Number)arguments[0]).intValue();
|
|
||||||
final int y = ((Number)arguments[1]).intValue();
|
|
||||||
final int z = ((Number)arguments[2]).intValue();
|
|
||||||
return context.executeMainThreadTask( new ILuaTask()
|
return context.executeMainThreadTask( new ILuaTask()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -16,6 +16,8 @@ import net.minecraft.util.math.BlockPos;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
public class CommandBlockPeripheral implements IPeripheral
|
public class CommandBlockPeripheral implements IPeripheral
|
||||||
{
|
{
|
||||||
private final TileEntityCommandBlock m_commandBlock;
|
private final TileEntityCommandBlock m_commandBlock;
|
||||||
@ -67,12 +69,7 @@ public class CommandBlockPeripheral implements IPeripheral
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// setCommand
|
// setCommand
|
||||||
if( arguments.length < 1 || !(arguments[0] instanceof String) )
|
final String command = getString( arguments, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
|
|
||||||
final String command = (String) arguments[ 0 ];
|
|
||||||
context.issueMainThreadTask( new ILuaTask()
|
context.issueMainThreadTask( new ILuaTask()
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,6 +18,8 @@ import net.minecraft.item.ItemStack;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.optString;
|
||||||
|
|
||||||
public class DiskDrivePeripheral implements IPeripheral
|
public class DiskDrivePeripheral implements IPeripheral
|
||||||
{
|
{
|
||||||
private final TileDiskDrive m_diskDrive;
|
private final TileDiskDrive m_diskDrive;
|
||||||
@ -78,15 +80,7 @@ public class DiskDrivePeripheral implements IPeripheral
|
|||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// setDiskLabel
|
// setDiskLabel
|
||||||
String label = null;
|
String label = optString( arguments, 0, null );
|
||||||
if( arguments.length > 0 )
|
|
||||||
{
|
|
||||||
if( arguments[0] != null && !(arguments[0] instanceof String) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
label = (String)arguments[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
IMedia media = m_diskDrive.getDiskMedia();
|
IMedia media = m_diskDrive.getDiskMedia();
|
||||||
if( media != null )
|
if( media != null )
|
||||||
|
@ -21,6 +21,8 @@ import net.minecraft.world.World;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
||||||
|
|
||||||
public abstract class ModemPeripheral
|
public abstract class ModemPeripheral
|
||||||
implements IPeripheral, IPacketSender, IPacketReceiver
|
implements IPeripheral, IPacketSender, IPacketReceiver
|
||||||
{
|
{
|
||||||
@ -147,11 +149,7 @@ public abstract class ModemPeripheral
|
|||||||
|
|
||||||
private static int parseChannel( Object[] arguments, int index ) throws LuaException
|
private static int parseChannel( Object[] arguments, int index ) throws LuaException
|
||||||
{
|
{
|
||||||
if( arguments.length <= index || !(arguments[index] instanceof Double) )
|
int channel = getInt( arguments, index );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
int channel = (int)((Double)arguments[index]).doubleValue();
|
|
||||||
if( channel < 0 || channel > 65535 )
|
if( channel < 0 || channel > 65535 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Expected number in range 0-65535" );
|
throw new LuaException( "Expected number in range 0-65535" );
|
||||||
|
@ -40,6 +40,8 @@ import javax.annotation.Nonnull;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
|
||||||
public class TileCable extends TileModemBase
|
public class TileCable extends TileModemBase
|
||||||
implements IPacketNetwork
|
implements IPacketNetwork
|
||||||
{
|
{
|
||||||
@ -116,15 +118,6 @@ public class TileCable extends TileModemBase
|
|||||||
return newMethods;
|
return newMethods;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parseString( Object[] arguments, int index ) throws LuaException
|
|
||||||
{
|
|
||||||
if( arguments.length < (index + 1) || !(arguments[index] instanceof String) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
return (String)arguments[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
public Object[] callMethod( @Nonnull IComputerAccess computer, @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
||||||
{
|
{
|
||||||
@ -148,13 +141,13 @@ public class TileCable extends TileModemBase
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// isPresentRemote
|
// isPresentRemote
|
||||||
String type = m_entity.getTypeRemote( parseString( arguments, 0 ) );
|
String type = m_entity.getTypeRemote( getString( arguments, 0 ) );
|
||||||
return new Object[] { type != null };
|
return new Object[] { type != null };
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// getTypeRemote
|
// getTypeRemote
|
||||||
String type = m_entity.getTypeRemote( parseString( arguments, 0 ) );
|
String type = m_entity.getTypeRemote( getString( arguments, 0 ) );
|
||||||
if( type != null )
|
if( type != null )
|
||||||
{
|
{
|
||||||
return new Object[] { type };
|
return new Object[] { type };
|
||||||
@ -164,7 +157,7 @@ public class TileCable extends TileModemBase
|
|||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// getMethodsRemote
|
// getMethodsRemote
|
||||||
String[] methodNames = m_entity.getMethodNamesRemote( parseString( arguments, 0 ) );
|
String[] methodNames = m_entity.getMethodNamesRemote( getString( arguments, 0 ) );
|
||||||
if( methodNames != null )
|
if( methodNames != null )
|
||||||
{
|
{
|
||||||
Map<Object,Object> table = new HashMap<Object,Object>();
|
Map<Object,Object> table = new HashMap<Object,Object>();
|
||||||
@ -178,8 +171,8 @@ public class TileCable extends TileModemBase
|
|||||||
case 4:
|
case 4:
|
||||||
{
|
{
|
||||||
// callRemote
|
// callRemote
|
||||||
String remoteName = parseString( arguments, 0 );
|
String remoteName = getString( arguments, 0 );
|
||||||
String methodName = parseString( arguments, 1 );
|
String methodName = getString( arguments, 1 );
|
||||||
Object[] methodArgs = new Object[ arguments.length - 2 ];
|
Object[] methodArgs = new Object[ arguments.length - 2 ];
|
||||||
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
|
System.arraycopy( arguments, 2, methodArgs, 0, arguments.length - 2 );
|
||||||
return m_entity.callMethodRemote( remoteName, context, methodName, methodArgs );
|
return m_entity.callMethodRemote( remoteName, context, methodName, methodArgs );
|
||||||
|
@ -10,14 +10,15 @@ import dan200.computercraft.api.lua.ILuaContext;
|
|||||||
import dan200.computercraft.api.lua.LuaException;
|
import dan200.computercraft.api.lua.LuaException;
|
||||||
import dan200.computercraft.api.peripheral.IComputerAccess;
|
import dan200.computercraft.api.peripheral.IComputerAccess;
|
||||||
import dan200.computercraft.api.peripheral.IPeripheral;
|
import dan200.computercraft.api.peripheral.IPeripheral;
|
||||||
|
import dan200.computercraft.core.apis.TermAPI;
|
||||||
import dan200.computercraft.core.terminal.Terminal;
|
import dan200.computercraft.core.terminal.Terminal;
|
||||||
import dan200.computercraft.shared.util.Palette;
|
import dan200.computercraft.shared.util.Palette;
|
||||||
import org.apache.commons.lang3.ArrayUtils;
|
import org.apache.commons.lang3.ArrayUtils;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||||
|
|
||||||
public class MonitorPeripheral implements IPeripheral
|
public class MonitorPeripheral implements IPeripheral
|
||||||
{
|
{
|
||||||
private final TileMonitor m_monitor;
|
private final TileMonitor m_monitor;
|
||||||
@ -90,23 +91,16 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// scroll
|
// scroll
|
||||||
if( args.length < 1 || !(args[0] instanceof Number) )
|
int value = getInt( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
terminal.scroll( ((Number)(args[0])).intValue() );
|
terminal.scroll( value );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
{
|
{
|
||||||
// setCursorPos
|
// setCursorPos
|
||||||
if( args.length < 2 || !(args[0] instanceof Number) || !(args[1] instanceof Number) )
|
int x = getInt( args, 0 ) - 1;
|
||||||
{
|
int y = getInt( args, 1 ) - 1;
|
||||||
throw new LuaException( "Expected number, number" );
|
|
||||||
}
|
|
||||||
int x = ((Number)args[0]).intValue() - 1;
|
|
||||||
int y = ((Number)args[1]).intValue() - 1;
|
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
terminal.setCursorPos( x, y );
|
terminal.setCursorPos( x, y );
|
||||||
return null;
|
return null;
|
||||||
@ -114,12 +108,9 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// setCursorBlink
|
// setCursorBlink
|
||||||
if( args.length < 1 || !(args[0] instanceof Boolean) )
|
boolean blink = getBoolean( args, 0 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected boolean" );
|
|
||||||
}
|
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
terminal.setCursorBlink( (Boolean) args[ 0 ] );
|
terminal.setCursorBlink( blink );
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
case 4:
|
case 4:
|
||||||
@ -157,11 +148,7 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
case 8:
|
case 8:
|
||||||
{
|
{
|
||||||
// setTextScale
|
// setTextScale
|
||||||
if( args.length < 1 || !(args[0] instanceof Number) )
|
int scale = (int) (getReal( args, 0 ) * 2.0);
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
int scale = (int)(((Number)args[0]).doubleValue() * 2.0);
|
|
||||||
if( scale < 1 || scale > 10 )
|
if( scale < 1 || scale > 10 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Expected number in range 0.5-5" );
|
throw new LuaException( "Expected number in range 0.5-5" );
|
||||||
@ -173,7 +160,7 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
case 10:
|
case 10:
|
||||||
{
|
{
|
||||||
// setTextColour/setTextColor
|
// setTextColour/setTextColor
|
||||||
int colour = dan200.computercraft.core.apis.TermAPI.parseColour( args );
|
int colour = TermAPI.parseColour( args );
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
terminal.setTextColour( colour );
|
terminal.setTextColour( colour );
|
||||||
return null;
|
return null;
|
||||||
@ -182,7 +169,7 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
case 12:
|
case 12:
|
||||||
{
|
{
|
||||||
// setBackgroundColour/setBackgroundColor
|
// setBackgroundColour/setBackgroundColor
|
||||||
int colour = dan200.computercraft.core.apis.TermAPI.parseColour( args );
|
int colour = TermAPI.parseColour( args );
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
terminal.setBackgroundColour( colour );
|
terminal.setBackgroundColour( colour );
|
||||||
return null;
|
return null;
|
||||||
@ -200,26 +187,21 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
{
|
{
|
||||||
// getTextColour/getTextColor
|
// getTextColour/getTextColor
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
return dan200.computercraft.core.apis.TermAPI.encodeColour( terminal.getTextColour() );
|
return TermAPI.encodeColour( terminal.getTextColour() );
|
||||||
}
|
}
|
||||||
case 17:
|
case 17:
|
||||||
case 18:
|
case 18:
|
||||||
{
|
{
|
||||||
// getBackgroundColour/getBackgroundColor
|
// getBackgroundColour/getBackgroundColor
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
return dan200.computercraft.core.apis.TermAPI.encodeColour( terminal.getBackgroundColour() );
|
return TermAPI.encodeColour( terminal.getBackgroundColour() );
|
||||||
}
|
}
|
||||||
case 19:
|
case 19:
|
||||||
{
|
{
|
||||||
// blit
|
// blit
|
||||||
if( args.length < 3 || !(args[0] instanceof String) || !(args[1] instanceof String) || !(args[2] instanceof String) )
|
String text = getString( args, 0 );
|
||||||
{
|
String textColour = getString( args, 1 );
|
||||||
throw new LuaException( "Expected string, string, string" );
|
String backgroundColour = getString( args, 2 );
|
||||||
}
|
|
||||||
|
|
||||||
String text = (String)args[0];
|
|
||||||
String textColour = (String)args[1];
|
|
||||||
String backgroundColour = (String)args[2];
|
|
||||||
if( textColour.length() != text.length() || backgroundColour.length() != text.length() )
|
if( textColour.length() != text.length() || backgroundColour.length() != text.length() )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Arguments must be the same length" );
|
throw new LuaException( "Arguments must be the same length" );
|
||||||
@ -236,26 +218,21 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
// setPaletteColour/setPaletteColor
|
// setPaletteColour/setPaletteColor
|
||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
|
|
||||||
if(args.length == 2 && args[0] instanceof Double && args[1] instanceof Double)
|
int colour = 15 - TermAPI.parseColour( args );
|
||||||
|
if( args.length == 2 )
|
||||||
{
|
{
|
||||||
int colour = 15 - dan200.computercraft.core.apis.TermAPI.parseColour( args );
|
int hex = getInt( args, 1 );
|
||||||
int hex = ((Double)args[1]).intValue();
|
|
||||||
double[] rgb = Palette.decodeRGB8( hex );
|
double[] rgb = Palette.decodeRGB8( hex );
|
||||||
dan200.computercraft.core.apis.TermAPI.setColour( terminal, colour, rgb[0], rgb[1], rgb[2] );
|
TermAPI.setColour( terminal, colour, rgb[ 0 ], rgb[ 1 ], rgb[ 2 ] );
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
if (args.length >= 4 && args[0] instanceof Double && args[1] instanceof Double && args[2] instanceof Double && args[3] instanceof Double)
|
|
||||||
{
|
{
|
||||||
int colour = 15 - dan200.computercraft.core.apis.TermAPI.parseColour( args );
|
double r = getReal( args, 1 );
|
||||||
double r = (Double)args[1];
|
double g = getReal( args, 2 );
|
||||||
double g = (Double)args[2];
|
double b = getReal( args, 3 );
|
||||||
double b = (Double)args[3];
|
TermAPI.setColour( terminal, colour, r, g, b );
|
||||||
dan200.computercraft.core.apis.TermAPI.setColour( terminal, colour, r, g, b );
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
throw new LuaException( "Expected number, number, number, number" );
|
|
||||||
}
|
}
|
||||||
case 22:
|
case 22:
|
||||||
case 23:
|
case 23:
|
||||||
@ -264,7 +241,7 @@ public class MonitorPeripheral implements IPeripheral
|
|||||||
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
Terminal terminal = m_monitor.getTerminal().getTerminal();
|
||||||
Palette palette = terminal.getPalette();
|
Palette palette = terminal.getPalette();
|
||||||
|
|
||||||
int colour = 15 - dan200.computercraft.core.apis.TermAPI.parseColour( args );
|
int colour = 15 - TermAPI.parseColour( args );
|
||||||
|
|
||||||
if( palette != null )
|
if( palette != null )
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,9 @@ import dan200.computercraft.core.terminal.Terminal;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.optString;
|
||||||
|
|
||||||
public class PrinterPeripheral implements IPeripheral
|
public class PrinterPeripheral implements IPeripheral
|
||||||
{
|
{
|
||||||
private final TilePrinter m_printer;
|
private final TilePrinter m_printer;
|
||||||
@ -70,13 +73,8 @@ public class PrinterPeripheral implements IPeripheral
|
|||||||
case 1:
|
case 1:
|
||||||
{
|
{
|
||||||
// setCursorPos
|
// setCursorPos
|
||||||
if( args.length != 2 || args[0] == null || !(args[0] instanceof Number) || args[1] == null || !(args[1] instanceof Number) )
|
int x = getInt( args, 0 ) - 1;
|
||||||
{
|
int y = getInt( args, 1 ) - 1;
|
||||||
throw new LuaException( "Expected number, number" );
|
|
||||||
}
|
|
||||||
|
|
||||||
int x = ((Number)args[0]).intValue() - 1;
|
|
||||||
int y = ((Number)args[1]).intValue() - 1;
|
|
||||||
Terminal page = getCurrentPage();
|
Terminal page = getCurrentPage();
|
||||||
page.setCursorPos( x, y );
|
page.setCursorPos( x, y );
|
||||||
return null;
|
return null;
|
||||||
@ -116,16 +114,7 @@ public class PrinterPeripheral implements IPeripheral
|
|||||||
case 7:
|
case 7:
|
||||||
{
|
{
|
||||||
// setPageTitle
|
// setPageTitle
|
||||||
String title = "";
|
String title = optString( args, 0, "" );
|
||||||
if( args.length > 0 && args[0] != null )
|
|
||||||
{
|
|
||||||
if( !(args[0] instanceof String) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
title = (String)args[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
getCurrentPage();
|
getCurrentPage();
|
||||||
m_printer.setPageTitle( title );
|
m_printer.setPageTitle( title );
|
||||||
return null;
|
return null;
|
||||||
|
@ -17,9 +17,13 @@ import net.minecraft.util.SoundCategory;
|
|||||||
import net.minecraft.util.SoundEvent;
|
import net.minecraft.util.SoundEvent;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.optReal;
|
||||||
|
|
||||||
public class SpeakerPeripheral implements IPeripheral {
|
public class SpeakerPeripheral implements IPeripheral {
|
||||||
private TileSpeaker m_speaker;
|
private TileSpeaker m_speaker;
|
||||||
private long m_clock;
|
private long m_clock;
|
||||||
@ -127,47 +131,20 @@ public class SpeakerPeripheral implements IPeripheral {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
private synchronized Object[] playNote( Object[] arguments, ILuaContext context ) throws LuaException
|
private synchronized Object[] playNote( Object[] arguments, ILuaContext context ) throws LuaException
|
||||||
{
|
{
|
||||||
float volume = 1.0f;
|
String name = getString(arguments, 0);
|
||||||
float pitch = 1.0f;
|
float volume = (float) optReal( arguments, 1, 1.0 );
|
||||||
|
float pitch = (float) optReal( arguments, 2, 1.0 );
|
||||||
|
|
||||||
// Check if arguments are correct
|
// Check if sound exists
|
||||||
if( arguments.length == 0 ) // Too few args
|
if ( !SoundEvent.REGISTRY.containsKey( new ResourceLocation( "block.note." + name ) ) )
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number (optional), number (optional)" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !(arguments[0] instanceof String) ) // Arg wrong type
|
|
||||||
{
|
|
||||||
throw new LuaException("Expected string, number (optional), number (optional)");
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !SoundEvent.REGISTRY.containsKey( new ResourceLocation( "block.note." + arguments[0] ) ) )
|
|
||||||
{
|
{
|
||||||
throw new LuaException("Invalid instrument, \"" + arguments[0] + "\"!");
|
throw new LuaException("Invalid instrument, \"" + arguments[0] + "\"!");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( arguments.length > 1 )
|
|
||||||
{
|
|
||||||
if ( arguments[1] != null && !(arguments[1] instanceof Double) ) // Arg wrong type
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number (optional), number (optional)" );
|
|
||||||
}
|
|
||||||
volume = arguments[1] != null ? ((Double) arguments[1]).floatValue() : 1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( arguments.length > 2 )
|
|
||||||
{
|
|
||||||
if( arguments[2] != null && !(arguments[2] instanceof Double) ) // Arg wrong type
|
|
||||||
{
|
|
||||||
throw new LuaException("Expected string, number (optional), number (optional)");
|
|
||||||
}
|
|
||||||
pitch = arguments[2] != null ? ((Double) arguments[2]).floatValue() : 1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the resource location for note block notes changes, this method call will need to be updated
|
// If the resource location for note block notes changes, this method call will need to be updated
|
||||||
Object[] returnValue = playSound(
|
Object[] returnValue = playSound(
|
||||||
new Object[] {
|
new Object[] {
|
||||||
"block.note." + arguments[0],
|
"block.note." + name,
|
||||||
(double)Math.min( volume, 3f ),
|
(double)Math.min( volume, 3f ),
|
||||||
Math.pow( 2.0f, ( pitch - 12.0f ) / 12.0f)
|
Math.pow( 2.0f, ( pitch - 12.0f ) / 12.0f)
|
||||||
}, context, true
|
}, context, true
|
||||||
@ -184,42 +161,11 @@ public class SpeakerPeripheral implements IPeripheral {
|
|||||||
@Nonnull
|
@Nonnull
|
||||||
private synchronized Object[] playSound( Object[] arguments, ILuaContext context, boolean isNote ) throws LuaException
|
private synchronized Object[] playSound( Object[] arguments, ILuaContext context, boolean isNote ) throws LuaException
|
||||||
{
|
{
|
||||||
|
String name = getString(arguments, 0);
|
||||||
|
float volume = (float) optReal( arguments, 1, 1.0 );
|
||||||
|
float pitch = (float) optReal( arguments, 2, 1.0 );
|
||||||
|
|
||||||
float volume = 1.0f;
|
ResourceLocation resourceName = new ResourceLocation( name );
|
||||||
float pitch = 1.0f;
|
|
||||||
|
|
||||||
// Check if arguments are correct
|
|
||||||
if( arguments.length == 0 ) // Too few args
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number (optional), number (optional)" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !(arguments[0] instanceof String) ) // Arg wrong type
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number (optional), number (optional)" );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( arguments.length > 1 )
|
|
||||||
{
|
|
||||||
if( arguments[1] != null && !(arguments[1] instanceof Double) ) // Arg wrong type
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number (optional), number (optional)" );
|
|
||||||
}
|
|
||||||
|
|
||||||
volume = arguments[1] != null ? ((Double) arguments[1]).floatValue() : 1f;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if( arguments.length > 2 )
|
|
||||||
{
|
|
||||||
if( arguments[2] != null && !(arguments[2] instanceof Double) ) // Arg wrong type
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string, number (optional), number (optional)" );
|
|
||||||
}
|
|
||||||
pitch = arguments[2] != null ? ((Double) arguments[2]).floatValue() : 1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
ResourceLocation resourceName = new ResourceLocation( (String) arguments[0] );
|
|
||||||
|
|
||||||
if( m_clock - m_lastPlayTime >= TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS || ( ( m_clock - m_lastPlayTime == 0 ) && ( m_notesThisTick < ComputerCraft.maxNotesPerTick ) && isNote ) )
|
if( m_clock - m_lastPlayTime >= TileSpeaker.MIN_TICKS_BETWEEN_SOUNDS || ( ( m_clock - m_lastPlayTime == 0 ) && ( m_notesThisTick < ComputerCraft.maxNotesPerTick ) && isNote ) )
|
||||||
{
|
{
|
||||||
|
@ -22,6 +22,8 @@ import javax.annotation.Nonnull;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.*;
|
||||||
|
|
||||||
public class TurtleAPI implements ILuaAPI
|
public class TurtleAPI implements ILuaAPI
|
||||||
{
|
{
|
||||||
private IAPIEnvironment m_environment;
|
private IAPIEnvironment m_environment;
|
||||||
@ -115,38 +117,23 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
|
|
||||||
private int parseSlotNumber( Object[] arguments, int index ) throws LuaException
|
private int parseSlotNumber( Object[] arguments, int index ) throws LuaException
|
||||||
{
|
{
|
||||||
int slot = parseOptionalSlotNumber( arguments, index, 99 );
|
int slot = getInt( arguments, index );
|
||||||
if( slot == 99 )
|
if( slot < 1 || slot > 16 ) throw new LuaException( "Slot number " + slot + " out of range" );
|
||||||
{
|
return slot - 1;
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
return slot;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parseOptionalSlotNumber( Object[] arguments, int index, int fallback ) throws LuaException
|
private int parseOptionalSlotNumber( Object[] arguments, int index, int fallback ) throws LuaException
|
||||||
{
|
{
|
||||||
if( arguments.length <= index || !(arguments[index] instanceof Number) )
|
if( index >= arguments.length || arguments[ index ] == null ) return fallback;
|
||||||
{
|
|
||||||
return fallback;
|
int slot = getInt( arguments, index );
|
||||||
}
|
if( slot < 1 || slot > 16 ) throw new LuaException( "Slot number " + slot + " out of range" );
|
||||||
int slot = ((Number)arguments[index]).intValue();
|
return slot - 1;
|
||||||
if( slot >= 1 && slot <= 16 )
|
|
||||||
{
|
|
||||||
return slot - 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
throw new LuaException( "Slot number " + slot + " out of range" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int parseCount( Object[] arguments, int index ) throws LuaException
|
private int parseCount( Object[] arguments, int index ) throws LuaException
|
||||||
{
|
{
|
||||||
if( arguments.length <= index || !(arguments[index] instanceof Number) )
|
int count = optInt( arguments, index, 64 );
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
int count = ((Number)arguments[index]).intValue();
|
|
||||||
if( count >= 0 && count <= 64 )
|
if( count >= 0 && count <= 64 )
|
||||||
{
|
{
|
||||||
return count;
|
return count;
|
||||||
@ -159,19 +146,16 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
|
|
||||||
private Optional<TurtleSide> parseSide( Object[] arguments, int index ) throws LuaException
|
private Optional<TurtleSide> parseSide( Object[] arguments, int index ) throws LuaException
|
||||||
{
|
{
|
||||||
if( arguments.length <= index || arguments[index] == null )
|
String side = optString( arguments, index, null );
|
||||||
|
if( side == null )
|
||||||
{
|
{
|
||||||
return Optional.absent();
|
return Optional.absent();
|
||||||
}
|
}
|
||||||
if( !(arguments[ index ] instanceof String) )
|
else if( side.equalsIgnoreCase( "left" ) )
|
||||||
{
|
|
||||||
throw new LuaException( "Expected string" );
|
|
||||||
}
|
|
||||||
if( arguments[ index ].equals( "left" ) )
|
|
||||||
{
|
{
|
||||||
return Optional.of( TurtleSide.Left );
|
return Optional.of( TurtleSide.Left );
|
||||||
}
|
}
|
||||||
else if( arguments[ index ].equals( "right" ) )
|
else if( side.equalsIgnoreCase( "right" ) )
|
||||||
{
|
{
|
||||||
return Optional.of( TurtleSide.Right );
|
return Optional.of( TurtleSide.Right );
|
||||||
}
|
}
|
||||||
@ -252,11 +236,7 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
case 12:
|
case 12:
|
||||||
{
|
{
|
||||||
// drop
|
// drop
|
||||||
int count = 64;
|
int count = parseCount( args, 0 );
|
||||||
if( args.length > 0 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 0 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleDropCommand( InteractDirection.Forward, count ) );
|
return tryCommand( context, new TurtleDropCommand( InteractDirection.Forward, count ) );
|
||||||
}
|
}
|
||||||
case 13:
|
case 13:
|
||||||
@ -343,51 +323,31 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
case 25:
|
case 25:
|
||||||
{
|
{
|
||||||
// dropUp
|
// dropUp
|
||||||
int count = 64;
|
int count = parseCount( args, 0 );
|
||||||
if( args.length > 0 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 0 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleDropCommand( InteractDirection.Up, count ) );
|
return tryCommand( context, new TurtleDropCommand( InteractDirection.Up, count ) );
|
||||||
}
|
}
|
||||||
case 26:
|
case 26:
|
||||||
{
|
{
|
||||||
// dropDown
|
// dropDown
|
||||||
int count = 64;
|
int count = parseCount( args, 0 );
|
||||||
if( args.length > 0 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 0 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleDropCommand( InteractDirection.Down, count ) );
|
return tryCommand( context, new TurtleDropCommand( InteractDirection.Down, count ) );
|
||||||
}
|
}
|
||||||
case 27:
|
case 27:
|
||||||
{
|
{
|
||||||
// suck
|
// suck
|
||||||
int count = 64;
|
int count = parseCount( args, 0 );
|
||||||
if( args.length > 0 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 0 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Forward, count ) );
|
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Forward, count ) );
|
||||||
}
|
}
|
||||||
case 28:
|
case 28:
|
||||||
{
|
{
|
||||||
// suckUp
|
// suckUp
|
||||||
int count = 64;
|
int count = parseCount( args, 0 );
|
||||||
if( args.length > 0 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 0 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Up, count ) );
|
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Up, count ) );
|
||||||
}
|
}
|
||||||
case 29:
|
case 29:
|
||||||
{
|
{
|
||||||
// suckDown
|
// suckDown
|
||||||
int count = 64;
|
int count = parseCount( args, 0 );
|
||||||
if( args.length > 0 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 0 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Down, count ) );
|
return tryCommand( context, new TurtleSuckCommand( InteractDirection.Down, count ) );
|
||||||
}
|
}
|
||||||
case 30:
|
case 30:
|
||||||
@ -405,11 +365,7 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
case 31:
|
case 31:
|
||||||
{
|
{
|
||||||
// refuel
|
// refuel
|
||||||
int count = 64;
|
int count = parseCount( args, 0 );
|
||||||
if( args.length > 0 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 0 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleRefuelCommand( count ) );
|
return tryCommand( context, new TurtleRefuelCommand( count ) );
|
||||||
}
|
}
|
||||||
case 32:
|
case 32:
|
||||||
@ -422,11 +378,7 @@ public class TurtleAPI implements ILuaAPI
|
|||||||
{
|
{
|
||||||
// transferTo
|
// transferTo
|
||||||
int slot = parseSlotNumber( args, 0 );
|
int slot = parseSlotNumber( args, 0 );
|
||||||
int count = 64;
|
int count = parseCount( args, 1 );
|
||||||
if( args.length > 1 )
|
|
||||||
{
|
|
||||||
count = parseCount( args, 1 );
|
|
||||||
}
|
|
||||||
return tryCommand( context, new TurtleTransferToCommand( slot, count ) );
|
return tryCommand( context, new TurtleTransferToCommand( slot, count ) );
|
||||||
}
|
}
|
||||||
case 34:
|
case 34:
|
||||||
|
@ -24,13 +24,16 @@ import net.minecraft.tileentity.TileEntity;
|
|||||||
import net.minecraft.tileentity.TileEntitySign;
|
import net.minecraft.tileentity.TileEntitySign;
|
||||||
import net.minecraft.util.ActionResult;
|
import net.minecraft.util.ActionResult;
|
||||||
import net.minecraft.util.EnumActionResult;
|
import net.minecraft.util.EnumActionResult;
|
||||||
|
import net.minecraft.util.EnumFacing;
|
||||||
import net.minecraft.util.EnumHand;
|
import net.minecraft.util.EnumHand;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.text.TextComponentString;
|
|
||||||
import net.minecraft.util.EnumFacing;
|
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.text.TextComponentString;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.WorldServer;
|
import net.minecraft.world.WorldServer;
|
||||||
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
|
import net.minecraftforge.event.entity.player.PlayerInteractEvent;
|
||||||
|
import net.minecraftforge.fml.common.eventhandler.Event;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
@ -215,7 +218,6 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load up the turtle's inventory
|
// Load up the turtle's inventory
|
||||||
Item item = stack.getItem();
|
|
||||||
ItemStack stackCopy = stack.copy();
|
ItemStack stackCopy = stack.copy();
|
||||||
turtlePlayer.loadInventory( stackCopy );
|
turtlePlayer.loadInventory( stackCopy );
|
||||||
|
|
||||||
@ -237,21 +239,26 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
|
|
||||||
// Place on the entity
|
// Place on the entity
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
if( hitEntity.applyPlayerInteraction( turtlePlayer, hitPos, stackCopy, EnumHand.MAIN_HAND ) == EnumActionResult.SUCCESS )
|
if( !ForgeHooks.onInteractEntityAt( turtlePlayer, hitEntity, hitPos, stack, EnumHand.MAIN_HAND ) &&
|
||||||
|
hitEntity.applyPlayerInteraction( turtlePlayer, hitPos, stackCopy, EnumHand.MAIN_HAND ) == EnumActionResult.SUCCESS )
|
||||||
{
|
{
|
||||||
placed = true;
|
placed = true;
|
||||||
turtlePlayer.loadInventory( stackCopy );
|
turtlePlayer.loadInventory( stackCopy );
|
||||||
}
|
}
|
||||||
else if( hitEntity.processInitialInteract( turtlePlayer, stackCopy, EnumHand.MAIN_HAND ) )
|
else if( !ForgeHooks.onInteractEntity( turtlePlayer, hitEntity, stack, EnumHand.MAIN_HAND ) )
|
||||||
{
|
{
|
||||||
placed = true;
|
// See EntityPlayer.interact
|
||||||
}
|
if( hitEntity.processInitialInteract( turtlePlayer, stackCopy, EnumHand.MAIN_HAND ) )
|
||||||
else if( hitEntity instanceof EntityLivingBase )
|
|
||||||
{
|
|
||||||
placed = item.itemInteractionForEntity( stackCopy, turtlePlayer, (EntityLivingBase)hitEntity, EnumHand.MAIN_HAND );
|
|
||||||
if( placed )
|
|
||||||
{
|
{
|
||||||
turtlePlayer.loadInventory( stackCopy );
|
placed = true;
|
||||||
|
}
|
||||||
|
else if( hitEntity instanceof EntityLivingBase )
|
||||||
|
{
|
||||||
|
placed = stackCopy.interactWithEntity( turtlePlayer, (EntityLivingBase) hitEntity, EnumHand.MAIN_HAND );
|
||||||
|
if( placed )
|
||||||
|
{
|
||||||
|
turtlePlayer.loadInventory( stackCopy );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -352,19 +359,29 @@ public class TurtlePlaceCommand implements ITurtleCommand
|
|||||||
|
|
||||||
// Do the deploying (put everything in the players inventory)
|
// Do the deploying (put everything in the players inventory)
|
||||||
boolean placed = false;
|
boolean placed = false;
|
||||||
if( item.onItemUseFirst( stackCopy, turtlePlayer, turtle.getWorld(), position, side, hitX, hitY, hitZ, EnumHand.MAIN_HAND ) == EnumActionResult.SUCCESS )
|
|
||||||
|
|
||||||
|
// See PlayerInteractionManager.processRightClickBlock
|
||||||
|
PlayerInteractEvent.RightClickBlock event = ForgeHooks.onRightClickBlock( turtlePlayer, EnumHand.MAIN_HAND, stackCopy, position, side, new Vec3d( hitX, hitY, hitZ ) );
|
||||||
|
if( !event.isCanceled() )
|
||||||
{
|
{
|
||||||
placed = true;
|
if( item.onItemUseFirst( stackCopy, turtlePlayer, turtle.getWorld(), position, side, hitX, hitY, hitZ, EnumHand.MAIN_HAND ) == EnumActionResult.SUCCESS )
|
||||||
turtlePlayer.loadInventory( stackCopy );
|
{
|
||||||
|
placed = true;
|
||||||
|
turtlePlayer.loadInventory( stackCopy );
|
||||||
|
}
|
||||||
|
else if( event.getUseItem() != Event.Result.DENY &&
|
||||||
|
stackCopy.onItemUse( turtlePlayer, turtle.getWorld(), position, EnumHand.MAIN_HAND, side, hitX, hitY, hitZ ) == EnumActionResult.SUCCESS )
|
||||||
|
{
|
||||||
|
placed = true;
|
||||||
|
turtlePlayer.loadInventory( stackCopy );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if( item.onItemUse( stackCopy, turtlePlayer, turtle.getWorld(), position, EnumHand.MAIN_HAND, side, hitX, hitY, hitZ ) == EnumActionResult.SUCCESS )
|
|
||||||
|
if( !placed && (item instanceof ItemBucket || item instanceof ItemBoat || item instanceof ItemLilyPad || item instanceof ItemGlassBottle)
|
||||||
|
&& ForgeHooks.onItemRightClick( turtlePlayer, EnumHand.MAIN_HAND, stackCopy ) )
|
||||||
{
|
{
|
||||||
placed = true;
|
ActionResult<ItemStack> result = stackCopy.useItemRightClick( turtle.getWorld(), turtlePlayer, EnumHand.MAIN_HAND );
|
||||||
turtlePlayer.loadInventory( stackCopy );
|
|
||||||
}
|
|
||||||
else if( item instanceof ItemBucket || item instanceof ItemBoat || item instanceof ItemLilyPad || item instanceof ItemGlassBottle )
|
|
||||||
{
|
|
||||||
ActionResult<ItemStack> result = item.onItemRightClick( stackCopy, turtle.getWorld(), turtlePlayer, EnumHand.MAIN_HAND );
|
|
||||||
if( result.getType() == EnumActionResult.SUCCESS && !ItemStack.areItemStacksEqual( stack, result.getResult() ) )
|
if( result.getType() == EnumActionResult.SUCCESS && !ItemStack.areItemStacksEqual( stack, result.getResult() ) )
|
||||||
{
|
{
|
||||||
placed = true;
|
placed = true;
|
||||||
|
@ -15,6 +15,8 @@ import dan200.computercraft.shared.turtle.core.TurtleCraftCommand;
|
|||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
|
import static dan200.computercraft.core.apis.ArgumentHelper.optInt;
|
||||||
|
|
||||||
public class CraftingTablePeripheral
|
public class CraftingTablePeripheral
|
||||||
implements IPeripheral
|
implements IPeripheral
|
||||||
{
|
{
|
||||||
@ -45,16 +47,7 @@ public class CraftingTablePeripheral
|
|||||||
|
|
||||||
private int parseCount( Object[] arguments ) throws LuaException
|
private int parseCount( Object[] arguments ) throws LuaException
|
||||||
{
|
{
|
||||||
if( arguments.length < 1 )
|
int count = optInt( arguments, 0, 64 );
|
||||||
{
|
|
||||||
return 64;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( !(arguments[0] instanceof Number) )
|
|
||||||
{
|
|
||||||
throw new LuaException( "Expected number" );
|
|
||||||
}
|
|
||||||
int count = ((Number)arguments[0]).intValue();
|
|
||||||
if( count < 0 || count > 64 )
|
if( count < 0 || count > 64 )
|
||||||
{
|
{
|
||||||
throw new LuaException( "Crafting count " + count + " out of range" );
|
throw new LuaException( "Crafting count " + count + " out of range" );
|
||||||
|
@ -22,14 +22,22 @@ import net.minecraft.client.renderer.block.model.IBakedModel;
|
|||||||
import net.minecraft.entity.Entity;
|
import net.minecraft.entity.Entity;
|
||||||
import net.minecraft.entity.SharedMonsterAttributes;
|
import net.minecraft.entity.SharedMonsterAttributes;
|
||||||
import net.minecraft.entity.item.EntityArmorStand;
|
import net.minecraft.entity.item.EntityArmorStand;
|
||||||
|
import net.minecraft.entity.player.EntityPlayer;
|
||||||
import net.minecraft.init.Blocks;
|
import net.minecraft.init.Blocks;
|
||||||
import net.minecraft.item.Item;
|
import net.minecraft.item.Item;
|
||||||
import net.minecraft.item.ItemStack;
|
import net.minecraft.item.ItemStack;
|
||||||
import net.minecraft.util.*;
|
import net.minecraft.util.DamageSource;
|
||||||
import net.minecraft.util.math.*;
|
import net.minecraft.util.EnumFacing;
|
||||||
|
import net.minecraft.util.ResourceLocation;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
import net.minecraft.util.math.Vec3d;
|
||||||
import net.minecraft.world.World;
|
import net.minecraft.world.World;
|
||||||
import net.minecraft.world.WorldServer;
|
import net.minecraft.world.WorldServer;
|
||||||
import net.minecraftforge.common.ForgeHooks;
|
import net.minecraftforge.common.ForgeHooks;
|
||||||
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
|
import net.minecraftforge.event.ForgeEventFactory;
|
||||||
|
import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
||||||
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
import net.minecraftforge.fml.relauncher.Side;
|
import net.minecraftforge.fml.relauncher.Side;
|
||||||
import net.minecraftforge.fml.relauncher.SideOnly;
|
import net.minecraftforge.fml.relauncher.SideOnly;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
@ -189,9 +197,10 @@ public class TurtleTool implements ITurtleUpgrade
|
|||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
|
|
||||||
// Place on the entity
|
// Attack the entity
|
||||||
boolean placed = false;
|
boolean attacked = false;
|
||||||
if( hitEntity.canBeAttackedWithItem() && !hitEntity.hitByEntity( turtlePlayer ) )
|
if( hitEntity.canBeAttackedWithItem() && !hitEntity.hitByEntity( turtlePlayer )
|
||||||
|
&& !MinecraftForge.EVENT_BUS.post( new AttackEntityEvent( turtlePlayer, hitEntity ) ) )
|
||||||
{
|
{
|
||||||
float damage = (float)turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue();
|
float damage = (float)turtlePlayer.getEntityAttribute( SharedMonsterAttributes.ATTACK_DAMAGE ).getAttributeValue();
|
||||||
damage *= getDamageMultiplier();
|
damage *= getDamageMultiplier();
|
||||||
@ -206,13 +215,13 @@ public class TurtleTool implements ITurtleUpgrade
|
|||||||
{
|
{
|
||||||
hitEntity.attackEntityFrom( source, damage );
|
hitEntity.attackEntityFrom( source, damage );
|
||||||
}
|
}
|
||||||
placed = true;
|
attacked = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if( hitEntity.attackEntityFrom( source, damage ) )
|
if( hitEntity.attackEntityFrom( source, damage ) )
|
||||||
{
|
{
|
||||||
placed = true;
|
attacked = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,7 +231,7 @@ public class TurtleTool implements ITurtleUpgrade
|
|||||||
ComputerCraft.clearEntityDropConsumer( hitEntity );
|
ComputerCraft.clearEntityDropConsumer( hitEntity );
|
||||||
|
|
||||||
// Put everything we collected into the turtles inventory, then return
|
// Put everything we collected into the turtles inventory, then return
|
||||||
if( placed )
|
if( attacked )
|
||||||
{
|
{
|
||||||
turtlePlayer.unloadInventory( turtle );
|
turtlePlayer.unloadInventory( turtle );
|
||||||
return TurtleCommandResult.success();
|
return TurtleCommandResult.success();
|
||||||
@ -243,10 +252,16 @@ public class TurtleTool implements ITurtleUpgrade
|
|||||||
!world.isAirBlock( newPosition ) &&
|
!world.isAirBlock( newPosition ) &&
|
||||||
!WorldUtil.isLiquidBlock( world, newPosition ) )
|
!WorldUtil.isLiquidBlock( world, newPosition ) )
|
||||||
{
|
{
|
||||||
|
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction );
|
||||||
if( ComputerCraft.turtlesObeyBlockProtection )
|
if( ComputerCraft.turtlesObeyBlockProtection )
|
||||||
{
|
{
|
||||||
// Check spawn protection
|
// Check spawn protection
|
||||||
TurtlePlayer turtlePlayer = TurtlePlaceCommand.createPlayer( turtle, position, direction );
|
|
||||||
|
if( MinecraftForge.EVENT_BUS.post( new BlockEvent.BreakEvent( world, newPosition, world.getBlockState( newPosition ), turtlePlayer ) ) )
|
||||||
|
{
|
||||||
|
return TurtleCommandResult.failure( "Cannot break protected block" );
|
||||||
|
}
|
||||||
|
|
||||||
if( !ComputerCraft.isBlockEditable( world, newPosition, turtlePlayer ) )
|
if( !ComputerCraft.isBlockEditable( world, newPosition, turtlePlayer ) )
|
||||||
{
|
{
|
||||||
return TurtleCommandResult.failure( "Cannot break protected block" );
|
return TurtleCommandResult.failure( "Cannot break protected block" );
|
||||||
@ -262,7 +277,7 @@ public class TurtleTool implements ITurtleUpgrade
|
|||||||
// Consume the items the block drops
|
// Consume the items the block drops
|
||||||
if( canHarvestBlock( world, newPosition ) )
|
if( canHarvestBlock( world, newPosition ) )
|
||||||
{
|
{
|
||||||
List<ItemStack> items = getBlockDropped( world, newPosition );
|
List<ItemStack> items = getBlockDropped( world, newPosition, turtlePlayer );
|
||||||
if( items != null && items.size() > 0 )
|
if( items != null && items.size() > 0 )
|
||||||
{
|
{
|
||||||
for( ItemStack stack : items )
|
for( ItemStack stack : items )
|
||||||
@ -279,7 +294,7 @@ public class TurtleTool implements ITurtleUpgrade
|
|||||||
|
|
||||||
// Destroy the block
|
// Destroy the block
|
||||||
IBlockState previousState = world.getBlockState( newPosition );
|
IBlockState previousState = world.getBlockState( newPosition );
|
||||||
world.playEvent(2001, newPosition, Block.getStateId(previousState));
|
world.playEvent(2001, newPosition, Block.getStateId(previousState));
|
||||||
world.setBlockToAir( newPosition );
|
world.setBlockToAir( newPosition );
|
||||||
|
|
||||||
// Remember the previous block
|
// Remember the previous block
|
||||||
@ -295,9 +310,20 @@ public class TurtleTool implements ITurtleUpgrade
|
|||||||
return TurtleCommandResult.failure( "Nothing to dig here" );
|
return TurtleCommandResult.failure( "Nothing to dig here" );
|
||||||
}
|
}
|
||||||
|
|
||||||
private java.util.List<ItemStack> getBlockDropped( World world, BlockPos pos )
|
private List<ItemStack> getBlockDropped( World world, BlockPos pos, EntityPlayer player )
|
||||||
{
|
{
|
||||||
Block block = world.getBlockState( pos ).getBlock();
|
IBlockState state = world.getBlockState( pos );
|
||||||
return block.getDrops( world, pos, world.getBlockState( pos ), 0 );
|
Block block = state.getBlock();
|
||||||
|
List<ItemStack> drops = block.getDrops( world, pos, world.getBlockState( pos ), 0 );
|
||||||
|
double chance = ForgeEventFactory.fireBlockHarvesting( drops, world, pos, state, 0, 1, false, player );
|
||||||
|
|
||||||
|
for( int i = drops.size() - 1; i >= 0; i-- )
|
||||||
|
{
|
||||||
|
if( world.rand.nextFloat() > chance )
|
||||||
|
{
|
||||||
|
drops.remove( i );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return drops;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -163,13 +163,13 @@ public class InventoryUtil
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Inspect the slots in order and try to find empty or stackable slots
|
// Inspect the slots in order and try to find empty or stackable slots
|
||||||
ItemStack remainder = stack;
|
ItemStack remainder = stack.copy();
|
||||||
for( int slot : slots )
|
for( int slot : slots )
|
||||||
{
|
{
|
||||||
if( remainder == null ) break;
|
if( remainder == null ) break;
|
||||||
remainder = inventory.insertItem( slot, remainder, false );
|
remainder = inventory.insertItem( slot, remainder, false );
|
||||||
}
|
}
|
||||||
return remainder;
|
return areItemsEqual( stack, remainder ) ? stack : remainder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ItemStack takeItems( int count, IItemHandler inventory, int[] slots )
|
private static ItemStack takeItems( int count, IItemHandler inventory, int[] slots )
|
||||||
|
@ -44,6 +44,7 @@ gui.computercraft:wired_modem.peripheral_disconnected=Peripheral "%s" disconnect
|
|||||||
|
|
||||||
gui.computercraft:config.http_enable=Enable HTTP API
|
gui.computercraft:config.http_enable=Enable HTTP API
|
||||||
gui.computercraft:config.http_whitelist=HTTP whitelist
|
gui.computercraft:config.http_whitelist=HTTP whitelist
|
||||||
|
gui.computercraft:config.http_blacklist=HTTP blacklist
|
||||||
gui.computercraft:config.disable_lua51_features=Disable Lua 5.1 features
|
gui.computercraft:config.disable_lua51_features=Disable Lua 5.1 features
|
||||||
gui.computercraft:config.default_computer_settings=Default Computer settings
|
gui.computercraft:config.default_computer_settings=Default Computer settings
|
||||||
gui.computercraft:config.log_peripheral_errors=Log peripheral errors
|
gui.computercraft:config.log_peripheral_errors=Log peripheral errors
|
||||||
|
@ -184,6 +184,9 @@ end
|
|||||||
|
|
||||||
-- Install globals
|
-- Install globals
|
||||||
function sleep( nTime )
|
function sleep( nTime )
|
||||||
|
if nTime ~= nil and type( nTime ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( nTime ) .. ")", 2 )
|
||||||
|
end
|
||||||
local timer = os.startTimer( nTime or 0 )
|
local timer = os.startTimer( nTime or 0 )
|
||||||
repeat
|
repeat
|
||||||
local sEvent, param = os.pullEvent( "timer" )
|
local sEvent, param = os.pullEvent( "timer" )
|
||||||
@ -191,6 +194,10 @@ function sleep( nTime )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function write( sText )
|
function write( sText )
|
||||||
|
if sText ~= nil and type( sText ) ~= "string" and type( sText ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( sText ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
|
||||||
local w,h = term.getSize()
|
local w,h = term.getSize()
|
||||||
local x,y = term.getCursorPos()
|
local x,y = term.getCursorPos()
|
||||||
|
|
||||||
@ -276,12 +283,29 @@ function printError( ... )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function read( _sReplaceChar, _tHistory, _fnComplete )
|
function read( _sReplaceChar, _tHistory, _fnComplete, _sDefault )
|
||||||
|
if _sReplaceChar ~= nil and type( _sReplaceChar ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sReplaceChar ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _tHistory ~= nil and type( _tHistory ) ~= "table" then
|
||||||
|
error( "bad argument #2 (expected table, got " .. type( _tHistory ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _fnComplete ~= nil and type( _fnComplete ) ~= "function" then
|
||||||
|
error( "bad argument #3 (expected function, got " .. type( _fnComplete ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _sDefault ~= nil and type( _sDefault ) ~= "string" then
|
||||||
|
error( "bad argument #4 (expected string, got " .. type( _sDefault ) .. ")", 2 )
|
||||||
|
end
|
||||||
term.setCursorBlink( true )
|
term.setCursorBlink( true )
|
||||||
|
|
||||||
local sLine = ""
|
local sLine
|
||||||
|
if type( _sDefault ) == "string" then
|
||||||
|
sLine = _sDefault
|
||||||
|
else
|
||||||
|
sLine = ""
|
||||||
|
end
|
||||||
local nHistoryPos
|
local nHistoryPos
|
||||||
local nPos = 0
|
local nPos = #sLine
|
||||||
if _sReplaceChar then
|
if _sReplaceChar then
|
||||||
_sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
|
_sReplaceChar = string.sub( _sReplaceChar, 1, 1 )
|
||||||
end
|
end
|
||||||
@ -530,6 +554,12 @@ function read( _sReplaceChar, _tHistory, _fnComplete )
|
|||||||
end
|
end
|
||||||
|
|
||||||
loadfile = function( _sFile, _tEnv )
|
loadfile = function( _sFile, _tEnv )
|
||||||
|
if type( _sFile ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sFile ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _tEnv ~= nil and type( _tEnv ) ~= "table" then
|
||||||
|
error( "bad argument #2 (expected table, got " .. type( _tEnv ) .. ")", 2 )
|
||||||
|
end
|
||||||
local file = fs.open( _sFile, "r" )
|
local file = fs.open( _sFile, "r" )
|
||||||
if file then
|
if file then
|
||||||
local func, err = load( file.readAll(), fs.getName( _sFile ), "t", _tEnv )
|
local func, err = load( file.readAll(), fs.getName( _sFile ), "t", _tEnv )
|
||||||
@ -540,6 +570,9 @@ loadfile = function( _sFile, _tEnv )
|
|||||||
end
|
end
|
||||||
|
|
||||||
dofile = function( _sFile )
|
dofile = function( _sFile )
|
||||||
|
if type( _sFile ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sFile ) .. ")", 2 )
|
||||||
|
end
|
||||||
local fnFile, e = loadfile( _sFile, _G )
|
local fnFile, e = loadfile( _sFile, _G )
|
||||||
if fnFile then
|
if fnFile then
|
||||||
return fnFile()
|
return fnFile()
|
||||||
@ -550,6 +583,12 @@ end
|
|||||||
|
|
||||||
-- Install the rest of the OS api
|
-- Install the rest of the OS api
|
||||||
function os.run( _tEnv, _sPath, ... )
|
function os.run( _tEnv, _sPath, ... )
|
||||||
|
if type( _tEnv ) ~= "table" then
|
||||||
|
error( "bad argument #1 (expected table, got " .. type( _tEnv ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( _sPath ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( _sPath ) .. ")", 2 )
|
||||||
|
end
|
||||||
local tArgs = table.pack( ... )
|
local tArgs = table.pack( ... )
|
||||||
local tEnv = _tEnv
|
local tEnv = _tEnv
|
||||||
setmetatable( tEnv, { __index = _G } )
|
setmetatable( tEnv, { __index = _G } )
|
||||||
@ -574,6 +613,9 @@ end
|
|||||||
|
|
||||||
local tAPIsLoading = {}
|
local tAPIsLoading = {}
|
||||||
function os.loadAPI( _sPath )
|
function os.loadAPI( _sPath )
|
||||||
|
if type( _sPath ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 )
|
||||||
|
end
|
||||||
local sName = fs.getName( _sPath )
|
local sName = fs.getName( _sPath )
|
||||||
if sName:sub(-4) == ".lua" then
|
if sName:sub(-4) == ".lua" then
|
||||||
sName = sName:sub(1,-5)
|
sName = sName:sub(1,-5)
|
||||||
@ -613,6 +655,9 @@ function os.loadAPI( _sPath )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function os.unloadAPI( _sName )
|
function os.unloadAPI( _sName )
|
||||||
|
if type( _sName ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sName ) .. ")", 2 )
|
||||||
|
end
|
||||||
if _sName ~= "_G" and type(_G[_sName]) == "table" then
|
if _sName ~= "_G" and type(_G[_sName]) == "table" then
|
||||||
_G[_sName] = nil
|
_G[_sName] = nil
|
||||||
end
|
end
|
||||||
@ -658,25 +703,73 @@ if http then
|
|||||||
end
|
end
|
||||||
|
|
||||||
http.get = function( _url, _headers, _binary)
|
http.get = function( _url, _headers, _binary)
|
||||||
|
if type( _url ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _headers ~= nil and type( _headers ) ~= "table" then
|
||||||
|
error( "bad argument #2 (expected table, got " .. type( _headers ) .. ")", 2 )
|
||||||
|
end
|
||||||
return wrapRequest( _url, nil, _headers, _binary)
|
return wrapRequest( _url, nil, _headers, _binary)
|
||||||
end
|
end
|
||||||
|
|
||||||
http.post = function( _url, _post, _headers, _binary)
|
http.post = function( _url, _post, _headers, _binary)
|
||||||
|
if type( _url ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( _post ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( _post ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _headers ~= nil and type( _headers ) ~= "table" then
|
||||||
|
error( "bad argument #3 (expected table, got " .. type( _headers ) .. ")", 2 )
|
||||||
|
end
|
||||||
return wrapRequest( _url, _post or "", _headers, _binary)
|
return wrapRequest( _url, _post or "", _headers, _binary)
|
||||||
end
|
end
|
||||||
|
|
||||||
http.request = function( _url, _post, _headers, _binary )
|
http.request = function( _url, _post, _headers, _binary )
|
||||||
|
if type( _url ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _url ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _post ~= nil and type( _post ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( _post ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _headers ~= nil and type( _headers ) ~= "table" then
|
||||||
|
error( "bad argument #3 (expected table, got " .. type( _headers ) .. ")", 2 )
|
||||||
|
end
|
||||||
local ok, err = nativeHTTPRequest( _url, _post, _headers, _binary )
|
local ok, err = nativeHTTPRequest( _url, _post, _headers, _binary )
|
||||||
if not ok then
|
if not ok then
|
||||||
os.queueEvent( "http_failure", _url, err )
|
os.queueEvent( "http_failure", _url, err )
|
||||||
end
|
end
|
||||||
return ok, err
|
return ok, err
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local nativeCheckURL = http.checkURL
|
||||||
|
http.checkURLAsync = nativeCheckURL
|
||||||
|
http.checkURL = function( _url )
|
||||||
|
local ok, err = nativeCheckURL( _url )
|
||||||
|
if not ok then return ok, err end
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local event, url, ok, err = os.pullEvent( "http_check" )
|
||||||
|
if url == _url then return ok, err end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Install the lua part of the FS api
|
-- Install the lua part of the FS api
|
||||||
local tEmpty = {}
|
local tEmpty = {}
|
||||||
function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs )
|
function fs.complete( sPath, sLocation, bIncludeFiles, bIncludeDirs )
|
||||||
|
if type( sPath ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( sLocation ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( sLocation ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if bIncludeFiles ~= nil and type( bIncludeFiles ) ~= "boolean" then
|
||||||
|
error( "bad argument #3 (expected boolean, got " .. type( bIncludeFiles ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if bIncludeDirs ~= nil and type( bIncludeDirs ) ~= "boolean" then
|
||||||
|
error( "bad argument #4 (expected boolean, got " .. type( bIncludeDirs ) .. ")", 2 )
|
||||||
|
end
|
||||||
bIncludeFiles = (bIncludeFiles ~= false)
|
bIncludeFiles = (bIncludeFiles ~= false)
|
||||||
bIncludeDirs = (bIncludeDirs ~= false)
|
bIncludeDirs = (bIncludeDirs ~= false)
|
||||||
local sDir = sLocation
|
local sDir = sLocation
|
||||||
@ -747,7 +840,7 @@ for n,sFile in ipairs( tApis ) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if turtle then
|
if turtle and fs.isDir( "rom/apis/turtle" ) then
|
||||||
-- Load turtle APIs
|
-- Load turtle APIs
|
||||||
local tApis = fs.list( "rom/apis/turtle" )
|
local tApis = fs.list( "rom/apis/turtle" )
|
||||||
for n,sFile in ipairs( tApis ) do
|
for n,sFile in ipairs( tApis ) do
|
||||||
|
@ -19,32 +19,51 @@ black = 32768
|
|||||||
function combine( ... )
|
function combine( ... )
|
||||||
local r = 0
|
local r = 0
|
||||||
for n,c in ipairs( { ... } ) do
|
for n,c in ipairs( { ... } ) do
|
||||||
|
if type( c ) ~= "number" then
|
||||||
|
error( "bad argument #"..n.." (expected number, got " .. type( c ) .. ")", 2 )
|
||||||
|
end
|
||||||
r = bit32.bor(r,c)
|
r = bit32.bor(r,c)
|
||||||
end
|
end
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
function subtract( colors, ... )
|
function subtract( colors, ... )
|
||||||
|
if type( colors ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( colors ) .. ")", 2 )
|
||||||
|
end
|
||||||
local r = colors
|
local r = colors
|
||||||
for n,c in ipairs( { ... } ) do
|
for n,c in ipairs( { ... } ) do
|
||||||
|
if type( c ) ~= "number" then
|
||||||
|
error( "bad argument #"..tostring( n+1 ).." (expected number, got " .. type( c ) .. ")", 2 )
|
||||||
|
end
|
||||||
r = bit32.band(r, bit32.bnot(c))
|
r = bit32.band(r, bit32.bnot(c))
|
||||||
end
|
end
|
||||||
return r
|
return r
|
||||||
end
|
end
|
||||||
|
|
||||||
function test( colors, color )
|
function test( colors, color )
|
||||||
|
if type( colors ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( colors ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( color ) ~= "number" then
|
||||||
|
error( "bad argument #2 (expected number, got " .. type( color ) .. ")", 2 )
|
||||||
|
end
|
||||||
return ((bit32.band(colors, color)) == color)
|
return ((bit32.band(colors, color)) == color)
|
||||||
end
|
end
|
||||||
|
|
||||||
function rgb8( r, g, b )
|
function rgb8( r, g, b )
|
||||||
if type(r) == "number" and g == nil and b == nil then
|
if type( r ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( r ) .. ")", 2 )
|
||||||
|
elseif type(r) == "number" and g == nil and b == nil then
|
||||||
return bit32.band( bit32.rshift( r, 16 ), 0xFF ) / 255, bit32.band( bit32.rshift( r, 8 ), 0xFF ) / 255, bit32.band( r, 0xFF ) / 255
|
return bit32.band( bit32.rshift( r, 16 ), 0xFF ) / 255, bit32.band( bit32.rshift( r, 8 ), 0xFF ) / 255, bit32.band( r, 0xFF ) / 255
|
||||||
elseif type(r) == "number" and type(g) == "number" and type(b) == "number" then
|
elseif type(r) == "number" and type(g) == "number" and type(b) == "number" then
|
||||||
return
|
return
|
||||||
bit32.lshift( bit32.band(r * 255, 0xFF), 16 ) +
|
bit32.lshift( bit32.band(r * 255, 0xFF), 16 ) +
|
||||||
bit32.lshift( bit32.band(g * 255, 0xFF), 8 ) +
|
bit32.lshift( bit32.band(g * 255, 0xFF), 8 ) +
|
||||||
bit32.band(b * 255, 0xFF)
|
bit32.band(b * 255, 0xFF)
|
||||||
else
|
elseif type( g ) ~= "number" then
|
||||||
error( "Expected 1 or 3 numbers" )
|
error( "bad argument #2 (expected number, got " .. type( g ) .. ")", 2 )
|
||||||
|
elseif type( b ) ~= "number" then
|
||||||
|
error( "bad argument #3 (expected number, got " .. type( b ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
|
|
||||||
local function isDrive( name )
|
local function isDrive( name )
|
||||||
|
if type( name ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 3 )
|
||||||
|
end
|
||||||
return peripheral.getType( name ) == "drive"
|
return peripheral.getType( name ) == "drive"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -56,6 +56,12 @@ local function narrow( p1, p2, fix )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function locate( _nTimeout, _bDebug )
|
function locate( _nTimeout, _bDebug )
|
||||||
|
if _nTimeout ~= nil and type( _nTimeout ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( _nTimeout ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if _bDebug ~= nil and type( _bDebug ) ~= "boolean" then
|
||||||
|
error( "bad argument #2 (expected boolean, got " .. type( _bDebug) .. ")", 2 )
|
||||||
|
end
|
||||||
-- Let command computers use their magic fourth-wall-breaking special abilities
|
-- Let command computers use their magic fourth-wall-breaking special abilities
|
||||||
if commands then
|
if commands then
|
||||||
return commands.getBlockPosition()
|
return commands.getBlockPosition()
|
||||||
|
@ -6,10 +6,16 @@ function path()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function setPath( _sPath )
|
function setPath( _sPath )
|
||||||
|
if type( _sPath ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 )
|
||||||
|
end
|
||||||
sPath = _sPath
|
sPath = _sPath
|
||||||
end
|
end
|
||||||
|
|
||||||
function lookup( _sTopic )
|
function lookup( _sTopic )
|
||||||
|
if type( _sTopic ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sTopic ) .. ")", 2 )
|
||||||
|
end
|
||||||
-- Look on the path variable
|
-- Look on the path variable
|
||||||
for sPath in string.gmatch(sPath, "[^:]+") do
|
for sPath in string.gmatch(sPath, "[^:]+") do
|
||||||
sPath = fs.combine( sPath, _sTopic )
|
sPath = fs.combine( sPath, _sTopic )
|
||||||
@ -57,6 +63,9 @@ function topics()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function completeTopic( sText )
|
function completeTopic( sText )
|
||||||
|
if type( sText ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( sText ) .. ")", 2 )
|
||||||
|
end
|
||||||
local tTopics = topics()
|
local tTopics = topics()
|
||||||
local tResults = {}
|
local tResults = {}
|
||||||
for n=1,#tTopics do
|
for n=1,#tTopics do
|
||||||
|
@ -55,5 +55,8 @@ end
|
|||||||
keys["return"] = keys.enter
|
keys["return"] = keys.enter
|
||||||
|
|
||||||
function getName( _nKey )
|
function getName( _nKey )
|
||||||
|
if type( _nKey ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( _nKey ) .. ")", 2 )
|
||||||
|
end
|
||||||
return tKeys[ _nKey ]
|
return tKeys[ _nKey ]
|
||||||
end
|
end
|
||||||
|
@ -11,7 +11,7 @@ end
|
|||||||
|
|
||||||
function loadImage( sPath )
|
function loadImage( sPath )
|
||||||
if type( sPath ) ~= "string" then
|
if type( sPath ) ~= "string" then
|
||||||
error( "Expected path", 2 )
|
error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
|
|
||||||
local tImage = {}
|
local tImage = {}
|
||||||
@ -33,9 +33,9 @@ function loadImage( sPath )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function drawPixel( xPos, yPos, nColour )
|
function drawPixel( xPos, yPos, nColour )
|
||||||
if type( xPos ) ~= "number" or type( yPos ) ~= "number" or (nColour ~= nil and type( nColour ) ~= "number") then
|
if type( xPos ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( xPos ) .. ")", 2 ) end
|
||||||
error( "Expected x, y, colour", 2 )
|
if type( yPos ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( yPos ) .. ")", 2 ) end
|
||||||
end
|
if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( nColour ) .. ")", 2 ) end
|
||||||
if nColour then
|
if nColour then
|
||||||
term.setBackgroundColor( nColour )
|
term.setBackgroundColor( nColour )
|
||||||
end
|
end
|
||||||
@ -43,11 +43,11 @@ function drawPixel( xPos, yPos, nColour )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function drawLine( startX, startY, endX, endY, nColour )
|
function drawLine( startX, startY, endX, endY, nColour )
|
||||||
if type( startX ) ~= "number" or type( startX ) ~= "number" or
|
if type( startX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( startX ) .. ")", 2 ) end
|
||||||
type( endX ) ~= "number" or type( endY ) ~= "number" or
|
if type( startY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( startY ) .. ")", 2 ) end
|
||||||
(nColour ~= nil and type( nColour ) ~= "number") then
|
if type( endX ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( endX ) .. ")", 2 ) end
|
||||||
error( "Expected startX, startY, endX, endY, colour", 2 )
|
if type( endY ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( endY ) .. ")", 2 ) end
|
||||||
end
|
if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nColour ) .. ")", 2 ) end
|
||||||
|
|
||||||
startX = math.floor(startX)
|
startX = math.floor(startX)
|
||||||
startY = math.floor(startY)
|
startY = math.floor(startY)
|
||||||
@ -103,11 +103,11 @@ function drawLine( startX, startY, endX, endY, nColour )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function drawBox( startX, startY, endX, endY, nColour )
|
function drawBox( startX, startY, endX, endY, nColour )
|
||||||
if type( startX ) ~= "number" or type( startX ) ~= "number" or
|
if type( startX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( startX ) .. ")", 2 ) end
|
||||||
type( endX ) ~= "number" or type( endY ) ~= "number" or
|
if type( startY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( startY ) .. ")", 2 ) end
|
||||||
(nColour ~= nil and type( nColour ) ~= "number") then
|
if type( endX ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( endX ) .. ")", 2 ) end
|
||||||
error( "Expected startX, startY, endX, endY, colour", 2 )
|
if type( endY ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( endY ) .. ")", 2 ) end
|
||||||
end
|
if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nColour ) .. ")", 2 ) end
|
||||||
|
|
||||||
startX = math.floor(startX)
|
startX = math.floor(startX)
|
||||||
startY = math.floor(startY)
|
startY = math.floor(startY)
|
||||||
@ -147,11 +147,11 @@ function drawBox( startX, startY, endX, endY, nColour )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function drawFilledBox( startX, startY, endX, endY, nColour )
|
function drawFilledBox( startX, startY, endX, endY, nColour )
|
||||||
if type( startX ) ~= "number" or type( startX ) ~= "number" or
|
if type( startX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( startX ) .. ")", 2 ) end
|
||||||
type( endX ) ~= "number" or type( endY ) ~= "number" or
|
if type( startY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( startY ) .. ")", 2 ) end
|
||||||
(nColour ~= nil and type( nColour ) ~= "number") then
|
if type( endX ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( endX ) .. ")", 2 ) end
|
||||||
error( "Expected startX, startY, endX, endY, colour", 2 )
|
if type( endY ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( endY ) .. ")", 2 ) end
|
||||||
end
|
if nColour ~= nil and type( nColour ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nColour ) .. ")", 2 ) end
|
||||||
|
|
||||||
startX = math.floor(startX)
|
startX = math.floor(startX)
|
||||||
startY = math.floor(startY)
|
startY = math.floor(startY)
|
||||||
@ -185,9 +185,9 @@ function drawFilledBox( startX, startY, endX, endY, nColour )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function drawImage( tImage, xPos, yPos )
|
function drawImage( tImage, xPos, yPos )
|
||||||
if type( tImage ) ~= "table" or type( xPos ) ~= "number" or type( yPos ) ~= "number" then
|
if type( tImage ) ~= "table" then error( "bad argument #1 (expected table, got " .. type( tImage ) .. ")", 2 ) end
|
||||||
error( "Expected image, x, y", 2 )
|
if type( xPos ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( xPos ) .. ")", 2 ) end
|
||||||
end
|
if type( yPos ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( yPos ) .. ")", 2 ) end
|
||||||
for y=1,#tImage do
|
for y=1,#tImage do
|
||||||
local tLine = tImage[y]
|
local tLine = tImage[y]
|
||||||
for x=1,#tLine do
|
for x=1,#tLine do
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
|
|
||||||
local function create( first, ... )
|
local function create( ... )
|
||||||
if first ~= nil then
|
local tFns = table.pack(...)
|
||||||
if type( first ) ~= "function" then
|
local tCos = {}
|
||||||
error( "Expected function, got "..type( first ), 3 )
|
for i = 1, tFns.n, 1 do
|
||||||
end
|
local fn = tFns[i]
|
||||||
return coroutine.create(first), create( ... )
|
if type( fn ) ~= "function" then
|
||||||
|
error( "bad argument #" .. i .. " (expected function, got " .. type( fn ) .. ")", 3 )
|
||||||
|
end
|
||||||
|
|
||||||
|
tCos[i] = coroutine.create(fn)
|
||||||
end
|
end
|
||||||
return nil
|
|
||||||
|
return tCos
|
||||||
end
|
end
|
||||||
|
|
||||||
local function runUntilLimit( _routines, _limit )
|
local function runUntilLimit( _routines, _limit )
|
||||||
@ -51,11 +56,11 @@ local function runUntilLimit( _routines, _limit )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function waitForAny( ... )
|
function waitForAny( ... )
|
||||||
local routines = { create( ... ) }
|
local routines = create( ... )
|
||||||
return runUntilLimit( routines, #routines - 1 )
|
return runUntilLimit( routines, #routines - 1 )
|
||||||
end
|
end
|
||||||
|
|
||||||
function waitForAll( ... )
|
function waitForAll( ... )
|
||||||
local routines = { create( ... ) }
|
local routines = create( ... )
|
||||||
runUntilLimit( routines, 0 )
|
runUntilLimit( routines, 0 )
|
||||||
end
|
end
|
||||||
|
@ -18,7 +18,7 @@ end
|
|||||||
|
|
||||||
function isPresent( _sSide )
|
function isPresent( _sSide )
|
||||||
if type( _sSide ) ~= "string" then
|
if type( _sSide ) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
if native.isPresent( _sSide ) then
|
if native.isPresent( _sSide ) then
|
||||||
return true
|
return true
|
||||||
@ -35,7 +35,7 @@ end
|
|||||||
|
|
||||||
function getType( _sSide )
|
function getType( _sSide )
|
||||||
if type( _sSide ) ~= "string" then
|
if type( _sSide ) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
if native.isPresent( _sSide ) then
|
if native.isPresent( _sSide ) then
|
||||||
return native.getType( _sSide )
|
return native.getType( _sSide )
|
||||||
@ -52,7 +52,7 @@ end
|
|||||||
|
|
||||||
function getMethods( _sSide )
|
function getMethods( _sSide )
|
||||||
if type( _sSide ) ~= "string" then
|
if type( _sSide ) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
if native.isPresent( _sSide ) then
|
if native.isPresent( _sSide ) then
|
||||||
return native.getMethods( _sSide )
|
return native.getMethods( _sSide )
|
||||||
@ -68,8 +68,11 @@ function getMethods( _sSide )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function call( _sSide, _sMethod, ... )
|
function call( _sSide, _sMethod, ... )
|
||||||
if type( _sSide ) ~= "string" or type( _sMethod ) ~= "string" then
|
if type( _sSide ) ~= "string" then
|
||||||
error( "Expected string, string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( _sSide ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( _sMethod ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
if native.isPresent( _sSide ) then
|
if native.isPresent( _sSide ) then
|
||||||
return native.call( _sSide, _sMethod, ... )
|
return native.call( _sSide, _sMethod, ... )
|
||||||
@ -85,8 +88,8 @@ function call( _sSide, _sMethod, ... )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function wrap( _sSide )
|
function wrap( _sSide )
|
||||||
if type( _sSide ) ~= "string" then
|
if type( _sSide ) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( _sSide ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
if peripheral.isPresent( _sSide ) then
|
if peripheral.isPresent( _sSide ) then
|
||||||
local tMethods = peripheral.getMethods( _sSide )
|
local tMethods = peripheral.getMethods( _sSide )
|
||||||
@ -102,8 +105,11 @@ function wrap( _sSide )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function find( sType, fnFilter )
|
function find( sType, fnFilter )
|
||||||
if type( sType ) ~= "string" or (fnFilter ~= nil and type( fnFilter ) ~= "function") then
|
if type( sType ) ~= "string" then
|
||||||
error( "Expected string, [function]", 2 )
|
error( "bad argument #1 (expected string, got " .. type( sType ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if fnFilter ~= nil and type( fnFilter ) ~= "function" then
|
||||||
|
error( "bad argument #2 (expected function, got " .. type( fnFilter ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
local tResults = {}
|
local tResults = {}
|
||||||
for n,sName in ipairs( peripheral.getNames() ) do
|
for n,sName in ipairs( peripheral.getNames() ) do
|
||||||
|
@ -7,14 +7,14 @@ local tReceivedMessageTimeouts = {}
|
|||||||
local tHostnames = {}
|
local tHostnames = {}
|
||||||
|
|
||||||
function open( sModem )
|
function open( sModem )
|
||||||
if type( sModem ) ~= "string" then
|
if type( sModem ) ~= "string" then
|
||||||
error( "expected string", 2 )
|
error( "expected string", 2 )
|
||||||
end
|
end
|
||||||
if peripheral.getType( sModem ) ~= "modem" then
|
if peripheral.getType( sModem ) ~= "modem" then
|
||||||
error( "No such modem: "..sModem, 2 )
|
error( "No such modem: "..sModem, 2 )
|
||||||
end
|
end
|
||||||
peripheral.call( sModem, "open", os.getComputerID() )
|
peripheral.call( sModem, "open", os.getComputerID() )
|
||||||
peripheral.call( sModem, "open", CHANNEL_BROADCAST )
|
peripheral.call( sModem, "open", CHANNEL_BROADCAST )
|
||||||
end
|
end
|
||||||
|
|
||||||
function close( sModem )
|
function close( sModem )
|
||||||
@ -55,7 +55,7 @@ function isOpen( sModem )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function send( nRecipient, message, sProtocol )
|
function send( nRecipient, message, sProtocol )
|
||||||
@ -93,7 +93,7 @@ function send( nRecipient, message, sProtocol )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function broadcast( message, sProtocol )
|
function broadcast( message, sProtocol )
|
||||||
send( CHANNEL_BROADCAST, message, sProtocol )
|
send( CHANNEL_BROADCAST, message, sProtocol )
|
||||||
end
|
end
|
||||||
|
|
||||||
function receive( sProtocolFilter, nTimeout )
|
function receive( sProtocolFilter, nTimeout )
|
||||||
@ -103,31 +103,31 @@ function receive( sProtocolFilter, nTimeout )
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- Start the timer
|
-- Start the timer
|
||||||
local timer = nil
|
local timer = nil
|
||||||
local sFilter = nil
|
local sFilter = nil
|
||||||
if nTimeout then
|
if nTimeout then
|
||||||
timer = os.startTimer( nTimeout )
|
timer = os.startTimer( nTimeout )
|
||||||
sFilter = nil
|
sFilter = nil
|
||||||
else
|
else
|
||||||
sFilter = "rednet_message"
|
sFilter = "rednet_message"
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Wait for events
|
-- Wait for events
|
||||||
while true do
|
while true do
|
||||||
local sEvent, p1, p2, p3 = os.pullEvent( sFilter )
|
local sEvent, p1, p2, p3 = os.pullEvent( sFilter )
|
||||||
if sEvent == "rednet_message" then
|
if sEvent == "rednet_message" then
|
||||||
-- Return the first matching rednet_message
|
-- Return the first matching rednet_message
|
||||||
local nSenderID, message, sProtocol = p1, p2, p3
|
local nSenderID, message, sProtocol = p1, p2, p3
|
||||||
if sProtocolFilter == nil or sProtocol == sProtocolFilter then
|
if sProtocolFilter == nil or sProtocol == sProtocolFilter then
|
||||||
return nSenderID, message, sProtocol
|
return nSenderID, message, sProtocol
|
||||||
end
|
end
|
||||||
elseif sEvent == "timer" then
|
elseif sEvent == "timer" then
|
||||||
-- Return nil if we timeout
|
-- Return nil if we timeout
|
||||||
if p1 == timer then
|
if p1 == timer then
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function host( sProtocol, sHostname )
|
function host( sProtocol, sHostname )
|
||||||
@ -219,41 +219,41 @@ end
|
|||||||
|
|
||||||
local bRunning = false
|
local bRunning = false
|
||||||
function run()
|
function run()
|
||||||
if bRunning then
|
if bRunning then
|
||||||
error( "rednet is already running", 2 )
|
error( "rednet is already running", 2 )
|
||||||
end
|
end
|
||||||
bRunning = true
|
bRunning = true
|
||||||
|
|
||||||
while bRunning do
|
while bRunning do
|
||||||
local sEvent, p1, p2, p3, p4 = os.pullEventRaw()
|
local sEvent, p1, p2, p3, p4 = os.pullEventRaw()
|
||||||
if sEvent == "modem_message" then
|
if sEvent == "modem_message" then
|
||||||
-- Got a modem message, process it and add it to the rednet event queue
|
-- Got a modem message, process it and add it to the rednet event queue
|
||||||
local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4
|
local sModem, nChannel, nReplyChannel, tMessage = p1, p2, p3, p4
|
||||||
if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then
|
if isOpen( sModem ) and ( nChannel == os.getComputerID() or nChannel == CHANNEL_BROADCAST ) then
|
||||||
if type( tMessage ) == "table" and tMessage.nMessageID then
|
if type( tMessage ) == "table" and tMessage.nMessageID then
|
||||||
if not tReceivedMessages[ tMessage.nMessageID ] then
|
if not tReceivedMessages[ tMessage.nMessageID ] then
|
||||||
tReceivedMessages[ tMessage.nMessageID ] = true
|
tReceivedMessages[ tMessage.nMessageID ] = true
|
||||||
tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = nMessageID
|
tReceivedMessageTimeouts[ os.startTimer( 30 ) ] = tMessage.nMessageID
|
||||||
os.queueEvent( "rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol )
|
os.queueEvent( "rednet_message", nReplyChannel, tMessage.message, tMessage.sProtocol )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif sEvent == "rednet_message" then
|
elseif sEvent == "rednet_message" then
|
||||||
-- Got a rednet message (queued from above), respond to dns lookup
|
-- Got a rednet message (queued from above), respond to dns lookup
|
||||||
local nSenderID, tMessage, sProtocol = p1, p2, p3
|
local nSenderID, tMessage, sProtocol = p1, p2, p3
|
||||||
if sProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup" then
|
if sProtocol == "dns" and type(tMessage) == "table" and tMessage.sType == "lookup" then
|
||||||
local sHostname = tHostnames[ tMessage.sProtocol ]
|
local sHostname = tHostnames[ tMessage.sProtocol ]
|
||||||
if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then
|
if sHostname ~= nil and (tMessage.sHostname == nil or tMessage.sHostname == sHostname) then
|
||||||
rednet.send( nSenderID, {
|
rednet.send( nSenderID, {
|
||||||
sType = "lookup response",
|
sType = "lookup response",
|
||||||
sHostname = sHostname,
|
sHostname = sHostname,
|
||||||
sProtocol = tMessage.sProtocol,
|
sProtocol = tMessage.sProtocol,
|
||||||
}, "dns" )
|
}, "dns" )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif sEvent == "timer" then
|
elseif sEvent == "timer" then
|
||||||
-- Got a timer event, use it to clear the event queue
|
-- Got a timer event, use it to clear the event queue
|
||||||
local nTimer = p1
|
local nTimer = p1
|
||||||
local nMessage = tReceivedMessageTimeouts[ nTimer ]
|
local nMessage = tReceivedMessageTimeouts[ nTimer ]
|
||||||
@ -261,6 +261,6 @@ function run()
|
|||||||
tReceivedMessageTimeouts[ nTimer ] = nil
|
tReceivedMessageTimeouts[ nTimer ] = nil
|
||||||
tReceivedMessages[ nMessage ] = nil
|
tReceivedMessages[ nMessage ] = nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -2,11 +2,13 @@
|
|||||||
local tSettings = {}
|
local tSettings = {}
|
||||||
|
|
||||||
function set( sName, value )
|
function set( sName, value )
|
||||||
if type(sName) ~= "string" or
|
if type( sName ) ~= "string" then error( "bad argument #1 (expected string, got " .. type( sName ) .. ")", 2 ) end
|
||||||
(type(value) ~= "string" and type(value) ~= "number" and type(value) ~= "boolean" and type(value) ~= "table") then
|
|
||||||
error( "Expected string, value", 2 )
|
local sValueTy = type(value)
|
||||||
|
if sValueTy ~= "number" and sValueTy ~= "string" and sValueTy ~= "boolean" and sValueTy ~= "table" then
|
||||||
|
error( "bad argument #2 (expected value, got " .. sValueTy .. ")", 2 )
|
||||||
end
|
end
|
||||||
if type(value) == "table" then
|
if sValueTy == "table" then
|
||||||
-- Ensure value is serializeable
|
-- Ensure value is serializeable
|
||||||
value = textutils.unserialize( textutils.serialize(value) )
|
value = textutils.unserialize( textutils.serialize(value) )
|
||||||
end
|
end
|
||||||
@ -28,7 +30,7 @@ end
|
|||||||
|
|
||||||
function get( sName, default )
|
function get( sName, default )
|
||||||
if type(sName) ~= "string" then
|
if type(sName) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( sName ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
local result = tSettings[ sName ]
|
local result = tSettings[ sName ]
|
||||||
if result ~= nil then
|
if result ~= nil then
|
||||||
@ -40,7 +42,7 @@ end
|
|||||||
|
|
||||||
function unset( sName )
|
function unset( sName )
|
||||||
if type(sName) ~= "string" then
|
if type(sName) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( sName ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
tSettings[ sName ] = nil
|
tSettings[ sName ] = nil
|
||||||
end
|
end
|
||||||
@ -54,12 +56,13 @@ function getNames()
|
|||||||
for k,v in pairs( tSettings ) do
|
for k,v in pairs( tSettings ) do
|
||||||
result[ #result + 1 ] = k
|
result[ #result + 1 ] = k
|
||||||
end
|
end
|
||||||
|
table.sort(result)
|
||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
function load( sPath )
|
function load( sPath )
|
||||||
if type(sPath) ~= "string" then
|
if type(sPath) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
local file = fs.open( sPath, "r" )
|
local file = fs.open( sPath, "r" )
|
||||||
if not file then
|
if not file then
|
||||||
@ -86,7 +89,7 @@ end
|
|||||||
|
|
||||||
function save( sPath )
|
function save( sPath )
|
||||||
if type(sPath) ~= "string" then
|
if type(sPath) ~= "string" then
|
||||||
error( "Expected string", 2 )
|
error( "bad argument #1 (expected string, got " .. type( sPath ) .. ")", 2 )
|
||||||
end
|
end
|
||||||
local file = fs.open( sPath, "w" )
|
local file = fs.open( sPath, "w" )
|
||||||
if not file then
|
if not file then
|
||||||
|
@ -7,7 +7,7 @@ function slowWrite( sText, nRate )
|
|||||||
local nSleep = 1 / nRate
|
local nSleep = 1 / nRate
|
||||||
|
|
||||||
sText = tostring( sText )
|
sText = tostring( sText )
|
||||||
local x,y = term.getCursorPos(x,y)
|
local x,y = term.getCursorPos()
|
||||||
local len = string.len( sText )
|
local len = string.len( sText )
|
||||||
|
|
||||||
for n=1,len do
|
for n=1,len do
|
||||||
@ -25,6 +25,12 @@ function slowPrint( sText, nRate )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function formatTime( nTime, bTwentyFourHour )
|
function formatTime( nTime, bTwentyFourHour )
|
||||||
|
if type( nTime ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( nTime ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if bTwentyFourHour ~= nil and type( bTwentyFourHour ) ~= "boolean" then
|
||||||
|
error( "bad argument #2 (expected boolean, got " .. type( bTwentyFourHour ) .. ")", 2 )
|
||||||
|
end
|
||||||
local sTOD = nil
|
local sTOD = nil
|
||||||
if not bTwentyFourHour then
|
if not bTwentyFourHour then
|
||||||
if nTime >= 12 then
|
if nTime >= 12 then
|
||||||
@ -68,6 +74,9 @@ local function makePagedScroll( _term, _nFreeLines )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function pagedPrint( _sText, _nFreeLines )
|
function pagedPrint( _sText, _nFreeLines )
|
||||||
|
if _nFreeLines ~= nil and type( _nFreeLines ) ~= "number" then
|
||||||
|
error( "bad argument #2 (expected number, got " .. type( _nFreeLines ) .. ")", 2 )
|
||||||
|
end
|
||||||
-- Setup a redirector
|
-- Setup a redirector
|
||||||
local oldTerm = term.current()
|
local oldTerm = term.current()
|
||||||
local newTerm = {}
|
local newTerm = {}
|
||||||
@ -99,6 +108,11 @@ end
|
|||||||
|
|
||||||
local function tabulateCommon( bPaged, ... )
|
local function tabulateCommon( bPaged, ... )
|
||||||
local tAll = { ... }
|
local tAll = { ... }
|
||||||
|
for k,v in ipairs( tAll ) do
|
||||||
|
if type( v ) ~= "number" and type( v ) ~= "table" then
|
||||||
|
error( "bad argument #"..k.." (expected number/table, got " .. type( v ) .. ")", 3 )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local w,h = term.getSize()
|
local w,h = term.getSize()
|
||||||
local nMaxLen = w / 8
|
local nMaxLen = w / 8
|
||||||
@ -301,6 +315,9 @@ function serialize( t )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function unserialize( s )
|
function unserialize( s )
|
||||||
|
if type( s ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( s ) .. ")", 2 )
|
||||||
|
end
|
||||||
local func = load( "return "..s, "unserialize", "t", {} )
|
local func = load( "return "..s, "unserialize", "t", {} )
|
||||||
if func then
|
if func then
|
||||||
local ok, result = pcall( func )
|
local ok, result = pcall( func )
|
||||||
@ -312,11 +329,20 @@ function unserialize( s )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function serializeJSON( t, bNBTStyle )
|
function serializeJSON( t, bNBTStyle )
|
||||||
|
if type( t ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( t ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if bNBTStyle ~= nil and type( bNBTStyle ) ~= "boolean" then
|
||||||
|
error( "bad argument #2 (expected boolean, got " .. type( bNBTStyle ) .. ")", 2 )
|
||||||
|
end
|
||||||
local tTracking = {}
|
local tTracking = {}
|
||||||
return serializeJSONImpl( t, tTracking, bNBTStyle or false )
|
return serializeJSONImpl( t, tTracking, bNBTStyle or false )
|
||||||
end
|
end
|
||||||
|
|
||||||
function urlEncode( str )
|
function urlEncode( str )
|
||||||
|
if type( str ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( str ) .. ")", 2 )
|
||||||
|
end
|
||||||
if str then
|
if str then
|
||||||
str = string.gsub(str, "\n", "\r\n")
|
str = string.gsub(str, "\n", "\r\n")
|
||||||
str = string.gsub(str, "([^A-Za-z0-9 %-%_%.])", function(c)
|
str = string.gsub(str, "([^A-Za-z0-9 %-%_%.])", function(c)
|
||||||
@ -338,6 +364,14 @@ end
|
|||||||
|
|
||||||
local tEmpty = {}
|
local tEmpty = {}
|
||||||
function complete( sSearchText, tSearchTable )
|
function complete( sSearchText, tSearchTable )
|
||||||
|
if type( sSearchText ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( sSearchText ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( tSearchTable ) ~= "table" then
|
||||||
|
error( "bad argument #2 (expected table, got " .. type( tSearchTable ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
|
||||||
|
if g_tLuaKeywords[sSearchText] then return tEmpty end
|
||||||
local nStart = 1
|
local nStart = 1
|
||||||
local nDot = string.find( sSearchText, ".", nStart, true )
|
local nDot = string.find( sSearchText, ".", nStart, true )
|
||||||
local tTable = tSearchTable or _ENV
|
local tTable = tSearchTable or _ENV
|
||||||
@ -352,8 +386,19 @@ function complete( sSearchText, tSearchTable )
|
|||||||
return tEmpty
|
return tEmpty
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local nColon = string.find( sSearchText, ":", nStart, true )
|
||||||
local sPart = string.sub( sSearchText, nStart, nDot )
|
if nColon then
|
||||||
|
local sPart = string.sub( sSearchText, nStart, nColon - 1 )
|
||||||
|
local value = tTable[ sPart ]
|
||||||
|
if type( value ) == "table" then
|
||||||
|
tTable = value
|
||||||
|
nStart = nColon + 1
|
||||||
|
else
|
||||||
|
return tEmpty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local sPart = string.sub( sSearchText, nStart )
|
||||||
local nPartLength = string.len( sPart )
|
local nPartLength = string.len( sPart )
|
||||||
|
|
||||||
local tResults = {}
|
local tResults = {}
|
||||||
|
@ -18,20 +18,18 @@ local tHex = {
|
|||||||
[ colors.black ] = "f",
|
[ colors.black ] = "f",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local type = type
|
||||||
local string_rep = string.rep
|
local string_rep = string.rep
|
||||||
local string_sub = string.sub
|
local string_sub = string.sub
|
||||||
local table_unpack = table.unpack
|
local table_unpack = table.unpack
|
||||||
|
|
||||||
function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
||||||
|
if type( parent ) ~= "table" then error( "bad argument #1 (expected table, got " .. type( parent ) .. ")", 2 ) end
|
||||||
if type( parent ) ~= "table" or
|
if type( nX ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( nX ) .. ")", 2 ) end
|
||||||
type( nX ) ~= "number" or
|
if type( nY ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( nY ) .. ")", 2 ) end
|
||||||
type( nY ) ~= "number" or
|
if type( nWidth ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( nWidth ) .. ")", 2 ) end
|
||||||
type( nWidth ) ~= "number" or
|
if type( nHeight ) ~= "number" then error( "bad argument #5 (expected number, got " .. type( nHeight ) .. ")", 2 ) end
|
||||||
type( nHeight ) ~= "number" or
|
if bStartVisible ~= nil and type( bStartVisible ) ~= "boolean" then error( "bad argument #6 (expected boolean, got " .. type( bStartVisible ) .. ")", 2 ) end
|
||||||
(bStartVisible ~= nil and type( bStartVisible ) ~= "boolean") then
|
|
||||||
error( "Expected object, number, number, number, number, [boolean]", 2 )
|
|
||||||
end
|
|
||||||
|
|
||||||
if parent == term then
|
if parent == term then
|
||||||
error( "term is not a recommended window parent, try term.current() instead", 2 )
|
error( "term is not a recommended window parent, try term.current() instead", 2 )
|
||||||
@ -193,9 +191,9 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function window.blit( sText, sTextColor, sBackgroundColor )
|
function window.blit( sText, sTextColor, sBackgroundColor )
|
||||||
if type(sText) ~= "string" or type(sTextColor) ~= "string" or type(sBackgroundColor) ~= "string" then
|
if type( sText ) ~= "string" then error( "bad argument #1 (expected string, got " .. type( sText ) .. ")", 2 ) end
|
||||||
error( "Expected string, string, string", 2 )
|
if type( sTextColor ) ~= "string" then error( "bad argument #2 (expected string, got " .. type( sTextColor ) .. ")", 2 ) end
|
||||||
end
|
if type( sBackgroundColor ) ~= "string" then error( "bad argument #3 (expected string, got " .. type( sBackgroundColor ) .. ")", 2 ) end
|
||||||
if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then
|
if #sTextColor ~= #sText or #sBackgroundColor ~= #sText then
|
||||||
error( "Arguments must be the same length", 2 )
|
error( "Arguments must be the same length", 2 )
|
||||||
end
|
end
|
||||||
@ -243,9 +241,8 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function window.setCursorPos( x, y )
|
function window.setCursorPos( x, y )
|
||||||
if type( x ) ~= "number" or type( y ) ~= "number" then
|
if type( x ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( x ) .. ")", 2 ) end
|
||||||
error( "Expected number, number", 2 )
|
if type( y ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( y ) .. ")", 2 ) end
|
||||||
end
|
|
||||||
nCursorX = math.floor( x )
|
nCursorX = math.floor( x )
|
||||||
nCursorY = math.floor( y )
|
nCursorY = math.floor( y )
|
||||||
if bVisible then
|
if bVisible then
|
||||||
@ -254,9 +251,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function window.setCursorBlink( blink )
|
function window.setCursorBlink( blink )
|
||||||
if type( blink ) ~= "boolean" then
|
if type( blink ) ~= "boolean" then error( "bad argument #1 (expected boolean, got " .. type( blink ) .. ")", 2 ) end
|
||||||
error( "Expected boolean", 2 )
|
|
||||||
end
|
|
||||||
bCursorBlink = blink
|
bCursorBlink = blink
|
||||||
if bVisible then
|
if bVisible then
|
||||||
updateCursorBlink()
|
updateCursorBlink()
|
||||||
@ -276,10 +271,10 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function setTextColor( color )
|
local function setTextColor( color )
|
||||||
if type(color) ~= "number" then
|
if type( color ) ~= "number" then
|
||||||
error( "Expected number", 3 )
|
error( "bad argument #1 (expected number, got " .. type( color ) .. ")", 2 )
|
||||||
elseif tHex[color] == nil then
|
elseif tHex[color] == nil then
|
||||||
error( "Invalid color", 3 )
|
error( "Invalid color", 2 )
|
||||||
end
|
end
|
||||||
nTextColor = color
|
nTextColor = color
|
||||||
if bVisible then
|
if bVisible then
|
||||||
@ -287,26 +282,25 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function window.setTextColor( color )
|
window.setTextColor = setTextColor
|
||||||
setTextColor( color )
|
window.setTextColour = setTextColor
|
||||||
end
|
|
||||||
|
|
||||||
function window.setTextColour( color )
|
|
||||||
setTextColor( color )
|
|
||||||
end
|
|
||||||
|
|
||||||
function window.setPaletteColour( colour, r, g, b )
|
function window.setPaletteColour( colour, r, g, b )
|
||||||
|
if type( colour ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( colour ) .. ")", 2 ) end
|
||||||
|
|
||||||
local tCol
|
local tCol
|
||||||
if type(colour) == "number" and type(r) == "number" and g == nil and b == nil then
|
if type(r) == "number" and g == nil and b == nil then
|
||||||
tCol = { colours.rgb8( r ) }
|
tCol = { colours.rgb8( r ) }
|
||||||
tPalette[ colour ] = tCol
|
tPalette[ colour ] = tCol
|
||||||
elseif type(colour) == "number" and type(r) == "number" and type(g) == "number" and type(b) == "number" then
|
else
|
||||||
|
if type( r ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( r ) .. ")", 2 ) end
|
||||||
|
if type( g ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( g ) .. ")", 2 ) end
|
||||||
|
if type( b ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( b ) .. ")", 2 ) end
|
||||||
|
|
||||||
tCol = tPalette[ colour ]
|
tCol = tPalette[ colour ]
|
||||||
tCol[1] = r
|
tCol[1] = r
|
||||||
tCol[2] = g
|
tCol[2] = g
|
||||||
tCol[3] = b
|
tCol[3] = b
|
||||||
else
|
|
||||||
error( "Expected number, number, number, number", 2 )
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if bVisible then
|
if bVisible then
|
||||||
@ -324,30 +318,23 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
window.getPaletteColor = window.getPaletteColour
|
window.getPaletteColor = window.getPaletteColour
|
||||||
|
|
||||||
local function setBackgroundColor( color )
|
local function setBackgroundColor( color )
|
||||||
if type(color) ~= "number" then
|
if type( color ) ~= "number" then
|
||||||
error( "Expected number", 3 )
|
error( "bad argument #1 (expected number, got " .. type( color ) .. ")", 2 )
|
||||||
elseif tHex[color] == nil then
|
elseif tHex[color] == nil then
|
||||||
error( "Invalid color", 3 )
|
error( "Invalid color", 3 )
|
||||||
end
|
end
|
||||||
nBackgroundColor = color
|
nBackgroundColor = color
|
||||||
end
|
end
|
||||||
|
|
||||||
function window.setBackgroundColor( color )
|
window.setBackgroundColor = setBackgroundColor
|
||||||
setBackgroundColor( color )
|
window.setBackgroundColour = setBackgroundColor
|
||||||
end
|
|
||||||
|
|
||||||
function window.setBackgroundColour( color )
|
|
||||||
setBackgroundColor( color )
|
|
||||||
end
|
|
||||||
|
|
||||||
function window.getSize()
|
function window.getSize()
|
||||||
return nWidth, nHeight
|
return nWidth, nHeight
|
||||||
end
|
end
|
||||||
|
|
||||||
function window.scroll( n )
|
function window.scroll( n )
|
||||||
if type( n ) ~= "number" then
|
if type( n ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 ) end
|
||||||
error( "Expected number", 2 )
|
|
||||||
end
|
|
||||||
if n ~= 0 then
|
if n ~= 0 then
|
||||||
local tNewLines = {}
|
local tNewLines = {}
|
||||||
local sEmptyText = sEmptySpaceLine
|
local sEmptyText = sEmptySpaceLine
|
||||||
@ -392,9 +379,7 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
|
|
||||||
-- Other functions
|
-- Other functions
|
||||||
function window.setVisible( bVis )
|
function window.setVisible( bVis )
|
||||||
if type( bVis) ~= "boolean" then
|
if type( bVis ) ~= "boolean" then error( "bad argument #1 (expected boolean, got " .. type( bVis ) .. ")", 2 ) end
|
||||||
error( "Expected boolean", 2 )
|
|
||||||
end
|
|
||||||
if bVisible ~= bVis then
|
if bVisible ~= bVis then
|
||||||
bVisible = bVis
|
bVisible = bVis
|
||||||
if bVisible then
|
if bVisible then
|
||||||
@ -426,9 +411,11 @@ function create( parent, nX, nY, nWidth, nHeight, bStartVisible )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight )
|
function window.reposition( nNewX, nNewY, nNewWidth, nNewHeight )
|
||||||
if type( nNewX ) ~= "number" or type( nNewY ) ~= "number" or type( nNewWidth ) ~= "number" or type( nNewWidth ) ~= "number" then
|
if type( nNewX ) ~= "number" then error( "bad argument #1 (expected number, got " .. type( nNewX ) .. ")", 2 ) end
|
||||||
error( "Expected number, number, number, number", 2 )
|
if type( nNewY ) ~= "number" then error( "bad argument #2 (expected number, got " .. type( nNewY ) .. ")", 2 ) end
|
||||||
end
|
if type( nNewWidth ) ~= "number" then error( "bad argument #3 (expected number, got " .. type( nNewWidth ) .. ")", 2 ) end
|
||||||
|
if type( nNewHeight ) ~= "number" then error( "bad argument #4 (expected number, got " .. type( nNewHeight ) .. ")", 2 ) end
|
||||||
|
|
||||||
nX = nNewX
|
nX = nNewX
|
||||||
nY = nNewY
|
nY = nNewY
|
||||||
if nNewWidth and nNewHeight then
|
if nNewWidth and nNewHeight then
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
equip is a program for Turtles. equip will equip an item from the Turtle's inventory for use as a tool of peripheral.
|
equip is a program for Turtles and Pocket Computer. equip will equip an item from the Turtle's inventory for use as a tool of peripheral. On a Pocket Computer you don't need to write a side.
|
||||||
|
|
||||||
ex:
|
ex:
|
||||||
"equip 5 left" will equip the item from slot 5 of the turtle onto the left side of the turtle
|
"equip 5 left" will equip the item from slot 5 of the turtle onto the left side of the turtle
|
||||||
|
"equip" on a Pocket Computer will equip the first item from your inventory.
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
Functions in the HTTP API:
|
Functions in the HTTP API:
|
||||||
http.checkURL( url )
|
http.checkURL( url )
|
||||||
|
http.checkURLAsync( url )
|
||||||
http.request( url, [postData], [headers] )
|
http.request( url, [postData], [headers] )
|
||||||
http.get( url, [headers] )
|
http.get( url, [headers] )
|
||||||
http.post( url, postData, [headers] )
|
http.post( url, postData, [headers] )
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
unequip is a program for Turtles. unequip will remove tools of peripherals from the specified side of the turtle.
|
unequip is a program for Turtles and Pocket Computers. unequip will remove tools of peripherals from the specified side of the turtle. On a Pocket Computer you don't need to write a side.
|
||||||
|
|
||||||
ex:
|
ex:
|
||||||
"unequip left" will remove the item on the left side of the turtle
|
"unequip left" will remove the item on the left side of the turtle
|
||||||
|
"unequip" on a Pocket Computer will remove the item from the Pocket Computer
|
||||||
|
@ -171,6 +171,9 @@ function multishell.getFocus()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function multishell.setFocus( n )
|
function multishell.setFocus( n )
|
||||||
|
if type( n ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 )
|
||||||
|
end
|
||||||
if n >= 1 and n <= #tProcesses then
|
if n >= 1 and n <= #tProcesses then
|
||||||
selectProcess( n )
|
selectProcess( n )
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
@ -180,6 +183,9 @@ function multishell.setFocus( n )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function multishell.getTitle( n )
|
function multishell.getTitle( n )
|
||||||
|
if type( n ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 )
|
||||||
|
end
|
||||||
if n >= 1 and n <= #tProcesses then
|
if n >= 1 and n <= #tProcesses then
|
||||||
return tProcesses[n].sTitle
|
return tProcesses[n].sTitle
|
||||||
end
|
end
|
||||||
@ -187,6 +193,12 @@ function multishell.getTitle( n )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function multishell.setTitle( n, sTitle )
|
function multishell.setTitle( n, sTitle )
|
||||||
|
if type( n ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( n ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( sTitle ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( sTitle ) .. ")", 2 )
|
||||||
|
end
|
||||||
if n >= 1 and n <= #tProcesses then
|
if n >= 1 and n <= #tProcesses then
|
||||||
setProcessTitle( n, sTitle )
|
setProcessTitle( n, sTitle )
|
||||||
redrawMenu()
|
redrawMenu()
|
||||||
@ -198,6 +210,12 @@ function multishell.getCurrent()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function multishell.launch( tProgramEnv, sProgramPath, ... )
|
function multishell.launch( tProgramEnv, sProgramPath, ... )
|
||||||
|
if type( tProgramArgs ) ~= "table" then
|
||||||
|
error( "bad argument #1 (expected table, got " .. type( tProgramEnv ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( sProgramPath ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( sProgramPath ) .. ")", 2 )
|
||||||
|
end
|
||||||
local previousTerm = term.current()
|
local previousTerm = term.current()
|
||||||
setMenuVisible( (#tProcesses + 1) >= 2 )
|
setMenuVisible( (#tProcesses + 1) >= 2 )
|
||||||
local nResult = launchProcess( tProgramEnv, sProgramPath, ... )
|
local nResult = launchProcess( tProgramEnv, sProgramPath, ... )
|
||||||
|
@ -175,7 +175,7 @@ local nCompletion
|
|||||||
local tCompleteEnv = _ENV
|
local tCompleteEnv = _ENV
|
||||||
local function complete( sLine )
|
local function complete( sLine )
|
||||||
if settings.get( "edit.autocomplete" ) then
|
if settings.get( "edit.autocomplete" ) then
|
||||||
local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.]+$" )
|
local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.:]+$" )
|
||||||
if nStartPos then
|
if nStartPos then
|
||||||
sLine = string.sub( sLine, nStartPos )
|
sLine = string.sub( sLine, nStartPos )
|
||||||
end
|
end
|
||||||
@ -709,7 +709,13 @@ while bRunning do
|
|||||||
end
|
end
|
||||||
|
|
||||||
elseif sEvent == "paste" then
|
elseif sEvent == "paste" then
|
||||||
if not bMenu and not bReadOnly then
|
if not bReadOnly then
|
||||||
|
-- Close menu if open
|
||||||
|
if bMenu then
|
||||||
|
bMenu = false
|
||||||
|
term.setCursorBlink( true )
|
||||||
|
redrawMenu()
|
||||||
|
end
|
||||||
-- Input text
|
-- Input text
|
||||||
local sLine = tLines[y]
|
local sLine = tLines[y]
|
||||||
tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
|
tLines[y] = string.sub(sLine,1,x-1) .. param .. string.sub(sLine,x)
|
||||||
|
@ -310,7 +310,7 @@ local function accessMenu()
|
|||||||
-- Select an option
|
-- Select an option
|
||||||
if mChoices[selection]=="Save" then
|
if mChoices[selection]=="Save" then
|
||||||
if bReadOnly then
|
if bReadOnly then
|
||||||
fMessage = "Access Denied"
|
fMessage = "Access denied"
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
local success = save(sPath)
|
local success = save(sPath)
|
||||||
|
@ -57,10 +57,6 @@ elseif sCommand == "host" then
|
|||||||
x,y,z = gps.locate( 2, true )
|
x,y,z = gps.locate( 2, true )
|
||||||
if x == nil then
|
if x == nil then
|
||||||
print( "Run \"gps host <x> <y> <z>\" to set position manually" )
|
print( "Run \"gps host <x> <y> <z>\" to set position manually" )
|
||||||
if bCloseChannel then
|
|
||||||
print( "Closing GPS channel" )
|
|
||||||
modem.close( gps.CHANNEL_GPS )
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -34,7 +34,7 @@ while bRunning do
|
|||||||
|
|
||||||
local s = read( nil, tCommandHistory, function( sLine )
|
local s = read( nil, tCommandHistory, function( sLine )
|
||||||
if settings.get( "lua.autocomplete" ) then
|
if settings.get( "lua.autocomplete" ) then
|
||||||
local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.]+$" )
|
local nStartPos = string.find( sLine, "[a-zA-Z0-9_%.:]+$" )
|
||||||
if nStartPos then
|
if nStartPos then
|
||||||
sLine = string.sub( sLine, nStartPos )
|
sLine = string.sub( sLine, nStartPos )
|
||||||
end
|
end
|
||||||
@ -64,10 +64,10 @@ while bRunning do
|
|||||||
end
|
end
|
||||||
|
|
||||||
if func then
|
if func then
|
||||||
local tResults = { pcall( func ) }
|
local tResults = table.pack( pcall( func ) )
|
||||||
if tResults[1] then
|
if tResults[1] then
|
||||||
local n = 1
|
local n = 1
|
||||||
while (tResults[n + 1] ~= nil) or (n <= nForcePrint) do
|
while n < tResults.n or (n <= nForcePrint) do
|
||||||
local value = tResults[ n + 1 ]
|
local value = tResults[ n + 1 ]
|
||||||
if type( value ) == "table" then
|
if type( value ) == "table" then
|
||||||
local metatable = getmetatable( value )
|
local metatable = getmetatable( value )
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
local ok, err = pcall( pocket.equipBack )
|
||||||
|
if not ok then
|
||||||
|
printError( "Nothing to equip" )
|
||||||
|
else
|
||||||
|
print( "Item equipped" )
|
||||||
|
end
|
@ -0,0 +1,6 @@
|
|||||||
|
local ok, err = pcall( pocket.unequipBack )
|
||||||
|
if not ok then
|
||||||
|
printError( "Nothing to unequip" )
|
||||||
|
else
|
||||||
|
print( "Item unequipped" )
|
||||||
|
end
|
@ -310,14 +310,14 @@ elseif sCommand == "join" then
|
|||||||
function printMessage( sMessage )
|
function printMessage( sMessage )
|
||||||
term.redirect( historyWindow )
|
term.redirect( historyWindow )
|
||||||
print()
|
print()
|
||||||
if string.match( sMessage, "^\*" ) then
|
if string.match( sMessage, "^%*" ) then
|
||||||
-- Information
|
-- Information
|
||||||
term.setTextColour( highlightColour )
|
term.setTextColour( highlightColour )
|
||||||
write( sMessage )
|
write( sMessage )
|
||||||
term.setTextColour( textColour )
|
term.setTextColour( textColour )
|
||||||
else
|
else
|
||||||
-- Chat
|
-- Chat
|
||||||
local sUsernameBit = string.match( sMessage, "^\<[^\>]*\>" )
|
local sUsernameBit = string.match( sMessage, "^<[^>]*>" )
|
||||||
if sUsernameBit then
|
if sUsernameBit then
|
||||||
term.setTextColour( highlightColour )
|
term.setTextColour( highlightColour )
|
||||||
write( sUsernameBit )
|
write( sUsernameBit )
|
||||||
|
@ -2,9 +2,12 @@
|
|||||||
local tArgs = { ... }
|
local tArgs = { ... }
|
||||||
if #tArgs == 0 then
|
if #tArgs == 0 then
|
||||||
-- "set"
|
-- "set"
|
||||||
|
local x,y = term.getCursorPos()
|
||||||
|
local tSettings = {}
|
||||||
for n,sName in ipairs( settings.getNames() ) do
|
for n,sName in ipairs( settings.getNames() ) do
|
||||||
print( textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName)) )
|
tSettings[n] = textutils.serialize(sName) .. " is " .. textutils.serialize(settings.get(sName))
|
||||||
end
|
end
|
||||||
|
textutils.pagedPrint(table.concat(tSettings,"\n"),y-3)
|
||||||
|
|
||||||
elseif #tArgs == 1 then
|
elseif #tArgs == 1 then
|
||||||
-- "set foo"
|
-- "set foo"
|
||||||
|
@ -31,6 +31,7 @@ local function createShellEnv( sDir )
|
|||||||
table = table,
|
table = table,
|
||||||
}
|
}
|
||||||
package.path = "?;?.lua;?/init.lua"
|
package.path = "?;?.lua;?/init.lua"
|
||||||
|
package.config = "/\n;\n?\n!\n-"
|
||||||
package.preload = {}
|
package.preload = {}
|
||||||
package.loaders = {
|
package.loaders = {
|
||||||
function( name )
|
function( name )
|
||||||
@ -68,6 +69,9 @@ local function createShellEnv( sDir )
|
|||||||
|
|
||||||
local sentinel = {}
|
local sentinel = {}
|
||||||
local function require( name )
|
local function require( name )
|
||||||
|
if type( name ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( name ) .. ")", 2 )
|
||||||
|
end
|
||||||
if package.loaded[name] == sentinel then
|
if package.loaded[name] == sentinel then
|
||||||
error("Loop detected requiring '" .. name .. "'", 0)
|
error("Loop detected requiring '" .. name .. "'", 0)
|
||||||
end
|
end
|
||||||
@ -181,6 +185,12 @@ function shell.dir()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function shell.setDir( _sDir )
|
function shell.setDir( _sDir )
|
||||||
|
if type( _sDir ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sDir ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if not fs.isDir( _sDir ) then
|
||||||
|
error( "Not a directory", 2 )
|
||||||
|
end
|
||||||
sDir = _sDir
|
sDir = _sDir
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -189,10 +199,16 @@ function shell.path()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function shell.setPath( _sPath )
|
function shell.setPath( _sPath )
|
||||||
|
if type( _sPath ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 )
|
||||||
|
end
|
||||||
sPath = _sPath
|
sPath = _sPath
|
||||||
end
|
end
|
||||||
|
|
||||||
function shell.resolve( _sPath )
|
function shell.resolve( _sPath )
|
||||||
|
if type( _sPath ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sPath ) .. ")", 2 )
|
||||||
|
end
|
||||||
local sStartChar = string.sub( _sPath, 1, 1 )
|
local sStartChar = string.sub( _sPath, 1, 1 )
|
||||||
if sStartChar == "/" or sStartChar == "\\" then
|
if sStartChar == "/" or sStartChar == "\\" then
|
||||||
return fs.combine( "", _sPath )
|
return fs.combine( "", _sPath )
|
||||||
@ -212,6 +228,9 @@ local function pathWithExtension( _sPath, _sExt )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function shell.resolveProgram( _sCommand )
|
function shell.resolveProgram( _sCommand )
|
||||||
|
if type( _sCommand ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 )
|
||||||
|
end
|
||||||
-- Substitute aliases firsts
|
-- Substitute aliases firsts
|
||||||
if tAliases[ _sCommand ] ~= nil then
|
if tAliases[ _sCommand ] ~= nil then
|
||||||
_sCommand = tAliases[ _sCommand ]
|
_sCommand = tAliases[ _sCommand ]
|
||||||
@ -327,6 +346,9 @@ local function completeProgramArgument( sProgram, nArgument, sPart, tPreviousPar
|
|||||||
end
|
end
|
||||||
|
|
||||||
function shell.complete( sLine )
|
function shell.complete( sLine )
|
||||||
|
if type( sLine ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( sLine ) .. ")", 2 )
|
||||||
|
end
|
||||||
if #sLine > 0 then
|
if #sLine > 0 then
|
||||||
local tWords = tokenise( sLine )
|
local tWords = tokenise( sLine )
|
||||||
local nIndex = #tWords
|
local nIndex = #tWords
|
||||||
@ -363,10 +385,19 @@ function shell.complete( sLine )
|
|||||||
end
|
end
|
||||||
|
|
||||||
function shell.completeProgram( sProgram )
|
function shell.completeProgram( sProgram )
|
||||||
|
if type( sProgram ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( sProgram ) .. ")", 2 )
|
||||||
|
end
|
||||||
return completeProgram( sProgram )
|
return completeProgram( sProgram )
|
||||||
end
|
end
|
||||||
|
|
||||||
function shell.setCompletionFunction( sProgram, fnComplete )
|
function shell.setCompletionFunction( sProgram, fnComplete )
|
||||||
|
if type( sProgram ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( sProgram ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( fnComplete ) ~= "function" then
|
||||||
|
error( "bad argument #2 (expected function, got " .. type( fnComplete ) .. ")", 2 )
|
||||||
|
end
|
||||||
tCompletionInfo[ sProgram ] = {
|
tCompletionInfo[ sProgram ] = {
|
||||||
fnComplete = fnComplete
|
fnComplete = fnComplete
|
||||||
}
|
}
|
||||||
@ -384,10 +415,19 @@ function shell.getRunningProgram()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function shell.setAlias( _sCommand, _sProgram )
|
function shell.setAlias( _sCommand, _sProgram )
|
||||||
|
if type( _sCommand ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 )
|
||||||
|
end
|
||||||
|
if type( _sProgram ) ~= "string" then
|
||||||
|
error( "bad argument #2 (expected string, got " .. type( _sProgram ) .. ")", 2 )
|
||||||
|
end
|
||||||
tAliases[ _sCommand ] = _sProgram
|
tAliases[ _sCommand ] = _sProgram
|
||||||
end
|
end
|
||||||
|
|
||||||
function shell.clearAlias( _sCommand )
|
function shell.clearAlias( _sCommand )
|
||||||
|
if type( _sCommand ) ~= "string" then
|
||||||
|
error( "bad argument #1 (expected string, got " .. type( _sCommand ) .. ")", 2 )
|
||||||
|
end
|
||||||
tAliases[ _sCommand ] = nil
|
tAliases[ _sCommand ] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -417,6 +457,9 @@ if multishell then
|
|||||||
end
|
end
|
||||||
|
|
||||||
function shell.switchTab( nID )
|
function shell.switchTab( nID )
|
||||||
|
if type( nID ) ~= "number" then
|
||||||
|
error( "bad argument #1 (expected number, got " .. type( nID ) .. ")", 2 )
|
||||||
|
end
|
||||||
multishell.setFocus( nID )
|
multishell.setFocus( nID )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -168,6 +168,15 @@ local function completeSet( shell, nIndex, sText, tPreviousText )
|
|||||||
return completeMultipleChoice( sText, settings.getNames(), true )
|
return completeMultipleChoice( sText, settings.getNames(), true )
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
local tCommands
|
||||||
|
if commands then
|
||||||
|
tCommands = commands.list()
|
||||||
|
end
|
||||||
|
local function completeExec( shell, nIndex, sText, tPreviousText )
|
||||||
|
if nIndex == 1 and commands then
|
||||||
|
return completeMultipleChoice( sText, tCommands, true )
|
||||||
|
end
|
||||||
|
end
|
||||||
shell.setCompletionFunction( "rom/programs/alias.lua", completeAlias )
|
shell.setCompletionFunction( "rom/programs/alias.lua", completeAlias )
|
||||||
shell.setCompletionFunction( "rom/programs/cd.lua", completeDir )
|
shell.setCompletionFunction( "rom/programs/cd.lua", completeDir )
|
||||||
shell.setCompletionFunction( "rom/programs/copy.lua", completeEitherEither )
|
shell.setCompletionFunction( "rom/programs/copy.lua", completeEitherEither )
|
||||||
@ -194,6 +203,36 @@ shell.setCompletionFunction( "rom/programs/fun/dj.lua", completeDJ )
|
|||||||
shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completeFile )
|
shell.setCompletionFunction( "rom/programs/fun/advanced/paint.lua", completeFile )
|
||||||
shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completePastebin )
|
shell.setCompletionFunction( "rom/programs/http/pastebin.lua", completePastebin )
|
||||||
shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completeChat )
|
shell.setCompletionFunction( "rom/programs/rednet/chat.lua", completeChat )
|
||||||
|
shell.setCompletionFunction( "rom/programs/command/exec.lua", completeExec )
|
||||||
|
|
||||||
|
if turtle then
|
||||||
|
local tGoOptions = { "left", "right", "forward", "back", "down", "up" }
|
||||||
|
local function completeGo( shell, nIndex, sText )
|
||||||
|
return completeMultipleChoice(sText,tGoOptions)
|
||||||
|
end
|
||||||
|
local tTurnOptions = { "left", "right" }
|
||||||
|
local function completeTurn( shell, nIndex, sText )
|
||||||
|
if nIndex == 1 then
|
||||||
|
return completeMultipleChoice( sText, tTurnOptions )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local tEquipOptions = { "left", "right" }
|
||||||
|
local function completeEquip( shell, nIndex, sText )
|
||||||
|
if nIndex == 2 then
|
||||||
|
return completeMultipleChoice( sText, tEquipOptions )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local function completeUnequip( shell, nIndex, sText )
|
||||||
|
if nIndex == 1 then
|
||||||
|
return completeMultipleChoice( sText, tEquipOptions )
|
||||||
|
end
|
||||||
|
end
|
||||||
|
shell.setCompletionFunction( "rom/programs/turtle/go.lua", completeGo )
|
||||||
|
shell.setCompletionFunction( "rom/programs/turtle/turn.lua", completeTurn )
|
||||||
|
shell.setCompletionFunction( "rom/programs/turtle/equip.lua", completeEquip )
|
||||||
|
shell.setCompletionFunction( "rom/programs/turtle/unequip.lua", completeUnequip )
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Run autorun files
|
-- Run autorun files
|
||||||
if fs.exists( "/rom/autorun" ) and fs.isDir( "/rom/autorun" ) then
|
if fs.exists( "/rom/autorun" ) and fs.isDir( "/rom/autorun" ) then
|
||||||
|
Loading…
Reference in New Issue
Block a user