1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-10-22 01:17:38 +00:00

Add redstone relay block (#2002)

- Move redstone methods out of the IAPIEnvironment, and into a new
   RedstoneAccess. We similarly move the implementation from Environment
   into a new RedstoneState class.

   The interface is possibly a little redundant (interfaces with a
   single implementation are always a little suspect), but it's nice to
   keep the consumer/producer interfaces separate.

 - Abstract most redstone API methods into a separate shared class, that
   can be used by both the rs API and the new redstone relay.

 - Add the new redstone relay block.

The docs are probably a little lacking here, but I really struggled to
write anything which wasn't just "look, it's the same as the redstone
API".
This commit is contained in:
Jonathan Coates
2024-11-12 09:05:27 +00:00
committed by GitHub
parent ba6da3bc6c
commit 4f66ac79d3
50 changed files with 1610 additions and 353 deletions

View File

@@ -43,18 +43,6 @@ public interface IAPIEnvironment {
void queueEvent(String event, @Nullable Object... args);
void setOutput(ComputerSide side, int output);
int getOutput(ComputerSide side);
int getInput(ComputerSide side);
void setBundledOutput(ComputerSide side, int output);
int getBundledOutput(ComputerSide side);
int getBundledInput(ComputerSide side);
void setPeripheralChangeListener(@Nullable IPeripheralChangeListener listener);
@Nullable

View File

@@ -5,9 +5,9 @@
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.ILuaAPI;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.redstone.RedstoneAccess;
import java.util.List;
@@ -53,11 +53,9 @@ import java.util.List;
* the Minecraft wiki."
* @cc.module redstone
*/
public class RedstoneAPI implements ILuaAPI {
private final IAPIEnvironment environment;
public RedstoneAPI(IAPIEnvironment environment) {
this.environment = environment;
public class RedstoneAPI extends RedstoneMethods implements ILuaAPI {
public RedstoneAPI(RedstoneAccess environment) {
super(environment);
}
@Override
@@ -76,131 +74,4 @@ public class RedstoneAPI implements ILuaAPI {
public final List<String> getSides() {
return ComputerSide.NAMES;
}
/**
* Turn the redstone signal of a specific side on or off.
*
* @param side The side to set.
* @param on Whether the redstone signal should be on or off. When on, a signal strength of 15 is emitted.
*/
@LuaFunction
public final void setOutput(ComputerSide side, boolean on) {
environment.setOutput(side, on ? 15 : 0);
}
/**
* Get the current redstone output of a specific side.
*
* @param side The side to get.
* @return Whether the redstone output is on or off.
* @see #setOutput
*/
@LuaFunction
public final boolean getOutput(ComputerSide side) {
return environment.getOutput(side) > 0;
}
/**
* Get the current redstone input of a specific side.
*
* @param side The side to get.
* @return Whether the redstone input is on or off.
*/
@LuaFunction
public final boolean getInput(ComputerSide side) {
return environment.getInput(side) > 0;
}
/**
* Set the redstone signal strength for a specific side.
*
* @param side The side to set.
* @param value The signal strength between 0 and 15.
* @throws LuaException If {@code value} is not between 0 and 15.
* @cc.since 1.51
*/
@LuaFunction({ "setAnalogOutput", "setAnalogueOutput" })
public final void setAnalogOutput(ComputerSide side, int value) throws LuaException {
if (value < 0 || value > 15) throw new LuaException("Expected number in range 0-15");
environment.setOutput(side, value);
}
/**
* Get the redstone output signal strength for a specific side.
*
* @param side The side to get.
* @return The output signal strength, between 0 and 15.
* @cc.since 1.51
* @see #setAnalogOutput
*/
@LuaFunction({ "getAnalogOutput", "getAnalogueOutput" })
public final int getAnalogOutput(ComputerSide side) {
return environment.getOutput(side);
}
/**
* Get the redstone input signal strength for a specific side.
*
* @param side The side to get.
* @return The input signal strength, between 0 and 15.
* @cc.since 1.51
*/
@LuaFunction({ "getAnalogInput", "getAnalogueInput" })
public final int getAnalogInput(ComputerSide side) {
return environment.getInput(side);
}
/**
* Set the bundled cable output for a specific side.
*
* @param side The side to set.
* @param output The colour bitmask to set.
* @cc.see colors.subtract For removing a colour from the bitmask.
* @cc.see colors.combine For adding a color to the bitmask.
*/
@LuaFunction
public final void setBundledOutput(ComputerSide side, int output) {
environment.setBundledOutput(side, output);
}
/**
* Get the bundled cable output for a specific side.
*
* @param side The side to get.
* @return The bundle cable's output.
*/
@LuaFunction
public final int getBundledOutput(ComputerSide side) {
return environment.getBundledOutput(side);
}
/**
* Get the bundled cable input for a specific side.
*
* @param side The side to get.
* @return The bundle cable's input.
* @see #testBundledInput To determine if a specific colour is set.
*/
@LuaFunction
public final int getBundledInput(ComputerSide side) {
return environment.getBundledInput(side);
}
/**
* Determine if a specific combination of colours are on for the given side.
*
* @param side The side to test.
* @param mask The mask to test.
* @return If the colours are on.
* @cc.usage Check if [`colors.white`] and [`colors.black`] are on above the computer.
* <pre>{@code
* print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black)))
* }</pre>
* @see #getBundledInput
*/
@LuaFunction
public final boolean testBundledInput(ComputerSide side, int mask) {
var input = environment.getBundledInput(side);
return (input & mask) == mask;
}
}

View File

@@ -0,0 +1,147 @@
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
//
// SPDX-License-Identifier: LicenseRef-CCPL
package dan200.computercraft.core.apis;
import dan200.computercraft.api.lua.LuaException;
import dan200.computercraft.api.lua.LuaFunction;
import dan200.computercraft.core.computer.ComputerSide;
import dan200.computercraft.core.redstone.RedstoneAccess;
/**
* A base class for all blocks with redstone integration.
*/
public class RedstoneMethods {
private final RedstoneAccess redstone;
public RedstoneMethods(RedstoneAccess redstone) {
this.redstone = redstone;
}
/**
* Turn the redstone signal of a specific side on or off.
*
* @param side The side to set.
* @param on Whether the redstone signal should be on or off. When on, a signal strength of 15 is emitted.
*/
@LuaFunction
public final void setOutput(ComputerSide side, boolean on) {
redstone.setOutput(side, on ? 15 : 0);
}
/**
* Get the current redstone output of a specific side.
*
* @param side The side to get.
* @return Whether the redstone output is on or off.
* @see #setOutput
*/
@LuaFunction
public final boolean getOutput(ComputerSide side) {
return redstone.getOutput(side) > 0;
}
/**
* Get the current redstone input of a specific side.
*
* @param side The side to get.
* @return Whether the redstone input is on or off.
*/
@LuaFunction
public final boolean getInput(ComputerSide side) {
return redstone.getInput(side) > 0;
}
/**
* Set the redstone signal strength for a specific side.
*
* @param side The side to set.
* @param value The signal strength between 0 and 15.
* @throws LuaException If {@code value} is not between 0 and 15.
* @cc.since 1.51
*/
@LuaFunction({ "setAnalogOutput", "setAnalogueOutput" })
public final void setAnalogOutput(ComputerSide side, int value) throws LuaException {
if (value < 0 || value > 15) throw new LuaException("Expected number in range 0-15");
redstone.setOutput(side, value);
}
/**
* Get the redstone output signal strength for a specific side.
*
* @param side The side to get.
* @return The output signal strength, between 0 and 15.
* @cc.since 1.51
* @see #setAnalogOutput
*/
@LuaFunction({ "getAnalogOutput", "getAnalogueOutput" })
public final int getAnalogOutput(ComputerSide side) {
return redstone.getOutput(side);
}
/**
* Get the redstone input signal strength for a specific side.
*
* @param side The side to get.
* @return The input signal strength, between 0 and 15.
* @cc.since 1.51
*/
@LuaFunction({ "getAnalogInput", "getAnalogueInput" })
public final int getAnalogInput(ComputerSide side) {
return redstone.getInput(side);
}
/**
* Set the bundled cable output for a specific side.
*
* @param side The side to set.
* @param output The colour bitmask to set.
* @cc.see colors.subtract For removing a colour from the bitmask.
* @cc.see colors.combine For adding a color to the bitmask.
*/
@LuaFunction
public final void setBundledOutput(ComputerSide side, int output) {
redstone.setBundledOutput(side, output);
}
/**
* Get the bundled cable output for a specific side.
*
* @param side The side to get.
* @return The bundle cable's output.
*/
@LuaFunction
public final int getBundledOutput(ComputerSide side) {
return redstone.getBundledOutput(side);
}
/**
* Get the bundled cable input for a specific side.
*
* @param side The side to get.
* @return The bundle cable's input.
* @see #testBundledInput To determine if a specific colour is set.
*/
@LuaFunction
public final int getBundledInput(ComputerSide side) {
return redstone.getBundledInput(side);
}
/**
* Determine if a specific combination of colours are on for the given side.
*
* @param side The side to test.
* @param mask The mask to test.
* @return If the colours are on.
* @cc.usage Check if [`colors.white`] and [`colors.black`] are on above this block.
* <pre>{@code
* print(redstone.testBundledInput("top", colors.combine(colors.white, colors.black)))
* }</pre>
* @see #getBundledInput
*/
@LuaFunction
public final boolean testBundledInput(ComputerSide side, int mask) {
var input = redstone.getBundledInput(side);
return (input & mask) == mask;
}
}

View File

@@ -12,10 +12,10 @@ import dan200.computercraft.core.ComputerContext;
import dan200.computercraft.core.apis.IAPIEnvironment;
import dan200.computercraft.core.computer.mainthread.MainThreadScheduler;
import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.redstone.RedstoneState;
import dan200.computercraft.core.terminal.Terminal;
import javax.annotation.Nullable;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
@@ -54,8 +54,7 @@ public class Computer {
// Additional state about the computer and its environment.
private final Environment internalEnvironment;
private final AtomicInteger externalOutputChanges = new AtomicInteger();
private final RedstoneState redstone = new RedstoneState();
private boolean startRequested;
private int ticksSinceStart = -1;
@@ -87,6 +86,10 @@ public class Computer {
return internalEnvironment;
}
public RedstoneState getRedstone() {
return redstone;
}
public IAPIEnvironment getAPIEnvironment() {
return internalEnvironment;
}
@@ -157,10 +160,8 @@ public class Computer {
executor.tick();
// Update the environment's internal state.
if (redstone.pollInputChanged()) queueEvent("redstone", null);
internalEnvironment.tick();
// Propagate the environment's output to the world.
externalOutputChanges.accumulateAndGet(internalEnvironment.updateOutput(), (x, y) -> x | y);
}
/**
@@ -168,8 +169,8 @@ public class Computer {
*
* @return What sides on the computer have changed.
*/
public int pollAndResetChanges() {
return externalOutputChanges.getAndSet(0);
public int pollRedstoneChanges() {
return redstone.updateOutput();
}
public boolean isBlinking() {

View File

@@ -153,11 +153,11 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
luaMethods = context.luaMethods();
executor = context.computerScheduler().createExecutor(this, metrics);
var environment = computer.getEnvironment();
var environment = computer.getAPIEnvironment();
// Add all default APIs to the loaded list.
addApi(new TermAPI(environment));
addApi(new RedstoneAPI(environment));
addApi(new RedstoneAPI(computer.getRedstone()));
addApi(new FSAPI(environment));
addApi(new PeripheralAPI(environment, context.peripheralMethods()));
addApi(new OSAPI(environment));
@@ -434,14 +434,13 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
// Shutdown our APIs
for (var api : apis) api.shutdown();
computer.getEnvironment().reset();
computer.getRedstone().clearOutput();
// Unload filesystem
if (fileSystem != null) {
fileSystem.close();
fileSystem = null;
}
computer.getEnvironment().resetOutput();
} finally {
isOnLock.unlock();
}

View File

@@ -16,24 +16,12 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.Iterator;
/**
* Represents the "environment" that a {@link Computer} exists in.
* <p>
* This handles storing and updating of peripherals and redstone.
*
* <h1>Redstone</h1>
* We holds three kinds of arrays for redstone, in normal and bundled versions:
* <ul>
* <li>{@link #internalOutput} is the redstone output which the computer has currently set. This is read on both
* threads, and written on the computer thread.</li>
* <li>{@link #externalOutput} is the redstone output currently propagated to the world. This is only read and written
* on the main thread.</li>
* <li>{@link #input} is the redstone input from external sources. This is read on both threads, and written on the main
* thread.</li>
* </ul>
* This handles storing and updating of peripherals and timers.
*
* <h1>Peripheral</h1>
* We also keep track of peripherals. These are read on both threads, and only written on the main thread.
@@ -43,17 +31,6 @@ public final class Environment implements IAPIEnvironment {
private final ComputerEnvironment environment;
private final MetricsObserver metrics;
private boolean internalOutputChanged = false;
private final int[] internalOutput = new int[ComputerSide.COUNT];
private final int[] internalBundledOutput = new int[ComputerSide.COUNT];
private final int[] externalOutput = new int[ComputerSide.COUNT];
private final int[] externalBundledOutput = new int[ComputerSide.COUNT];
private boolean inputChanged = false;
private final int[] input = new int[ComputerSide.COUNT];
private final int[] bundledInput = new int[ComputerSide.COUNT];
private final IPeripheral[] peripherals = new IPeripheral[ComputerSide.COUNT];
private @Nullable IPeripheralChangeListener peripheralListener = null;
@@ -111,76 +88,6 @@ public final class Environment implements IAPIEnvironment {
computer.queueEvent(event, args);
}
@Override
public int getInput(ComputerSide side) {
return input[side.ordinal()];
}
@Override
public int getBundledInput(ComputerSide side) {
return bundledInput[side.ordinal()];
}
@Override
public void setOutput(ComputerSide side, int output) {
var index = side.ordinal();
synchronized (internalOutput) {
if (internalOutput[index] != output) {
internalOutput[index] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getOutput(ComputerSide side) {
synchronized (internalOutput) {
return computer.isOn() ? internalOutput[side.ordinal()] : 0;
}
}
@Override
public void setBundledOutput(ComputerSide side, int output) {
var index = side.ordinal();
synchronized (internalOutput) {
if (internalBundledOutput[index] != output) {
internalBundledOutput[index] = output;
internalOutputChanged = true;
}
}
}
@Override
public int getBundledOutput(ComputerSide side) {
synchronized (internalOutput) {
return computer.isOn() ? internalBundledOutput[side.ordinal()] : 0;
}
}
public int getExternalRedstoneOutput(ComputerSide side) {
return computer.isOn() ? externalOutput[side.ordinal()] : 0;
}
public int getExternalBundledRedstoneOutput(ComputerSide side) {
return computer.isOn() ? externalBundledOutput[side.ordinal()] : 0;
}
public void setRedstoneInput(ComputerSide side, int level) {
var index = side.ordinal();
if (input[index] != level) {
input[index] = level;
inputChanged = true;
}
}
public void setBundledRedstoneInput(ComputerSide side, int combination) {
var index = side.ordinal();
if (bundledInput[index] != combination) {
bundledInput[index] = combination;
inputChanged = true;
}
}
/**
* Called when the computer starts up or shuts down, to reset any internal state.
*
@@ -197,11 +104,6 @@ public final class Environment implements IAPIEnvironment {
* Called on the main thread to update the internal state of the computer.
*/
void tick() {
if (inputChanged) {
inputChanged = false;
queueEvent("redstone");
}
synchronized (timers) {
// Countdown all of our active timers
Iterator<Int2ObjectMap.Entry<Timer>> it = timers.int2ObjectEntrySet().iterator();
@@ -218,45 +120,6 @@ public final class Environment implements IAPIEnvironment {
}
}
/**
* Called on the main thread to propagate the internal outputs to the external ones.
*
* @return If the outputs have changed.
*/
int updateOutput() {
// Mark output as changed if the internal redstone has changed
synchronized (internalOutput) {
if (!internalOutputChanged) return 0;
var changed = 0;
for (var i = 0; i < ComputerSide.COUNT; i++) {
if (externalOutput[i] != internalOutput[i]) {
externalOutput[i] = internalOutput[i];
changed |= 1 << i;
}
if (externalBundledOutput[i] != internalBundledOutput[i]) {
externalBundledOutput[i] = internalBundledOutput[i];
changed |= 1 << i;
}
}
internalOutputChanged = false;
return changed;
}
}
void resetOutput() {
// Reset redstone output
synchronized (internalOutput) {
Arrays.fill(internalOutput, 0);
Arrays.fill(internalBundledOutput, 0);
internalOutputChanged = true;
}
}
@Nullable
@Override
public IPeripheral getPeripheral(ComputerSide side) {

View File

@@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: 2024 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.core.redstone;
import dan200.computercraft.core.apis.RedstoneMethods;
import dan200.computercraft.core.computer.ComputerSide;
/**
* Common interface between blocks which provide and consume a redstone signal.
*
* @see RedstoneMethods Lua-facing methods wrapping this interface.
* @see RedstoneState A concrete implementation of this class.
*/
public interface RedstoneAccess {
/**
* Set the redstone output on a given side.
*
* @param side The side to set.
* @param output The output level, between 0 and 15.
*/
void setOutput(ComputerSide side, int output);
/**
* Get the redstone output on a given side.
*
* @param side The side to get.
* @return The output level, between 0 and 15.
*/
int getOutput(ComputerSide side);
/**
* Get the redstone input on a given side.
*
* @param side The side to get.
* @return The input level, between 0 and 15.
*/
int getInput(ComputerSide side);
/**
* Set the bundled redstone output on a given side.
*
* @param side The side to set.
* @param output The output state, as a 16-bit bitmask.
*/
void setBundledOutput(ComputerSide side, int output);
/**
* Get the bundled redstone output on a given side.
*
* @param side The side to get.
* @return The output state, as a 16-bit bitmask.
*/
int getBundledOutput(ComputerSide side);
/**
* Set the bundled redstone input on a given side.
*
* @param side The side to get.
* @return The input state, as a 16-bit bitmask.
*/
int getBundledInput(ComputerSide side);
}

View File

@@ -0,0 +1,248 @@
// Copyright Daniel Ratcliffe, 2011-2022. Do not distribute without permission.
//
// SPDX-License-Identifier: LicenseRef-CCPL
package dan200.computercraft.core.redstone;
import dan200.computercraft.core.computer.ComputerSide;
import javax.annotation.Nullable;
import javax.annotation.concurrent.GuardedBy;
import java.util.Arrays;
import java.util.concurrent.locks.ReentrantLock;
/**
* Manages the state of redstone inputs and ouputs on a computer (or other redstone emitting block).
* <p>
* As computers execute on a separate thread to the main Minecraft world, computers cannot immediately read or write
* redstone values. Instead, we maintain a copy of the block's redstone inputs and outputs, and sync that with the
* Minecraft world when needed.
*
* <h2>Input</h2>
* Redstone inputs should be propagated immediately to the internal state of the computer. Computers (and other redstone
* blocks) listen for block updates, fetch their neighbour's redstone state, and then call
* {@link #setInput(ComputerSide, int, int)}.
* <p>
* However, we do not want to immediately schedule a {@code "redstone"} event, as otherwise we could schedule many
* events in a single tick. Instead, the next time the block is ticked, the consumer should call
* {@link #pollInputChanged()} and queue an event if needed.
*
* <h2>Output</h2>
* In order to reduce block updates, we maintain a separate "internal" and "external" output state. Whenever a computer
* sets a redstone output, the "internal" state is updated, and a dirty flag is set. When the computer is ticked,
* {@link #updateOutput()} should be called, to copy the internal state to the external state. This returns a bitmask
* indicating which sides have changed. The external outputs may then be read with {@link #getExternalOutput(ComputerSide)}
* and {@link #getExternalBundledOutput(ComputerSide)}.
*/
public final class RedstoneState implements RedstoneAccess {
private final @Nullable Runnable onOutputChanged;
private final ReentrantLock outputLock = new ReentrantLock();
private @GuardedBy("outputLock") boolean internalOutputChanged = false;
private final @GuardedBy("outputLock") int[] internalOutput = new int[ComputerSide.COUNT];
private final @GuardedBy("outputLock") int[] internalBundledOutput = new int[ComputerSide.COUNT];
private final int[] externalOutput = new int[ComputerSide.COUNT];
private final int[] externalBundledOutput = new int[ComputerSide.COUNT];
private final ReentrantLock inputLock = new ReentrantLock();
private boolean inputChanged = false;
private final @GuardedBy("inputLock") int[] input = new int[ComputerSide.COUNT];
private final @GuardedBy("inputLock") int[] bundledInput = new int[ComputerSide.COUNT];
public RedstoneState() {
this(null);
}
/**
* Construct a new {@link RedstoneState}, with a callback function to invoke when the <em>internal</em> output has
* changed. This function is called from the computer thread.
*
* @param outputChanged The function to invoke when output has changed.
*/
public RedstoneState(@Nullable Runnable outputChanged) {
this.onOutputChanged = outputChanged;
}
@Override
public int getInput(ComputerSide side) {
inputLock.lock();
try {
return input[side.ordinal()];
} finally {
inputLock.unlock();
}
}
@Override
public int getBundledInput(ComputerSide side) {
inputLock.lock();
try {
return bundledInput[side.ordinal()];
} finally {
inputLock.unlock();
}
}
@Override
public void setOutput(ComputerSide side, int output) {
var index = side.ordinal();
outputLock.lock();
try {
if (internalOutput[index] == output) return;
internalOutput[index] = output;
setOutputChanged();
} finally {
outputLock.unlock();
}
}
@Override
public int getOutput(ComputerSide side) {
outputLock.lock();
try {
return internalOutput[side.ordinal()];
} finally {
outputLock.unlock();
}
}
@Override
public void setBundledOutput(ComputerSide side, int output) {
var index = side.ordinal();
outputLock.lock();
try {
if (internalBundledOutput[index] == output) return;
internalBundledOutput[index] = output;
setOutputChanged();
} finally {
outputLock.unlock();
}
}
@Override
public int getBundledOutput(ComputerSide side) {
outputLock.lock();
try {
return internalBundledOutput[side.ordinal()];
} finally {
outputLock.unlock();
}
}
@GuardedBy("outputLock")
private void setOutputChanged() {
if (internalOutputChanged) return;
internalOutputChanged = true;
if (onOutputChanged != null) onOutputChanged.run();
}
/**
* Propagate redstone changes from the computer to the outside world. The effective outputs can be acquired with
* {@link #getExternalOutput(ComputerSide)} and {@link #getExternalBundledOutput(ComputerSide)}.
*
* @return A bitmask indicating which sides have changed (indexed via {@link ComputerSide#ordinal()}).
*/
public int updateOutput() {
outputLock.lock();
try {
if (!internalOutputChanged) return 0;
var changed = 0;
for (var i = 0; i < ComputerSide.COUNT; i++) {
if (externalOutput[i] != internalOutput[i]) {
externalOutput[i] = internalOutput[i];
changed |= 1 << i;
}
if (externalBundledOutput[i] != internalBundledOutput[i]) {
externalBundledOutput[i] = internalBundledOutput[i];
changed |= 1 << i;
}
}
internalOutputChanged = false;
return changed;
} finally {
outputLock.unlock();
}
}
/**
* Get the redstone output for a given side.
*
* @param side The side to get.
* @return The effective redstone output.
*/
public int getExternalOutput(ComputerSide side) {
return externalOutput[side.ordinal()];
}
/**
* Get the bundled redstone output for a given side.
*
* @param side The side to get.
* @return The effective bundled redstone output.
*/
public int getExternalBundledOutput(ComputerSide side) {
return externalBundledOutput[side.ordinal()];
}
/**
* Reset any redstone output set by the computer.
*/
public void clearOutput() {
outputLock.lock();
try {
Arrays.fill(internalOutput, 0);
Arrays.fill(internalBundledOutput, 0);
internalOutputChanged = true;
} finally {
outputLock.unlock();
}
}
/**
* Set the redstone input for a given side.
*
* @param side The side to update.
* @param level The redstone level.
* @param bundledState The bundled redstone state.
* @return Whether the input has changed.
*/
public boolean setInput(ComputerSide side, int level, int bundledState) {
var index = side.ordinal();
inputLock.lock();
try {
var changed = false;
if (input[index] != level) {
input[index] = level;
changed = true;
}
if (bundledInput[index] != bundledState) {
bundledInput[index] = bundledState;
changed = true;
}
inputChanged |= changed;
return changed;
} finally {
inputLock.unlock();
}
}
/**
* Check whether any redstone inputs set by {@link #setInput(ComputerSide, int, int)} have changed since the last
* call to this function.
*
* @return Whether any redstone inputs has changed.
*/
public boolean pollInputChanged() {
var changed = inputChanged;
inputChanged = false;
return changed;
}
}

View File

@@ -63,34 +63,6 @@ public abstract class BasicApiEnvironment implements IAPIEnvironment {
public void reboot() {
}
@Override
public void setOutput(ComputerSide side, int output) {
}
@Override
public int getOutput(ComputerSide side) {
return 0;
}
@Override
public int getInput(ComputerSide side) {
return 0;
}
@Override
public void setBundledOutput(ComputerSide side, int output) {
}
@Override
public int getBundledOutput(ComputerSide side) {
return 0;
}
@Override
public int getBundledInput(ComputerSide side) {
return 0;
}
@Override
public void setPeripheralChangeListener(@Nullable IPeripheralChangeListener listener) {
}