diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 3a7d08cec..ef41767da 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -118,7 +118,7 @@ public class ServerComputer implements InputHandler, ComputerEnvironment { } public TerminalState getTerminalState() { - return new TerminalState(terminal); + return TerminalState.create(terminal); } public void keepAlive() { diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminal.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminal.java index 99734a9f8..e4b670ad3 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminal.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminal.java @@ -8,7 +8,6 @@ import dan200.computercraft.core.terminal.Palette; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.core.util.Colour; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; public class NetworkedTerminal extends Terminal { public NetworkedTerminal(int width, int height, boolean colour) { @@ -19,59 +18,61 @@ public class NetworkedTerminal extends Terminal { super(width, height, colour, changedCallback); } - public synchronized void write(FriendlyByteBuf buffer) { - buffer.writeInt(cursorX); - buffer.writeInt(cursorY); - buffer.writeBoolean(cursorBlink); - buffer.writeByte(cursorBackgroundColour << 4 | cursorColour); + synchronized TerminalState write() { + var contents = new byte[width * height * 2 + Palette.PALETTE_SIZE * 3]; + var idx = 0; for (var y = 0; y < height; y++) { var text = this.text[y]; var textColour = this.textColour[y]; var backColour = backgroundColour[y]; - for (var x = 0; x < width; x++) buffer.writeByte(text.charAt(x) & 0xFF); + for (var x = 0; x < width; x++) contents[idx++] = (byte) (text.charAt(x) & 0xFF); for (var x = 0; x < width; x++) { - buffer.writeByte(getColour( - backColour.charAt(x), Colour.BLACK) << 4 | - getColour(textColour.charAt(x), Colour.WHITE) - ); + contents[idx++] = (byte) (getColour(backColour.charAt(x), Colour.BLACK) << 4 | getColour(textColour.charAt(x), Colour.WHITE)); } } for (var i = 0; i < Palette.PALETTE_SIZE; i++) { - for (var channel : palette.getColour(i)) buffer.writeByte((int) (channel * 0xFF) & 0xFF); + for (var channel : palette.getColour(i)) contents[idx++] = (byte) ((int) (channel * 0xFF) & 0xFF); } + + assert idx == contents.length; + return new TerminalState(colour, width, height, cursorX, cursorY, cursorBlink, cursorColour, cursorBackgroundColour, contents); } - public synchronized void read(FriendlyByteBuf buffer) { - cursorX = buffer.readInt(); - cursorY = buffer.readInt(); - cursorBlink = buffer.readBoolean(); + synchronized void read(TerminalState state) { + resize(state.width, state.height); + cursorX = state.cursorX; + cursorY = state.cursorY; + cursorBlink = state.cursorBlink; - var cursorColour = buffer.readByte(); - cursorBackgroundColour = (cursorColour >> 4) & 0xF; - this.cursorColour = cursorColour & 0xF; + cursorBackgroundColour = state.cursorBgColour; + this.cursorColour = state.cursorFgColour; + var contents = state.contents; + var idx = 0; for (var y = 0; y < height; y++) { var text = this.text[y]; var textColour = this.textColour[y]; var backColour = backgroundColour[y]; - for (var x = 0; x < width; x++) text.setChar(x, (char) (buffer.readByte() & 0xFF)); + for (var x = 0; x < width; x++) text.setChar(x, (char) (contents[idx++] & 0xFF)); for (var x = 0; x < width; x++) { - var colour = buffer.readByte(); + var colour = contents[idx++]; backColour.setChar(x, BASE_16.charAt((colour >> 4) & 0xF)); textColour.setChar(x, BASE_16.charAt(colour & 0xF)); } } for (var i = 0; i < Palette.PALETTE_SIZE; i++) { - var r = (buffer.readByte() & 0xFF) / 255.0; - var g = (buffer.readByte() & 0xFF) / 255.0; - var b = (buffer.readByte() & 0xFF) / 255.0; + var r = (contents[idx++] & 0xFF) / 255.0; + var g = (contents[idx++] & 0xFF) / 255.0; + var b = (contents[idx++] & 0xFF) / 255.0; palette.setColour(i, r, g, b); } + + assert idx == contents.length; setChanged(); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java index 13d23561b..e756108e7 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/terminal/TerminalState.java @@ -4,8 +4,6 @@ package dan200.computercraft.shared.computer.terminal; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; import net.minecraft.network.FriendlyByteBuf; import org.jetbrains.annotations.Contract; @@ -20,53 +18,72 @@ import javax.annotation.Nullable; */ public class TerminalState { private final boolean colour; - private final int width; - private final int height; - private final ByteBuf buffer; + final int width; + final int height; + final int cursorX; + final int cursorY; + final boolean cursorBlink; + final int cursorBgColour; + final int cursorFgColour; + final byte[] contents; - public TerminalState(NetworkedTerminal terminal) { - colour = terminal.isColour(); - width = terminal.getWidth(); - height = terminal.getHeight(); - - var buf = buffer = Unpooled.buffer(); - terminal.write(new FriendlyByteBuf(buf)); + TerminalState( + boolean colour, int width, int height, int cursorX, int cursorY, boolean cursorBlink, int cursorFgColour, int cursorBgColour, byte[] contents + ) { + this.colour = colour; + this.width = width; + this.height = height; + this.cursorX = cursorX; + this.cursorY = cursorY; + this.cursorBlink = cursorBlink; + this.cursorFgColour = cursorFgColour; + this.cursorBgColour = cursorBgColour; + this.contents = contents; } @Contract("null -> null; !null -> !null") public static @Nullable TerminalState create(@Nullable NetworkedTerminal terminal) { - return terminal == null ? null : new TerminalState(terminal); + return terminal == null ? null : terminal.write(); } public TerminalState(FriendlyByteBuf buf) { colour = buf.readBoolean(); width = buf.readVarInt(); height = buf.readVarInt(); + cursorX = buf.readVarInt(); + cursorY = buf.readVarInt(); + cursorBlink = buf.readBoolean(); - var length = buf.readVarInt(); - buffer = buf.readBytes(length); + var cursorColour = buf.readByte(); + this.cursorBgColour = (cursorColour >> 4) & 0xF; + this.cursorFgColour = cursorColour & 0xF; + + contents = buf.readByteArray(); } public void write(FriendlyByteBuf buf) { buf.writeBoolean(colour); buf.writeVarInt(width); buf.writeVarInt(height); - buf.writeVarInt(buffer.readableBytes()); - buf.writeBytes(buffer, buffer.readerIndex(), buffer.readableBytes()); + buf.writeVarInt(cursorX); + buf.writeVarInt(cursorY); + buf.writeBoolean(cursorBlink); + buf.writeByte(cursorBgColour << 4 | cursorFgColour); + + buf.writeByteArray(contents); } public int size() { - return buffer.readableBytes(); + return contents.length; } public void apply(NetworkedTerminal terminal) { - terminal.resize(width, height); - terminal.read(new FriendlyByteBuf(buffer)); + terminal.read(this); } public NetworkedTerminal create() { var terminal = new NetworkedTerminal(width, height, colour); - terminal.read(new FriendlyByteBuf(buffer)); + terminal.read(this); return terminal; } } diff --git a/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminalTest.java b/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminalTest.java index 677c35a5c..36bf9a5bd 100644 --- a/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminalTest.java +++ b/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/NetworkedTerminalTest.java @@ -7,9 +7,7 @@ package dan200.computercraft.shared.computer.terminal; import dan200.computercraft.api.lua.LuaValues; import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.test.core.CallCounter; -import io.netty.buffer.Unpooled; import net.minecraft.nbt.CompoundTag; -import net.minecraft.network.FriendlyByteBuf; import org.junit.jupiter.api.Test; import static dan200.computercraft.test.core.terminal.TerminalMatchers.*; @@ -18,36 +16,6 @@ import static org.hamcrest.Matchers.allOf; import static org.junit.jupiter.api.Assertions.assertEquals; class NetworkedTerminalTest { - @Test - void testPacketBufferRoundtrip() { - var writeTerminal = new NetworkedTerminal(2, 1, true); - - blit(writeTerminal, "hi", "11", "ee"); - writeTerminal.setCursorPos(2, 5); - writeTerminal.setTextColour(3); - writeTerminal.setBackgroundColour(5); - - var packetBuffer = new FriendlyByteBuf(Unpooled.buffer()); - writeTerminal.write(packetBuffer); - - var callCounter = new CallCounter(); - var readTerminal = new NetworkedTerminal(2, 1, true, callCounter); - packetBuffer.writeBytes(packetBuffer); - readTerminal.read(packetBuffer); - - assertThat(readTerminal, allOf( - textMatches(new String[]{ "hi", }), - textColourMatches(new String[]{ "11", }), - backgroundColourMatches(new String[]{ "ee", }) - )); - - assertEquals(2, readTerminal.getCursorX()); - assertEquals(5, readTerminal.getCursorY()); - assertEquals(3, readTerminal.getTextColour()); - assertEquals(5, readTerminal.getBackgroundColour()); - callCounter.assertCalledTimes(1); - } - @Test void testNbtRoundtrip() { var writeTerminal = new NetworkedTerminal(10, 5, true); diff --git a/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java b/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java index 1d953dd2a..26e3ccfad 100644 --- a/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java +++ b/projects/common/src/test/java/dan200/computercraft/shared/computer/terminal/TerminalStateTest.java @@ -23,7 +23,7 @@ public class TerminalStateTest { var terminal = randomTerminal(); var buffer = new FriendlyByteBuf(Unpooled.directBuffer()); - new TerminalState(terminal).write(buffer); + TerminalState.create(terminal).write(buffer); checkEqual(terminal, read(buffer)); assertEquals(0, buffer.readableBytes()); @@ -37,6 +37,10 @@ public class TerminalStateTest { for (var x = 0; x < buffer.length(); x++) buffer.setChar(x, (char) (random.nextInt(26) + 65)); } + terminal.setTextColour(random.nextInt(16)); + terminal.setBackgroundColour(random.nextInt(16)); + terminal.setCursorPos(random.nextInt(terminal.getWidth()), random.nextInt(terminal.getHeight())); + return terminal; } @@ -46,6 +50,10 @@ public class TerminalStateTest { assertEquals(expected.isColour(), actual.isColour(), "isColour must match"); assertEquals(expected.getHeight(), actual.getHeight(), "Heights must match"); assertEquals(expected.getWidth(), actual.getWidth(), "Widths must match"); + assertEquals(expected.getTextColour(), actual.getTextColour(), "Text colours must match"); + assertEquals(expected.getBackgroundColour(), actual.getBackgroundColour(), "Background colours must match"); + assertEquals(expected.getCursorX(), actual.getCursorX(), "Cursor x must match"); + assertEquals(expected.getCursorY(), actual.getCursorY(), "Cursor y must match"); for (var y = 0; y < expected.getHeight(); y++) { assertEquals(expected.getLine(y).toString(), actual.getLine(y).toString());