1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-02-10 16:10:05 +00:00

Delete previous chat messages of the same type

This uses a custom ComputerCraft packet to send chat messages to the
client. When received, we delete all messages of the same category
before sending the new ones.

This avoids cluttering the chat with near-identical messages, and helps
make working with the "individual dump" command easier, as the previous
computer's dump output is deleted.

Also change the max height of the TextTable to 18, so it fits within
Minecraft's default chat limit.
This commit is contained in:
SquidDev 2018-05-15 11:44:23 +01:00
parent 5bf9f9e3c5
commit 7ec8ddcf7d
5 changed files with 100 additions and 27 deletions

View File

@ -34,8 +34,10 @@ import dan200.computercraft.shared.proxy.ComputerCraftProxyCommon;
import dan200.computercraft.shared.turtle.blocks.TileTurtle; import dan200.computercraft.shared.turtle.blocks.TileTurtle;
import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera; import dan200.computercraft.shared.turtle.entity.TurtleVisionCamera;
import dan200.computercraft.shared.util.Colour; import dan200.computercraft.shared.util.Colour;
import gnu.trove.map.hash.TIntIntHashMap;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.renderer.ItemMeshDefinition; import net.minecraft.client.renderer.ItemMeshDefinition;
import net.minecraft.client.renderer.block.model.ModelBakery; import net.minecraft.client.renderer.block.model.ModelBakery;
import net.minecraft.client.renderer.block.model.ModelResourceLocation; import net.minecraft.client.renderer.block.model.ModelResourceLocation;
@ -50,6 +52,7 @@ import net.minecraft.util.IThreadListener;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
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.util.text.ITextComponent;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.minecraftforge.client.event.ModelRegistryEvent; import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.client.event.RenderGameOverlayEvent;
@ -71,6 +74,8 @@ import java.util.List;
public class ComputerCraftProxyClient extends ComputerCraftProxyCommon public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{ {
private static TIntIntHashMap lastCounts = new TIntIntHashMap();
private long m_tick; private long m_tick;
private long m_renderFrame; private long m_renderFrame;
private FixedWidthFontRenderer m_fixedWidthFontRenderer; private FixedWidthFontRenderer m_fixedWidthFontRenderer;
@ -384,6 +389,7 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
case ComputerCraftPacket.ComputerTerminalChanged: case ComputerCraftPacket.ComputerTerminalChanged:
case ComputerCraftPacket.ComputerDeleted: case ComputerCraftPacket.ComputerDeleted:
case ComputerCraftPacket.PlayRecord: case ComputerCraftPacket.PlayRecord:
case ComputerCraftPacket.PostChat:
{ {
// Packet from Server to Client // Packet from Server to Client
IThreadListener listener = Minecraft.getMinecraft(); IThreadListener listener = Minecraft.getMinecraft();
@ -450,6 +456,36 @@ public class ComputerCraftProxyClient extends ComputerCraftProxyCommon
{ {
mc.world.playRecord( pos, null ); mc.world.playRecord( pos, null );
} }
break;
}
case ComputerCraftPacket.PostChat:
{
/*
This allows us to send delete chat messages of the same "category" as the previous one.
It's used by the various /computercraft commands to avoid filling the chat with repetitive
messages.
*/
int id = packet.m_dataInt[0];
ITextComponent[] components = new ITextComponent[packet.m_dataString.length];
for( int i = 0; i < packet.m_dataString.length; i++ )
{
components[i] = ITextComponent.Serializer.jsonToComponent( packet.m_dataString[i] );
}
GuiNewChat chat = Minecraft.getMinecraft().ingameGUI.getChatGUI();
// Keep track of how many lines we wrote last time, deleting any extra ones.
int lastCount = lastCounts.get( id );
for( int i = components.length; i < lastCount; i++ ) chat.deleteChatLine( i + id );
lastCounts.put( id, components.length );
// Add new lines
for( int i = 0; i < components.length; i++ )
{
chat.printChatMessageWithOptionalDeletion( components[i], id + i );
}
break;
} }
} }

View File

@ -99,7 +99,7 @@ public class ComputerTracker
if( field == TrackingField.TASKS ) return tasks; if( field == TrackingField.TASKS ) return tasks;
if( field == TrackingField.MAX_TIME ) return maxTime; if( field == TrackingField.MAX_TIME ) return maxTime;
if( field == TrackingField.TOTAL_TIME ) return totalTime; if( field == TrackingField.TOTAL_TIME ) return totalTime;
if( field == TrackingField.AVERAGE_TIME ) return totalTime / tasks; if( field == TrackingField.AVERAGE_TIME ) return tasks == 0 ? 0 : totalTime / tasks;
if( field == TrackingField.SERVER_COUNT ) return serverCount; if( field == TrackingField.SERVER_COUNT ) return serverCount;
if( field == TrackingField.SERVER_TIME ) return serverTime; if( field == TrackingField.SERVER_TIME ) return serverTime;

View File

@ -31,6 +31,10 @@ public final class CommandComputerCraft extends CommandDelegate
{ {
public static final UUID SYSTEM_UUID = new UUID( 0, 0 ); public static final UUID SYSTEM_UUID = new UUID( 0, 0 );
private static final int DUMP_LIST_ID = 5373952;
private static final int DUMP_SINGLE_ID = 1844510720;
private static final int TRACK_ID = 373882880;
public CommandComputerCraft() public CommandComputerCraft()
{ {
super( create() ); super( create() );
@ -55,7 +59,7 @@ public final class CommandComputerCraft extends CommandDelegate
{ {
if( arguments.size() == 0 ) if( arguments.size() == 0 )
{ {
TextTable table = new TextTable( "Instance", "Id", "On", "Position" ); TextTable table = new TextTable( DUMP_LIST_ID, "Instance", "Id", "On", "Position" );
List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() ); List<ServerComputer> computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() );
@ -101,7 +105,7 @@ public final class CommandComputerCraft extends CommandDelegate
{ {
ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) ); ServerComputer computer = ComputerSelector.getComputer( arguments.get( 0 ) );
TextTable table = new TextTable(); TextTable table = new TextTable( DUMP_SINGLE_ID );
table.addRow( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) ); table.addRow( header( "Instance" ), text( Integer.toString( computer.getInstanceID() ) ) );
table.addRow( header( "Id" ), text( Integer.toString( computer.getID() ) ) ); table.addRow( header( "Id" ), text( Integer.toString( computer.getID() ) ) );
table.addRow( header( "Label" ), text( computer.getLabel() ) ); table.addRow( header( "Label" ), text( computer.getLabel() ) );
@ -464,8 +468,8 @@ public final class CommandComputerCraft extends CommandDelegate
TextTable table = defaultLayout TextTable table = defaultLayout
? new TextTable( "Computer", "Tasks", "Total", "Average", "Maximum" ) ? new TextTable( TRACK_ID, "Computer", "Tasks", "Total", "Average", "Maximum" )
: new TextTable( "Computer", field.displayName() ); : new TextTable( TRACK_ID, "Computer", field.displayName() );
for( ComputerTracker entry : timings ) for( ComputerTracker entry : timings )
{ {

View File

@ -1,13 +1,17 @@
package dan200.computercraft.shared.command.framework; package dan200.computercraft.shared.command.framework;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.shared.network.ComputerCraftPacket;
import net.minecraft.command.ICommandSender; import net.minecraft.command.ICommandSender;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TextFormatting;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured; import static dan200.computercraft.shared.command.framework.ChatHelpers.coloured;
@ -19,23 +23,27 @@ public class TextTable
private static final ITextComponent SEPARATOR = coloured( "| ", TextFormatting.GRAY ); private static final ITextComponent SEPARATOR = coloured( "| ", TextFormatting.GRAY );
private static final ITextComponent LINE = text( "\n" ); private static final ITextComponent LINE = text( "\n" );
private final int id;
private int columns = -1; private int columns = -1;
private final ITextComponent[] header; private final ITextComponent[] header;
private final List<ITextComponent[]> rows = Lists.newArrayList(); private final List<ITextComponent[]> rows = Lists.newArrayList();
public TextTable( @Nonnull ITextComponent... header ) public TextTable( int id, @Nonnull ITextComponent... header )
{ {
this.id = id;
this.header = header; this.header = header;
this.columns = header.length; this.columns = header.length;
} }
public TextTable() public TextTable(int id)
{ {
header = null; this.id = id;
this.header = null;
} }
public TextTable( @Nonnull String... header ) public TextTable( int id, @Nonnull String... header )
{ {
this.id = id;
this.header = new ITextComponent[header.length]; this.header = new ITextComponent[header.length];
for( int i = 0; i < header.length; i++ ) for( int i = 0; i < header.length; i++ )
{ {
@ -72,9 +80,10 @@ public class TextTable
} }
} }
// Limit the number of rows to something sensible. // Limit the number of rows to fit within a single chat window on default Minecraft
int limit = isPlayer( sender ) ? 30 : 100; // options.
if( limit > rows.size() ) limit = rows.size(); int height = isPlayer( sender ) ? 18 : 100;
int limit = rows.size() <= height ? rows.size() : height - 1;
for( int y = 0; y < limit; y++ ) for( int y = 0; y < limit; y++ )
{ {
@ -95,43 +104,66 @@ public class TextTable
// TODO: Limit the widths of some entries if totalWidth > maxWidth // TODO: Limit the widths of some entries if totalWidth > maxWidth
ITextComponent out = new TextComponentString( "" ); List<ITextComponent> out = new ArrayList<>();
if( header != null ) if( header != null )
{ {
TextComponentString line = new TextComponentString( "" );
for( int i = 0; i < columns - 1; i++ ) for( int i = 0; i < columns - 1; i++ )
{ {
appendFixedWidth( out, sender, header[i], maxWidths[i] ); appendFixedWidth( line, sender, header[i], maxWidths[i] );
out.appendSibling( SEPARATOR ); line.appendSibling( SEPARATOR );
} }
out.appendSibling( header[columns - 1] ); line.appendSibling( header[columns - 1] );
out.appendSibling( LINE ); out.add( line );
// Round the width up rather than down // Round the width up rather than down
int rowCharWidth = getWidthFor( '=', sender ); int rowCharWidth = getWidthFor( '=', sender );
int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1); int rowWidth = totalWidth / rowCharWidth + (totalWidth % rowCharWidth == 0 ? 0 : 1);
out.appendSibling( coloured( StringUtils.repeat( '=', rowWidth ), TextFormatting.GRAY ) ); out.add( coloured( StringUtils.repeat( '=', rowWidth ), TextFormatting.GRAY ) );
out.appendSibling( LINE );
} }
for( int i = 0; i < limit; i++ ) for( int i = 0; i < limit; i++ )
{ {
TextComponentString line = new TextComponentString( "" );
ITextComponent[] row = rows.get( i ); ITextComponent[] row = rows.get( i );
if( i != 0 ) out.appendSibling( LINE );
for( int j = 0; j < columns - 1; j++ ) for( int j = 0; j < columns - 1; j++ )
{ {
appendFixedWidth( out, sender, row[j], maxWidths[j] ); appendFixedWidth( line, sender, row[j], maxWidths[j] );
out.appendSibling( SEPARATOR ); line.appendSibling( SEPARATOR );
} }
out.appendSibling( row[columns - 1] ); line.appendSibling( row[columns - 1] );
out.add( line );
} }
if( limit != rows.size() ) if( rows.size() > limit )
{ {
out.appendSibling( LINE ); out.add( coloured( (rows.size() - limit) + " additional rows...", TextFormatting.AQUA ) );
out.appendSibling( coloured( (rows.size() - limit) + " additional rows...", TextFormatting.AQUA ) );
} }
sender.sendMessage( out ); if( isPlayer( sender ) && id != 0 )
{
ComputerCraftPacket packet = new ComputerCraftPacket();
packet.m_packetType = ComputerCraftPacket.PostChat;
packet.m_dataInt = new int[]{ id };
String[] lines = packet.m_dataString = new String[out.size()];
for( int i = 0; i < out.size(); i++ )
{
lines[i] = ITextComponent.Serializer.componentToJson( out.get( i ) );
}
ComputerCraft.sendToPlayer( (EntityPlayerMP) sender, packet );
}
else
{
ITextComponent result = new TextComponentString( "" );
for( int i = 0; i < out.size(); i++ )
{
if( i > 0 ) result.appendSibling( LINE );
result.appendSibling( out.get( 0 ) );
}
sender.sendMessage( result );
}
} }
} }

View File

@ -33,6 +33,7 @@ public class ComputerCraftPacket
public static final byte ComputerTerminalChanged = 8; public static final byte ComputerTerminalChanged = 8;
public static final byte ComputerDeleted = 9; public static final byte ComputerDeleted = 9;
public static final byte PlayRecord = 10; public static final byte PlayRecord = 10;
public static final byte PostChat = 11;
// Packet class // Packet class
public byte m_packetType; public byte m_packetType;