From 938eb38ad504c634267190cdd22c500991e07f19 Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Sat, 18 Jan 2025 19:18:09 +0000 Subject: [PATCH] Move computer events to a single point This abstraction never made much sense on InputHandler, as we only leave the default methods on ServerComputer. We now add a new class (ComputerEvents), which has a series of *static* methods, that can queue an event on a ComputerEvents.Receiver object. This is a bit of an odd indirection (why not just make them instance methods on Receiver?!), but I don't really want those methods leaking everywhere. --- .../shared/computer/core/InputHandler.java | 27 +++---- .../shared/computer/core/ServerComputer.java | 70 ++++++++++--------- .../computer/menu/ServerInputState.java | 17 ++--- .../computercraft/gametest/core/TestHooks.kt | 4 +- .../computercraft/core/computer/Computer.java | 3 +- .../core/computer/ComputerEvents.java | 47 +++++++++++++ .../cc/tweaked/standalone/InputState.java | 13 ++-- 7 files changed, 112 insertions(+), 69 deletions(-) create mode 100644 projects/core/src/main/java/dan200/computercraft/core/computer/ComputerEvents.java diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java index c5108e874..deed8e42b 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/InputHandler.java @@ -9,7 +9,8 @@ import dan200.computercraft.shared.computer.menu.ServerInputHandler; import javax.annotation.Nullable; /** - * Handles user-provided input, forwarding it to a computer. This is used + * Handles user-provided input, forwarding it to a computer. This describes the "shape" of both the client-and + * server-side input handlers. * * @see ServerInputHandler * @see ServerComputer @@ -21,29 +22,17 @@ public interface InputHandler { queueEvent(event, null); } - default void keyDown(int key, boolean repeat) { - queueEvent("key", new Object[]{ key, repeat }); - } + void keyDown(int key, boolean repeat); - default void keyUp(int key) { - queueEvent("key_up", new Object[]{ key }); - } + void keyUp(int key); - default void mouseClick(int button, int x, int y) { - queueEvent("mouse_click", new Object[]{ button, x, y }); - } + void mouseClick(int button, int x, int y); - default void mouseUp(int button, int x, int y) { - queueEvent("mouse_up", new Object[]{ button, x, y }); - } + void mouseUp(int button, int x, int y); - default void mouseDrag(int button, int x, int y) { - queueEvent("mouse_drag", new Object[]{ button, x, y }); - } + void mouseDrag(int button, int x, int y); - default void mouseScroll(int direction, int x, int y) { - queueEvent("mouse_scroll", new Object[]{ direction, x, y }); - } + void mouseScroll(int direction, int x, int y); void shutdown(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index ef41767da..a6a21dbcb 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -12,6 +12,7 @@ import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.api.peripheral.WorkMonitor; import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.ComputerEnvironment; +import dan200.computercraft.core.computer.ComputerEvents; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.metrics.MetricsObserver; import dan200.computercraft.impl.ApiFactories; @@ -34,7 +35,7 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; -public class ServerComputer implements InputHandler, ComputerEnvironment { +public class ServerComputer implements ComputerEnvironment, ComputerEvents.Receiver { private final int instanceID; private final UUID instanceUUID = UUID.randomUUID(); @@ -86,24 +87,24 @@ public class ServerComputer implements InputHandler, ComputerEnvironment { } } - public ComputerFamily getFamily() { + public final ComputerFamily getFamily() { return family; } - public ServerLevel getLevel() { + public final ServerLevel getLevel() { return level; } - public BlockPos getPosition() { + public final BlockPos getPosition() { return position; } - public void setPosition(ServerLevel level, BlockPos pos) { + public final void setPosition(ServerLevel level, BlockPos pos) { this.level = level; position = pos.immutable(); } - protected void markTerminalChanged() { + protected final void markTerminalChanged() { terminalChanged.set(true); } @@ -117,11 +118,11 @@ public class ServerComputer implements InputHandler, ComputerEnvironment { sendToAllInteracting(c -> new ComputerTerminalClientMessage(c, getTerminalState())); } - public TerminalState getTerminalState() { + public final TerminalState getTerminalState() { return TerminalState.create(terminal); } - public void keepAlive() { + public final void keepAlive() { ticksSincePing = 0; } @@ -134,7 +135,7 @@ public class ServerComputer implements InputHandler, ComputerEnvironment { * * @return What sides on the computer have changed. */ - public int pollRedstoneChanges() { + public final int pollRedstoneChanges() { return computer.pollRedstoneChanges(); } @@ -147,7 +148,7 @@ public class ServerComputer implements InputHandler, ComputerEnvironment { computer.unload(); } - public void close() { + public final void close() { unload(); ServerContext.get(level.getServer()).registry().remove(this); } @@ -176,97 +177,98 @@ public class ServerComputer implements InputHandler, ComputerEnvironment { protected void onRemoved() { } - public int getInstanceID() { + public final int getInstanceID() { return instanceID; } - public UUID getInstanceUUID() { + public final UUID getInstanceUUID() { return instanceUUID; } - public int getID() { + public final int getID() { return computer.getID(); } - public @Nullable String getLabel() { + public final @Nullable String getLabel() { return computer.getLabel(); } - public boolean isOn() { + public final boolean isOn() { return computer.isOn(); } - public ComputerState getState() { + public final ComputerState getState() { if (!computer.isOn()) return ComputerState.OFF; return computer.isBlinking() ? ComputerState.BLINKING : ComputerState.ON; } - @Override - public void turnOn() { + public final void turnOn() { computer.turnOn(); } - @Override - public void shutdown() { + public final void shutdown() { computer.shutdown(); } - @Override - public void reboot() { + public final void reboot() { computer.reboot(); } @Override - public void queueEvent(String event, @Nullable Object[] arguments) { + public final void queueEvent(String event, @Nullable Object[] arguments) { computer.queueEvent(event, arguments); } - public int getRedstoneOutput(ComputerSide side) { + public final void queueEvent(String event) { + queueEvent(event, null); + } + + public final int getRedstoneOutput(ComputerSide side) { return computer.isOn() ? computer.getRedstone().getExternalOutput(side) : 0; } - public void setRedstoneInput(ComputerSide side, int level, int bundledState) { + public final void setRedstoneInput(ComputerSide side, int level, int bundledState) { computer.getRedstone().setInput(side, level, bundledState); } - public int getBundledRedstoneOutput(ComputerSide side) { + public final int getBundledRedstoneOutput(ComputerSide side) { return computer.isOn() ? computer.getRedstone().getExternalBundledOutput(side) : 0; } - public void setPeripheral(ComputerSide side, @Nullable IPeripheral peripheral) { + public final void setPeripheral(ComputerSide side, @Nullable IPeripheral peripheral) { computer.getEnvironment().setPeripheral(side, peripheral); } @Nullable - public IPeripheral getPeripheral(ComputerSide side) { + public final IPeripheral getPeripheral(ComputerSide side) { return computer.getEnvironment().getPeripheral(side); } - public void setLabel(@Nullable String label) { + public final void setLabel(@Nullable String label) { computer.setLabel(label); } @Override - public double getTimeOfDay() { + public final double getTimeOfDay() { return (level.getDayTime() + 6000) % 24000 / 1000.0; } @Override - public int getDay() { + public final int getDay() { return (int) ((level.getDayTime() + 6000) / 24000) + 1; } @Override - public MetricsObserver getMetrics() { + public final MetricsObserver getMetrics() { return metrics; } - public WorkMonitor getMainThreadMonitor() { + public final WorkMonitor getMainThreadMonitor() { return computer.getMainThreadMonitor(); } @Override - public @Nullable WritableMount createRootMount() { + public final WritableMount createRootMount() { return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + computer.getID(), Config.computerSpaceLimit); } } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java index 21753d281..08e6702b0 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/menu/ServerInputState.java @@ -7,6 +7,7 @@ package dan200.computercraft.shared.computer.menu; import dan200.computercraft.core.apis.handles.ByteBufferChannel; import dan200.computercraft.core.apis.transfer.TransferredFile; import dan200.computercraft.core.apis.transfer.TransferredFiles; +import dan200.computercraft.core.computer.ComputerEvents; import dan200.computercraft.shared.computer.upload.FileSlice; import dan200.computercraft.shared.computer.upload.FileUpload; import dan200.computercraft.shared.computer.upload.UploadResult; @@ -56,13 +57,13 @@ public class ServerInputState im @Override public void keyDown(int key, boolean repeat) { keysDown.add(key); - owner.getComputer().keyDown(key, repeat); + ComputerEvents.keyDown(owner.getComputer(), key, repeat); } @Override public void keyUp(int key) { keysDown.remove(key); - owner.getComputer().keyUp(key); + ComputerEvents.keyUp(owner.getComputer(), key); } @Override @@ -71,7 +72,7 @@ public class ServerInputState im lastMouseY = y; lastMouseDown = button; - owner.getComputer().mouseClick(button, x, y); + ComputerEvents.mouseClick(owner.getComputer(), button, x, y); } @Override @@ -80,7 +81,7 @@ public class ServerInputState im lastMouseY = y; lastMouseDown = -1; - owner.getComputer().mouseUp(button, x, y); + ComputerEvents.mouseUp(owner.getComputer(), button, x, y); } @Override @@ -89,7 +90,7 @@ public class ServerInputState im lastMouseY = y; lastMouseDown = button; - owner.getComputer().mouseDrag(button, x, y); + ComputerEvents.mouseDrag(owner.getComputer(), button, x, y); } @Override @@ -97,7 +98,7 @@ public class ServerInputState im lastMouseX = x; lastMouseY = y; - owner.getComputer().mouseScroll(direction, x, y); + ComputerEvents.mouseScroll(owner.getComputer(), direction, x, y); } @Override @@ -169,9 +170,9 @@ public class ServerInputState im public void close() { var computer = owner.getComputer(); var keys = keysDown.iterator(); - while (keys.hasNext()) computer.keyUp(keys.nextInt()); + while (keys.hasNext()) ComputerEvents.keyUp(computer, keys.nextInt()); - if (lastMouseDown != -1) computer.mouseUp(lastMouseDown, lastMouseX, lastMouseY); + if (lastMouseDown != -1) ComputerEvents.mouseUp(computer, lastMouseDown, lastMouseX, lastMouseY); keysDown.clear(); lastMouseDown = -1; diff --git a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt index f59a0b602..da5bf7f18 100644 --- a/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt +++ b/projects/common/src/testMod/kotlin/dan200/computercraft/gametest/core/TestHooks.kt @@ -148,7 +148,9 @@ object TestHooks { GameTestRegistry.getAllTestFunctions().add( TestFunction( - testName, testName, testInfo.template.ifEmpty { testName }, + testName, + testName, + testInfo.template.ifEmpty { testName }, testInfo.timeoutTicks, 0, true, diff --git a/projects/core/src/main/java/dan200/computercraft/core/computer/Computer.java b/projects/core/src/main/java/dan200/computercraft/core/computer/Computer.java index e3cb9f2e7..bab208506 100644 --- a/projects/core/src/main/java/dan200/computercraft/core/computer/Computer.java +++ b/projects/core/src/main/java/dan200/computercraft/core/computer/Computer.java @@ -31,7 +31,7 @@ import java.util.concurrent.atomic.AtomicLong; *
  • Passes main thread tasks to the {@link MainThreadScheduler.Executor}.
  • * */ -public class Computer { +public class Computer implements ComputerEvents.Receiver { private static final int START_DELAY = 50; // Various properties of the computer @@ -114,6 +114,7 @@ public class Computer { executor.queueStop(false, true); } + @Override public void queueEvent(String event, @Nullable Object[] args) { executor.queueEvent(event, args); } diff --git a/projects/core/src/main/java/dan200/computercraft/core/computer/ComputerEvents.java b/projects/core/src/main/java/dan200/computercraft/core/computer/ComputerEvents.java new file mode 100644 index 000000000..ba82a28e0 --- /dev/null +++ b/projects/core/src/main/java/dan200/computercraft/core/computer/ComputerEvents.java @@ -0,0 +1,47 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.core.computer; + +import javax.annotation.Nullable; + +/** + * Built-in events that can be queued on a computer. + */ +public final class ComputerEvents { + private ComputerEvents() { + } + + public static void keyDown(Receiver receiver, int key, boolean repeat) { + receiver.queueEvent("key", new Object[]{ key, repeat }); + } + + public static void keyUp(Receiver receiver, int key) { + receiver.queueEvent("key_up", new Object[]{ key }); + } + + public static void mouseClick(Receiver receiver, int button, int x, int y) { + receiver.queueEvent("mouse_click", new Object[]{ button, x, y }); + } + + public static void mouseUp(Receiver receiver, int button, int x, int y) { + receiver.queueEvent("mouse_up", new Object[]{ button, x, y }); + } + + public static void mouseDrag(Receiver receiver, int button, int x, int y) { + receiver.queueEvent("mouse_drag", new Object[]{ button, x, y }); + } + + public static void mouseScroll(Receiver receiver, int direction, int x, int y) { + receiver.queueEvent("mouse_scroll", new Object[]{ direction, x, y }); + } + + /** + * An object that can receive computer events. + */ + @FunctionalInterface + public interface Receiver { + void queueEvent(String event, @Nullable Object[] arguments); + } +} diff --git a/projects/standalone/src/main/java/cc/tweaked/standalone/InputState.java b/projects/standalone/src/main/java/cc/tweaked/standalone/InputState.java index 70a0ea6c1..6b7d80eb6 100644 --- a/projects/standalone/src/main/java/cc/tweaked/standalone/InputState.java +++ b/projects/standalone/src/main/java/cc/tweaked/standalone/InputState.java @@ -8,6 +8,7 @@ import dan200.computercraft.core.apis.handles.ArrayByteChannel; import dan200.computercraft.core.apis.transfer.TransferredFile; import dan200.computercraft.core.apis.transfer.TransferredFiles; import dan200.computercraft.core.computer.Computer; +import dan200.computercraft.core.computer.ComputerEvents; import dan200.computercraft.core.util.StringUtil; import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFWDropCallback; @@ -92,7 +93,7 @@ public class InputState { // Queue the "key" event and add to the down set var repeat = keysDown.get(key); keysDown.set(key); - computer.queueEvent("key", new Object[]{ key, repeat }); + ComputerEvents.keyDown(computer, key, repeat); } } @@ -100,7 +101,7 @@ public class InputState { // Queue the "key_up" event and remove from the down set if (key >= 0 && keysDown.get(key)) { keysDown.set(key, false); - computer.queueEvent("key_up", new Object[]{ key }); + ComputerEvents.keyUp(computer, key); } switch (key) { @@ -115,12 +116,12 @@ public class InputState { public void onMouseClick(int button, int action) { switch (action) { case GLFW.GLFW_PRESS -> { - computer.queueEvent("mouse_click", new Object[]{ button + 1, lastMouseX + 1, lastMouseY + 1 }); + ComputerEvents.mouseClick(computer, button + 1, lastMouseX + 1, lastMouseY + 1); lastMouseButton = button; } case GLFW.GLFW_RELEASE -> { if (button == lastMouseButton) { - computer.queueEvent("mouse_click", new Object[]{ button + 1, lastMouseX + 1, lastMouseY + 1 }); + ComputerEvents.mouseUp(computer, button + 1, lastMouseX + 1, lastMouseY + 1); lastMouseButton = -1; } } @@ -133,13 +134,13 @@ public class InputState { lastMouseX = mouseX; lastMouseY = mouseY; if (lastMouseButton != -1) { - computer.queueEvent("mouse_drag", new Object[]{ lastMouseButton + 1, mouseX + 1, mouseY + 1 }); + ComputerEvents.mouseDrag(computer, lastMouseButton + 1, mouseX + 1, mouseY + 1); } } public void onMouseScroll(double yOffset) { if (yOffset != 0) { - computer.queueEvent("mouse_scroll", new Object[]{ yOffset < 0 ? 1 : -1, lastMouseX + 1, lastMouseY + 1 }); + ComputerEvents.mouseScroll(computer, yOffset < 0 ? 1 : -1, lastMouseX + 1, lastMouseY + 1); } }