1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-11-11 19:03:03 +00:00

Don't propagate redstone when blink/label changes

Historically, computers tracked whether any world-visible state
(on/off/blinking, label and redstone outputs) had changed with a single
"has changed" flag. While this is simple to use, this has the curious
side effect of that term.setCursorBlink() or os.setComputerLabel() would
cause a block update!

This isn't really a problem in practice - it just means slightly more
block updates. However, the redstone propagation sometimes causes the
computer to invalidate/recheck peripherals, which masks several other
(yet unfixed) bugs.
This commit is contained in:
Jonathan Coates
2024-03-06 18:56:40 +00:00
parent 6e374579a4
commit d38b1da974
12 changed files with 115 additions and 77 deletions

View File

@@ -15,8 +15,7 @@ import dan200.computercraft.core.filesystem.FileSystem;
import dan200.computercraft.core.terminal.Terminal;
import javax.annotation.Nullable;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
/**
@@ -54,9 +53,9 @@ public class Computer {
private final AtomicLong lastTaskId = new AtomicLong();
// Additional state about the computer and its environment.
private boolean blinking = false;
private final Environment internalEnvironment;
private final AtomicBoolean externalOutputChanged = new AtomicBoolean();
private final AtomicInteger externalOutputChanges = new AtomicInteger();
private boolean startRequested;
private int ticksSinceStart = -1;
@@ -140,10 +139,7 @@ public class Computer {
}
public void setLabel(@Nullable String label) {
if (!Objects.equals(label, this.label)) {
this.label = label;
externalOutputChanged.set(true);
}
this.label = label;
}
public void tick() {
@@ -164,28 +160,24 @@ public class Computer {
internalEnvironment.tick();
// Propagate the environment's output to the world.
if (internalEnvironment.updateOutput()) externalOutputChanged.set(true);
// Set output changed if the terminal has changed from blinking to not
var blinking = terminal.getCursorBlink() &&
terminal.getCursorX() >= 0 && terminal.getCursorX() < terminal.getWidth() &&
terminal.getCursorY() >= 0 && terminal.getCursorY() < terminal.getHeight();
if (blinking != this.blinking) {
this.blinking = blinking;
externalOutputChanged.set(true);
}
externalOutputChanges.accumulateAndGet(internalEnvironment.updateOutput(), (x, y) -> x | y);
}
void markChanged() {
externalOutputChanged.set(true);
}
public boolean pollAndResetChanged() {
return externalOutputChanged.getAndSet(false);
/**
* Get a bitmask returning which sides on the computer have changed, resetting the internal state.
*
* @return What sides on the computer have changed.
*/
public int pollAndResetChanges() {
return externalOutputChanges.getAndSet(0);
}
public boolean isBlinking() {
return isOn() && blinking;
if (!isOn() || !terminal.getCursorBlink()) return false;
var cursorX = terminal.getCursorX();
var cursorY = terminal.getCursorY();
return cursorX >= 0 && cursorX < terminal.getWidth() && cursorY >= 0 && cursorY < terminal.getHeight();
}
public void addApi(ILuaAPI api) {

View File

@@ -411,7 +411,6 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
// Initialisation has finished, so let's mark ourselves as on.
isOn = true;
computer.markChanged();
} finally {
isOnLock.unlock();
}
@@ -446,7 +445,6 @@ final class ComputerExecutor implements ComputerScheduler.Worker {
}
computer.getEnvironment().resetOutput();
computer.markChanged();
} finally {
isOnLock.unlock();
}

View File

@@ -222,22 +222,22 @@ public final class Environment implements IAPIEnvironment {
*
* @return If the outputs have changed.
*/
boolean updateOutput() {
int updateOutput() {
// Mark output as changed if the internal redstone has changed
synchronized (internalOutput) {
if (!internalOutputChanged) return false;
if (!internalOutputChanged) return 0;
var changed = false;
var changed = 0;
for (var i = 0; i < ComputerSide.COUNT; i++) {
if (externalOutput[i] != internalOutput[i]) {
externalOutput[i] = internalOutput[i];
changed = true;
changed |= 1 << i;
}
if (externalBundledOutput[i] != internalBundledOutput[i]) {
externalBundledOutput[i] = internalBundledOutput[i];
changed = true;
changed |= 1 << i;
}
}