1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-08 01:12:59 +00:00

Rewrite monitor networking (#453)

This moves monitor networking into its own packet, rather than serialising
using NBT. This allows us to be more flexible with how monitors are
serialised.

We now compress terminal data using gzip. This reduces the packet size
of a max-sized-monitor from ~25kb to as little as 100b.

On my test set of images (what I would consider to be the extreme end of
the "reasonable" case), we have packets from 1.4kb bytes up to 12kb,
with a mean of 6kb. Even in the worst case, this is a 2x reduction in
packet size.

While this is a fantastic win for the common case, it is not abuse-proof.
One can create a terminal with high entropy (and so uncompressible). This
will still be close to the original packet size.

In order to prevent any other abuse, we also limit the amount of monitor
data a client can possibly receive to 1MB (configurable).
This commit is contained in:
Jonathan Coates
2020-05-20 08:44:44 +01:00
committed by GitHub
parent 161a5b4707
commit d50a08a549
18 changed files with 507 additions and 72 deletions

View File

@@ -0,0 +1,94 @@
/*
* This file is part of ComputerCraft - http://www.computercraft.info
* Copyright Daniel Ratcliffe, 2011-2020. Do not distribute without permission.
* Send enquiries to dratcliffe@gmail.com
*/
package dan200.computercraft.shared.network.client;
import dan200.computercraft.ComputerCraft;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.terminal.TextBuffer;
import io.netty.buffer.Unpooled;
import net.minecraft.network.PacketBuffer;
import org.apache.logging.log4j.LogManager;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.RepeatedTest;
import java.util.Random;
import static org.junit.jupiter.api.Assertions.*;
/**
* Tests {@link TerminalState} round tripping works as expected.
*/
public class TerminalStateTest
{
@BeforeAll
public static void before()
{
ComputerCraft.log = LogManager.getLogger( ComputerCraft.MOD_ID );
}
@RepeatedTest( 5 )
public void testCompressed()
{
Terminal terminal = randomTerminal();
PacketBuffer buffer = new PacketBuffer( Unpooled.directBuffer() );
new TerminalState( true, terminal, true ).write( buffer );
checkEqual( terminal, read( buffer ) );
assertEquals( 0, buffer.readableBytes() );
}
@RepeatedTest( 5 )
public void testUncompressed()
{
Terminal terminal = randomTerminal();
PacketBuffer buffer = new PacketBuffer( Unpooled.directBuffer() );
new TerminalState( true, terminal, false ).write( buffer );
checkEqual( terminal, read( buffer ) );
assertEquals( 0, buffer.readableBytes() );
}
private static Terminal randomTerminal()
{
Random random = new Random();
Terminal terminal = new Terminal( 10, 5 );
for( int y = 0; y < terminal.getHeight(); y++ )
{
TextBuffer buffer = terminal.getLine( y );
for( int x = 0; x < buffer.length(); x++ ) buffer.setChar( x, (char) (random.nextInt( 26 ) + 65) );
}
return terminal;
}
private static void checkEqual( Terminal expected, Terminal actual )
{
assertNotNull( expected, "Expected cannot be null" );
assertNotNull( actual, "Actual cannot be null" );
assertEquals( expected.getHeight(), actual.getHeight(), "Heights must match" );
assertEquals( expected.getWidth(), actual.getWidth(), "Widths must match" );
for( int y = 0; y < expected.getHeight(); y++ )
{
assertEquals( expected.getLine( y ).toString(), actual.getLine( y ).toString() );
}
}
private static Terminal read( PacketBuffer buffer )
{
TerminalState state = new TerminalState( buffer );
assertTrue( state.colour );
if( !state.hasTerminal() ) return null;
Terminal other = new Terminal( state.width, state.height );
state.apply( other );
return other;
}
}