From c49547b962186f5245a3fec457c8c53a0e8a66c1 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Fri, 21 Oct 2022 18:17:42 +0100 Subject: [PATCH] Remove ClientComputer Historically CC has maintained two computer registries; one on the server (which runs the actual computer) and one on the client (which stores the terminal and some small bits of additional data). This means when a user opens the computer UI, we send the terminal contents and store it in the client computer registry. We then send the instance id alongside the "open container" packet, which is used to look up the client computer (and thus terminal) in our client-side registry. This patch makes the computer menu syncing behaviour more consistent with vanilla. The initial terminal contents is sent alongside the "open container" packet, and subsequent terminal changes apply /just/ to the open container. Computer on/off state is synced via a vanilla ContainerData/IIntArray. Likewise, sending user input to the server now targets the open container, rather than an arbitrary instance id. The one remaining usage of ClientComputer is for pocket computers. For these, we still need to sync the current on/off/blinking state and the pocket computer light. We don't need the full ClientComputer interface for this case (after all, you can't send input to a pocket computer someone else is holding!). This means we can tear out ClientComputer and ClientComputerRegistry, replacing it with a much simpler ClientPocketComputers store. This in turn allows the following changes: - Remove IComputer, as we no longer need to abstract over client and server computers. - Likewise, we can merge ComputerRegistry into the server registry. This commit also cleans up the handling of instance IDs a little bit: ServerComputers are now responsible for generating their ID and adding/removing themselves from the registry. - As the client-side terminal will never be null, we can remove a whole bunch of null checks throughout the codebase. - As the terminal is available immediately, we don't need to explicitly pass in terminal sizes to the computer GUIs. This means we're no longer reliant on those config values on the client side! - Remove the "request computer state" packet. Pocket computers now store which players need to know the computer state, automatically sending data when a new player starts tracking the computer. --- .../dan200/computercraft/ComputerCraft.java | 7 - .../computercraft/client/ClientHooks.java | 5 +- .../computercraft/client/ClientRegistry.java | 12 +- .../client/gui/ClientInputHandler.java | 92 ++++++ .../client/gui/ComputerScreenBase.java | 22 +- .../computercraft/client/gui/GuiComputer.java | 45 +-- .../computercraft/client/gui/GuiTurtle.java | 4 +- .../client/gui/NoTermComputerScreen.java | 8 +- .../client/gui/widgets/ComputerSidebar.java | 21 +- .../client/gui/widgets/WidgetTerminal.java | 114 ++++---- .../client/pocket/ClientPocketComputers.java | 63 +++++ .../client/pocket/PocketComputerData.java | 78 ++++++ .../client/render/ItemPocketRenderer.java | 48 +--- .../computercraft/shared/CommonHooks.java | 25 +- .../dan200/computercraft/shared/Registry.java | 5 +- .../shared/command/CommandComputerCraft.java | 14 +- .../arguments/ComputersArgumentType.java | 8 +- .../shared/common/ServerTerminal.java | 2 +- .../shared/computer/blocks/ComputerProxy.java | 3 +- .../computer/blocks/TileCommandComputer.java | 4 +- .../shared/computer/blocks/TileComputer.java | 8 +- .../computer/blocks/TileComputerBase.java | 32 +-- .../shared/computer/core/ClientComputer.java | 128 --------- .../computer/core/ClientComputerRegistry.java | 16 -- .../computer/core/ComputerRegistry.java | 77 ------ .../shared/computer/core/IComputer.java | 37 --- .../shared/computer/core/InputHandler.java | 23 +- .../shared/computer/core/InputState.java | 110 -------- .../shared/computer/core/ServerComputer.java | 176 +++++------- .../computer/core/ServerComputerRegistry.java | 90 +++--- .../ComputerMenuWithoutInventory.java | 22 +- .../inventory/ContainerComputerBase.java | 206 ++++---------- .../inventory/ContainerViewComputer.java | 24 +- .../shared/computer/menu/ComputerMenu.java | 42 +++ .../ServerInputHandler.java} | 42 +-- .../computer/menu/ServerInputState.java | 261 ++++++++++++++++++ .../shared/network/NetworkHandler.java | 29 +- .../network/client/ComputerClientMessage.java | 52 ---- .../client/ComputerDataClientMessage.java | 51 ---- .../client/ComputerDeletedClientMessage.java | 29 -- .../client/ComputerTerminalClientMessage.java | 33 ++- .../network/client/MonitorClientMessage.java | 3 + .../client/PocketComputerDataMessage.java | 58 ++++ .../PocketComputerDeletedClientMessage.java | 40 +++ .../shared/network/client/TerminalState.java | 8 + .../container/ComputerContainerData.java | 21 +- .../container/ViewComputerContainerData.java | 63 ----- .../server/ComputerActionServerMessage.java | 16 +- .../network/server/ComputerServerMessage.java | 39 ++- .../network/server/ContinueUploadMessage.java | 12 +- .../network/server/KeyEventServerMessage.java | 15 +- .../server/MouseEventServerMessage.java | 14 +- .../server/QueueEventServerMessage.java | 15 +- .../server/RequestComputerMessage.java | 42 --- .../network/server/UploadFileMessage.java | 28 +- .../peripheral/monitor/ServerMonitor.java | 2 +- .../pocket/core/PocketServerComputer.java | 92 +++--- .../pocket/items/ItemPocketComputer.java | 102 ++----- .../shared/turtle/blocks/TileTurtle.java | 7 +- .../shared/turtle/core/TurtleBrain.java | 3 +- .../turtle/inventory/ContainerTurtle.java | 34 +-- 61 files changed, 1242 insertions(+), 1440 deletions(-) create mode 100644 src/main/java/dan200/computercraft/client/gui/ClientInputHandler.java create mode 100644 src/main/java/dan200/computercraft/client/pocket/ClientPocketComputers.java create mode 100644 src/main/java/dan200/computercraft/client/pocket/PocketComputerData.java delete mode 100644 src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java delete mode 100644 src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java delete mode 100644 src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java delete mode 100644 src/main/java/dan200/computercraft/shared/computer/core/IComputer.java delete mode 100644 src/main/java/dan200/computercraft/shared/computer/core/InputState.java create mode 100644 src/main/java/dan200/computercraft/shared/computer/menu/ComputerMenu.java rename src/main/java/dan200/computercraft/shared/computer/{core/IContainerComputer.java => menu/ServerInputHandler.java} (53%) create mode 100644 src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java create mode 100644 src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java create mode 100644 src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java delete mode 100644 src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java diff --git a/src/main/java/dan200/computercraft/ComputerCraft.java b/src/main/java/dan200/computercraft/ComputerCraft.java index c40041171..c6417240b 100644 --- a/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/src/main/java/dan200/computercraft/ComputerCraft.java @@ -10,8 +10,6 @@ import dan200.computercraft.core.apis.http.options.Action; import dan200.computercraft.core.apis.http.options.AddressRule; import dan200.computercraft.shared.Config; import dan200.computercraft.shared.Registry; -import dan200.computercraft.shared.computer.core.ClientComputerRegistry; -import dan200.computercraft.shared.computer.core.ServerComputerRegistry; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.pocket.peripherals.PocketModem; import dan200.computercraft.shared.pocket.peripherals.PocketSpeaker; @@ -105,11 +103,6 @@ public final class ComputerCraft public static PocketSpeaker speaker; } - // Registries - public static final ClientComputerRegistry clientComputerRegistry = new ClientComputerRegistry(); - public static final ServerComputerRegistry serverComputerRegistry = new ServerComputerRegistry(); - - // Logging public static final Logger log = LogManager.getLogger( MOD_ID ); public ComputerCraft() diff --git a/src/main/java/dan200/computercraft/client/ClientHooks.java b/src/main/java/dan200/computercraft/client/ClientHooks.java index 9d86cfda3..7b94a4aae 100644 --- a/src/main/java/dan200/computercraft/client/ClientHooks.java +++ b/src/main/java/dan200/computercraft/client/ClientHooks.java @@ -6,6 +6,7 @@ package dan200.computercraft.client; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.pocket.ClientPocketComputers; import dan200.computercraft.client.sound.SpeakerManager; import dan200.computercraft.shared.peripheral.monitor.ClientMonitor; import net.minecraftforge.api.distmarker.Dist; @@ -30,12 +31,12 @@ public class ClientHooks @SubscribeEvent public static void onLogIn( ClientPlayerNetworkEvent.LoggedInEvent event ) { - ComputerCraft.clientComputerRegistry.reset(); + ClientPocketComputers.reset(); } @SubscribeEvent public static void onLogOut( ClientPlayerNetworkEvent.LoggedOutEvent event ) { - ComputerCraft.clientComputerRegistry.reset(); + ClientPocketComputers.reset(); } } diff --git a/src/main/java/dan200/computercraft/client/ClientRegistry.java b/src/main/java/dan200/computercraft/client/ClientRegistry.java index b9e553b9b..aa0bc77c5 100644 --- a/src/main/java/dan200/computercraft/client/ClientRegistry.java +++ b/src/main/java/dan200/computercraft/client/ClientRegistry.java @@ -7,6 +7,7 @@ package dan200.computercraft.client; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.*; +import dan200.computercraft.client.pocket.ClientPocketComputers; import dan200.computercraft.client.render.TileEntityMonitorRenderer; import dan200.computercraft.client.render.TileEntityTurtleRenderer; import dan200.computercraft.client.render.TurtleModelLoader; @@ -16,7 +17,6 @@ import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import dan200.computercraft.shared.media.items.ItemDisk; import dan200.computercraft.shared.media.items.ItemTreasureDisk; -import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; import net.minecraft.client.gui.ScreenManager; import net.minecraft.client.renderer.RenderType; @@ -106,7 +106,7 @@ public final class ClientRegistry return IColouredItem.getColourBasic( stack ); case 2: // Light colour { - int light = ItemPocketComputer.getLightState( stack ); + int light = ClientPocketComputers.get( stack ).getLightState(); return light == -1 ? Colour.BLACK.getHex() : light; } } @@ -140,7 +140,7 @@ public final class ClientRegistry registerContainers(); registerItemProperty( "state", - ( stack, world, player ) -> ItemPocketComputer.getState( stack ).ordinal(), + ( stack, world, player ) -> ClientPocketComputers.get( stack ).getState().ordinal(), Registry.ModItems.POCKET_COMPUTER_NORMAL, Registry.ModItems.POCKET_COMPUTER_ADVANCED ); registerItemProperty( "coloured", @@ -165,8 +165,8 @@ public final class ClientRegistry { // My IDE doesn't think so, but we do actually need these generics. - ScreenManager.>register( Registry.ModContainers.COMPUTER.get(), GuiComputer::create ); - ScreenManager.>register( Registry.ModContainers.POCKET_COMPUTER.get(), GuiComputer::createPocket ); + ScreenManager.>register( Registry.ModContainers.COMPUTER.get(), GuiComputer::new ); + ScreenManager.>register( Registry.ModContainers.POCKET_COMPUTER.get(), GuiComputer::new ); ScreenManager.>register( Registry.ModContainers.POCKET_COMPUTER_NO_TERM.get(), NoTermComputerScreen::new ); ScreenManager.register( Registry.ModContainers.TURTLE.get(), GuiTurtle::new ); @@ -174,6 +174,6 @@ public final class ClientRegistry ScreenManager.register( Registry.ModContainers.DISK_DRIVE.get(), GuiDiskDrive::new ); ScreenManager.register( Registry.ModContainers.PRINTOUT.get(), GuiPrintout::new ); - ScreenManager.>register( Registry.ModContainers.VIEW_COMPUTER.get(), GuiComputer::createView ); + ScreenManager.>register( Registry.ModContainers.VIEW_COMPUTER.get(), GuiComputer::new ); } } diff --git a/src/main/java/dan200/computercraft/client/gui/ClientInputHandler.java b/src/main/java/dan200/computercraft/client/gui/ClientInputHandler.java new file mode 100644 index 000000000..f12a0abb9 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/gui/ClientInputHandler.java @@ -0,0 +1,92 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.gui; + +import dan200.computercraft.shared.computer.core.InputHandler; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.network.server.ComputerActionServerMessage; +import dan200.computercraft.shared.network.server.KeyEventServerMessage; +import dan200.computercraft.shared.network.server.MouseEventServerMessage; +import dan200.computercraft.shared.network.server.QueueEventServerMessage; +import net.minecraft.inventory.container.Container; + +import javax.annotation.Nullable; + +/** + * An {@link InputHandler} which for use on the client. + *

+ * This queues events on the remote player's open {@link ComputerMenu} + */ +public final class ClientInputHandler implements InputHandler +{ + private final Container menu; + + public ClientInputHandler( Container menu ) + { + this.menu = menu; + } + + @Override + public void turnOn() + { + NetworkHandler.sendToServer( new ComputerActionServerMessage( menu, ComputerActionServerMessage.Action.TURN_ON ) ); + } + + @Override + public void shutdown() + { + NetworkHandler.sendToServer( new ComputerActionServerMessage( menu, ComputerActionServerMessage.Action.SHUTDOWN ) ); + } + + @Override + public void reboot() + { + NetworkHandler.sendToServer( new ComputerActionServerMessage( menu, ComputerActionServerMessage.Action.REBOOT ) ); + } + + @Override + public void queueEvent( String event, @Nullable Object[] arguments ) + { + NetworkHandler.sendToServer( new QueueEventServerMessage( menu, event, arguments ) ); + } + + @Override + public void keyDown( int key, boolean repeat ) + { + NetworkHandler.sendToServer( new KeyEventServerMessage( menu, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key ) ); + } + + @Override + public void keyUp( int key ) + { + NetworkHandler.sendToServer( new KeyEventServerMessage( menu, KeyEventServerMessage.TYPE_UP, key ) ); + } + + @Override + public void mouseClick( int button, int x, int y ) + { + NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_CLICK, button, x, y ) ); + } + + @Override + public void mouseUp( int button, int x, int y ) + { + NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_UP, button, x, y ) ); + } + + @Override + public void mouseDrag( int button, int x, int y ) + { + NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_DRAG, button, x, y ) ); + } + + @Override + public void mouseScroll( int direction, int x, int y ) + { + NetworkHandler.sendToServer( new MouseEventServerMessage( menu, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) ); + } +} diff --git a/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java b/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java index 92b942dcf..268e256e6 100644 --- a/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java +++ b/src/main/java/dan200/computercraft/client/gui/ComputerScreenBase.java @@ -10,8 +10,9 @@ import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.ComputerSidebar; import dan200.computercraft.client.gui.widgets.DynamicImageButton; import dan200.computercraft.client.gui.widgets.WidgetTerminal; -import dan200.computercraft.shared.computer.core.ClientComputer; +import dan200.computercraft.core.terminal.Terminal; import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.InputHandler; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.computer.upload.FileUpload; import dan200.computercraft.shared.computer.upload.UploadResult; @@ -42,16 +43,18 @@ public abstract class ComputerScreenBase extend private static final ITextComponent OVERWRITE = new TranslationTextComponent( "gui.computercraft.upload.overwrite_button" ); protected WidgetTerminal terminal; - protected final ClientComputer computer; + protected Terminal terminalData; protected final ComputerFamily family; + protected final InputHandler input; protected final int sidebarYOffset; public ComputerScreenBase( T container, PlayerInventory player, ITextComponent title, int sidebarYOffset ) { super( container, player, title ); - computer = (ClientComputer) container.getComputer(); + terminalData = container.getTerminal(); family = container.getFamily(); + input = new ClientInputHandler( menu ); this.sidebarYOffset = sidebarYOffset; } @@ -64,7 +67,7 @@ public abstract class ComputerScreenBase extend minecraft.keyboardHandler.setSendRepeatsToGui( true ); terminal = addButton( createTerminal() ); - ComputerSidebar.addButtons( this, computer, this::addButton, leftPos, topPos + sidebarYOffset ); + ComputerSidebar.addButtons( this, menu::isOn, input, this::addButton, leftPos, topPos + sidebarYOffset ); setFocused( terminal ); } @@ -132,7 +135,7 @@ public abstract class ComputerScreenBase extend { if( files.isEmpty() ) return; - if( computer == null || !computer.isOn() ) + if( !menu.isOn() ) { alert( UploadResult.FAILED_TITLE, UploadResult.COMPUTER_OFF_MSG ); return; @@ -188,10 +191,7 @@ public abstract class ComputerScreenBase extend return; } - if( toUpload.size() > 0 ) - { - UploadFileMessage.send( computer.getInstanceID(), toUpload ); - } + if( toUpload.size() > 0 ) UploadFileMessage.send( menu, toUpload ); } public void uploadResult( UploadResult result, ITextComponent message ) @@ -220,13 +220,13 @@ public abstract class ComputerScreenBase extend private void continueUpload() { if( minecraft.screen instanceof OptionScreen ) ((OptionScreen) minecraft.screen).disable(); - NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), true ) ); + NetworkHandler.sendToServer( new ContinueUploadMessage( menu, true ) ); } private void cancelUpload() { minecraft.setScreen( this ); - NetworkHandler.sendToServer( new ContinueUploadMessage( computer.getInstanceID(), false ) ); + NetworkHandler.sendToServer( new ContinueUploadMessage( menu, false ) ); } private void alert( ITextComponent title, ITextComponent message ) diff --git a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java index bf2e39de7..daff80f65 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiComputer.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiComputer.java @@ -6,12 +6,11 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.matrix.MatrixStack; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.ComputerSidebar; import dan200.computercraft.client.gui.widgets.WidgetTerminal; import dan200.computercraft.client.render.ComputerBorderRenderer; +import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; -import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.util.text.ITextComponent; @@ -22,50 +21,20 @@ import static dan200.computercraft.client.render.RenderTypes.FULL_BRIGHT_LIGHTMA public final class GuiComputer extends ComputerScreenBase { - private final int termWidth; - private final int termHeight; - - private GuiComputer( - T container, PlayerInventory player, ITextComponent title, int termWidth, int termHeight - ) + public GuiComputer( T container, PlayerInventory player, ITextComponent title ) { super( container, player, title, BORDER ); - this.termWidth = termWidth; - this.termHeight = termHeight; - imageWidth = WidgetTerminal.getWidth( termWidth ) + BORDER * 2 + ComputerSidebar.WIDTH; - imageHeight = WidgetTerminal.getHeight( termHeight ) + BORDER * 2; - } - - public static GuiComputer create( ContainerComputerBase container, PlayerInventory inventory, ITextComponent component ) - { - return new GuiComputer<>( - container, inventory, component, - ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight - ); - } - - public static GuiComputer createPocket( ContainerComputerBase container, PlayerInventory inventory, ITextComponent component ) - { - return new GuiComputer<>( - container, inventory, component, - ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight - ); - } - - public static GuiComputer createView( ContainerViewComputer container, PlayerInventory inventory, ITextComponent component ) - { - return new GuiComputer<>( - container, inventory, component, - container.getWidth(), container.getHeight() - ); + imageWidth = WidgetTerminal.getWidth( terminalData.getWidth() ) + BORDER * 2 + ComputerSidebar.WIDTH; + imageHeight = WidgetTerminal.getHeight( terminalData.getHeight() ) + BORDER * 2; } @Override protected WidgetTerminal createTerminal() { - return new WidgetTerminal( computer, - leftPos + ComputerSidebar.WIDTH + BORDER, topPos + BORDER, termWidth, termHeight + return new WidgetTerminal( + getMenu().getFamily() != ComputerFamily.NORMAL, terminalData, input, + leftPos + ComputerSidebar.WIDTH + BORDER, topPos + BORDER ); } diff --git a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java index 1e48e0e6a..eec24f88a 100644 --- a/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java +++ b/src/main/java/dan200/computercraft/client/gui/GuiTurtle.java @@ -44,8 +44,8 @@ public class GuiTurtle extends ComputerScreenBase protected WidgetTerminal createTerminal() { return new WidgetTerminal( - computer, leftPos + BORDER + ComputerSidebar.WIDTH, topPos + BORDER, - ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight + getMenu().getFamily() != ComputerFamily.NORMAL, terminalData, input, + leftPos + BORDER + ComputerSidebar.WIDTH, topPos + BORDER ); } diff --git a/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java b/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java index 6fcdd7753..3632914c1 100644 --- a/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java +++ b/src/main/java/dan200/computercraft/client/gui/NoTermComputerScreen.java @@ -6,9 +6,9 @@ package dan200.computercraft.client.gui; import com.mojang.blaze3d.matrix.MatrixStack; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.gui.widgets.WidgetTerminal; -import dan200.computercraft.shared.computer.core.ClientComputer; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.IHasContainer; @@ -26,12 +26,14 @@ import java.util.List; public class NoTermComputerScreen extends Screen implements IHasContainer { private final T menu; + private final Terminal terminalData; private WidgetTerminal terminal; public NoTermComputerScreen( T menu, PlayerInventory player, ITextComponent title ) { super( title ); this.menu = menu; + terminalData = menu.getTerminal(); } @Nonnull @@ -54,7 +56,7 @@ public class NoTermComputerScreen extends Scree super.init(); minecraft.keyboardHandler.setSendRepeatsToGui( true ); - terminal = addWidget( new WidgetTerminal( (ClientComputer) menu.getComputer(), 0, 0, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ) ); + terminal = addWidget( new WidgetTerminal( getMenu().getFamily() != ComputerFamily.NORMAL, terminalData, new ClientInputHandler( menu ), 0, 0 ) ); terminal.visible = false; terminal.active = false; setFocused( terminal ); diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java b/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java index 100d68a6c..1ec68d08c 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/ComputerSidebar.java @@ -8,7 +8,7 @@ package dan200.computercraft.client.gui.widgets; import com.mojang.blaze3d.matrix.MatrixStack; import dan200.computercraft.ComputerCraft; import dan200.computercraft.client.render.ComputerBorderRenderer; -import dan200.computercraft.shared.computer.core.ClientComputer; +import dan200.computercraft.shared.computer.core.InputHandler; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.gui.widget.Widget; import net.minecraft.util.ResourceLocation; @@ -16,6 +16,7 @@ import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; import java.util.Arrays; +import java.util.function.BooleanSupplier; import java.util.function.Consumer; /** @@ -44,15 +45,15 @@ public final class ComputerSidebar { } - public static void addButtons( Screen screen, ClientComputer computer, Consumer add, int x, int y ) + public static void addButtons( Screen screen, BooleanSupplier isOn, InputHandler input, Consumer add, int x, int y ) { x += CORNERS_BORDER + 1; y += CORNERS_BORDER + ICON_MARGIN; add.accept( new DynamicImageButton( - screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> computer.isOn() ? 15 : 1, 1, ICON_TEX_Y_DIFF, - TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( computer ), - () -> computer.isOn() ? Arrays.asList( + screen, x, y, ICON_WIDTH, ICON_HEIGHT, () -> isOn.getAsBoolean() ? 15 : 1, 1, ICON_TEX_Y_DIFF, + TEXTURE, TEX_SIZE, TEX_SIZE, b -> toggleComputer( isOn, input ), + () -> isOn.getAsBoolean() ? Arrays.asList( new TranslationTextComponent( "gui.computercraft.tooltip.turn_off" ), new TranslationTextComponent( "gui.computercraft.tooltip.turn_off.key" ).withStyle( TextFormatting.GRAY ) ) : Arrays.asList( @@ -65,7 +66,7 @@ public final class ComputerSidebar add.accept( new DynamicImageButton( screen, x, y, ICON_WIDTH, ICON_HEIGHT, 29, 1, ICON_TEX_Y_DIFF, - TEXTURE, TEX_SIZE, TEX_SIZE, b -> computer.queueEvent( "terminate" ), + TEXTURE, TEX_SIZE, TEX_SIZE, b -> input.queueEvent( "terminate" ), Arrays.asList( new TranslationTextComponent( "gui.computercraft.tooltip.terminate" ), new TranslationTextComponent( "gui.computercraft.tooltip.terminate.key" ).withStyle( TextFormatting.GRAY ) @@ -92,15 +93,15 @@ public final class ComputerSidebar ); } - private static void toggleComputer( ClientComputer computer ) + private static void toggleComputer( BooleanSupplier isOn, InputHandler input ) { - if( computer.isOn() ) + if( isOn.getAsBoolean() ) { - computer.shutdown(); + input.shutdown(); } else { - computer.turnOn(); + input.turnOn(); } } } diff --git a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java index 056af5604..a2b1bafae 100644 --- a/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java +++ b/src/main/java/dan200/computercraft/client/gui/widgets/WidgetTerminal.java @@ -11,7 +11,7 @@ import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.client.render.RenderTypes; import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.shared.computer.core.ClientComputer; +import dan200.computercraft.shared.computer.core.InputHandler; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.widget.Widget; import net.minecraft.client.renderer.IRenderTypeBuffer; @@ -33,7 +33,10 @@ public class WidgetTerminal extends Widget { private static final float TERMINATE_TIME = 0.5f; - private final ClientComputer computer; + private final boolean isColour; + private final @Nonnull Terminal terminal; + private final @Nonnull InputHandler computer; + // The positions of the actual terminal private final int innerX; @@ -51,16 +54,18 @@ public class WidgetTerminal extends Widget private final BitSet keysDown = new BitSet( 256 ); - public WidgetTerminal( @Nonnull ClientComputer computer, int x, int y, int termWidth, int termHeight ) + public WidgetTerminal( boolean isColour, @Nonnull Terminal terminal, @Nonnull InputHandler computer, int x, int y ) { - super( x, y, termWidth * FONT_WIDTH + MARGIN * 2, termHeight * FONT_HEIGHT + MARGIN * 2, StringTextComponent.EMPTY ); + super( x, y, terminal.getWidth() * FONT_WIDTH + MARGIN * 2, terminal.getHeight() * FONT_HEIGHT + MARGIN * 2, StringTextComponent.EMPTY ); + this.isColour = isColour; + this.terminal = terminal; this.computer = computer; innerX = x + MARGIN; innerY = y + MARGIN; - innerWidth = termWidth * FONT_WIDTH; - innerHeight = termHeight * FONT_HEIGHT; + innerWidth = terminal.getWidth() * FONT_WIDTH; + innerHeight = terminal.getHeight() * FONT_HEIGHT; } @Override @@ -173,22 +178,18 @@ public class WidgetTerminal extends Widget public boolean mouseClicked( double mouseX, double mouseY, int button ) { if( !inTermRegion( mouseX, mouseY ) ) return false; - if( !computer.isColour() || button < 0 || button > 2 ) return false; + if( !isColour || button < 0 || button > 2 ) return false; - Terminal term = computer.getTerminal(); - if( term != null ) - { - int charX = (int) ((mouseX - innerX) / FONT_WIDTH); - int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); - charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); - charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); + int charX = (int) ((mouseX - innerX) / FONT_WIDTH); + int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 ); - computer.mouseClick( button + 1, charX + 1, charY + 1 ); + computer.mouseClick( button + 1, charX + 1, charY + 1 ); - lastMouseButton = button; - lastMouseX = charX; - lastMouseY = charY; - } + lastMouseButton = button; + lastMouseX = charX; + lastMouseY = charY; return true; } @@ -197,26 +198,22 @@ public class WidgetTerminal extends Widget public boolean mouseReleased( double mouseX, double mouseY, int button ) { if( !inTermRegion( mouseX, mouseY ) ) return false; - if( !computer.isColour() || button < 0 || button > 2 ) return false; + if( !isColour || button < 0 || button > 2 ) return false; - Terminal term = computer.getTerminal(); - if( term != null ) + int charX = (int) ((mouseX - innerX) / FONT_WIDTH); + int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 ); + + if( lastMouseButton == button ) { - int charX = (int) ((mouseX - innerX) / FONT_WIDTH); - int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); - charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); - charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); - - if( lastMouseButton == button ) - { - computer.mouseUp( lastMouseButton + 1, charX + 1, charY + 1 ); - lastMouseButton = -1; - } - - lastMouseX = charX; - lastMouseY = charY; + computer.mouseUp( lastMouseButton + 1, charX + 1, charY + 1 ); + lastMouseButton = -1; } + lastMouseX = charX; + lastMouseY = charY; + return false; } @@ -224,22 +221,18 @@ public class WidgetTerminal extends Widget public boolean mouseDragged( double mouseX, double mouseY, int button, double v2, double v3 ) { if( !inTermRegion( mouseX, mouseY ) ) return false; - if( !computer.isColour() || button < 0 || button > 2 ) return false; + if( !isColour || button < 0 || button > 2 ) return false; - Terminal term = computer.getTerminal(); - if( term != null ) + int charX = (int) ((mouseX - innerX) / FONT_WIDTH); + int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 ); + + if( button == lastMouseButton && (charX != lastMouseX || charY != lastMouseY) ) { - int charX = (int) ((mouseX - innerX) / FONT_WIDTH); - int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); - charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); - charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); - - if( button == lastMouseButton && (charX != lastMouseX || charY != lastMouseY) ) - { - computer.mouseDrag( button + 1, charX + 1, charY + 1 ); - lastMouseX = charX; - lastMouseY = charY; - } + computer.mouseDrag( button + 1, charX + 1, charY + 1 ); + lastMouseX = charX; + lastMouseY = charY; } return false; @@ -249,21 +242,17 @@ public class WidgetTerminal extends Widget public boolean mouseScrolled( double mouseX, double mouseY, double delta ) { if( !inTermRegion( mouseX, mouseY ) ) return false; - if( !computer.isColour() || delta == 0 ) return false; + if( !isColour || delta == 0 ) return false; - Terminal term = computer.getTerminal(); - if( term != null ) - { - int charX = (int) ((mouseX - innerX) / FONT_WIDTH); - int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); - charX = Math.min( Math.max( charX, 0 ), term.getWidth() - 1 ); - charY = Math.min( Math.max( charY, 0 ), term.getHeight() - 1 ); + int charX = (int) ((mouseX - innerX) / FONT_WIDTH); + int charY = (int) ((mouseY - innerY) / FONT_HEIGHT); + charX = Math.min( Math.max( charX, 0 ), terminal.getWidth() - 1 ); + charY = Math.min( Math.max( charY, 0 ), terminal.getHeight() - 1 ); - computer.mouseScroll( delta < 0 ? 1 : -1, charX + 1, charY + 1 ); + computer.mouseScroll( delta < 0 ? 1 : -1, charX + 1, charY + 1 ); - lastMouseX = charX; - lastMouseY = charY; - } + lastMouseX = charX; + lastMouseY = charY; return true; } @@ -319,7 +308,6 @@ public class WidgetTerminal extends Widget { if( !visible ) return; Matrix4f matrix = transform.last().pose(); - Terminal terminal = computer.getTerminal(); Minecraft.getInstance().getTextureManager().bind( FixedWidthFontRenderer.FONT ); RenderSystem.texParameter( GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP ); @@ -329,7 +317,7 @@ public class WidgetTerminal extends Widget if( terminal != null ) { - FixedWidthFontRenderer.drawTerminal( matrix, buffer, innerX, innerY, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN ); + FixedWidthFontRenderer.drawTerminal( matrix, buffer, innerX, innerY, terminal, !isColour, MARGIN, MARGIN, MARGIN, MARGIN ); } else { diff --git a/src/main/java/dan200/computercraft/client/pocket/ClientPocketComputers.java b/src/main/java/dan200/computercraft/client/pocket/ClientPocketComputers.java new file mode 100644 index 000000000..504df0c89 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/pocket/ClientPocketComputers.java @@ -0,0 +1,63 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.pocket; + +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.items.ItemComputer; +import dan200.computercraft.shared.network.client.PocketComputerDataMessage; +import dan200.computercraft.shared.pocket.items.ItemPocketComputer; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import net.minecraft.item.ItemStack; + +import javax.annotation.Nonnull; + +/** + * Maps {@link ServerComputer#getInstanceID()} to locals {@link PocketComputerData}. + *

+ * This is populated by {@link PocketComputerDataMessage} and accessed when rendering pocket computers + */ +public final class ClientPocketComputers +{ + private static final Int2ObjectMap instances = new Int2ObjectOpenHashMap<>(); + + private ClientPocketComputers() + { + } + + public static void reset() + { + instances.clear(); + } + + public static void remove( int id ) + { + instances.remove( id ); + } + + /** + * Get or create a pocket computer. + * + * @param instanceId The instance ID of the pocket computer. + * @param advanced Whether this computer has an advanced terminal. + * @return The pocket computer data. + */ + @Nonnull + public static PocketComputerData get( int instanceId, boolean advanced ) + { + PocketComputerData computer = instances.get( instanceId ); + if( computer == null ) instances.put( instanceId, computer = new PocketComputerData( advanced ) ); + return computer; + } + + @Nonnull + public static PocketComputerData get( ItemStack stack ) + { + ComputerFamily family = stack.getItem() instanceof ItemComputer ? ((ItemComputer) stack.getItem()).getFamily() : ComputerFamily.NORMAL; + return get( ItemPocketComputer.getInstanceID( stack ), family != ComputerFamily.NORMAL ); + } +} diff --git a/src/main/java/dan200/computercraft/client/pocket/PocketComputerData.java b/src/main/java/dan200/computercraft/client/pocket/PocketComputerData.java new file mode 100644 index 000000000..671eb4f15 --- /dev/null +++ b/src/main/java/dan200/computercraft/client/pocket/PocketComputerData.java @@ -0,0 +1,78 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.client.pocket; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.computer.core.ComputerState; +import dan200.computercraft.shared.network.client.TerminalState; +import dan200.computercraft.shared.pocket.core.PocketServerComputer; + +import javax.annotation.Nonnull; + +/** + * Clientside data about a pocket computer. + *

+ * Normal computers don't store any state long-term on the client - everything is tied to the container and only synced + * while the UI is open. Pocket computers are a little more complex, as their on/off state is visible on the item's + * texture, and the terminal can be viewed at any time. This class is what holds this needed data clientside. + * + * @see ClientPocketComputers The registry which holds pocket computers. + * @see PocketServerComputer The server-side pocket computer. + */ +public class PocketComputerData +{ + private boolean isColour; + private Terminal terminal; + private ComputerState state = ComputerState.OFF; + private int lightColour = -1; + + public PocketComputerData( boolean colour ) + { + isColour = colour; + terminal = new Terminal( ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); + } + + public int getLightState() + { + return state != ComputerState.OFF ? lightColour : -1; + } + + public boolean isColour() + { + return isColour; + } + + @Nonnull + public Terminal getTerminal() + { + return terminal; + } + + public ComputerState getState() + { + return state; + } + + public void setState( ComputerState state, int lightColour ) + { + this.state = state; + this.lightColour = lightColour; + } + + public void setTerminal( TerminalState state ) + { + isColour = state.colour; + if( state.width != terminal.getWidth() || state.height != terminal.getHeight() ) + { + terminal = state.create(); + } + else + { + state.apply( terminal ); + } + } +} diff --git a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java index c5c8b2efa..74ccdcfa4 100644 --- a/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java +++ b/src/main/java/dan200/computercraft/client/render/ItemPocketRenderer.java @@ -8,9 +8,10 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import dan200.computercraft.ComputerCraft; +import dan200.computercraft.client.pocket.ClientPocketComputers; +import dan200.computercraft.client.pocket.PocketComputerData; import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import dan200.computercraft.shared.util.Colour; @@ -56,20 +57,11 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer @Override protected void renderItem( MatrixStack transform, IRenderTypeBuffer bufferSource, ItemStack stack, int light ) { - ClientComputer computer = ItemPocketComputer.createClientComputer( stack ); - Terminal terminal = computer == null ? null : computer.getTerminal(); + PocketComputerData computer = ClientPocketComputers.get( stack ); + Terminal terminal = computer.getTerminal(); - int termWidth, termHeight; - if( terminal == null ) - { - termWidth = ComputerCraft.pocketTermWidth; - termHeight = ComputerCraft.pocketTermHeight; - } - else - { - termWidth = terminal.getWidth(); - termHeight = terminal.getHeight(); - } + int termWidth = terminal.getWidth(); + int termHeight = terminal.getHeight(); int width = termWidth * FONT_WIDTH + MARGIN * 2; int height = termHeight * FONT_HEIGHT + MARGIN * 2; @@ -94,28 +86,18 @@ public final class ItemPocketRenderer extends ItemMapLikeRenderer renderFrame( matrix, bufferSource, family, frameColour, light, width, height ); // Render the light - int lightColour = ItemPocketComputer.getLightState( stack ); + int lightColour = ClientPocketComputers.get( stack ).getLightState(); if( lightColour == -1 ) lightColour = Colour.BLACK.getHex(); renderLight( matrix, bufferSource, lightColour, width, height ); - if( computer != null && terminal != null ) - { - FixedWidthFontRenderer.drawTerminal( - matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), - MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN - ); - FixedWidthFontRenderer.drawBlocker( - matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_BLOCKER ), - 0, 0, width, height - ); - } - else - { - FixedWidthFontRenderer.drawEmptyTerminal( - matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITH_DEPTH ), - 0, 0, width, height - ); - } + FixedWidthFontRenderer.drawTerminal( + matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_WITHOUT_DEPTH ), + MARGIN, MARGIN, terminal, !computer.isColour(), MARGIN, MARGIN, MARGIN, MARGIN + ); + FixedWidthFontRenderer.drawBlocker( + matrix, bufferSource.getBuffer( RenderTypes.TERMINAL_BLOCKER ), + 0, 0, width, height + ); transform.popPose(); } diff --git a/src/main/java/dan200/computercraft/shared/CommonHooks.java b/src/main/java/dan200/computercraft/shared/CommonHooks.java index 864772eba..e48fa3d2b 100644 --- a/src/main/java/dan200/computercraft/shared/CommonHooks.java +++ b/src/main/java/dan200/computercraft/shared/CommonHooks.java @@ -12,12 +12,9 @@ import dan200.computercraft.core.filesystem.ResourceMount; import dan200.computercraft.core.tracking.ComputerMBean; import dan200.computercraft.core.tracking.Tracking; import dan200.computercraft.shared.command.CommandComputerCraft; -import dan200.computercraft.shared.computer.core.IComputer; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.ServerComputerRegistry; import dan200.computercraft.shared.peripheral.modem.wireless.WirelessNetwork; import net.minecraft.entity.EntityType; -import net.minecraft.inventory.container.Container; import net.minecraft.loot.ConstantRange; import net.minecraft.loot.LootPool; import net.minecraft.loot.LootTables; @@ -26,7 +23,6 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.util.ResourceLocation; import net.minecraftforge.event.*; -import net.minecraftforge.event.entity.player.PlayerContainerEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.server.FMLServerStartingEvent; @@ -56,22 +52,7 @@ public final class CommonHooks if( event.phase == TickEvent.Phase.START ) { MainThread.executePendingTasks(); - ComputerCraft.serverComputerRegistry.update(); - } - } - - @SubscribeEvent - public static void onContainerOpen( PlayerContainerEvent.Open event ) - { - // If we're opening a computer container then broadcast the terminal state - Container container = event.getContainer(); - if( container instanceof IContainerComputer ) - { - IComputer computer = ((IContainerComputer) container).getComputer(); - if( computer instanceof ServerComputer ) - { - ((ServerComputer) computer).sendTerminalState( event.getPlayer() ); - } + ServerComputerRegistry.INSTANCE.update(); } } @@ -102,7 +83,7 @@ public final class CommonHooks private static void resetState() { - ComputerCraft.serverComputerRegistry.reset(); + ServerComputerRegistry.INSTANCE.reset(); MainThread.reset(); WirelessNetwork.resetNetworks(); Tracking.reset(); diff --git a/src/main/java/dan200/computercraft/shared/Registry.java b/src/main/java/dan200/computercraft/shared/Registry.java index cf141a0a6..8710b434f 100644 --- a/src/main/java/dan200/computercraft/shared/Registry.java +++ b/src/main/java/dan200/computercraft/shared/Registry.java @@ -37,7 +37,6 @@ import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.network.container.ContainerData; import dan200.computercraft.shared.network.container.HeldItemContainerData; -import dan200.computercraft.shared.network.container.ViewComputerContainerData; import dan200.computercraft.shared.peripheral.diskdrive.BlockDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.ContainerDiskDrive; import dan200.computercraft.shared.peripheral.diskdrive.TileDiskDrive; @@ -306,7 +305,7 @@ public final class Registry () -> ContainerData.toType( ComputerContainerData::new, ComputerMenuWithoutInventory::new ) ); public static final RegistryObject> TURTLE = CONTAINERS.register( "turtle", - () -> ContainerData.toType( ComputerContainerData::new, ContainerTurtle::new ) ); + () -> ContainerData.toType( ComputerContainerData::new, ContainerTurtle::ofMenuData ) ); public static final RegistryObject> DISK_DRIVE = CONTAINERS.register( "disk_drive", () -> new ContainerType<>( ContainerDiskDrive::new ) ); @@ -318,7 +317,7 @@ public final class Registry () -> ContainerData.toType( HeldItemContainerData::new, ContainerHeldItem::createPrintout ) ); public static final RegistryObject> VIEW_COMPUTER = CONTAINERS.register( "view_computer", - () -> ContainerData.toType( ViewComputerContainerData::new, ContainerViewComputer::new ) ); + () -> ContainerData.toType( ComputerContainerData::new, ContainerViewComputer::new ) ); } @SubscribeEvent diff --git a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java index 70e000046..8fe36725a 100644 --- a/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java +++ b/src/main/java/dan200/computercraft/shared/command/CommandComputerCraft.java @@ -8,7 +8,6 @@ package dan200.computercraft.shared.command; 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.computer.Computer; import dan200.computercraft.core.computer.ComputerSide; @@ -19,8 +18,9 @@ import dan200.computercraft.core.tracking.TrackingField; 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.computer.core.ServerComputerRegistry; import dan200.computercraft.shared.computer.inventory.ContainerViewComputer; -import dan200.computercraft.shared.network.container.ViewComputerContainerData; +import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.util.IDAssigner; import net.minecraft.command.CommandSource; import net.minecraft.entity.Entity; @@ -75,7 +75,7 @@ public final class CommandComputerCraft TableBuilder table = new TableBuilder( DUMP_LIST_ID, "Computer", "On", "Position" ); CommandSource source = context.getSource(); - List computers = new ArrayList<>( ComputerCraft.serverComputerRegistry.getComputers() ); + List computers = new ArrayList<>( ServerComputerRegistry.INSTANCE.getComputers() ); // Unless we're on a server, limit the number of rows we can send. World world = source.getLevel(); @@ -140,7 +140,7 @@ public final class CommandComputerCraft .then( command( "shutdown" ) .requires( UserLevel.OWNER_OP ) - .argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() ) + .argManyValue( "computers", manyComputers(), s -> ServerComputerRegistry.INSTANCE.getComputers() ) .executes( ( context, computerSelectors ) -> { int shutdown = 0; Set computers = unwrap( context.getSource(), computerSelectors ); @@ -155,7 +155,7 @@ public final class CommandComputerCraft .then( command( "turn-on" ) .requires( UserLevel.OWNER_OP ) - .argManyValue( "computers", manyComputers(), s -> ComputerCraft.serverComputerRegistry.getComputers() ) + .argManyValue( "computers", manyComputers(), s -> ServerComputerRegistry.INSTANCE.getComputers() ) .executes( ( context, computerSelectors ) -> { int on = 0; Set computers = unwrap( context.getSource(), computerSelectors ); @@ -226,7 +226,7 @@ public final class CommandComputerCraft .executes( context -> { ServerPlayerEntity player = context.getSource().getPlayerOrException(); ServerComputer computer = getComputerArgument( context, "computer" ); - new ViewComputerContainerData( computer ).open( player, new INamedContainerProvider() + new ComputerContainerData( computer ).open( player, new INamedContainerProvider() { @Nonnull @Override @@ -382,7 +382,7 @@ public final class CommandComputerCraft Map lookup = new HashMap<>(); int maxId = 0, maxInstance = 0; - for( ServerComputer server : ComputerCraft.serverComputerRegistry.getComputers() ) + for( ServerComputer server : ServerComputerRegistry.INSTANCE.getComputers() ) { lookup.put( server.getComputer(), server ); diff --git a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java index 242cdf850..d4bf2be5d 100644 --- a/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java +++ b/src/main/java/dan200/computercraft/shared/command/arguments/ComputersArgumentType.java @@ -12,9 +12,9 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.ServerComputerRegistry; import net.minecraft.command.CommandSource; import net.minecraft.command.arguments.IArgumentSerializer; import net.minecraft.network.PacketBuffer; @@ -89,7 +89,7 @@ public final class ComputersArgumentType implements ArgumentType { - ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance ); + ServerComputer computer = ServerComputerRegistry.INSTANCE.get( instance ); return computer == null ? Collections.emptyList() : Collections.singletonList( computer ); }; } @@ -151,7 +151,7 @@ public final class ComputersArgumentType implements ArgumentType renderer ) { remaining = remaining.toLowerCase( Locale.ROOT ); - for( ServerComputer computer : ComputerCraft.serverComputerRegistry.getComputers() ) + for( ServerComputer computer : ServerComputerRegistry.INSTANCE.getComputers() ) { String converted = renderer.apply( computer ); if( converted != null && converted.toLowerCase( Locale.ROOT ).startsWith( remaining ) ) @@ -163,7 +163,7 @@ public final class ComputersArgumentType implements ArgumentType predicate ) { - return s -> Collections.unmodifiableList( ComputerCraft.serverComputerRegistry + return s -> Collections.unmodifiableList( ServerComputerRegistry.INSTANCE .getComputers() .stream() .filter( predicate ) diff --git a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java index c8f60963b..f3af43711 100644 --- a/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java +++ b/src/main/java/dan200/computercraft/shared/common/ServerTerminal.java @@ -56,7 +56,7 @@ public class ServerTerminal implements ITerminal terminalChanged.set( true ); } - public void update() + public void tickServer() { terminalChangedLastFrame = terminalChanged.getAndSet( false ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java index b60b1d2e5..a486b4288 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerProxy.java @@ -5,13 +5,12 @@ */ package dan200.computercraft.shared.computer.blocks; -import dan200.computercraft.shared.computer.core.IComputer; import dan200.computercraft.shared.computer.core.ServerComputer; import java.util.function.Supplier; /** - * A proxy object for computer objects, delegating to {@link IComputer} or {@link TileComputer} where appropriate. + * A proxy object for computer objects, delegating to {@link ServerComputer} or {@link TileComputer} where appropriate. */ public final class ComputerProxy { diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java index 4fd1664a1..a0a5c3519 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileCommandComputer.java @@ -105,9 +105,9 @@ public class TileCommandComputer extends TileComputer } @Override - protected ServerComputer createComputer( int instanceID, int id ) + protected ServerComputer createComputer( int id ) { - ServerComputer computer = super.createComputer( instanceID, id ); + ServerComputer computer = super.createComputer( id ); computer.addAPI( new CommandAPI( this ) ); return computer; } diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java index 2ef8b8ea1..2b81ce42b 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputer.java @@ -20,6 +20,7 @@ import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.Container; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.Direction; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; @@ -39,13 +40,12 @@ public class TileComputer extends TileComputerBase } @Override - protected ServerComputer createComputer( int instanceID, int id ) + protected ServerComputer createComputer( int id ) { ComputerFamily family = getFamily(); ServerComputer computer = new ServerComputer( - getLevel(), id, label, instanceID, family, - ComputerCraft.computerTermWidth, - ComputerCraft.computerTermHeight + (ServerWorld) getLevel(), id, label, family, + ComputerCraft.computerTermWidth, ComputerCraft.computerTermHeight ); computer.setPosition( getBlockPos() ); return computer; diff --git a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java index 3d4f98852..b1aac103a 100644 --- a/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/blocks/TileComputerBase.java @@ -5,7 +5,6 @@ */ package dan200.computercraft.shared.computer.blocks; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.BundledRedstone; @@ -14,6 +13,7 @@ import dan200.computercraft.shared.common.TileGeneric; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.ServerComputerRegistry; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.util.DirectionUtil; import dan200.computercraft.shared.util.RedstoneUtil; @@ -81,11 +81,11 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT protected void unload() { - if( instanceID >= 0 ) - { - if( !getLevel().isClientSide ) ComputerCraft.serverComputerRegistry.remove( instanceID ); - instanceID = -1; - } + if( getLevel().isClientSide ) return; + + ServerComputer computer = getServerComputer(); + if( computer != null ) computer.close(); + instanceID = -1; } @Override @@ -142,8 +142,9 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT // Regular right click to activate computer if( !getLevel().isClientSide && isUsable( player ) ) { - createServerComputer().turnOn(); - new ComputerContainerData( createServerComputer() ).open( player, this ); + ServerComputer computer = createServerComputer(); + computer.turnOn(); + new ComputerContainerData( computer ).open( player, this ); } return ActionResultType.SUCCESS; } @@ -327,7 +328,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT } } - protected abstract ServerComputer createComputer( int instanceID, int id ); + protected abstract ServerComputer createComputer( int id ); @Override public final int getComputerID() @@ -375,17 +376,12 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT if( getLevel().isClientSide ) throw new IllegalStateException( "Cannot access server computer on the client." ); boolean changed = false; - if( instanceID < 0 ) - { - instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID(); - changed = true; - } - ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instanceID ); + ServerComputer computer = ServerComputerRegistry.INSTANCE.get( instanceID ); if( computer == null ) { - computer = createComputer( instanceID, computerID ); - ComputerCraft.serverComputerRegistry.add( instanceID, computer ); + computer = createComputer( computerID ); + instanceID = computer.register(); fresh = true; changed = true; } @@ -397,7 +393,7 @@ public abstract class TileComputerBase extends TileGeneric implements IComputerT @Nullable public ServerComputer getServerComputer() { - return getLevel().isClientSide ? null : ComputerCraft.serverComputerRegistry.get( instanceID ); + return getLevel().isClientSide ? null : ServerComputerRegistry.INSTANCE.get( instanceID ); } // Networking stuff diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java deleted file mode 100644 index bb7d31637..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputer.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.computer.core; - -import dan200.computercraft.shared.common.ClientTerminal; -import dan200.computercraft.shared.network.NetworkHandler; -import dan200.computercraft.shared.network.server.*; -import net.minecraft.nbt.CompoundNBT; - -public class ClientComputer extends ClientTerminal implements IComputer -{ - private final int instanceID; - - private boolean on = false; - private boolean blinking = false; - private CompoundNBT userData = null; - - public ClientComputer( int instanceID ) - { - super( false ); - this.instanceID = instanceID; - } - - public CompoundNBT getUserData() - { - return userData; - } - - public void requestState() - { - // Request state from server - NetworkHandler.sendToServer( new RequestComputerMessage( getInstanceID() ) ); - } - - // IComputer - - @Override - public int getInstanceID() - { - return instanceID; - } - - @Override - public boolean isOn() - { - return on; - } - - @Override - public boolean isCursorDisplayed() - { - return on && blinking; - } - - @Override - public void turnOn() - { - // Send turnOn to server - NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.TURN_ON ) ); - } - - @Override - public void shutdown() - { - // Send shutdown to server - NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.SHUTDOWN ) ); - } - - @Override - public void reboot() - { - // Send reboot to server - NetworkHandler.sendToServer( new ComputerActionServerMessage( instanceID, ComputerActionServerMessage.Action.REBOOT ) ); - } - - @Override - public void queueEvent( String event, Object[] arguments ) - { - // Send event to server - NetworkHandler.sendToServer( new QueueEventServerMessage( instanceID, event, arguments ) ); - } - - @Override - public void keyDown( int key, boolean repeat ) - { - NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID, repeat ? KeyEventServerMessage.TYPE_REPEAT : KeyEventServerMessage.TYPE_DOWN, key ) ); - } - - @Override - public void keyUp( int key ) - { - NetworkHandler.sendToServer( new KeyEventServerMessage( instanceID, KeyEventServerMessage.TYPE_UP, key ) ); - } - - @Override - public void mouseClick( int button, int x, int y ) - { - NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_CLICK, button, x, y ) ); - } - - @Override - public void mouseUp( int button, int x, int y ) - { - NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_UP, button, x, y ) ); - } - - @Override - public void mouseDrag( int button, int x, int y ) - { - NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_DRAG, button, x, y ) ); - } - - @Override - public void mouseScroll( int direction, int x, int y ) - { - NetworkHandler.sendToServer( new MouseEventServerMessage( instanceID, MouseEventServerMessage.TYPE_SCROLL, direction, x, y ) ); - } - - public void setState( ComputerState state, CompoundNBT userData ) - { - on = state != ComputerState.OFF; - blinking = state == ComputerState.BLINKING; - this.userData = userData; - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java deleted file mode 100644 index 4f111a09d..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/core/ClientComputerRegistry.java +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.computer.core; - -public class ClientComputerRegistry extends ComputerRegistry -{ - @Override - public void add( int instanceID, ClientComputer computer ) - { - super.add( instanceID, computer ); - computer.requestState(); - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java deleted file mode 100644 index 2a1ad4928..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/core/ComputerRegistry.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.computer.core; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; -import java.util.Random; - -public class ComputerRegistry -{ - private final Map computers = new HashMap<>(); - private int nextUnusedInstanceID; - private int sessionID; - - protected ComputerRegistry() - { - reset(); - } - - public int getSessionID() - { - return sessionID; - } - - public int getUnusedInstanceID() - { - return nextUnusedInstanceID++; - } - - public Collection getComputers() - { - return computers.values(); - } - - public T get( int instanceID ) - { - if( instanceID >= 0 ) - { - if( computers.containsKey( instanceID ) ) - { - return computers.get( instanceID ); - } - } - return null; - } - - public boolean contains( int instanceID ) - { - return computers.containsKey( instanceID ); - } - - public void add( int instanceID, T computer ) - { - if( computers.containsKey( instanceID ) ) - { - remove( instanceID ); - } - computers.put( instanceID, computer ); - nextUnusedInstanceID = Math.max( nextUnusedInstanceID, instanceID + 1 ); - } - - public void remove( int instanceID ) - { - computers.remove( instanceID ); - } - - public void reset() - { - computers.clear(); - nextUnusedInstanceID = 0; - sessionID = new Random().nextInt(); - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java deleted file mode 100644 index e68319cd8..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/core/IComputer.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.computer.core; - -import dan200.computercraft.shared.common.ITerminal; - -public interface IComputer extends ITerminal, InputHandler -{ - int getInstanceID(); - - boolean isOn(); - - boolean isCursorDisplayed(); - - void turnOn(); - - void shutdown(); - - void reboot(); - - @Override - void queueEvent( String event, Object[] arguments ); - - default void queueEvent( String event ) - { - queueEvent( event, null ); - } - - default ComputerState getState() - { - if( !isOn() ) return ComputerState.OFF; - return isCursorDisplayed() ? ComputerState.BLINKING : ComputerState.ON; - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java index 1bc64510f..ef3cdc447 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java @@ -5,15 +5,24 @@ */ package dan200.computercraft.shared.computer.core; +import dan200.computercraft.shared.computer.menu.ServerInputHandler; + +import javax.annotation.Nullable; + /** - * Receives some input and forwards it to a computer. + * Handles user-provided input, forwarding it to a computer. This is used * - * @see InputState - * @see IComputer + * @see ServerInputHandler + * @see ServerComputer */ public interface InputHandler { - void queueEvent( String event, Object[] arguments ); + void queueEvent( String event, @Nullable Object[] arguments ); + + default void queueEvent( String event ) + { + queueEvent( event, null ); + } default void keyDown( int key, boolean repeat ) { @@ -44,4 +53,10 @@ public interface InputHandler { queueEvent( "mouse_scroll", new Object[] { direction, x, y } ); } + + void shutdown(); + + void turnOn(); + + void reboot(); } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/InputState.java b/src/main/java/dan200/computercraft/shared/computer/core/InputState.java deleted file mode 100644 index 8e17bb58b..000000000 --- a/src/main/java/dan200/computercraft/shared/computer/core/InputState.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.computer.core; - -import it.unimi.dsi.fastutil.ints.IntIterator; -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.ints.IntSet; - -/** - * An {@link InputHandler} which keeps track of the current key and mouse state, and releases them when the container - * is closed. - */ -public class InputState implements InputHandler -{ - private final IContainerComputer owner; - private final IntSet keysDown = new IntOpenHashSet( 4 ); - - private int lastMouseX; - private int lastMouseY; - private int lastMouseDown = -1; - - public InputState( IContainerComputer owner ) - { - this.owner = owner; - } - - @Override - public void queueEvent( String event, Object[] arguments ) - { - IComputer computer = owner.getComputer(); - if( computer != null ) computer.queueEvent( event, arguments ); - } - - @Override - public void keyDown( int key, boolean repeat ) - { - keysDown.add( key ); - IComputer computer = owner.getComputer(); - if( computer != null ) computer.keyDown( key, repeat ); - } - - @Override - public void keyUp( int key ) - { - keysDown.remove( key ); - IComputer computer = owner.getComputer(); - if( computer != null ) computer.keyUp( key ); - } - - @Override - public void mouseClick( int button, int x, int y ) - { - lastMouseX = x; - lastMouseY = y; - lastMouseDown = button; - - IComputer computer = owner.getComputer(); - if( computer != null ) computer.mouseClick( button, x, y ); - } - - @Override - public void mouseUp( int button, int x, int y ) - { - lastMouseX = x; - lastMouseY = y; - lastMouseDown = -1; - - IComputer computer = owner.getComputer(); - if( computer != null ) computer.mouseUp( button, x, y ); - } - - @Override - public void mouseDrag( int button, int x, int y ) - { - lastMouseX = x; - lastMouseY = y; - lastMouseDown = button; - - IComputer computer = owner.getComputer(); - if( computer != null ) computer.mouseDrag( button, x, y ); - } - - @Override - public void mouseScroll( int direction, int x, int y ) - { - lastMouseX = x; - lastMouseY = y; - - IComputer computer = owner.getComputer(); - if( computer != null ) computer.mouseScroll( direction, x, y ); - } - - public void close() - { - IComputer computer = owner.getComputer(); - if( computer != null ) - { - IntIterator keys = keysDown.iterator(); - while( keys.hasNext() ) computer.keyUp( keys.nextInt() ); - - if( lastMouseDown != -1 ) computer.mouseUp( lastMouseDown, lastMouseX, lastMouseY ); - } - - keysDown.clear(); - lastMouseDown = -1; - } -} diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 6e5396291..772b65f7c 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -16,62 +16,69 @@ import dan200.computercraft.core.apis.IAPIEnvironment; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.IComputerEnvironment; -import dan200.computercraft.shared.common.ServerTerminal; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.computer.menu.ComputerMenu; import dan200.computercraft.shared.network.NetworkHandler; import dan200.computercraft.shared.network.NetworkMessage; -import dan200.computercraft.shared.network.client.ComputerDataClientMessage; -import dan200.computercraft.shared.network.client.ComputerDeletedClientMessage; import dan200.computercraft.shared.network.client.ComputerTerminalClientMessage; -import net.minecraft.entity.player.PlayerEntity; +import dan200.computercraft.shared.network.client.TerminalState; +import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.Container; -import net.minecraft.nbt.CompoundNBT; import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; -import net.minecraftforge.fml.server.ServerLifecycleHooks; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.versions.mcp.MCPVersion; import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.io.InputStream; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Function; -public class ServerComputer extends ServerTerminal implements IComputer, IComputerEnvironment +public class ServerComputer implements InputHandler, IComputerEnvironment { private final int instanceID; - private World world; + private ServerWorld world; private BlockPos position; private final ComputerFamily family; private final Computer computer; - private CompoundNBT userData; - private boolean changed; + + private final Terminal terminal; + private final AtomicBoolean terminalChanged = new AtomicBoolean( false ); private boolean changedLastFrame; private int ticksSincePing; - public ServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family, int terminalWidth, int terminalHeight ) + public ServerComputer( ServerWorld world, int computerID, String label, ComputerFamily family, int terminalWidth, int terminalHeight ) { - super( family != ComputerFamily.NORMAL, terminalWidth, terminalHeight ); - this.instanceID = instanceID; - this.world = world; this.family = family; - computer = new Computer( this, getTerminal(), computerID ); + + instanceID = ServerComputerRegistry.INSTANCE.getUnusedInstanceID(); + terminal = new Terminal( terminalWidth, terminalHeight, this::markTerminalChanged ); + + computer = new Computer( this, terminal, computerID ); computer.setLabel( label ); } + @Override + public boolean isColour() + { + return family != ComputerFamily.NORMAL; + } + public ComputerFamily getFamily() { return family; } - public World getWorld() + public ServerWorld getWorld() { return world; } - public void setWorld( World world ) + public void setWorld( ServerWorld world ) { this.world = world; } @@ -96,16 +103,30 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return computer; } - @Override - public void update() + protected void markTerminalChanged() { - super.update(); + terminalChanged.set( true ); + } + + + public void tickServer() + { + ticksSincePing++; + computer.tick(); - changedLastFrame = computer.pollAndResetChanged() || changed; - changed = false; + changedLastFrame = computer.pollAndResetChanged(); + if( terminalChanged.getAndSet( false ) ) onTerminalChanged(); + } - ticksSincePing++; + protected void onTerminalChanged() + { + sendToAllInteracting( c -> new ComputerTerminalClientMessage( c, getTerminalState() ) ); + } + + public TerminalState getTerminalState() + { + return new TerminalState( isColour(), terminal ); } public void keepAlive() @@ -123,76 +144,38 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return changedLastFrame; } - public void unload() + public int register() + { + ServerComputerRegistry.INSTANCE.add( instanceID, this ); + return instanceID; + } + + void unload() { computer.unload(); } - public CompoundNBT getUserData() + public void close() { - if( userData == null ) + unload(); + ServerComputerRegistry.INSTANCE.remove( instanceID ); + } + + private void sendToAllInteracting( Function createPacket ) + { + MinecraftServer server = world.getServer(); + + for( ServerPlayerEntity player : server.getPlayerList().getPlayers() ) { - userData = new CompoundNBT(); - } - return userData; - } - - public void updateUserData() - { - changed = true; - } - - private NetworkMessage createComputerPacket() - { - return new ComputerDataClientMessage( this ); - } - - protected NetworkMessage createTerminalPacket() - { - return new ComputerTerminalClientMessage( getInstanceID(), write() ); - } - - public void broadcastState( boolean force ) - { - if( hasOutputChanged() || force ) - { - // Send computer state to all clients - NetworkHandler.sendToAllPlayers( createComputerPacket() ); - } - - if( hasTerminalChanged() || force ) - { - // Send terminal state to clients who are currently interacting with the computer. - MinecraftServer server = ServerLifecycleHooks.getCurrentServer(); - - NetworkMessage packet = null; - for( PlayerEntity player : server.getPlayerList().getPlayers() ) + if( player.containerMenu instanceof ComputerMenu && ((ComputerMenu) player.containerMenu).getComputer() == this ) { - if( isInteracting( player ) ) - { - if( packet == null ) packet = createTerminalPacket(); - NetworkHandler.sendToPlayer( player, packet ); - } + NetworkHandler.sendToPlayer( player, createPacket.apply( player.containerMenu ) ); } } } - public void sendComputerState( PlayerEntity player ) + protected void onRemoved() { - // Send state to client - NetworkHandler.sendToPlayer( player, createComputerPacket() ); - } - - public void sendTerminalState( PlayerEntity player ) - { - // Send terminal state to client - NetworkHandler.sendToPlayer( player, createTerminalPacket() ); - } - - public void broadcastDelete() - { - // Send deletion to client - NetworkHandler.sendToAllPlayers( new ComputerDeletedClientMessage( getInstanceID() ) ); } public void setID( int id ) @@ -200,9 +183,6 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput computer.setID( id ); } - // IComputer - - @Override public int getInstanceID() { return instanceID; @@ -218,16 +198,15 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput return computer.getLabel(); } - @Override public boolean isOn() { return computer.isOn(); } - @Override - public boolean isCursorDisplayed() + public ComputerState getState() { - return computer.isOn() && computer.isBlinking(); + if( !isOn() ) return ComputerState.OFF; + return computer.isBlinking() ? ComputerState.BLINKING : ComputerState.ON; } @Override @@ -355,21 +334,4 @@ public class ServerComputer extends ServerTerminal implements IComputer, IComput { return ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer" ); } - - @Nullable - public IContainerComputer getContainer( PlayerEntity player ) - { - if( player == null ) return null; - - Container container = player.containerMenu; - if( !(container instanceof IContainerComputer) ) return null; - - IContainerComputer computerContainer = (IContainerComputer) container; - return computerContainer.getComputer() != this ? null : computerContainer; - } - - protected boolean isInteracting( PlayerEntity player ) - { - return getContainer( player ) != null; - } } diff --git a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java index 0edad5c7d..ae743566e 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java +++ b/src/main/java/dan200/computercraft/shared/computer/core/ServerComputerRegistry.java @@ -5,10 +5,45 @@ */ package dan200.computercraft.shared.computer.core; -import java.util.Iterator; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -public class ServerComputerRegistry extends ComputerRegistry +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Iterator; +import java.util.Random; + +public class ServerComputerRegistry { + private static final Random RANDOM = new Random(); + public static final ServerComputerRegistry INSTANCE = new ServerComputerRegistry(); + + private int sessionId = RANDOM.nextInt(); + private final Int2ObjectMap computers = new Int2ObjectOpenHashMap<>(); + private int nextInstanceId; + + public int getSessionID() + { + return sessionId; + } + + int getUnusedInstanceID() + { + return nextInstanceId++; + } + + @Nullable + public ServerComputer get( int instanceID ) + { + return instanceID >= 0 ? computers.get( instanceID ) : null; + } + + @Nullable + public ServerComputer get( int sessionId, int instanceId ) + { + return sessionId == this.sessionId ? get( instanceId ) : null; + } + public void update() { Iterator it = getComputers().iterator(); @@ -17,66 +52,45 @@ public class ServerComputerRegistry extends ComputerRegistry ServerComputer computer = it.next(); if( computer.hasTimedOut() ) { - //System.out.println( "TIMED OUT SERVER COMPUTER " + computer.getInstanceID() ); computer.unload(); - computer.broadcastDelete(); + computer.onRemoved(); it.remove(); - //System.out.println( getComputers().size() + " SERVER COMPUTERS" ); } else { - computer.update(); - if( computer.hasTerminalChanged() || computer.hasOutputChanged() ) - { - computer.broadcastState( false ); - } + computer.tickServer(); } } } - @Override - public void add( int instanceID, ServerComputer computer ) + void add( int instanceID, ServerComputer computer ) { - //System.out.println( "ADD SERVER COMPUTER " + instanceID ); - super.add( instanceID, computer ); - computer.broadcastState( true ); - //System.out.println( getComputers().size() + " SERVER COMPUTERS" ); + remove( instanceID ); + computers.put( instanceID, computer ); + nextInstanceId = Math.max( nextInstanceId, instanceID + 1 ); } - @Override - public void remove( int instanceID ) + void remove( int instanceID ) { - //System.out.println( "REMOVE SERVER COMPUTER " + instanceID ); ServerComputer computer = get( instanceID ); if( computer != null ) { computer.unload(); - computer.broadcastDelete(); + computer.onRemoved(); } - super.remove( instanceID ); - //System.out.println( getComputers().size() + " SERVER COMPUTERS" ); + + computers.remove( instanceID ); } - @Override public void reset() { - //System.out.println( "RESET SERVER COMPUTERS" ); - for( ServerComputer computer : getComputers() ) - { - computer.unload(); - } - super.reset(); - //System.out.println( getComputers().size() + " SERVER COMPUTERS" ); + for( ServerComputer computer : getComputers() ) computer.unload(); + computers.clear(); + sessionId = RANDOM.nextInt(); } - public ServerComputer lookup( int computerID ) + public Collection getComputers() { - if( computerID < 0 ) return null; - - for( ServerComputer computer : getComputers() ) - { - if( computer.getID() == computerID ) return computer; - } - return null; + return computers.values(); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java index 5372bdd55..ed3eee627 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ComputerMenuWithoutInventory.java @@ -6,13 +6,15 @@ package dan200.computercraft.shared.computer.inventory; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; +import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.util.InvisibleSlot; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.inventory.container.ContainerType; +import net.minecraft.item.ItemStack; +import javax.annotation.Nonnull; import java.util.function.Predicate; /** @@ -22,15 +24,18 @@ import java.util.function.Predicate; */ public class ComputerMenuWithoutInventory extends ContainerComputerBase { - public ComputerMenuWithoutInventory( ContainerType type, int id, PlayerInventory player, Predicate canUse, IComputer computer, ComputerFamily family ) + public ComputerMenuWithoutInventory( + ContainerType type, int id, PlayerInventory player, Predicate canUse, + ServerComputer computer, ComputerFamily family + ) { - super( type, id, canUse, computer, family ); + super( type, id, canUse, family, computer, null ); addSlots( player ); } - public ComputerMenuWithoutInventory( ContainerType type, int id, PlayerInventory player, ComputerContainerData data ) + public ComputerMenuWithoutInventory( ContainerType type, int id, PlayerInventory player, ComputerContainerData menuData ) { - super( type, id, player, data ); + super( type, id, p -> true, menuData.family(), null, menuData ); addSlots( player ); } @@ -38,4 +43,11 @@ public class ComputerMenuWithoutInventory extends ContainerComputerBase { for( int i = 0; i < 9; i++ ) addSlot( new InvisibleSlot( player, i ) ); } + + @Nonnull + @Override + public ItemStack quickMoveStack( @Nonnull PlayerEntity player, int slot ) + { + return ItemStack.EMPTY; + } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java index 0237b4f87..67bba7602 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerComputerBase.java @@ -5,68 +5,49 @@ */ package dan200.computercraft.shared.computer.inventory; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.core.filesystem.FileSystem; -import dan200.computercraft.core.filesystem.FileSystemException; -import dan200.computercraft.core.filesystem.FileSystemWrapper; -import dan200.computercraft.shared.computer.core.*; -import dan200.computercraft.shared.computer.upload.FileSlice; -import dan200.computercraft.shared.computer.upload.FileUpload; -import dan200.computercraft.shared.computer.upload.UploadResult; -import dan200.computercraft.shared.network.NetworkHandler; -import dan200.computercraft.shared.network.client.UploadResultMessage; +import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.shared.computer.core.ComputerFamily; +import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import dan200.computercraft.shared.computer.menu.ServerInputState; +import dan200.computercraft.shared.network.client.TerminalState; import dan200.computercraft.shared.network.container.ComputerContainerData; +import dan200.computercraft.shared.util.SingleIntArray; import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.player.PlayerInventory; -import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.ContainerType; -import net.minecraft.util.text.TranslationTextComponent; +import net.minecraft.util.IIntArray; +import net.minecraft.util.IntArray; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.io.IOException; -import java.nio.channels.WritableByteChannel; -import java.util.ArrayList; -import java.util.List; -import java.util.StringJoiner; -import java.util.UUID; -import java.util.function.Function; import java.util.function.Predicate; -public abstract class ContainerComputerBase extends Container implements IContainerComputer +public abstract class ContainerComputerBase extends Container implements ComputerMenu { - private static final String LIST_PREFIX = "\n \u2022 "; - private final Predicate canUse; - private final IComputer computer; private final ComputerFamily family; - private final InputState input = new InputState( this ); + private final IIntArray data; - private UUID toUploadId; - private List toUpload; + private final @Nullable ServerComputer computer; + private final @Nullable ServerInputState input; - public ContainerComputerBase( ContainerType type, int id, Predicate canUse, IComputer computer, ComputerFamily family ) + private final @Nullable Terminal terminal; + + public ContainerComputerBase( + ContainerType type, int id, Predicate canUse, + ComputerFamily family, @Nullable ServerComputer computer, @Nullable ComputerContainerData containerData + ) { super( type, id ); this.canUse = canUse; - this.computer = computer; this.family = family; - } + data = computer == null ? new IntArray( 1 ) : (SingleIntArray) () -> computer.isOn() ? 1 : 0; + addDataSlots( data ); - public ContainerComputerBase( ContainerType type, int id, PlayerInventory player, ComputerContainerData data ) - { - this( type, id, x -> true, getComputer( player, data ), data.getFamily() ); - } - - protected static IComputer getComputer( PlayerInventory player, ComputerContainerData data ) - { - int id = data.getInstanceId(); - if( !player.player.level.isClientSide ) return ComputerCraft.serverComputerRegistry.get( id ); - - ClientComputer computer = ComputerCraft.clientComputerRegistry.get( id ); - if( computer == null ) ComputerCraft.clientComputerRegistry.add( id, computer = new ClientComputer( id ) ); - return computer; + this.computer = computer; + input = computer == null ? null : new ServerInputState( this ); + terminal = containerData == null ? null : containerData.terminal().create(); } @Override @@ -81,141 +62,48 @@ public abstract class ContainerComputerBase extends Container implements IContai return family; } - @Nullable - @Override - public IComputer getComputer() + public boolean isOn() { + return data.get( 0 ) != 0; + } + + @Override + public ServerComputer getComputer() + { + if( computer == null ) throw new UnsupportedOperationException( "Cannot access server computer on the client" ); return computer; } - @Nonnull @Override - public InputState getInput() + public ServerInputState getInput() { + if( input == null ) throw new UnsupportedOperationException( "Cannot access server computer on the client" ); return input; } @Override - public void startUpload( @Nonnull UUID uuid, @Nonnull List files ) + public void updateTerminal( TerminalState state ) { - toUploadId = uuid; - toUpload = files; + if( terminal == null ) throw new UnsupportedOperationException( "Cannot update terminal on the server" ); + state.apply( terminal ); } - @Override - public void continueUpload( @Nonnull UUID uploadId, @Nonnull List slices ) + /** + * Get the current terminal state. + * + * @return The current terminal state. + * @throws IllegalStateException When accessed on the server. + */ + public Terminal getTerminal() { - if( toUploadId == null || toUpload == null || !toUploadId.equals( uploadId ) ) - { - ComputerCraft.log.warn( "Invalid continueUpload call, skipping." ); - return; - } - - for( FileSlice slice : slices ) slice.apply( toUpload ); - } - - @Override - public void finishUpload( @Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId ) - { - if( toUploadId == null || toUpload == null || toUpload.isEmpty() || !toUploadId.equals( uploadId ) ) - { - ComputerCraft.log.warn( "Invalid finishUpload call, skipping." ); - return; - } - - UploadResultMessage message = finishUpload( false ); - NetworkHandler.sendToPlayer( uploader, message ); - } - - @Override - public void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite ) - { - if( toUploadId == null || toUpload == null || toUpload.isEmpty() ) - { - ComputerCraft.log.warn( "Invalid finishUpload call, skipping." ); - return; - } - - UploadResultMessage message = finishUpload( true ); - NetworkHandler.sendToPlayer( uploader, message ); - } - - @Nonnull - private UploadResultMessage finishUpload( boolean forceOverwrite ) - { - ServerComputer computer = (ServerComputer) getComputer(); - if( computer == null ) return UploadResultMessage.COMPUTER_OFF; - - FileSystem fs = computer.getComputer().getEnvironment().getFileSystem(); - if( fs == null ) return UploadResultMessage.COMPUTER_OFF; - - for( FileUpload upload : toUpload ) - { - if( !upload.checksumMatches() ) - { - ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() ); - return new UploadResultMessage( UploadResult.ERROR, new TranslationTextComponent( "gui.computercraft.upload.failed.corrupted" ) ); - } - } - - try - { - List overwrite = new ArrayList<>(); - List files = toUpload; - toUpload = null; - for( FileUpload upload : files ) - { - if( !fs.exists( upload.getName() ) ) continue; - if( fs.isDir( upload.getName() ) ) - { - return new UploadResultMessage( - UploadResult.ERROR, - new TranslationTextComponent( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() ) - ); - } - - overwrite.add( upload.getName() ); - } - - if( !overwrite.isEmpty() && !forceOverwrite ) - { - StringJoiner joiner = new StringJoiner( LIST_PREFIX, LIST_PREFIX, "" ); - for( String value : overwrite ) joiner.add( value ); - toUpload = files; - return new UploadResultMessage( - UploadResult.CONFIRM_OVERWRITE, - new TranslationTextComponent( "gui.computercraft.upload.overwrite.detail", joiner.toString() ) - ); - } - - long availableSpace = fs.getFreeSpace( "/" ); - long neededSpace = 0; - for( FileUpload upload : files ) neededSpace += Math.max( 512, upload.getBytes().remaining() ); - if( neededSpace > availableSpace ) return UploadResultMessage.OUT_OF_SPACE; - - for( FileUpload file : files ) - { - try( FileSystemWrapper channel = fs.openForWrite( file.getName(), false, Function.identity() ) ) - { - channel.get().write( file.getBytes() ); - } - } - - return new UploadResultMessage( - UploadResult.SUCCESS, new TranslationTextComponent( "gui.computercraft.upload.success.msg", files.size() ) - ); - } - catch( FileSystemException | IOException e ) - { - ComputerCraft.log.error( "Error uploading files", e ); - return new UploadResultMessage( UploadResult.ERROR, new TranslationTextComponent( "gui.computercraft.upload.failed.generic", e.getMessage() ) ); - } + if( terminal == null ) throw new IllegalStateException( "Cannot update terminal on the server" ); + return terminal; } @Override public void removed( @Nonnull PlayerEntity player ) { super.removed( player ); - input.close(); + if( input != null ) input.close(); } } diff --git a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java index 5bdb9060d..cb963d0d8 100644 --- a/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/inventory/ContainerViewComputer.java @@ -5,12 +5,12 @@ */ package dan200.computercraft.shared.computer.inventory; -import dan200.computercraft.ComputerCraft; import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.blocks.TileCommandComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.network.container.ViewComputerContainerData; +import dan200.computercraft.shared.computer.core.ServerComputerRegistry; +import dan200.computercraft.shared.network.container.ComputerContainerData; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; @@ -18,26 +18,20 @@ import javax.annotation.Nonnull; public class ContainerViewComputer extends ComputerMenuWithoutInventory { - private final int width; - private final int height; - public ContainerViewComputer( int id, PlayerInventory player, ServerComputer computer ) { super( Registry.ModContainers.VIEW_COMPUTER.get(), id, player, p -> canInteractWith( computer, p ), computer, computer.getFamily() ); - width = height = 0; } - public ContainerViewComputer( int id, PlayerInventory player, ViewComputerContainerData data ) + public ContainerViewComputer( int id, PlayerInventory player, ComputerContainerData data ) { super( Registry.ModContainers.VIEW_COMPUTER.get(), id, player, data ); - width = data.getWidth(); - height = data.getHeight(); } private static boolean canInteractWith( @Nonnull ServerComputer computer, @Nonnull PlayerEntity player ) { // If this computer no longer exists then discard it. - if( ComputerCraft.serverComputerRegistry.get( computer.getInstanceID() ) != computer ) + if( ServerComputerRegistry.INSTANCE.get( computer.getInstanceID() ) != computer ) { return false; } @@ -50,14 +44,4 @@ public class ContainerViewComputer extends ComputerMenuWithoutInventory return true; } - - public int getWidth() - { - return width; - } - - public int getHeight() - { - return height; - } } diff --git a/src/main/java/dan200/computercraft/shared/computer/menu/ComputerMenu.java b/src/main/java/dan200/computercraft/shared/computer/menu/ComputerMenu.java new file mode 100644 index 000000000..b76d221ee --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/computer/menu/ComputerMenu.java @@ -0,0 +1,42 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.computer.menu; + +import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.network.client.TerminalState; +import net.minecraft.inventory.container.Container; + +/** + * An instance of {@link Container} which provides a computer. You should implement this if you provide custom computer + * GUIs. + */ +public interface ComputerMenu +{ + /** + * Get the computer you are interacting with. + * + * @return The computer you are interacting with. + * @throws UnsupportedOperationException When used on the client side. + */ + ServerComputer getComputer(); + + /** + * Get the input controller for this container. This should be used when receiving events from the client. + * + * @return This container's input. + * @throws UnsupportedOperationException When used on the client side. + */ + ServerInputHandler getInput(); + + /** + * Set the current terminal state. This is called on the client when the server syncs a computer's terminal + * contents. + * + * @param state The new terminal state. + * @throws UnsupportedOperationException When used on the server. + */ + void updateTerminal( TerminalState state ); +} diff --git a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java b/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputHandler.java similarity index 53% rename from src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java rename to src/main/java/dan200/computercraft/shared/computer/menu/ServerInputHandler.java index beec6e96f..e6f6bf8f2 100644 --- a/src/main/java/dan200/computercraft/shared/computer/core/IContainerComputer.java +++ b/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputHandler.java @@ -3,49 +3,33 @@ * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. * Send enquiries to dratcliffe@gmail.com */ -package dan200.computercraft.shared.computer.core; +package dan200.computercraft.shared.computer.menu; +import dan200.computercraft.shared.computer.core.InputHandler; import dan200.computercraft.shared.computer.upload.FileSlice; import dan200.computercraft.shared.computer.upload.FileUpload; +import dan200.computercraft.shared.network.server.ComputerServerMessage; import net.minecraft.entity.player.ServerPlayerEntity; -import net.minecraft.inventory.container.Container; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; import java.util.List; import java.util.UUID; /** - * An instance of {@link Container} which provides a computer. You should implement this - * if you provide custom computers/GUIs to interact with them. + * An {@link InputHandler} which operates on the server, receiving data from the client over the network. + * + * @see ServerInputState The default implementation of this interface. + * @see ComputerServerMessage Packets which consume this interface. + * @see ComputerMenu */ -public interface IContainerComputer +public interface ServerInputHandler extends InputHandler { - /** - * Get the computer you are interacting with. - * - * This will only be called on the server. - * - * @return The computer you are interacting with. - */ - @Nullable - IComputer getComputer(); - - /** - * Get the input controller for this container. - * - * @return This container's input. - */ - @Nonnull - InputState getInput(); - /** * Start a file upload into this container. * * @param uploadId The unique ID of this upload. * @param files The files to upload. */ - void startUpload( @Nonnull UUID uploadId, @Nonnull List files ); + void startUpload( UUID uploadId, List files ); /** * Append more data to partially uploaded files. @@ -53,7 +37,7 @@ public interface IContainerComputer * @param uploadId The unique ID of this upload. * @param slices Additional parts of file data to upload. */ - void continueUpload( @Nonnull UUID uploadId, @Nonnull List slices ); + void continueUpload( UUID uploadId, List slices ); /** * Finish off an upload. This either writes the uploaded files or informs the user that files will be overwritten. @@ -61,7 +45,7 @@ public interface IContainerComputer * @param uploader The player uploading files. * @param uploadId The unique ID of this upload. */ - void finishUpload( @Nonnull ServerPlayerEntity uploader, @Nonnull UUID uploadId ); + void finishUpload( ServerPlayerEntity uploader, UUID uploadId ); /** * Continue an upload. @@ -69,5 +53,5 @@ public interface IContainerComputer * @param uploader The player uploading files. * @param overwrite Whether the files should be overwritten or not. */ - void confirmUpload( @Nonnull ServerPlayerEntity uploader, boolean overwrite ); + void confirmUpload( ServerPlayerEntity uploader, boolean overwrite ); } diff --git a/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java b/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java new file mode 100644 index 000000000..d8ee57b9f --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java @@ -0,0 +1,261 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.computer.menu; + +import dan200.computercraft.ComputerCraft; +import dan200.computercraft.core.filesystem.FileSystem; +import dan200.computercraft.core.filesystem.FileSystemException; +import dan200.computercraft.core.filesystem.FileSystemWrapper; +import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.upload.FileSlice; +import dan200.computercraft.shared.computer.upload.FileUpload; +import dan200.computercraft.shared.computer.upload.UploadResult; +import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.network.NetworkMessage; +import dan200.computercraft.shared.network.client.UploadResultMessage; +import it.unimi.dsi.fastutil.ints.IntIterator; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.util.text.TranslationTextComponent; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.nio.channels.WritableByteChannel; +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; +import java.util.UUID; +import java.util.function.Function; + +/** + * The default concrete implementation of {@link ServerInputHandler}. + *

+ * This keeps track of the current key and mouse state, and releases them when the container is closed. + */ +public class ServerInputState implements ServerInputHandler +{ + private static final String LIST_PREFIX = "\n \u2022 "; + + private final ComputerMenu owner; + private final IntSet keysDown = new IntOpenHashSet( 4 ); + + private int lastMouseX; + private int lastMouseY; + private int lastMouseDown = -1; + + private @Nullable UUID toUploadId; + private @Nullable List toUpload; + + public ServerInputState( ComputerMenu owner ) + { + this.owner = owner; + } + + @Override + public void queueEvent( String event, @Nullable Object[] arguments ) + { + owner.getComputer().queueEvent( event, arguments ); + } + + @Override + public void keyDown( int key, boolean repeat ) + { + keysDown.add( key ); + owner.getComputer().keyDown( key, repeat ); + } + + @Override + public void keyUp( int key ) + { + keysDown.remove( key ); + owner.getComputer().keyUp( key ); + } + + @Override + public void mouseClick( int button, int x, int y ) + { + lastMouseX = x; + lastMouseY = y; + lastMouseDown = button; + + owner.getComputer().mouseClick( button, x, y ); + } + + @Override + public void mouseUp( int button, int x, int y ) + { + lastMouseX = x; + lastMouseY = y; + lastMouseDown = -1; + + owner.getComputer().mouseUp( button, x, y ); + } + + @Override + public void mouseDrag( int button, int x, int y ) + { + lastMouseX = x; + lastMouseY = y; + lastMouseDown = button; + + owner.getComputer().mouseDrag( button, x, y ); + } + + @Override + public void mouseScroll( int direction, int x, int y ) + { + lastMouseX = x; + lastMouseY = y; + + owner.getComputer().mouseScroll( direction, x, y ); + } + + @Override + public void shutdown() + { + owner.getComputer().shutdown(); + } + + @Override + public void turnOn() + { + owner.getComputer().turnOn(); + } + + @Override + public void reboot() + { + owner.getComputer().reboot(); + } + + @Override + public void startUpload( UUID uuid, List files ) + { + toUploadId = uuid; + toUpload = files; + } + + @Override + public void continueUpload( UUID uploadId, List slices ) + { + if( toUploadId == null || toUpload == null || !toUploadId.equals( uploadId ) ) + { + ComputerCraft.log.warn( "Invalid continueUpload call, skipping." ); + return; + } + + for( FileSlice slice : slices ) slice.apply( toUpload ); + } + + @Override + public void finishUpload( ServerPlayerEntity uploader, UUID uploadId ) + { + if( toUploadId == null || toUpload == null || toUpload.isEmpty() || !toUploadId.equals( uploadId ) ) + { + ComputerCraft.log.warn( "Invalid finishUpload call, skipping." ); + return; + } + + NetworkMessage message = finishUpload( false ); + NetworkHandler.sendToPlayer( uploader, message ); + } + + @Override + public void confirmUpload( ServerPlayerEntity uploader, boolean overwrite ) + { + if( toUploadId == null || toUpload == null || toUpload.isEmpty() ) + { + ComputerCraft.log.warn( "Invalid finishUpload call, skipping." ); + return; + } + + NetworkMessage message = finishUpload( true ); + NetworkHandler.sendToPlayer( uploader, message ); + } + + private UploadResultMessage finishUpload( boolean forceOverwrite ) + { + ServerComputer computer = owner.getComputer(); + if( toUpload == null ) return UploadResultMessage.COMPUTER_OFF; + + FileSystem fs = computer.getComputer().getAPIEnvironment().getFileSystem(); + + for( FileUpload upload : toUpload ) + { + if( !upload.checksumMatches() ) + { + ComputerCraft.log.warn( "Checksum failed to match for {}.", upload.getName() ); + return new UploadResultMessage( UploadResult.ERROR, new TranslationTextComponent( "gui.computercraft.upload.failed.corrupted" ) ); + } + } + + try + { + List overwrite = new ArrayList<>(); + List files = toUpload; + toUpload = null; + for( FileUpload upload : files ) + { + if( !fs.exists( upload.getName() ) ) continue; + if( fs.isDir( upload.getName() ) ) + { + return new UploadResultMessage( + UploadResult.ERROR, + new TranslationTextComponent( "gui.computercraft.upload.failed.overwrite_dir", upload.getName() ) + ); + } + + overwrite.add( upload.getName() ); + } + + if( !overwrite.isEmpty() && !forceOverwrite ) + { + StringJoiner joiner = new StringJoiner( LIST_PREFIX, LIST_PREFIX, "" ); + for( String value : overwrite ) joiner.add( value ); + toUpload = files; + return new UploadResultMessage( + UploadResult.CONFIRM_OVERWRITE, + new TranslationTextComponent( "gui.computercraft.upload.overwrite.detail", joiner.toString() ) + ); + } + + long availableSpace = fs.getFreeSpace( "/" ); + long neededSpace = 0; + for( FileUpload upload : files ) neededSpace += Math.max( 512, upload.getBytes().remaining() ); + if( neededSpace > availableSpace ) return UploadResultMessage.OUT_OF_SPACE; + + for( FileUpload file : files ) + { + try( FileSystemWrapper channel = fs.openForWrite( file.getName(), false, Function.identity() ) ) + { + channel.get().write( file.getBytes() ); + } + } + + return new UploadResultMessage( + UploadResult.SUCCESS, new TranslationTextComponent( "gui.computercraft.upload.success.msg", files.size() ) + ); + } + catch( FileSystemException | IOException e ) + { + ComputerCraft.log.error( "Error uploading files", e ); + return new UploadResultMessage( UploadResult.ERROR, new TranslationTextComponent( "gui.computercraft.upload.failed.generic", e.getMessage() ) ); + } + } + + public void close() + { + ServerComputer computer = owner.getComputer(); + IntIterator keys = keysDown.iterator(); + while( keys.hasNext() ) computer.keyUp( keys.nextInt() ); + + if( lastMouseDown != -1 ) computer.mouseUp( lastMouseDown, lastMouseX, lastMouseY ); + + keysDown.clear(); + lastMouseDown = -1; + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java index f05f2e35d..9dc79a00b 100644 --- a/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java +++ b/src/main/java/dan200/computercraft/shared/network/NetworkHandler.java @@ -11,8 +11,8 @@ import dan200.computercraft.shared.network.client.*; import dan200.computercraft.shared.network.server.*; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.IPacket; import net.minecraft.network.PacketBuffer; import net.minecraft.util.ResourceLocation; import net.minecraft.util.math.vector.Vector3d; @@ -24,6 +24,7 @@ import net.minecraftforge.fml.network.NetworkRegistry; import net.minecraftforge.fml.network.PacketDistributor; import net.minecraftforge.fml.network.simple.SimpleChannel; +import java.util.Collection; import java.util.function.Function; public final class NetworkHandler @@ -46,16 +47,15 @@ public final class NetworkHandler // Server messages registerMainThread( 0, NetworkDirection.PLAY_TO_SERVER, ComputerActionServerMessage.class, ComputerActionServerMessage::new ); registerMainThread( 1, NetworkDirection.PLAY_TO_SERVER, QueueEventServerMessage.class, QueueEventServerMessage::new ); - registerMainThread( 2, NetworkDirection.PLAY_TO_SERVER, RequestComputerMessage.class, RequestComputerMessage::new ); - registerMainThread( 3, NetworkDirection.PLAY_TO_SERVER, KeyEventServerMessage.class, KeyEventServerMessage::new ); - registerMainThread( 4, NetworkDirection.PLAY_TO_SERVER, MouseEventServerMessage.class, MouseEventServerMessage::new ); - registerMainThread( 5, NetworkDirection.PLAY_TO_SERVER, UploadFileMessage.class, UploadFileMessage::new ); - registerMainThread( 6, NetworkDirection.PLAY_TO_SERVER, ContinueUploadMessage.class, ContinueUploadMessage::new ); + registerMainThread( 2, NetworkDirection.PLAY_TO_SERVER, KeyEventServerMessage.class, KeyEventServerMessage::new ); + registerMainThread( 3, NetworkDirection.PLAY_TO_SERVER, MouseEventServerMessage.class, MouseEventServerMessage::new ); + registerMainThread( 4, NetworkDirection.PLAY_TO_SERVER, UploadFileMessage.class, UploadFileMessage::new ); + registerMainThread( 5, NetworkDirection.PLAY_TO_SERVER, ContinueUploadMessage.class, ContinueUploadMessage::new ); // Client messages registerMainThread( 10, NetworkDirection.PLAY_TO_CLIENT, ChatTableClientMessage.class, ChatTableClientMessage::new ); - registerMainThread( 11, NetworkDirection.PLAY_TO_CLIENT, ComputerDataClientMessage.class, ComputerDataClientMessage::new ); - registerMainThread( 12, NetworkDirection.PLAY_TO_CLIENT, ComputerDeletedClientMessage.class, ComputerDeletedClientMessage::new ); + registerMainThread( 11, NetworkDirection.PLAY_TO_CLIENT, PocketComputerDataMessage.class, PocketComputerDataMessage::new ); + registerMainThread( 12, NetworkDirection.PLAY_TO_CLIENT, PocketComputerDeletedClientMessage.class, PocketComputerDeletedClientMessage::new ); registerMainThread( 13, NetworkDirection.PLAY_TO_CLIENT, ComputerTerminalClientMessage.class, ComputerTerminalClientMessage::new ); registerMainThread( 14, NetworkDirection.PLAY_TO_CLIENT, PlayRecordClientMessage.class, PlayRecordClientMessage::new ); registerMainThread( 15, NetworkDirection.PLAY_TO_CLIENT, MonitorClientMessage.class, MonitorClientMessage::new ); @@ -66,9 +66,9 @@ public final class NetworkHandler registerMainThread( 20, NetworkDirection.PLAY_TO_CLIENT, UploadResultMessage.class, UploadResultMessage::new ); } - public static void sendToPlayer( PlayerEntity player, NetworkMessage packet ) + public static void sendToPlayer( ServerPlayerEntity player, NetworkMessage packet ) { - network.sendTo( packet, ((ServerPlayerEntity) player).connection.connection, NetworkDirection.PLAY_TO_CLIENT ); + network.sendTo( packet, player.connection.connection, NetworkDirection.PLAY_TO_CLIENT ); } public static void sendToAllPlayers( NetworkMessage packet ) @@ -92,6 +92,15 @@ public final class NetworkHandler network.send( PacketDistributor.TRACKING_CHUNK.with( () -> chunk ), packet ); } + public static void sendToPlayers( NetworkMessage packet, Collection players ) + { + if( players.isEmpty() ) return; + + IPacket vanillaPacket = network.toVanillaPacket( packet, NetworkDirection.PLAY_TO_CLIENT ); + for( ServerPlayerEntity player : players ) player.connection.send( vanillaPacket ); + } + + /** * Register packet, and a thread-unsafe handler for it. * diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java deleted file mode 100644 index 52d569b26..000000000 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerClientMessage.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.network.client; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ClientComputer; -import dan200.computercraft.shared.network.NetworkMessage; -import net.minecraft.network.PacketBuffer; - -import javax.annotation.Nonnull; - -/** - * A packet, which performs an action on a {@link ClientComputer}. - */ -public abstract class ComputerClientMessage implements NetworkMessage -{ - private final int instanceId; - - public ComputerClientMessage( int instanceId ) - { - this.instanceId = instanceId; - } - - public ComputerClientMessage( @Nonnull PacketBuffer buf ) - { - instanceId = buf.readVarInt(); - } - - public int getInstanceId() - { - return instanceId; - } - - @Override - public void toBytes( @Nonnull PacketBuffer buf ) - { - buf.writeVarInt( instanceId ); - } - - public ClientComputer getComputer() - { - ClientComputer computer = ComputerCraft.clientComputerRegistry.get( instanceId ); - if( computer == null ) - { - ComputerCraft.clientComputerRegistry.add( instanceId, computer = new ClientComputer( instanceId ) ); - } - return computer; - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java deleted file mode 100644 index e5a520d9d..000000000 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDataClientMessage.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.network.client; - -import dan200.computercraft.shared.computer.core.ComputerState; -import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.nbt.CompoundNBT; -import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.network.NetworkEvent; - -import javax.annotation.Nonnull; - -/** - * Provides additional data about a client computer, such as its ID and current state. - */ -public class ComputerDataClientMessage extends ComputerClientMessage -{ - private final ComputerState state; - private final CompoundNBT userData; - - public ComputerDataClientMessage( ServerComputer computer ) - { - super( computer.getInstanceID() ); - state = computer.getState(); - userData = computer.getUserData(); - } - - public ComputerDataClientMessage( @Nonnull PacketBuffer buf ) - { - super( buf ); - state = buf.readEnum( ComputerState.class ); - userData = buf.readNbt(); - } - - @Override - public void toBytes( @Nonnull PacketBuffer buf ) - { - super.toBytes( buf ); - buf.writeEnum( state ); - buf.writeNbt( userData ); - } - - @Override - public void handle( NetworkEvent.Context context ) - { - getComputer().setState( state, userData ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java deleted file mode 100644 index e0601cafe..000000000 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerDeletedClientMessage.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.network.client; - -import dan200.computercraft.ComputerCraft; -import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.network.NetworkEvent; - -public class ComputerDeletedClientMessage extends ComputerClientMessage -{ - public ComputerDeletedClientMessage( int instanceId ) - { - super( instanceId ); - } - - public ComputerDeletedClientMessage( PacketBuffer buffer ) - { - super( buffer ); - } - - @Override - public void handle( NetworkEvent.Context context ) - { - ComputerCraft.clientComputerRegistry.remove( getInstanceId() ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java index ca75f719f..121a59c9e 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/ComputerTerminalClientMessage.java @@ -5,37 +5,50 @@ */ package dan200.computercraft.shared.network.client; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import dan200.computercraft.shared.network.NetworkMessage; +import net.minecraft.client.Minecraft; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; -public class ComputerTerminalClientMessage extends ComputerClientMessage +public class ComputerTerminalClientMessage implements NetworkMessage { - private final TerminalState state; + private final int containerId; + private final TerminalState terminal; - public ComputerTerminalClientMessage( int instanceId, TerminalState state ) + public ComputerTerminalClientMessage( Container menu, TerminalState terminal ) { - super( instanceId ); - this.state = state; + containerId = menu.containerId; + this.terminal = terminal; } public ComputerTerminalClientMessage( @Nonnull PacketBuffer buf ) { - super( buf ); - state = new TerminalState( buf ); + containerId = buf.readVarInt(); + terminal = new TerminalState( buf ); } @Override public void toBytes( @Nonnull PacketBuffer buf ) { - super.toBytes( buf ); - state.write( buf ); + buf.writeVarInt( containerId ); + terminal.write( buf ); } @Override + @OnlyIn( Dist.CLIENT ) public void handle( NetworkEvent.Context context ) { - getComputer().read( state ); + PlayerEntity player = Minecraft.getInstance().player; + if( player != null && player.containerMenu.containerId == containerId && player.containerMenu instanceof ComputerMenu ) + { + ((ComputerMenu) player.containerMenu).updateTerminal( terminal ); + } } } diff --git a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java index 6391f16d5..ff2fafeb3 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/client/MonitorClientMessage.java @@ -12,6 +12,8 @@ import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.network.PacketBuffer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.math.BlockPos; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; @@ -41,6 +43,7 @@ public class MonitorClientMessage implements NetworkMessage } @Override + @OnlyIn( Dist.CLIENT ) public void handle( NetworkEvent.Context context ) { ClientPlayerEntity player = Minecraft.getInstance().player; diff --git a/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java new file mode 100644 index 000000000..a4f476d5b --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDataMessage.java @@ -0,0 +1,58 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.network.client; + +import dan200.computercraft.client.pocket.ClientPocketComputers; +import dan200.computercraft.client.pocket.PocketComputerData; +import dan200.computercraft.shared.computer.core.ComputerState; +import dan200.computercraft.shared.network.NetworkMessage; +import dan200.computercraft.shared.pocket.core.PocketServerComputer; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +/** + * Provides additional data about a client computer, such as its ID and current state. + */ +public class PocketComputerDataMessage implements NetworkMessage +{ + private final int instanceId; + private final ComputerState state; + private final int lightState; + private final TerminalState terminal; + + public PocketComputerDataMessage( PocketServerComputer computer, boolean sendTerminal ) + { + instanceId = computer.getInstanceID(); + state = computer.getState(); + lightState = computer.getLight(); + terminal = sendTerminal ? computer.getTerminalState() : new TerminalState( false, null ); + } + + public PocketComputerDataMessage( PacketBuffer buf ) + { + instanceId = buf.readVarInt(); + state = buf.readEnum( ComputerState.class ); + lightState = buf.readVarInt(); + terminal = new TerminalState( buf ); + } + + @Override + public void toBytes( PacketBuffer buf ) + { + buf.writeVarInt( instanceId ); + buf.writeEnum( state ); + buf.writeVarInt( lightState ); + terminal.write( buf ); + } + + @Override + public void handle( NetworkEvent.Context context ) + { + PocketComputerData computer = ClientPocketComputers.get( instanceId, terminal.colour ); + computer.setState( state, lightState ); + if( terminal.hasTerminal() ) computer.setTerminal( terminal ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java b/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java new file mode 100644 index 000000000..2de9a8610 --- /dev/null +++ b/src/main/java/dan200/computercraft/shared/network/client/PocketComputerDeletedClientMessage.java @@ -0,0 +1,40 @@ +/* + * This file is part of ComputerCraft - http://www.computercraft.info + * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. + * Send enquiries to dratcliffe@gmail.com + */ +package dan200.computercraft.shared.network.client; + +import dan200.computercraft.client.pocket.ClientPocketComputers; +import dan200.computercraft.shared.network.NetworkMessage; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import javax.annotation.Nonnull; + +public class PocketComputerDeletedClientMessage implements NetworkMessage +{ + private final int instanceId; + + public PocketComputerDeletedClientMessage( int instanceId ) + { + this.instanceId = instanceId; + } + + public PocketComputerDeletedClientMessage( PacketBuffer buffer ) + { + instanceId = buffer.readVarInt(); + } + + @Override + public void toBytes( @Nonnull PacketBuffer buf ) + { + buf.writeVarInt( instanceId ); + } + + @Override + public void handle( NetworkEvent.Context context ) + { + ClientPocketComputers.remove( instanceId ); + } +} diff --git a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java index 8a3d77a3c..9a0a5f413 100644 --- a/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java +++ b/src/main/java/dan200/computercraft/shared/network/client/TerminalState.java @@ -120,6 +120,14 @@ public class TerminalState terminal.read( new PacketBuffer( buffer ) ); } + public Terminal create() + { + if( buffer == null ) throw new NullPointerException( "Terminal does not exist" ); + Terminal terminal = new Terminal( width, height ); + terminal.read( new PacketBuffer( buffer ) ); + return terminal; + } + private ByteBuf getCompressed() { if( buffer == null ) throw new NullPointerException( "buffer" ); diff --git a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java index 977b936c3..926029ec2 100644 --- a/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java +++ b/src/main/java/dan200/computercraft/shared/network/container/ComputerContainerData.java @@ -7,39 +7,40 @@ package dan200.computercraft.shared.network.container; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.network.client.TerminalState; import net.minecraft.network.PacketBuffer; public class ComputerContainerData implements ContainerData { - private final int id; private final ComputerFamily family; + private final TerminalState terminal; public ComputerContainerData( ServerComputer computer ) { - id = computer.getInstanceID(); family = computer.getFamily(); + terminal = computer.getTerminalState(); } public ComputerContainerData( PacketBuffer buf ) { - id = buf.readInt(); family = buf.readEnum( ComputerFamily.class ); + terminal = new TerminalState( buf ); } @Override public void toBytes( PacketBuffer buf ) { - buf.writeInt( id ); buf.writeEnum( family ); + terminal.write( buf ); } - public int getInstanceId() - { - return id; - } - - public ComputerFamily getFamily() + public ComputerFamily family() { return family; } + + public TerminalState terminal() + { + return terminal; + } } diff --git a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java b/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java deleted file mode 100644 index 2fc3f4058..000000000 --- a/src/main/java/dan200/computercraft/shared/network/container/ViewComputerContainerData.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.network.container; - -import dan200.computercraft.core.terminal.Terminal; -import dan200.computercraft.shared.computer.core.ServerComputer; -import net.minecraft.network.PacketBuffer; - -import javax.annotation.Nonnull; - -/** - * View an arbitrary computer on the client. - * - * @see dan200.computercraft.shared.command.CommandComputerCraft - */ -public class ViewComputerContainerData extends ComputerContainerData -{ - private final int width; - private final int height; - - public ViewComputerContainerData( ServerComputer computer ) - { - super( computer ); - Terminal terminal = computer.getTerminal(); - if( terminal != null ) - { - width = terminal.getWidth(); - height = terminal.getHeight(); - } - else - { - width = height = 0; - } - } - - public ViewComputerContainerData( PacketBuffer buffer ) - { - super( buffer ); - width = buffer.readVarInt(); - height = buffer.readVarInt(); - } - - @Override - public void toBytes( @Nonnull PacketBuffer buf ) - { - super.toBytes( buf ); - buf.writeVarInt( width ); - buf.writeVarInt( height ); - } - - public int getWidth() - { - return width; - } - - public int getHeight() - { - return height; - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java index 0f4df7741..c2e7d7264 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerActionServerMessage.java @@ -5,8 +5,8 @@ */ package dan200.computercraft.shared.network.server; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -16,9 +16,9 @@ public class ComputerActionServerMessage extends ComputerServerMessage { private final Action action; - public ComputerActionServerMessage( int instanceId, Action action ) + public ComputerActionServerMessage( Container menu, Action action ) { - super( instanceId ); + super( menu ); this.action = action; } @@ -36,18 +36,18 @@ public class ComputerActionServerMessage extends ComputerServerMessage } @Override - protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) + protected void handle( NetworkEvent.Context context, @Nonnull ComputerMenu container ) { switch( action ) { case TURN_ON: - computer.turnOn(); + container.getInput().turnOn(); break; case REBOOT: - computer.reboot(); + container.getInput().reboot(); break; case SHUTDOWN: - computer.shutdown(); + container.getInput().shutdown(); break; } } diff --git a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java index 804daa289..31292c91c 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ComputerServerMessage.java @@ -5,52 +5,49 @@ */ package dan200.computercraft.shared.network.server; -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; import dan200.computercraft.shared.network.NetworkMessage; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; import javax.annotation.Nonnull; +import javax.annotation.OverridingMethodsMustInvokeSuper; /** - * A packet, which performs an action on a {@link ServerComputer}. - * - * This requires that the sending player is interacting with that computer via a - * {@link IContainerComputer}. + * A packet, which performs an action on the currently open {@link ComputerMenu}. */ public abstract class ComputerServerMessage implements NetworkMessage { - private final int instanceId; + private final int containerId; - public ComputerServerMessage( int instanceId ) + protected ComputerServerMessage( Container menu ) { - this.instanceId = instanceId; + containerId = menu.containerId; } - public ComputerServerMessage( @Nonnull PacketBuffer buf ) + protected ComputerServerMessage( PacketBuffer buffer ) { - instanceId = buf.readVarInt(); + containerId = buffer.readVarInt(); } @Override + @OverridingMethodsMustInvokeSuper public void toBytes( @Nonnull PacketBuffer buf ) { - buf.writeVarInt( instanceId ); + buf.writeVarInt( containerId ); } @Override public void handle( NetworkEvent.Context context ) { - ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instanceId ); - if( computer == null ) return; - - IContainerComputer container = computer.getContainer( context.getSender() ); - if( container == null ) return; - - handle( context, computer, container ); + PlayerEntity player = context.getSender(); + if( player.containerMenu.containerId == containerId && player.containerMenu instanceof ComputerMenu ) + { + handle( context, (ComputerMenu) player.containerMenu ); + } } - protected abstract void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ); + protected abstract void handle( NetworkEvent.Context context, @Nonnull ComputerMenu container ); } diff --git a/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java b/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java index 9e2ad2f9f..4b4973643 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/ContinueUploadMessage.java @@ -5,9 +5,9 @@ */ package dan200.computercraft.shared.network.server; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -17,9 +17,9 @@ public class ContinueUploadMessage extends ComputerServerMessage { private final boolean overwrite; - public ContinueUploadMessage( int instanceId, boolean overwrite ) + public ContinueUploadMessage( Container menu, boolean overwrite ) { - super( instanceId ); + super( menu ); this.overwrite = overwrite; } @@ -37,9 +37,9 @@ public class ContinueUploadMessage extends ComputerServerMessage } @Override - protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) + protected void handle( NetworkEvent.Context context, @Nonnull ComputerMenu container ) { ServerPlayerEntity player = context.getSender(); - if( player != null ) container.confirmUpload( player, overwrite ); + if( player != null ) container.getInput().confirmUpload( player, overwrite ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java index e30e246c5..50d835587 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/KeyEventServerMessage.java @@ -5,9 +5,9 @@ */ package dan200.computercraft.shared.network.server; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.InputState; -import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import dan200.computercraft.shared.computer.menu.ServerInputHandler; +import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -22,9 +22,9 @@ public class KeyEventServerMessage extends ComputerServerMessage private final int type; private final int key; - public KeyEventServerMessage( int instanceId, int type, int key ) + public KeyEventServerMessage( Container menu, int type, int key ) { - super( instanceId ); + super( menu ); this.type = type; this.key = key; } @@ -39,15 +39,14 @@ public class KeyEventServerMessage extends ComputerServerMessage @Override public void toBytes( @Nonnull PacketBuffer buf ) { - super.toBytes( buf ); buf.writeByte( type ); buf.writeVarInt( key ); } @Override - protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) + protected void handle( NetworkEvent.Context context, @Nonnull ComputerMenu container ) { - InputState input = container.getInput(); + ServerInputHandler input = container.getInput(); if( type == TYPE_UP ) { input.keyUp( key ); diff --git a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java index b89c865be..efc84476d 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/MouseEventServerMessage.java @@ -5,9 +5,9 @@ */ package dan200.computercraft.shared.network.server; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.InputState; -import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import dan200.computercraft.shared.computer.menu.ServerInputHandler; +import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -25,9 +25,9 @@ public class MouseEventServerMessage extends ComputerServerMessage private final int y; private final int arg; - public MouseEventServerMessage( int instanceId, int type, int arg, int x, int y ) + public MouseEventServerMessage( Container menu, int type, int arg, int x, int y ) { - super( instanceId ); + super( menu ); this.type = type; this.arg = arg; this.x = x; @@ -54,9 +54,9 @@ public class MouseEventServerMessage extends ComputerServerMessage } @Override - protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) + protected void handle( NetworkEvent.Context context, @Nonnull ComputerMenu container ) { - InputState input = container.getInput(); + ServerInputHandler input = container.getInput(); switch( type ) { case TYPE_CLICK: diff --git a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java index b1348f771..382a4d5b2 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/QueueEventServerMessage.java @@ -5,9 +5,11 @@ */ package dan200.computercraft.shared.network.server; -import dan200.computercraft.shared.computer.core.IContainerComputer; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import dan200.computercraft.shared.computer.menu.ServerInputHandler; import dan200.computercraft.shared.util.NBTUtil; +import net.minecraft.inventory.container.Container; import net.minecraft.nbt.CompoundNBT; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -18,17 +20,16 @@ import javax.annotation.Nullable; /** * Queue an event on a {@link ServerComputer}. * - * @see dan200.computercraft.shared.computer.core.ClientComputer#queueEvent(String) - * @see ServerComputer#queueEvent(String) + * @see ServerInputHandler#queueEvent(String) */ public class QueueEventServerMessage extends ComputerServerMessage { private final String event; private final Object[] args; - public QueueEventServerMessage( int instanceId, @Nonnull String event, @Nullable Object[] args ) + public QueueEventServerMessage( Container menu, @Nonnull String event, @Nullable Object[] args ) { - super( instanceId ); + super( menu ); this.event = event; this.args = args; } @@ -51,8 +52,8 @@ public class QueueEventServerMessage extends ComputerServerMessage } @Override - protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) + protected void handle( NetworkEvent.Context context, @Nonnull ComputerMenu container ) { - computer.queueEvent( event, args ); + container.getInput().queueEvent( event, args ); } } diff --git a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java b/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java deleted file mode 100644 index 4ceefd56d..000000000 --- a/src/main/java/dan200/computercraft/shared/network/server/RequestComputerMessage.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of ComputerCraft - http://www.computercraft.info - * Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission. - * Send enquiries to dratcliffe@gmail.com - */ -package dan200.computercraft.shared.network.server; - -import dan200.computercraft.ComputerCraft; -import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.network.NetworkMessage; -import net.minecraft.network.PacketBuffer; -import net.minecraftforge.fml.network.NetworkEvent; - -import javax.annotation.Nonnull; - -public class RequestComputerMessage implements NetworkMessage -{ - private final int instance; - - public RequestComputerMessage( int instance ) - { - this.instance = instance; - } - - public RequestComputerMessage( @Nonnull PacketBuffer buf ) - { - instance = buf.readVarInt(); - } - - @Override - public void toBytes( @Nonnull PacketBuffer buf ) - { - buf.writeVarInt( instance ); - } - - @Override - public void handle( NetworkEvent.Context context ) - { - ServerComputer computer = ComputerCraft.serverComputerRegistry.get( instance ); - if( computer != null ) computer.sendComputerState( context.getSender() ); - } -} diff --git a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java index 38c924789..86ec6b92c 100644 --- a/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java +++ b/src/main/java/dan200/computercraft/shared/network/server/UploadFileMessage.java @@ -5,13 +5,14 @@ */ package dan200.computercraft.shared.network.server; -import dan200.computercraft.shared.computer.core.IContainerComputer; -import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.menu.ComputerMenu; +import dan200.computercraft.shared.computer.menu.ServerInputHandler; import dan200.computercraft.shared.computer.upload.FileSlice; import dan200.computercraft.shared.computer.upload.FileUpload; import dan200.computercraft.shared.network.NetworkHandler; import io.netty.handler.codec.DecoderException; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.container.Container; import net.minecraft.network.PacketBuffer; import net.minecraftforge.fml.network.NetworkEvent; @@ -37,9 +38,9 @@ public class UploadFileMessage extends ComputerServerMessage private final List files; private final List slices; - UploadFileMessage( int instanceId, UUID uuid, int flag, List files, List slices ) + UploadFileMessage( Container menu, UUID uuid, int flag, List files, List slices ) { - super( instanceId ); + super( menu ); this.uuid = uuid; this.flag = flag; this.files = files; @@ -127,7 +128,7 @@ public class UploadFileMessage extends ComputerServerMessage } } - public static void send( int instanceId, List files ) + public static void send( Container container, List files ) { UUID uuid = UUID.randomUUID(); @@ -148,8 +149,8 @@ public class UploadFileMessage extends ComputerServerMessage if( remaining <= 0 ) { NetworkHandler.sendToServer( first - ? new UploadFileMessage( instanceId, uuid, FLAG_FIRST, files, new ArrayList<>( slices ) ) - : new UploadFileMessage( instanceId, uuid, 0, null, new ArrayList<>( slices ) ) ); + ? new UploadFileMessage( container, uuid, FLAG_FIRST, files, new ArrayList<>( slices ) ) + : new UploadFileMessage( container, uuid, 0, null, new ArrayList<>( slices ) ) ); slices.clear(); remaining = MAX_PACKET_SIZE; first = false; @@ -167,19 +168,20 @@ public class UploadFileMessage extends ComputerServerMessage } NetworkHandler.sendToServer( first - ? new UploadFileMessage( instanceId, uuid, FLAG_FIRST | FLAG_LAST, files, new ArrayList<>( slices ) ) - : new UploadFileMessage( instanceId, uuid, FLAG_LAST, null, new ArrayList<>( slices ) ) ); + ? new UploadFileMessage( container, uuid, FLAG_FIRST | FLAG_LAST, files, new ArrayList<>( slices ) ) + : new UploadFileMessage( container, uuid, FLAG_LAST, null, new ArrayList<>( slices ) ) ); } @Override - protected void handle( NetworkEvent.Context context, @Nonnull ServerComputer computer, @Nonnull IContainerComputer container ) + protected void handle( NetworkEvent.Context context, @Nonnull ComputerMenu container ) { ServerPlayerEntity player = context.getSender(); if( player != null ) { - if( (flag & FLAG_FIRST) != 0 ) container.startUpload( uuid, files ); - container.continueUpload( uuid, slices ); - if( (flag & FLAG_LAST) != 0 ) container.finishUpload( player, uuid ); + ServerInputHandler input = container.getInput(); + if( (flag & FLAG_FIRST) != 0 ) input.startUpload( uuid, files ); + input.continueUpload( uuid, slices ); + if( (flag & FLAG_LAST) != 0 ) input.finishUpload( player, uuid ); } } } diff --git a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java index e8a152777..669c2e1e1 100644 --- a/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java +++ b/src/main/java/dan200/computercraft/shared/peripheral/monitor/ServerMonitor.java @@ -85,7 +85,7 @@ public class ServerMonitor extends ServerTerminal public boolean pollTerminalChanged() { - update(); + tickServer(); return hasTerminalChanged(); } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index 9d894980c..da21800fa 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -14,6 +14,8 @@ import dan200.computercraft.shared.common.IColouredItem; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.network.NetworkHandler; +import dan200.computercraft.shared.network.client.PocketComputerDataMessage; +import dan200.computercraft.shared.network.client.PocketComputerDeletedClientMessage; import dan200.computercraft.shared.pocket.items.ItemPocketComputer; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -24,15 +26,11 @@ import net.minecraft.entity.player.ServerPlayerEntity; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.ResourceLocation; -import net.minecraft.world.World; -import net.minecraftforge.common.util.Constants; +import net.minecraft.world.server.ServerWorld; import javax.annotation.Nonnull; import javax.annotation.Nullable; -import java.util.Collections; -import java.util.Map; - -import static dan200.computercraft.shared.pocket.items.ItemPocketComputer.NBT_LIGHT; +import java.util.*; public class PocketServerComputer extends ServerComputer implements IPocketAccess { @@ -40,9 +38,14 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces private Entity entity; private ItemStack stack; - public PocketServerComputer( World world, int computerID, String label, int instanceID, ComputerFamily family ) + private int lightColour = -1; + private boolean lightChanged = false; + + private final Set tracking = new HashSet<>(); + + public PocketServerComputer( ServerWorld world, int computerID, String label, ComputerFamily family ) { - super( world, computerID, label, instanceID, family, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); + super( world, computerID, label, family, ComputerCraft.pocketTermWidth, ComputerCraft.pocketTermHeight ); } @Nullable @@ -89,27 +92,17 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces @Override public int getLight() { - CompoundNBT tag = getUserData(); - return tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) ? tag.getInt( NBT_LIGHT ) : -1; + return lightColour; } @Override public void setLight( int colour ) { - CompoundNBT tag = getUserData(); - if( colour >= 0 && colour <= 0xFFFFFF ) - { - if( !tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) || tag.getInt( NBT_LIGHT ) != colour ) - { - tag.putInt( NBT_LIGHT, colour ); - updateUserData(); - } - } - else if( tag.contains( NBT_LIGHT, Constants.NBT.TAG_ANY_NUMERIC ) ) - { - tag.remove( NBT_LIGHT ); - updateUserData(); - } + if( colour < 0 || colour > 0xFFFFFF ) colour = -1; + + if( lightColour == colour ) return; + lightColour = colour; + lightChanged = true; } @Nonnull @@ -168,7 +161,7 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces { if( entity != null ) { - setWorld( entity.getCommandSenderWorld() ); + setWorld( (ServerWorld) entity.getCommandSenderWorld() ); setPosition( entity.blockPosition() ); } @@ -186,18 +179,53 @@ public class PocketServerComputer extends ServerComputer implements IPocketAcces } @Override - public void broadcastState( boolean force ) + public void tickServer() { - super.broadcastState( force ); + super.tickServer(); - if( (hasTerminalChanged() || force) && entity instanceof ServerPlayerEntity ) + // Find any players which have gone missing and remove them from the tracking list. + tracking.removeIf( player -> !player.isAlive() || player.level != getWorld() ); + + // And now find any new players, add them to the tracking list, and broadcast state where appropriate. + boolean sendState = hasOutputChanged() || lightChanged; + lightChanged = false; + if( sendState ) { - // Broadcast the state to the current entity if they're not already interacting with it. - ServerPlayerEntity player = (ServerPlayerEntity) entity; - if( player.connection != null && !isInteracting( player ) ) + // Broadcast the state to all players + tracking.addAll( getWorld().players() ); + NetworkHandler.sendToPlayers( new PocketComputerDataMessage( this, false ), tracking ); + } + else + { + // Broadcast the state to new players. + List added = new ArrayList<>(); + for( ServerPlayerEntity player : getWorld().players() ) { - NetworkHandler.sendToPlayer( player, createTerminalPacket() ); + if( tracking.add( player ) ) added.add( player ); + } + if( !added.isEmpty() ) + { + NetworkHandler.sendToPlayers( new PocketComputerDataMessage( this, false ), added ); } } } + + @Override + protected void onTerminalChanged() + { + super.onTerminalChanged(); + + if( entity instanceof ServerPlayerEntity && entity.isAlive() ) + { + // Broadcast the terminal to the current player. + NetworkHandler.sendToPlayer( (ServerPlayerEntity) entity, new PocketComputerDataMessage( this, true ) ); + } + } + + @Override + protected void onRemoved() + { + super.onRemoved(); + NetworkHandler.sendToAllPlayers( new PocketComputerDeletedClientMessage( getInstanceID() ) ); + } } diff --git a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java index 7b7862cbb..501f0bc52 100644 --- a/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java +++ b/src/main/java/dan200/computercraft/shared/pocket/items/ItemPocketComputer.java @@ -14,9 +14,8 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.shared.PocketUpgrades; import dan200.computercraft.shared.common.IColouredItem; -import dan200.computercraft.shared.computer.core.ClientComputer; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.ComputerState; +import dan200.computercraft.shared.computer.core.ServerComputerRegistry; import dan200.computercraft.shared.computer.items.IComputerItem; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.pocket.apis.PocketAPI; @@ -40,6 +39,7 @@ import net.minecraft.util.text.StringTextComponent; import net.minecraft.util.text.TextFormatting; import net.minecraft.util.text.TranslationTextComponent; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -88,7 +88,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I { IPocketUpgrade upgrade = getUpgrade( stack ); - computer.setWorld( world ); + computer.setWorld( (ServerWorld) world ); computer.updateValues( entity, stack, upgrade ); boolean changed = false; @@ -125,19 +125,13 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I @Override public void inventoryTick( @Nonnull ItemStack stack, World world, @Nonnull Entity entity, int slotNum, boolean selected ) { - if( !world.isClientSide ) - { - IInventory inventory = entity instanceof PlayerEntity ? ((PlayerEntity) entity).inventory : null; - PocketServerComputer computer = createServerComputer( world, entity, inventory, stack ); - computer.keepAlive(); + if( world.isClientSide ) return; + IInventory inventory = entity instanceof PlayerEntity ? ((PlayerEntity) entity).inventory : null; + PocketServerComputer computer = createServerComputer( (ServerWorld) world, entity, inventory, stack ); + computer.keepAlive(); - boolean changed = tick( stack, world, entity, computer ); - if( changed && inventory != null ) inventory.setChanged(); - } - else - { - createClientComputer( stack ); - } + boolean changed = tick( stack, world, entity, computer ); + if( changed && inventory != null ) inventory.setChanged(); } @Override @@ -157,7 +151,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I ItemStack stack = player.getItemInHand( hand ); if( !world.isClientSide ) { - PocketServerComputer computer = createServerComputer( world, player, player.inventory, stack ); + PocketServerComputer computer = createServerComputer( (ServerWorld) world, player, player.inventory, stack ); computer.turnOn(); boolean stop = false; @@ -227,37 +221,29 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I } @Nonnull - public PocketServerComputer createServerComputer( World world, Entity entity, @Nullable IInventory inventory, @Nonnull ItemStack stack ) + public PocketServerComputer createServerComputer( ServerWorld world, Entity entity, @Nullable IInventory inventory, @Nonnull ItemStack stack ) { if( world.isClientSide ) throw new IllegalStateException( "Cannot call createServerComputer on the client" ); - PocketServerComputer computer; - int instanceID = getInstanceID( stack ); int sessionID = getSessionID( stack ); - int correctSessionID = ComputerCraft.serverComputerRegistry.getSessionID(); - if( instanceID >= 0 && sessionID == correctSessionID && ComputerCraft.serverComputerRegistry.contains( instanceID ) ) + PocketServerComputer computer = (PocketServerComputer) ServerComputerRegistry.INSTANCE.get( sessionID, getInstanceID( stack ) ); + if( computer == null ) { - computer = (PocketServerComputer) ComputerCraft.serverComputerRegistry.get( instanceID ); - } - else - { - if( instanceID < 0 || sessionID != correctSessionID ) - { - instanceID = ComputerCraft.serverComputerRegistry.getUnusedInstanceID(); - setInstanceID( stack, instanceID ); - setSessionID( stack, correctSessionID ); - } int computerID = getComputerID( stack ); if( computerID < 0 ) { computerID = ComputerCraftAPI.createUniqueNumberedSaveDir( world, "computer" ); setComputerID( stack, computerID ); } - computer = new PocketServerComputer( world, computerID, getLabel( stack ), instanceID, getFamily() ); + + computer = new PocketServerComputer( world, getComputerID( stack ), getLabel( stack ), getFamily() ); + + setInstanceID( stack, computer.register() ); + setSessionID( stack, ServerComputerRegistry.INSTANCE.getSessionID() ); + computer.updateValues( entity, stack, getUpgrade( stack ) ); computer.addAPI( new PocketAPI( computer ) ); - ComputerCraft.serverComputerRegistry.add( instanceID, computer ); // Only turn on when initially creating the computer, rather than each tick. if( isMarkedOn( stack ) && entity instanceof PlayerEntity ) computer.turnOn(); @@ -271,33 +257,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I @Nullable public static PocketServerComputer getServerComputer( @Nonnull ItemStack stack ) { - int session = getSessionID( stack ); - if( session != ComputerCraft.serverComputerRegistry.getSessionID() ) return null; - - int instanceID = getInstanceID( stack ); - return instanceID >= 0 ? (PocketServerComputer) ComputerCraft.serverComputerRegistry.get( instanceID ) : null; - } - - @Nullable - public static ClientComputer createClientComputer( @Nonnull ItemStack stack ) - { - int instanceID = getInstanceID( stack ); - if( instanceID >= 0 ) - { - if( !ComputerCraft.clientComputerRegistry.contains( instanceID ) ) - { - ComputerCraft.clientComputerRegistry.add( instanceID, new ClientComputer( instanceID ) ); - } - return ComputerCraft.clientComputerRegistry.get( instanceID ); - } - return null; - } - - @Nullable - private static ClientComputer getClientComputer( @Nonnull ItemStack stack ) - { - int instanceID = getInstanceID( stack ); - return instanceID >= 0 ? ComputerCraft.clientComputerRegistry.get( instanceID ) : null; + return (PocketServerComputer) ServerComputerRegistry.INSTANCE.get( getSessionID( stack ), getInstanceID( stack ) ); } // IComputerItem implementation @@ -355,7 +315,7 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I return null; } - private static int getInstanceID( @Nonnull ItemStack stack ) + public static int getInstanceID( @Nonnull ItemStack stack ) { CompoundNBT nbt = stack.getTag(); return nbt != null && nbt.contains( NBT_INSTANCE ) ? nbt.getInt( NBT_INSTANCE ) : -1; @@ -383,26 +343,6 @@ public class ItemPocketComputer extends Item implements IComputerItem, IMedia, I return nbt != null && nbt.getBoolean( NBT_ON ); } - public static ComputerState getState( @Nonnull ItemStack stack ) - { - ClientComputer computer = getClientComputer( stack ); - return computer == null ? ComputerState.OFF : computer.getState(); - } - - public static int getLightState( @Nonnull ItemStack stack ) - { - ClientComputer computer = getClientComputer( stack ); - if( computer != null && computer.isOn() ) - { - CompoundNBT computerNBT = computer.getUserData(); - if( computerNBT != null && computerNBT.contains( NBT_LIGHT ) ) - { - return computerNBT.getInt( NBT_LIGHT ); - } - } - return -1; - } - public static IPocketUpgrade getUpgrade( @Nonnull ItemStack stack ) { CompoundNBT compound = stack.getTag(); diff --git a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java index 96e2eee20..29fd1fd0b 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/blocks/TileTurtle.java @@ -38,6 +38,7 @@ import net.minecraft.util.*; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockRayTraceResult; import net.minecraft.util.math.vector.Vector3d; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.Constants; import net.minecraftforge.common.util.LazyOptional; @@ -84,10 +85,10 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default } @Override - protected ServerComputer createComputer( int instanceID, int id ) + protected ServerComputer createComputer( int id ) { ServerComputer computer = new ServerComputer( - getLevel(), id, label, instanceID, getFamily(), + (ServerWorld) getLevel(), id, label, getFamily(), ComputerCraft.turtleTermWidth, ComputerCraft.turtleTermHeight ); computer.setPosition( getBlockPos() ); @@ -576,6 +577,6 @@ public class TileTurtle extends TileComputerBase implements ITurtleTile, Default @Override public Container createMenu( int id, @Nonnull PlayerInventory inventory, @Nonnull PlayerEntity player ) { - return new ContainerTurtle( id, inventory, brain ); + return ContainerTurtle.ofBrain( id, inventory, brain ); } } diff --git a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java index ba336e923..d74fe7e19 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java +++ b/src/main/java/dan200/computercraft/shared/turtle/core/TurtleBrain.java @@ -40,6 +40,7 @@ import net.minecraft.util.math.AxisAlignedBB; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; import net.minecraft.world.World; +import net.minecraft.world.server.ServerWorld; import net.minecraftforge.common.util.Constants; import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.wrapper.InvWrapper; @@ -339,7 +340,7 @@ public class TurtleBrain implements ITurtleAccess newTurtle.transferStateFrom( oldOwner ); ServerComputer computer = newTurtle.createServerComputer(); - computer.setWorld( world ); + computer.setWorld( (ServerWorld) world ); computer.setPosition( pos ); // Remove the old turtle diff --git a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java index 7142773ab..cc6fbfbd2 100644 --- a/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java +++ b/src/main/java/dan200/computercraft/shared/turtle/inventory/ContainerTurtle.java @@ -8,7 +8,7 @@ package dan200.computercraft.shared.turtle.inventory; import dan200.computercraft.client.gui.widgets.ComputerSidebar; import dan200.computercraft.shared.Registry; import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.IComputer; +import dan200.computercraft.shared.computer.core.ServerComputer; import dan200.computercraft.shared.computer.inventory.ContainerComputerBase; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.turtle.blocks.TileTurtle; @@ -24,26 +24,26 @@ import net.minecraft.util.IIntArray; import net.minecraft.util.IntArray; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.function.Predicate; -public class ContainerTurtle extends ContainerComputerBase +public final class ContainerTurtle extends ContainerComputerBase { public static final int BORDER = 8; public static final int PLAYER_START_Y = 134; public static final int TURTLE_START_X = ComputerSidebar.WIDTH + 175; public static final int PLAYER_START_X = ComputerSidebar.WIDTH + BORDER; - private final IIntArray properties; + private final IIntArray data; private ContainerTurtle( - int id, Predicate canUse, IComputer computer, ComputerFamily family, - PlayerInventory playerInventory, IInventory inventory, IIntArray properties + int id, Predicate canUse, ComputerFamily family, @Nullable ServerComputer computer, @Nullable ComputerContainerData menuData, + PlayerInventory playerInventory, IInventory inventory, IIntArray data ) { - super( Registry.ModContainers.TURTLE.get(), id, canUse, computer, family ); - this.properties = properties; - - addDataSlots( properties ); + super( Registry.ModContainers.TURTLE.get(), id, canUse, family, computer, menuData ); + this.data = data; + addDataSlots( data ); // Turtle inventory for( int y = 0; y < 4; y++ ) @@ -70,25 +70,25 @@ public class ContainerTurtle extends ContainerComputerBase } } - public ContainerTurtle( int id, PlayerInventory player, TurtleBrain turtle ) + public static ContainerTurtle ofBrain( int id, PlayerInventory player, TurtleBrain turtle ) { - this( - id, p -> turtle.getOwner().stillValid( p ), turtle.getOwner().createServerComputer(), turtle.getFamily(), + return new ContainerTurtle( + // Laziness in turtle.getOwner() is important here! + id, p -> turtle.getOwner().stillValid( p ), turtle.getFamily(), turtle.getOwner().createServerComputer(), null, player, turtle.getInventory(), (SingleIntArray) turtle::getSelectedSlot ); } - public ContainerTurtle( int id, PlayerInventory player, ComputerContainerData data ) + public static ContainerTurtle ofMenuData( int id, PlayerInventory player, ComputerContainerData data ) { - this( - id, x -> true, getComputer( player, data ), data.getFamily(), - player, new Inventory( TileTurtle.INVENTORY_SIZE ), new IntArray( 1 ) + return new ContainerTurtle( + id, x -> true, data.family(), null, data, player, new Inventory( TileTurtle.INVENTORY_SIZE ), new IntArray( 1 ) ); } public int getSelectedSlot() { - return properties.get( 0 ); + return data.get( 0 ); } @Nonnull