2017-05-07 00:18:59 +00:00
|
|
|
/*
|
2017-05-01 13:32:39 +00:00
|
|
|
* This file is part of ComputerCraft - http://www.computercraft.info
|
2017-05-13 18:20:39 +00:00
|
|
|
* Copyright Daniel Ratcliffe, 2011-2017. Do not distribute without permission.
|
2017-05-01 13:32:39 +00:00
|
|
|
* Send enquiries to dratcliffe@gmail.com
|
|
|
|
*/
|
|
|
|
|
|
|
|
package dan200.computercraft.shared.computer.apis;
|
|
|
|
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
2017-05-13 21:26:35 +00:00
|
|
|
import dan200.computercraft.ComputerCraft;
|
2017-05-01 13:32:39 +00:00
|
|
|
import dan200.computercraft.api.lua.ILuaContext;
|
|
|
|
import dan200.computercraft.api.lua.LuaException;
|
|
|
|
import dan200.computercraft.core.apis.ILuaAPI;
|
|
|
|
import dan200.computercraft.shared.computer.blocks.TileCommandComputer;
|
|
|
|
import dan200.computercraft.shared.util.WorldUtil;
|
|
|
|
import net.minecraft.block.Block;
|
|
|
|
import net.minecraft.block.properties.IProperty;
|
|
|
|
import net.minecraft.block.state.IBlockState;
|
|
|
|
import net.minecraft.command.ICommand;
|
|
|
|
import net.minecraft.command.ICommandManager;
|
|
|
|
import net.minecraft.command.ICommandSender;
|
|
|
|
import net.minecraft.server.MinecraftServer;
|
2017-05-01 13:51:26 +00:00
|
|
|
import net.minecraft.util.math.BlockPos;
|
2017-05-01 13:32:39 +00:00
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
2017-05-06 23:07:42 +00:00
|
|
|
import javax.annotation.Nonnull;
|
2017-05-01 13:32:39 +00:00
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.Map;
|
|
|
|
|
2017-06-12 09:28:31 +00:00
|
|
|
import static dan200.computercraft.core.apis.ArgumentHelper.getInt;
|
|
|
|
import static dan200.computercraft.core.apis.ArgumentHelper.getString;
|
|
|
|
|
2017-05-01 13:32:39 +00:00
|
|
|
public class CommandAPI implements ILuaAPI
|
|
|
|
{
|
|
|
|
private TileCommandComputer m_computer;
|
|
|
|
|
|
|
|
public CommandAPI( TileCommandComputer computer )
|
|
|
|
{
|
|
|
|
m_computer = computer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ILuaAPI implementation
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public String[] getNames()
|
|
|
|
{
|
|
|
|
return new String[] {
|
|
|
|
"commands"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void startup()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void advance( double dt )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void shutdown()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-06 23:07:42 +00:00
|
|
|
@Nonnull
|
2017-05-01 13:32:39 +00:00
|
|
|
@Override
|
|
|
|
public String[] getMethodNames()
|
|
|
|
{
|
|
|
|
return new String[] {
|
|
|
|
"exec",
|
|
|
|
"execAsync",
|
|
|
|
"list",
|
|
|
|
"getBlockPosition",
|
|
|
|
"getBlockInfos",
|
|
|
|
"getBlockInfo"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private Map<Object, Object> createOutput( String output )
|
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
Map<Object, Object> result = new HashMap<>( 1 );
|
2017-05-01 13:32:39 +00:00
|
|
|
result.put( 1, output );
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
private Object[] doCommand( String command )
|
|
|
|
{
|
2017-05-01 13:51:26 +00:00
|
|
|
MinecraftServer server = m_computer.getWorld().getMinecraftServer();
|
2017-05-01 13:32:39 +00:00
|
|
|
if( server != null && server.isCommandBlockEnabled() )
|
|
|
|
{
|
|
|
|
ICommandManager commandManager = server.getCommandManager();
|
|
|
|
try
|
|
|
|
{
|
|
|
|
TileCommandComputer.CommandSender sender = m_computer.getCommandSender();
|
|
|
|
sender.clearOutput();
|
|
|
|
|
|
|
|
int result = commandManager.executeCommand( sender, command );
|
|
|
|
return new Object[]{ (result > 0), sender.copyOutput() };
|
|
|
|
}
|
|
|
|
catch( Throwable t )
|
|
|
|
{
|
2017-05-16 14:59:09 +00:00
|
|
|
if( ComputerCraft.logPeripheralErrors )
|
|
|
|
{
|
|
|
|
ComputerCraft.log.error( "Error running command.", t );
|
|
|
|
}
|
2017-05-01 13:32:39 +00:00
|
|
|
return new Object[]{ false, createOutput( "Java Exception Thrown: " + t.toString() ) };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return new Object[] { false, createOutput( "Command blocks disabled by server" ) };
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private Object getBlockInfo( World world, BlockPos pos )
|
|
|
|
{
|
|
|
|
// Get the details of the block
|
|
|
|
IBlockState state = world.getBlockState( pos );
|
|
|
|
Block block = state.getBlock();
|
2017-05-06 23:42:00 +00:00
|
|
|
String name = Block.REGISTRY.getNameForObject( block ).toString();
|
2017-05-01 13:32:39 +00:00
|
|
|
int metadata = block.getMetaFromState( state );
|
|
|
|
|
2017-06-12 20:08:35 +00:00
|
|
|
Map<Object, Object> table = new HashMap<>();
|
2017-05-01 13:32:39 +00:00
|
|
|
table.put( "name", name );
|
|
|
|
table.put( "metadata", metadata );
|
|
|
|
|
2017-06-12 20:08:35 +00:00
|
|
|
Map<Object, Object> stateTable = new HashMap<>();
|
2017-05-07 00:16:08 +00:00
|
|
|
for( ImmutableMap.Entry<IProperty<?>, Comparable<?>> entry : state.getActualState( world, pos ).getProperties().entrySet() )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
|
|
|
String propertyName = entry.getKey().getName();
|
|
|
|
Object value = entry.getValue();
|
|
|
|
if( value instanceof String || value instanceof Number || value instanceof Boolean )
|
|
|
|
{
|
|
|
|
stateTable.put( propertyName, value );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
stateTable.put( propertyName, value.toString() );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
table.put( "state", stateTable );
|
|
|
|
// TODO: NBT data?
|
|
|
|
return table;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2017-05-06 23:07:42 +00:00
|
|
|
public Object[] callMethod( @Nonnull ILuaContext context, int method, @Nonnull Object[] arguments ) throws LuaException, InterruptedException
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
|
|
|
switch( method )
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
{
|
|
|
|
// exec
|
2017-06-12 09:28:31 +00:00
|
|
|
final String command = getString( arguments, 0 );
|
2017-06-12 20:08:35 +00:00
|
|
|
return context.executeMainThreadTask( () -> doCommand( command ) );
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
{
|
|
|
|
// execAsync
|
2017-06-12 09:28:31 +00:00
|
|
|
final String command = getString( arguments, 0 );
|
2017-06-12 20:08:35 +00:00
|
|
|
long taskID = context.issueMainThreadTask( () -> doCommand( command ) );
|
2017-05-01 13:32:39 +00:00
|
|
|
return new Object[] { taskID };
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
{
|
|
|
|
// list
|
2017-06-12 20:08:35 +00:00
|
|
|
return context.executeMainThreadTask( () ->
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
int i = 1;
|
|
|
|
Map<Object, Object> result = new HashMap<>();
|
|
|
|
MinecraftServer server = m_computer.getWorld().getMinecraftServer();
|
|
|
|
if( server != null )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
ICommandManager commandManager = server.getCommandManager();
|
|
|
|
ICommandSender commmandSender = m_computer.getCommandSender();
|
|
|
|
Map<String, ICommand> commands = commandManager.getCommands();
|
|
|
|
for( Map.Entry<String, ICommand> entry : commands.entrySet() )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
String name = entry.getKey();
|
|
|
|
ICommand command = entry.getValue();
|
|
|
|
try
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
if( command.checkPermission( server, commmandSender ) )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
result.put( i++, name );
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
2017-06-12 20:08:35 +00:00
|
|
|
}
|
|
|
|
catch( Throwable t )
|
|
|
|
{
|
|
|
|
// Ignore buggy command
|
|
|
|
if( ComputerCraft.logPeripheralErrors )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
ComputerCraft.log.error( "Error checking permissions of command.", t );
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-12 20:08:35 +00:00
|
|
|
return new Object[]{ result };
|
2017-05-01 13:32:39 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
case 3:
|
|
|
|
{
|
|
|
|
// getBlockPosition
|
|
|
|
// This is probably safe to do on the Lua thread. Probably.
|
|
|
|
BlockPos pos = m_computer.getPos();
|
|
|
|
return new Object[] { pos.getX(), pos.getY(), pos.getZ() };
|
|
|
|
}
|
|
|
|
case 4:
|
|
|
|
{
|
|
|
|
// getBlockInfos
|
2017-06-12 09:28:31 +00:00
|
|
|
final int minx = getInt( arguments, 0 );
|
|
|
|
final int miny = getInt( arguments, 1 );
|
|
|
|
final int minz = getInt( arguments, 2 );
|
|
|
|
final int maxx = getInt( arguments, 3 );
|
|
|
|
final int maxy = getInt( arguments, 4 );
|
|
|
|
final int maxz = getInt( arguments, 5 );
|
2017-06-12 20:08:35 +00:00
|
|
|
return context.executeMainThreadTask( () ->
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
// Get the details of the block
|
|
|
|
World world = m_computer.getWorld();
|
|
|
|
BlockPos min = new BlockPos(
|
|
|
|
Math.min( minx, maxx ),
|
|
|
|
Math.min( miny, maxy ),
|
|
|
|
Math.min( minz, maxz )
|
|
|
|
);
|
|
|
|
BlockPos max = new BlockPos(
|
|
|
|
Math.max( minx, maxx ),
|
|
|
|
Math.max( miny, maxy ),
|
|
|
|
Math.max( minz, maxz )
|
|
|
|
);
|
|
|
|
if( !WorldUtil.isBlockInWorld( world, min ) || !WorldUtil.isBlockInWorld( world, max ) )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
throw new LuaException( "Co-ordinates out or range" );
|
|
|
|
}
|
|
|
|
if( ( max.getX() - min.getX() + 1 ) * ( max.getY() - min.getY() + 1 ) * ( max.getZ() - min.getZ() + 1 ) > 4096 )
|
|
|
|
{
|
|
|
|
throw new LuaException( "Too many blocks" );
|
|
|
|
}
|
|
|
|
int i=1;
|
|
|
|
Map<Object, Object> results = new HashMap<>();
|
|
|
|
for( int y=min.getY(); y<= max.getY(); ++y )
|
|
|
|
{
|
|
|
|
for( int z = min.getZ(); z <= max.getZ(); ++z )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
for( int x = min.getX(); x <= max.getX(); ++x )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
BlockPos pos = new BlockPos( x, y, z );
|
|
|
|
results.put( i++, getBlockInfo( world, pos ) );
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-12 20:08:35 +00:00
|
|
|
return new Object[]{ results };
|
2017-05-01 13:32:39 +00:00
|
|
|
} );
|
|
|
|
}
|
|
|
|
case 5:
|
|
|
|
{
|
|
|
|
// getBlockInfo
|
2017-06-12 09:28:31 +00:00
|
|
|
final int x = getInt( arguments, 0 );
|
|
|
|
final int y = getInt( arguments, 1 );
|
|
|
|
final int z = getInt( arguments, 2 );
|
2017-06-12 20:08:35 +00:00
|
|
|
return context.executeMainThreadTask( () ->
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
// Get the details of the block
|
|
|
|
World world = m_computer.getWorld();
|
|
|
|
BlockPos position = new BlockPos( x, y, z );
|
|
|
|
if( WorldUtil.isBlockInWorld( world, position ) )
|
2017-05-01 13:32:39 +00:00
|
|
|
{
|
2017-06-12 20:08:35 +00:00
|
|
|
return new Object[]{ getBlockInfo( world, position ) };
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw new LuaException( "co-ordinates out or range" );
|
2017-05-01 13:32:39 +00:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|