Update CC: Tweaked to 1.13

Look, I originally had this split into several commits, but lots of
other cleanups got mixed in. I then backported some of the cleanups to
1.12, did other tidy ups there, and eventually the web of merges was
unreadable.

Yes, this is a horrible mess, but it's still nicer than it was. Anyway,
changes:

 - Flatten everything. For instance, there are now three instances of
   BlockComputer, two BlockTurtle, ItemPocketComputer. There's also no
   more BlockPeripheral (thank heavens) - there's separate block classes
   for each peripheral type.

 - Remove pretty much all legacy code. As we're breaking world
   compatibility anyway, we can remove all the code to load worlds from
   1.4 days.
 - The command system is largely rewriten to take advantage of 1.13's
   new system. It's very fancy!

 - WidgetTerminal now uses Minecraft's "GUI listener" system.

 - BREAKING CHANGE: All the codes in keys.lua are different, due to the
   move to LWJGL 3. Hopefully this won't have too much of an impact.

   I don't want to map to the old key codes on the Java side, as there
   always ends up being small but slight inconsistencies. IMO it's
   better to make a clean break - people should be using keys rather
   than hard coding the constants anyway.

 - commands.list now allows fetching sub-commands. The ROM has already
   been updated to allow fancy usage such as commands.time.set("noon").

 - Turtles, modems and cables can be waterlogged.
This commit is contained in:
SquidDev committed 2019-04-02 20:59:48 +01:00
1 parent 810258e9b8
commit f9e13ca67a
273 files changed
+8194 -11111

No files matched your search

@@ -6,7 +6,9 @@
package dan200.computercraft.shared.command;
import com.google.common.collect.Sets;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.core.apis.IAPIEnvironment;
@@ -15,30 +17,37 @@ import dan200.computercraft.core.tracking.ComputerTracker;
import dan200.computercraft.core.tracking.Tracking;
import dan200.computercraft.core.tracking.TrackingContext;
import dan200.computercraft.core.tracking.TrackingField;
import dan200.computercraft.shared.Config;
import dan200.computercraft.shared.command.framework.*;
import dan200.computercraft.shared.command.text.TableBuilder;
import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.network.Containers;
import net.minecraft.command.CommandBase;
import net.minecraft.command.CommandException;
import net.minecraft.command.ICommandSender;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.server.MinecraftServer;
import net.minecraft.network.play.server.SPacketPlayerPosLook;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.world.World;
import net.minecraft.world.WorldServer;
import javax.annotation.Nonnull;
import java.util.*;
import java.util.function.Consumer;
import static dan200.computercraft.shared.command.CommandUtils.isPlayer;
import static dan200.computercraft.shared.command.Exceptions.*;
import static dan200.computercraft.shared.command.arguments.ComputerArgumentType.getComputerArgument;
import static dan200.computercraft.shared.command.arguments.ComputerArgumentType.oneComputer;
import static dan200.computercraft.shared.command.arguments.ComputersArgumentType.*;
import static dan200.computercraft.shared.command.arguments.TrackingFieldArgumentType.trackingField;
import static dan200.computercraft.shared.command.builder.CommandBuilder.args;
import static dan200.computercraft.shared.command.builder.CommandBuilder.command;
import static dan200.computercraft.shared.command.builder.HelpingArgumentBuilder.choice;
import static dan200.computercraft.shared.command.text.ChatHelpers.*;
import static net.minecraft.command.Commands.literal;
public final class CommandComputerCraft extends CommandDelegate
public final class CommandComputerCraft
{
public static final UUID SYSTEM_UUID = new UUID( 0, 0 );
@@ -46,335 +55,209 @@ public final class CommandComputerCraft extends CommandDelegate
private static final int DUMP_SINGLE_ID = 1844510720;
private static final int TRACK_ID = 373882880;
public CommandComputerCraft()
private CommandComputerCraft()
{
super( create() );
}
private static ISubCommand create()
public static void register( CommandDispatcher<CommandSource> dispatcher )
{
CommandRoot root = new CommandRoot( "computercraft" );
root.register( new SubCommandBase( "dump", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.isEmpty() )
{
dispatcher.register( choice( "computercraft" )
.then( literal( "dump" )
.requires( UserLevel.OWNER_OP )
.executes( context -> {
TableBuilder table = new TableBuilder( DUMP_LIST_ID, "Computer", "On", "Position" );
CommandSource source = context.getSource();
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
// Unless we're on a server, limit the number of rows we can send.
if( !(context.getSender() instanceof MinecraftServer) )
{
World world = context.getSender().getEntityWorld();
BlockPos pos = context.getSender().getPosition();
World world = source.getWorld();
BlockPos pos = new BlockPos( source.getPos() );
computers.sort( ( a, b ) -> {
if( a.getWorld() == b.getWorld() && a.getWorld() == world )
{
return Double.compare( a.getPosition().distanceSq( pos ), b.getPosition().distanceSq( pos ) );
}
else if( a.getWorld() == world )
{
return -1;
}
else if( b.getWorld() == world )
{
return 1;
}
else
{
return Integer.compare( a.getInstanceID(), b.getInstanceID() );
}
} );
}
computers.sort( ( a, b ) -> {
if( a.getWorld() == b.getWorld() && a.getWorld() == world )
{
return Double.compare( a.getPosition().distanceSq( pos ), b.getPosition().distanceSq( pos ) );
}
else if( a.getWorld() == world )
{
return -1;
}
else if( b.getWorld() == world )
{
return 1;
}
else
{
return Integer.compare( a.getInstanceID(), b.getInstanceID() );
}
} );
for( ServerComputer computer : computers )
{
table.row(
linkComputer( context, computer, computer.getID() ),
linkComputer( source, computer, computer.getID() ),
bool( computer.isOn() ),
linkPosition( context, computer )
linkPosition( source, computer )
);
}
table.display( context.getSender() );
}
else if( arguments.size() == 1 )
{
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
table.display( context.getSource() );
return computers.size();
} )
.then( args()
.arg( "computer", oneComputer() )
.executes( context -> {
ServerComputer computer = getComputerArgument( context, "computer" );
TableBuilder table = new TableBuilder( DUMP_SINGLE_ID );
table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.row( header( "Label" ), text( computer.getLabel() ) );
table.row( header( "On" ), bool( computer.isOn() ) );
table.row( header( "Position" ), linkPosition( context, computer ) );
table.row( header( "Family" ), text( computer.getFamily().toString() ) );
TableBuilder table = new TableBuilder( DUMP_SINGLE_ID );
table.row( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.row( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.row( header( "Label" ), text( computer.getLabel() ) );
table.row( header( "On" ), bool( computer.isOn() ) );
table.row( header( "Position" ), linkPosition( context.getSource(), computer ) );
table.row( header( "Family" ), text( computer.getFamily().toString() ) );
for( int i = 0; i < 6; i++ )
{
IPeripheral peripheral = computer.getPeripheral( i );
if( peripheral != null )
for( int i = 0; i < 6; i++ )
{
table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) );
IPeripheral peripheral = computer.getPeripheral( i );
if( peripheral != null )
{
table.row( header( "Peripheral " + IAPIEnvironment.SIDE_NAMES[i] ), text( peripheral.getType() ) );
}
}
}
table.display( context.getSender() );
}
else
{
throw new CommandException( context.getFullUsage() );
}
}
table.display( context.getSource() );
return 1;
} ) ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.size() == 1
? ComputerSelector.completeComputer( arguments.get( 0 ) )
: Collections.emptyList();
}
} );
root.register( new SubCommandBase( "shutdown", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
withComputers( arguments, computers -> {
.then( command( "shutdown" )
.requires( UserLevel.OWNER_OP )
.argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() )
.executes( ( context, computers ) -> {
int shutdown = 0;
for( ServerComputer computer : computers )
for( ServerComputer computer : unwrap( context.getSource(), computers ) )
{
if( computer.isOn() ) shutdown++;
computer.shutdown();
}
context.getSender().sendMessage( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ) );
} );
}
context.getSource().sendFeedback( translate( "commands.computercraft.shutdown.done", shutdown, computers.size() ), false );
return shutdown;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.isEmpty()
? Collections.emptyList()
: ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) );
}
} );
root.register( new SubCommandBase( "turn-on", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
withComputers( arguments, computers -> {
.then( command( "turn-on" )
.requires( UserLevel.OWNER_OP )
.argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() )
.executes( ( context, computers ) -> {
int on = 0;
for( ServerComputer computer : computers )
for( ServerComputer computer : unwrap( context.getSource(), computers ) )
{
if( !computer.isOn() ) on++;
computer.turnOn();
}
context.getSender().sendMessage( translate( "commands.computercraft.turn_on.done", on, computers.size() ) );
} );
}
context.getSource().sendFeedback( translate( "commands.computercraft.turn_on.done", on, computers.size() ), false );
return on;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.isEmpty()
? Collections.emptyList()
: ComputerSelector.completeComputer( arguments.get( arguments.size() - 1 ) );
}
} );
.then( command( "tp" )
.requires( UserLevel.OP )
.arg( "computer", oneComputer() )
.executes( context -> {
ServerComputer computer = getComputerArgument( context, "computer" );
World world = computer.getWorld();
BlockPos pos = computer.getPosition();
root.register( new SubCommandBase( "tp", UserLevel.OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.size() != 1 ) throw new CommandException( context.getFullUsage() );
if( world == null || pos == null ) throw TP_NOT_THERE.create();
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
World world = computer.getWorld();
BlockPos pos = computer.getPosition();
Entity entity = context.getSource().assertIsEntity();
if( !(entity instanceof EntityPlayerMP) ) throw TP_NOT_PLAYER.create();
if( world == null || pos == null ) throw new CommandException( "commands.computercraft.tp.not_there" );
ICommandSender sender = context.getSender();
if( !(sender instanceof Entity) ) throw new CommandException( "commands.computercraft.tp.not_entity" );
if( sender instanceof EntityPlayerMP )
{
EntityPlayerMP entity = (EntityPlayerMP) sender;
if( entity.getEntityWorld() != world )
EntityPlayerMP player = (EntityPlayerMP) entity;
if( player.getEntityWorld() == world )
{
context.getServer().getPlayerList().changePlayerDimension( entity, world.provider.getDimension() );
player.connection.setPlayerLocation( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0, EnumSet.noneOf( SPacketPlayerPosLook.EnumFlags.class ) );
}
else
{
player.teleport( (WorldServer) world, pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5, 0, 0 );
}
entity.setPositionAndUpdate( pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5 );
}
else
{
Entity entity = (Entity) sender;
if( entity.getEntityWorld() != world )
return 1;
} ) )
.then( command( "queue" )
.requires( UserLevel.ANYONE )
.arg( "computer", manyComputers() )
.argManyValue( "args", StringArgumentType.string(), Collections.emptyList() )
.executes( ( ctx, args ) -> {
Collection<ServerComputer> computers = getComputersArgument( ctx, "computer" );
Object[] rest = args.toArray();
int queued = 0;
for( ServerComputer computer : computers )
{
entity.changeDimension( world.provider.getDimension() );
if( computer.getFamily() == ComputerFamily.Command && computer.isOn() )
{
computer.queueEvent( "computer_command", rest );
queued++;
}
}
entity.setLocationAndAngles(
pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5,
entity.rotationYaw, entity.rotationPitch
);
}
}
return queued;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.size() == 1
? ComputerSelector.completeComputer( arguments.get( 0 ) )
: Collections.emptyList();
}
} );
.then( command( "view" )
.requires( UserLevel.OP )
.arg( "computer", oneComputer() )
.executes( context -> {
EntityPlayerMP player = context.getSource().asPlayer();
ServerComputer computer = getComputerArgument( context, "computer" );
Containers.openComputerGUI( player, computer );
return 1;
} ) )
root.register( new SubCommandBase( "view", UserLevel.OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.size() != 1 ) throw new CommandException( context.getFullUsage() );
.then( choice( "track" )
.then( command( "start" )
.requires( UserLevel.OWNER_OP )
.executes( context -> {
getTimingContext( context.getSource() ).start();
ICommandSender sender = context.getSender();
if( !(sender instanceof EntityPlayerMP) )
{
throw new CommandException( "commands.computercraft.view.not_player" );
}
String stopCommand = "/computercraft track stop";
context.getSource().sendFeedback( translate( "commands.computercraft.track.start.stop",
link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) ), false );
return 1;
} ) )
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
Containers.openComputerGUI( (EntityPlayerMP) sender, computer );
}
.then( command( "stop" )
.requires( UserLevel.OWNER_OP )
.executes( context -> {
TrackingContext timings = getTimingContext( context.getSource() );
if( !timings.stop() ) throw NOT_TRACKING_EXCEPTION.create();
displayTimings( context.getSource(), timings.getImmutableTimings(), TrackingField.AVERAGE_TIME, DEFAULT_FIELDS );
return 1;
} ) )
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
return arguments.size() == 1
? ComputerSelector.completeComputer( arguments.get( 0 ) )
: Collections.emptyList();
}
} );
.then( command( "dump" )
.requires( UserLevel.OWNER_OP )
.argManyValue( "fields", trackingField(), DEFAULT_FIELDS )
.executes( ( context, fields ) -> {
TrackingField sort;
if( fields.size() == 1 && DEFAULT_FIELDS.contains( fields.get( 0 ) ) )
{
sort = fields.get( 0 );
fields = DEFAULT_FIELDS;
}
else
{
sort = fields.get( 0 );
}
root.register( new CommandRoot( "track" ).register( new SubCommandBase( "start", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
getTimingContext( context ).start();
String stopCommand = "/" + context.parent().getFullPath() + " stop";
context.getSender().sendMessage( list(
translate( "commands.computercraft.track.start.stop",
link( text( stopCommand ), stopCommand, translate( "commands.computercraft.track.stop.action" ) ) )
) );
}
} ).register( new SubCommandBase( "stop", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
TrackingContext timings = getTimingContext( context );
if( !timings.stop() ) throw new CommandException( "commands.computercraft.track.stop.not_enabled" );
displayTimings( context, timings.getImmutableTimings(), TrackingField.AVERAGE_TIME );
}
} ).register( new SubCommandBase( "dump", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
TrackingField field = TrackingField.AVERAGE_TIME;
if( arguments.size() >= 1 )
{
field = TrackingField.fields().get( arguments.get( 0 ) );
if( field == null )
{
throw new CommandException( "commands.computercraft.track.dump.no_field", arguments.get( 0 ) );
}
}
displayTimings( context, getTimingContext( context ).getImmutableTimings(), field );
}
@Nonnull
@Override
public List<String> getCompletion( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
if( arguments.size() == 1 )
{
String match = arguments.get( 0 );
List<String> out = new ArrayList<>();
for( String key : TrackingField.fields().keySet() )
{
if( CommandBase.doesStringStartWith( match, key ) ) out.add( key );
}
out.sort( Comparator.naturalOrder() );
return out;
}
else
{
return super.getCompletion( context, arguments );
}
}
} ) );
root.register( new SubCommandBase( "reload", UserLevel.OWNER_OP )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments )
{
Config.reload();
context.getSender().sendMessage( translate( "commands.computercraft.reload.done" ) );
}
} );
root.register( new SubCommandBase( "queue", UserLevel.ANYONE )
{
@Override
public void execute( @Nonnull CommandContext context, @Nonnull List<String> arguments ) throws CommandException
{
if( arguments.size() < 1 ) throw new CommandException( context.getFullUsage() );
String selector = arguments.get( 0 );
Object[] rest = arguments.subList( 1, arguments.size() ).toArray();
boolean found = false;
for( ServerComputer computer : ComputerSelector.getComputers( selector ) )
{
if( computer.getFamily() != ComputerFamily.Command || !computer.isOn() ) continue;
found = true;
computer.queueEvent( "computer_command", rest );
}
if( !found )
{
throw new CommandException( "commands.computercraft.argument.no_matching", selector );
}
}
} );
return root;
return displayTimings( context.getSource(), sort, fields );
} ) ) )
);
}
private static ITextComponent linkComputer( CommandContext context, ServerComputer serverComputer, int computerId )
private static ITextComponent linkComputer( CommandSource source, ServerComputer serverComputer, int computerId )
{
ITextComponent out = new TextComponentString( "" );
@@ -396,7 +279,7 @@ public final class CommandComputerCraft extends CommandDelegate
out.appendText( " (id " + computerId + ")" );
// And, if we're a player, some useful links
if( serverComputer != null && UserLevel.OP.canExecute( context ) && context.fromPlayer() )
if( serverComputer != null && UserLevel.OP.test( source ) && isPlayer( source ) )
{
out
.appendText( " " )
@@ -416,9 +299,9 @@ public final class CommandComputerCraft extends CommandDelegate
return out;
}
private static ITextComponent linkPosition( CommandContext context, ServerComputer computer )
private static ITextComponent linkPosition( CommandSource context, ServerComputer computer )
{
if( UserLevel.OP.canExecute( context ) )
if( UserLevel.OP.test( context ) )
{
return link(
position( computer.getPosition() ),
@@ -432,22 +315,23 @@ public final class CommandComputerCraft extends CommandDelegate
}
}
private static TrackingContext getTimingContext( CommandContext context )
@Nonnull
private static TrackingContext getTimingContext( CommandSource source )
{
Entity entity = context.getSender().getCommandSenderEntity();
if( entity instanceof EntityPlayerMP )
{
return Tracking.getContext( entity.getUniqueID() );
}
else
{
return Tracking.getContext( SYSTEM_UUID );
}
Entity entity = source.getEntity();
return entity instanceof EntityPlayer ? Tracking.getContext( entity.getUniqueID() ) : Tracking.getContext( SYSTEM_UUID );
}
private static void displayTimings( CommandContext context, List<ComputerTracker> timings, TrackingField field ) throws CommandException
private static final List<TrackingField> DEFAULT_FIELDS = Arrays.asList( TrackingField.TASKS, TrackingField.TOTAL_TIME, TrackingField.AVERAGE_TIME, TrackingField.MAX_TIME );
private static int displayTimings( CommandSource source, TrackingField sortField, List<TrackingField> fields ) throws CommandSyntaxException
{
if( timings.isEmpty() ) throw new CommandException( "commands.computercraft.track.dump.no_timings" );
return displayTimings( source, getTimingContext( source ).getTimings(), sortField, fields );
}
private static int displayTimings( CommandSource source, @Nonnull List<ComputerTracker> timings, @Nonnull TrackingField sortField, @Nonnull List<TrackingField> fields ) throws CommandSyntaxException
{
if( timings.isEmpty() ) throw NO_TIMINGS_EXCEPTION.create();
Map<Computer, ServerComputer> lookup = new HashMap<>();
int maxId = 0, maxInstance = 0;
@@ -459,74 +343,27 @@ public final class CommandComputerCraft extends CommandDelegate
if( server.getID() > maxId ) maxId = server.getID();
}
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( field ) ).reversed() );
timings.sort( Comparator.<ComputerTracker, Long>comparing( x -> x.get( sortField ) ).reversed() );
boolean defaultLayout = field == TrackingField.TASKS || field == TrackingField.TOTAL_TIME
|| field == TrackingField.AVERAGE_TIME || field == TrackingField.MAX_TIME;
TableBuilder table = defaultLayout ? new TableBuilder(
TRACK_ID,
translate( "commands.computercraft.track.dump.computer" ),
translate( TrackingField.TASKS.translationKey() ),
translate( TrackingField.TOTAL_TIME.translationKey() ),
translate( TrackingField.AVERAGE_TIME.translationKey() ),
translate( TrackingField.MAX_TIME.translationKey() )
) : new TableBuilder(
TRACK_ID,
translate( "commands.computercraft.track.dump.computer" ),
translate( field.translationKey() )
);
ITextComponent[] headers = new ITextComponent[1 + fields.size()];
headers[0] = translate( "commands.computercraft.track.dump.computer" );
for( int i = 0; i < fields.size(); i++ ) headers[i + 1] = translate( fields.get( i ).translationKey() );
TableBuilder table = new TableBuilder( TRACK_ID, headers );
for( ComputerTracker entry : timings )
{
Computer computer = entry.getComputer();
ServerComputer serverComputer = computer == null ? null : lookup.get( computer );
ITextComponent computerComponent = linkComputer( context, serverComputer, entry.getComputerId() );
ITextComponent computerComponent = linkComputer( source, serverComputer, entry.getComputerId() );
if( defaultLayout )
{
table.row(
computerComponent,
text( entry.getFormatted( TrackingField.TASKS ) ),
text( entry.getFormatted( TrackingField.TOTAL_TIME ) ),
text( entry.getFormatted( TrackingField.AVERAGE_TIME ) ),
text( entry.getFormatted( TrackingField.MAX_TIME ) )
);
}
else
{
table.row( computerComponent, text( entry.getFormatted( field ) ) );
}
ITextComponent[] row = new ITextComponent[1 + fields.size()];
row[0] = computerComponent;
for( int i = 0; i < fields.size(); i++ ) row[i + 1] = text( entry.getFormatted( fields.get( i ) ) );
table.row( row );
}
table.display( context.getSender() );
}
private static void withComputers( List<String> selectors, Consumer<Collection<ServerComputer>> action ) throws CommandException
{
Set<ServerComputer> computers = Sets.newHashSet();
List<String> failed = new ArrayList<>();
if( selectors.isEmpty() )
{
computers.addAll( ComputerCraft.serverComputerRegistry.getComputers() );
}
else
{
for( String selector : selectors )
{
List<ServerComputer> selected = ComputerSelector.getComputers( selector );
computers.addAll( selected );
if( selected.isEmpty() ) failed.add( selector );
}
}
action.accept( computers );
if( !failed.isEmpty() )
{
throw new CommandException( "commands.computercraft.argument.no_matching", String.join( ", ", failed ) );
}
table.display( source );
return timings.size();
}
}