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

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.
This commit is contained in:
Jonathan Coates 2025-01-18 19:18:09 +00:00
parent 6739c4c6c0
commit 938eb38ad5
No known key found for this signature in database
GPG Key ID: B9E431FF07C98D06
7 changed files with 112 additions and 69 deletions

View File

@ -9,7 +9,8 @@ import dan200.computercraft.shared.computer.menu.ServerInputHandler;
import javax.annotation.Nullable; 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 ServerInputHandler
* @see ServerComputer * @see ServerComputer
@ -21,29 +22,17 @@ public interface InputHandler {
queueEvent(event, null); queueEvent(event, null);
} }
default void keyDown(int key, boolean repeat) { void keyDown(int key, boolean repeat);
queueEvent("key", new Object[]{ key, repeat });
}
default void keyUp(int key) { void keyUp(int key);
queueEvent("key_up", new Object[]{ key });
}
default void mouseClick(int button, int x, int y) { void mouseClick(int button, int x, int y);
queueEvent("mouse_click", new Object[]{ button, x, y });
}
default void mouseUp(int button, int x, int y) { void mouseUp(int button, int x, int y);
queueEvent("mouse_up", new Object[]{ button, x, y });
}
default void mouseDrag(int button, int x, int y) { void mouseDrag(int button, int x, int y);
queueEvent("mouse_drag", new Object[]{ button, x, y });
}
default void mouseScroll(int direction, int x, int y) { void mouseScroll(int direction, int x, int y);
queueEvent("mouse_scroll", new Object[]{ direction, x, y });
}
void shutdown(); void shutdown();

View File

@ -12,6 +12,7 @@ import dan200.computercraft.api.peripheral.IPeripheral;
import dan200.computercraft.api.peripheral.WorkMonitor; import dan200.computercraft.api.peripheral.WorkMonitor;
import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerEnvironment; import dan200.computercraft.core.computer.ComputerEnvironment;
import dan200.computercraft.core.computer.ComputerEvents;
import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.metrics.MetricsObserver; import dan200.computercraft.core.metrics.MetricsObserver;
import dan200.computercraft.impl.ApiFactories; import dan200.computercraft.impl.ApiFactories;
@ -34,7 +35,7 @@ import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function; import java.util.function.Function;
public class ServerComputer implements InputHandler, ComputerEnvironment { public class ServerComputer implements ComputerEnvironment, ComputerEvents.Receiver {
private final int instanceID; private final int instanceID;
private final UUID instanceUUID = UUID.randomUUID(); 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; return family;
} }
public ServerLevel getLevel() { public final ServerLevel getLevel() {
return level; return level;
} }
public BlockPos getPosition() { public final BlockPos getPosition() {
return position; return position;
} }
public void setPosition(ServerLevel level, BlockPos pos) { public final void setPosition(ServerLevel level, BlockPos pos) {
this.level = level; this.level = level;
position = pos.immutable(); position = pos.immutable();
} }
protected void markTerminalChanged() { protected final void markTerminalChanged() {
terminalChanged.set(true); terminalChanged.set(true);
} }
@ -117,11 +118,11 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
sendToAllInteracting(c -> new ComputerTerminalClientMessage(c, getTerminalState())); sendToAllInteracting(c -> new ComputerTerminalClientMessage(c, getTerminalState()));
} }
public TerminalState getTerminalState() { public final TerminalState getTerminalState() {
return TerminalState.create(terminal); return TerminalState.create(terminal);
} }
public void keepAlive() { public final void keepAlive() {
ticksSincePing = 0; ticksSincePing = 0;
} }
@ -134,7 +135,7 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
* *
* @return What sides on the computer have changed. * @return What sides on the computer have changed.
*/ */
public int pollRedstoneChanges() { public final int pollRedstoneChanges() {
return computer.pollRedstoneChanges(); return computer.pollRedstoneChanges();
} }
@ -147,7 +148,7 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
computer.unload(); computer.unload();
} }
public void close() { public final void close() {
unload(); unload();
ServerContext.get(level.getServer()).registry().remove(this); ServerContext.get(level.getServer()).registry().remove(this);
} }
@ -176,97 +177,98 @@ public class ServerComputer implements InputHandler, ComputerEnvironment {
protected void onRemoved() { protected void onRemoved() {
} }
public int getInstanceID() { public final int getInstanceID() {
return instanceID; return instanceID;
} }
public UUID getInstanceUUID() { public final UUID getInstanceUUID() {
return instanceUUID; return instanceUUID;
} }
public int getID() { public final int getID() {
return computer.getID(); return computer.getID();
} }
public @Nullable String getLabel() { public final @Nullable String getLabel() {
return computer.getLabel(); return computer.getLabel();
} }
public boolean isOn() { public final boolean isOn() {
return computer.isOn(); return computer.isOn();
} }
public ComputerState getState() { public final ComputerState getState() {
if (!computer.isOn()) return ComputerState.OFF; if (!computer.isOn()) return ComputerState.OFF;
return computer.isBlinking() ? ComputerState.BLINKING : ComputerState.ON; return computer.isBlinking() ? ComputerState.BLINKING : ComputerState.ON;
} }
@Override public final void turnOn() {
public void turnOn() {
computer.turnOn(); computer.turnOn();
} }
@Override public final void shutdown() {
public void shutdown() {
computer.shutdown(); computer.shutdown();
} }
@Override public final void reboot() {
public void reboot() {
computer.reboot(); computer.reboot();
} }
@Override @Override
public void queueEvent(String event, @Nullable Object[] arguments) { public final void queueEvent(String event, @Nullable Object[] arguments) {
computer.queueEvent(event, 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; 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); 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; 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); computer.getEnvironment().setPeripheral(side, peripheral);
} }
@Nullable @Nullable
public IPeripheral getPeripheral(ComputerSide side) { public final IPeripheral getPeripheral(ComputerSide side) {
return computer.getEnvironment().getPeripheral(side); return computer.getEnvironment().getPeripheral(side);
} }
public void setLabel(@Nullable String label) { public final void setLabel(@Nullable String label) {
computer.setLabel(label); computer.setLabel(label);
} }
@Override @Override
public double getTimeOfDay() { public final double getTimeOfDay() {
return (level.getDayTime() + 6000) % 24000 / 1000.0; return (level.getDayTime() + 6000) % 24000 / 1000.0;
} }
@Override @Override
public int getDay() { public final int getDay() {
return (int) ((level.getDayTime() + 6000) / 24000) + 1; return (int) ((level.getDayTime() + 6000) / 24000) + 1;
} }
@Override @Override
public MetricsObserver getMetrics() { public final MetricsObserver getMetrics() {
return metrics; return metrics;
} }
public WorkMonitor getMainThreadMonitor() { public final WorkMonitor getMainThreadMonitor() {
return computer.getMainThreadMonitor(); return computer.getMainThreadMonitor();
} }
@Override @Override
public @Nullable WritableMount createRootMount() { public final WritableMount createRootMount() {
return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + computer.getID(), Config.computerSpaceLimit); return ComputerCraftAPI.createSaveDirMount(level.getServer(), "computer/" + computer.getID(), Config.computerSpaceLimit);
} }
} }

View File

@ -7,6 +7,7 @@ package dan200.computercraft.shared.computer.menu;
import dan200.computercraft.core.apis.handles.ByteBufferChannel; import dan200.computercraft.core.apis.handles.ByteBufferChannel;
import dan200.computercraft.core.apis.transfer.TransferredFile; import dan200.computercraft.core.apis.transfer.TransferredFile;
import dan200.computercraft.core.apis.transfer.TransferredFiles; 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.FileSlice;
import dan200.computercraft.shared.computer.upload.FileUpload; import dan200.computercraft.shared.computer.upload.FileUpload;
import dan200.computercraft.shared.computer.upload.UploadResult; import dan200.computercraft.shared.computer.upload.UploadResult;
@ -56,13 +57,13 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
@Override @Override
public void keyDown(int key, boolean repeat) { public void keyDown(int key, boolean repeat) {
keysDown.add(key); keysDown.add(key);
owner.getComputer().keyDown(key, repeat); ComputerEvents.keyDown(owner.getComputer(), key, repeat);
} }
@Override @Override
public void keyUp(int key) { public void keyUp(int key) {
keysDown.remove(key); keysDown.remove(key);
owner.getComputer().keyUp(key); ComputerEvents.keyUp(owner.getComputer(), key);
} }
@Override @Override
@ -71,7 +72,7 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
lastMouseY = y; lastMouseY = y;
lastMouseDown = button; lastMouseDown = button;
owner.getComputer().mouseClick(button, x, y); ComputerEvents.mouseClick(owner.getComputer(), button, x, y);
} }
@Override @Override
@ -80,7 +81,7 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
lastMouseY = y; lastMouseY = y;
lastMouseDown = -1; lastMouseDown = -1;
owner.getComputer().mouseUp(button, x, y); ComputerEvents.mouseUp(owner.getComputer(), button, x, y);
} }
@Override @Override
@ -89,7 +90,7 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
lastMouseY = y; lastMouseY = y;
lastMouseDown = button; lastMouseDown = button;
owner.getComputer().mouseDrag(button, x, y); ComputerEvents.mouseDrag(owner.getComputer(), button, x, y);
} }
@Override @Override
@ -97,7 +98,7 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
lastMouseX = x; lastMouseX = x;
lastMouseY = y; lastMouseY = y;
owner.getComputer().mouseScroll(direction, x, y); ComputerEvents.mouseScroll(owner.getComputer(), direction, x, y);
} }
@Override @Override
@ -169,9 +170,9 @@ public class ServerInputState<T extends AbstractContainerMenu & ComputerMenu> im
public void close() { public void close() {
var computer = owner.getComputer(); var computer = owner.getComputer();
var keys = keysDown.iterator(); 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(); keysDown.clear();
lastMouseDown = -1; lastMouseDown = -1;

View File

@ -148,7 +148,9 @@ object TestHooks {
GameTestRegistry.getAllTestFunctions().add( GameTestRegistry.getAllTestFunctions().add(
TestFunction( TestFunction(
testName, testName, testInfo.template.ifEmpty { testName }, testName,
testName,
testInfo.template.ifEmpty { testName },
testInfo.timeoutTicks, testInfo.timeoutTicks,
0, 0,
true, true,

View File

@ -31,7 +31,7 @@ import java.util.concurrent.atomic.AtomicLong;
* <li>Passes main thread tasks to the {@link MainThreadScheduler.Executor}.</li> * <li>Passes main thread tasks to the {@link MainThreadScheduler.Executor}.</li>
* </ul> * </ul>
*/ */
public class Computer { public class Computer implements ComputerEvents.Receiver {
private static final int START_DELAY = 50; private static final int START_DELAY = 50;
// Various properties of the computer // Various properties of the computer
@ -114,6 +114,7 @@ public class Computer {
executor.queueStop(false, true); executor.queueStop(false, true);
} }
@Override
public void queueEvent(String event, @Nullable Object[] args) { public void queueEvent(String event, @Nullable Object[] args) {
executor.queueEvent(event, args); executor.queueEvent(event, args);
} }

View File

@ -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);
}
}

View File

@ -8,6 +8,7 @@ import dan200.computercraft.core.apis.handles.ArrayByteChannel;
import dan200.computercraft.core.apis.transfer.TransferredFile; import dan200.computercraft.core.apis.transfer.TransferredFile;
import dan200.computercraft.core.apis.transfer.TransferredFiles; import dan200.computercraft.core.apis.transfer.TransferredFiles;
import dan200.computercraft.core.computer.Computer; import dan200.computercraft.core.computer.Computer;
import dan200.computercraft.core.computer.ComputerEvents;
import dan200.computercraft.core.util.StringUtil; import dan200.computercraft.core.util.StringUtil;
import org.lwjgl.glfw.GLFW; import org.lwjgl.glfw.GLFW;
import org.lwjgl.glfw.GLFWDropCallback; import org.lwjgl.glfw.GLFWDropCallback;
@ -92,7 +93,7 @@ public class InputState {
// Queue the "key" event and add to the down set // Queue the "key" event and add to the down set
var repeat = keysDown.get(key); var repeat = keysDown.get(key);
keysDown.set(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 // Queue the "key_up" event and remove from the down set
if (key >= 0 && keysDown.get(key)) { if (key >= 0 && keysDown.get(key)) {
keysDown.set(key, false); keysDown.set(key, false);
computer.queueEvent("key_up", new Object[]{ key }); ComputerEvents.keyUp(computer, key);
} }
switch (key) { switch (key) {
@ -115,12 +116,12 @@ public class InputState {
public void onMouseClick(int button, int action) { public void onMouseClick(int button, int action) {
switch (action) { switch (action) {
case GLFW.GLFW_PRESS -> { 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; lastMouseButton = button;
} }
case GLFW.GLFW_RELEASE -> { case GLFW.GLFW_RELEASE -> {
if (button == lastMouseButton) { 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; lastMouseButton = -1;
} }
} }
@ -133,13 +134,13 @@ public class InputState {
lastMouseX = mouseX; lastMouseX = mouseX;
lastMouseY = mouseY; lastMouseY = mouseY;
if (lastMouseButton != -1) { 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) { public void onMouseScroll(double yOffset) {
if (yOffset != 0) { 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);
} }
} }