Add button to view computer's folder

Implementation is a little awkward, as we can't send OPEN_FILE links
from the server, so we ensure the client runs a
/computercraft open-computer ID command instead. We then intercept this
on the client side and use that to open the folder.
This commit is contained in:
Jonathan Coates 2021-05-28 22:19:04 +01:00
parent b129ae627b
commit 9f7cc00fcb
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
8 changed files with 107 additions and 79 deletions

View File

@ -0,0 +1,58 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.util.IDAssigner;
import net.minecraft.util.Util;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ClientChatEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import java.io.File;
/**
* Basic client-side commands.
*
* Simply hooks into client chat messages and intercepts matching strings.
*/
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class ClientCommands
{
public static final String OPEN_COMPUTER = "/computercraft open-computer ";
private ClientCommands()
{
}
@SubscribeEvent
public static void onClientSendMessage( ClientChatEvent event )
{
// Emulate the command on the client side
if( event.getMessage().startsWith( OPEN_COMPUTER ) )
{
event.setCanceled( true );
String idStr = event.getMessage().substring( OPEN_COMPUTER.length() ).trim();
int id;
try
{
id = Integer.parseInt( idStr );
}
catch( NumberFormatException ignore )
{
return;
}
File file = new File( IDAssigner.getDir(), "computer/" + id );
if( !file.isDirectory() ) return;
Util.getPlatform().openFile( file );
}
}
}

View File

@ -21,6 +21,7 @@
import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.inventory.ContainerViewComputer;
import dan200.computercraft.shared.network.container.ViewComputerContainerData;
import dan200.computercraft.shared.util.IDAssigner;
import net.minecraft.command.CommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
@ -37,6 +38,7 @@
import net.minecraft.world.server.ServerWorld;
import javax.annotation.Nonnull;
import java.io.File;
import java.util.*;
import static dan200.computercraft.shared.command.CommandUtils.isPlayer;
@ -320,6 +322,12 @@ private static ITextComponent linkComputer( CommandSource source, ServerComputer
) );
}
if( UserLevel.OWNER.test( source ) && isPlayer( source ) )
{
ITextComponent linkPath = linkStorage( computerId );
if( linkPath != null ) out.append( " " ).append( linkPath );
}
return out;
}
@ -339,6 +347,18 @@ private static ITextComponent linkPosition( CommandSource context, ServerCompute
}
}
private static ITextComponent linkStorage( int id )
{
File file = new File( IDAssigner.getDir(), "computer/" + id );
if( !file.isDirectory() ) return null;
return link(
text( "\u270E" ),
ClientCommands.OPEN_COMPUTER + id,
translate( "commands.computercraft.dump.open_path" )
);
}
@Nonnull
private static TrackingContext getTimingContext( CommandSource source )
{

View File

@ -1,66 +0,0 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2021. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.command;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.StringArgumentType;
import dan200.computercraft.ComputerCraft;
import net.minecraft.client.Minecraft;
import net.minecraft.command.CommandSource;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.StringTextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.client.event.ClientChatEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import static net.minecraft.command.Commands.argument;
import static net.minecraft.command.Commands.literal;
@Mod.EventBusSubscriber( modid = ComputerCraft.MOD_ID, value = Dist.CLIENT )
public final class CommandCopy
{
private static final String PREFIX = "/computercraft copy ";
private CommandCopy()
{
}
public static void register( CommandDispatcher<CommandSource> registry )
{
registry.register( literal( "computercraft" )
.then( literal( "copy" ) )
.then( argument( "message", StringArgumentType.greedyString() ) )
.executes( context -> {
Minecraft.getInstance().keyboardHandler.setClipboard( context.getArgument( "message", String.class ) );
return 1;
} )
);
}
@SubscribeEvent
public static void onClientSendMessage( ClientChatEvent event )
{
// Emulate the command on the client side
if( event.getMessage().startsWith( PREFIX ) )
{
Minecraft.getInstance().keyboardHandler.setClipboard( event.getMessage().substring( PREFIX.length() ) );
event.setCanceled( true );
}
}
public static ITextComponent createCopyText( String text )
{
StringTextComponent name = new StringTextComponent( text );
name.getStyle()
.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, PREFIX + text ) )
.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) );
return name;
}
}

View File

@ -57,14 +57,15 @@ public boolean test( CommandSource source )
{
if( this == ANYONE ) return true;
// We *always* allow level 0 stuff, even if the
MinecraftServer server = source.getServer();
Entity sender = source.getEntity();
if( server.isSingleplayer() && sender instanceof PlayerEntity &&
((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) )
if( this == OWNER || this == OWNER_OP )
{
if( this == OWNER || this == OWNER_OP ) return true;
MinecraftServer server = source.getServer();
Entity sender = source.getEntity();
if( server.isSingleplayer() && sender instanceof PlayerEntity &&
((PlayerEntity) sender).getGameProfile().getName().equalsIgnoreCase( server.getServerModName() ) )
{
return true;
}
}
return source.hasPermission( toLevel() );

View File

@ -71,11 +71,16 @@ public static ITextComponent bool( boolean value )
}
public static ITextComponent link( ITextComponent component, String command, ITextComponent toolTip )
{
return link( component, new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ), toolTip );
}
public static ITextComponent link( ITextComponent component, ClickEvent click, ITextComponent toolTip )
{
Style style = component.getStyle();
if( style.getColor() == null ) style.setColor( TextFormatting.YELLOW );
style.setClickEvent( new ClickEvent( ClickEvent.Action.RUN_COMMAND, command ) );
style.setClickEvent( click );
style.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, toolTip ) );
return component;
@ -85,4 +90,13 @@ public static ITextComponent header( String text )
{
return coloured( text, HEADER );
}
public static ITextComponent copy( String text )
{
StringTextComponent name = new StringTextComponent( text );
name.getStyle()
.setClickEvent( new ClickEvent( ClickEvent.Action.COPY_TO_CLIPBOARD, text ) )
.setHoverEvent( new HoverEvent( HoverEvent.Action.SHOW_TEXT, new TranslationTextComponent( "gui.computercraft.tooltip.copy" ) ) );
return name;
}
}

View File

@ -11,7 +11,7 @@
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.Registry;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.CapabilityUtil;
@ -268,12 +268,12 @@ public ActionResultType onActivate( PlayerEntity player, Hand hand, BlockRayTrac
if( oldName != null )
{
player.displayClientMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_disconnected",
CommandCopy.createCopyText( oldName ) ), false );
ChatHelpers.copy( oldName ) ), false );
}
if( newName != null )
{
player.displayClientMessage( new TranslationTextComponent( "chat.computercraft.wired_modem.peripheral_connected",
CommandCopy.createCopyText( newName ) ), false );
ChatHelpers.copy( newName ) ), false );
}
}

View File

@ -10,7 +10,7 @@
import dan200.computercraft.api.network.wired.IWiredElement;
import dan200.computercraft.api.network.wired.IWiredNode;
import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.shared.command.CommandCopy;
import dan200.computercraft.shared.command.text.ChatHelpers;
import dan200.computercraft.shared.common.TileGeneric;
import dan200.computercraft.shared.peripheral.modem.ModemState;
import dan200.computercraft.shared.util.CapabilityUtil;
@ -218,7 +218,7 @@ private static void sendPeripheralChanges( PlayerEntity player, String kind, Col
for( int i = 0; i < names.size(); i++ )
{
if( i > 0 ) base.append( ", " );
base.append( CommandCopy.createCopyText( names.get( i ) ) );
base.append( ChatHelpers.copy( names.get( i ) ) );
}
player.displayClientMessage( new TranslationTextComponent( kind, base ), false );

View File

@ -48,6 +48,7 @@
"commands.computercraft.dump.synopsis": "Display the status of computers.",
"commands.computercraft.dump.desc": "Display the status of all computers or specific information about one computer. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").",
"commands.computercraft.dump.action": "View more info about this computer",
"commands.computercraft.dump.open_path": "View this computer's files",
"commands.computercraft.shutdown.synopsis": "Shutdown computers remotely.",
"commands.computercraft.shutdown.desc": "Shutdown the listed computers or all if none are specified. You can specify the computer's instance id (e.g. 123), computer id (e.g #123) or label (e.g. \"@My Computer\").",
"commands.computercraft.shutdown.done": "Shutdown %s/%s computers",