mirror of
https://github.com/SquidDev-CC/CC-Tweaked
synced 2025-10-25 19:07:39 +00:00
Merge branch 'mc-1.20.x' into mc-1.21.x
This commit is contained in:
@@ -40,6 +40,8 @@ dependencies {
|
||||
}
|
||||
|
||||
tasks.processResources {
|
||||
inputs.property("gitHash", cct.gitHash)
|
||||
|
||||
var props = mapOf("gitContributors" to cct.gitContributors.get().joinToString("\n"))
|
||||
filesMatching("data/computercraft/lua/rom/help/credits.md") { expand(props) }
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ import java.util.concurrent.atomic.AtomicLong;
|
||||
* <li>Passes main thread tasks to the {@link MainThreadScheduler.Executor}.</li>
|
||||
* </ul>
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
|
||||
//
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package dan200.computercraft.core.computer;
|
||||
|
||||
import dan200.computercraft.core.util.StringUtil;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* 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 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Type a character on the computer.
|
||||
*
|
||||
* @param receiver The computer to queue the event on.
|
||||
* @param chr The character to type.
|
||||
* @see StringUtil#isTypableChar(byte)
|
||||
*/
|
||||
public static void charTyped(Receiver receiver, byte chr) {
|
||||
receiver.queueEvent("char", new Object[]{ new byte[]{ chr } });
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste a string.
|
||||
*
|
||||
* @param receiver The computer to queue the event on.
|
||||
* @param contents The string to paste.
|
||||
* @see StringUtil#getClipboardString(String)
|
||||
*/
|
||||
public static void paste(Receiver receiver, ByteBuffer contents) {
|
||||
receiver.queueEvent("paste", new Object[]{ contents });
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -433,6 +433,16 @@ public final class ComputerThread implements ComputerScheduler {
|
||||
return computerQueueSize() > idleWorkers.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if no work is queued, and all workers are idle.
|
||||
*
|
||||
* @return If the threads are fully idle.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
boolean isFullyIdle() {
|
||||
return computerQueueSize() == 0 && idleWorkers.get() >= workerCount();
|
||||
}
|
||||
|
||||
private void workerFinished(WorkerThread worker) {
|
||||
// We should only shut down a worker once! This should only happen if we fail to abort a worker and then the
|
||||
// worker finishes normally.
|
||||
|
||||
@@ -4,52 +4,116 @@
|
||||
|
||||
package dan200.computercraft.core.util;
|
||||
|
||||
import dan200.computercraft.core.computer.ComputerEvents;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public final class StringUtil {
|
||||
public static final int MAX_PASTE_LENGTH = 512;
|
||||
|
||||
private StringUtil() {
|
||||
}
|
||||
|
||||
private static boolean isAllowed(char c) {
|
||||
return (c >= ' ' && c <= '~') || (c >= 161 && c <= 172) || (c >= 174 && c <= 255);
|
||||
}
|
||||
|
||||
private static String removeSpecialCharacters(String text, int length) {
|
||||
var builder = new StringBuilder(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
var c = text.charAt(i);
|
||||
builder.append(isAllowed(c) ? c : '?');
|
||||
/**
|
||||
* Convert a Unicode character to a terminal one.
|
||||
*
|
||||
* @param chr The Unicode character.
|
||||
* @return The terminal character.
|
||||
*/
|
||||
public static byte unicodeToTerminal(int chr) {
|
||||
// ASCII and latin1 map to themselves
|
||||
if (chr == 0 || chr == '\t' || chr == '\n' || chr == '\r' || (chr >= ' ' && chr <= '~') || (chr >= 160 && chr <= 255)) {
|
||||
return (byte) chr;
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
// Teletext block mosaics are *fairly* contiguous.
|
||||
if (chr >= 0x1FB00 && chr <= 0x1FB13) return (byte) (chr + (129 - 0x1fb00));
|
||||
if (chr >= 0x1FB14 && chr <= 0x1FB1D) return (byte) (chr + (150 - 0x1fb14));
|
||||
|
||||
// Everything else is just a manual lookup. For now, we just use a big switch statement, which we spin into a
|
||||
// separate function to hopefully avoid inlining it here.
|
||||
return unicodeToCraftOsFallback(chr);
|
||||
}
|
||||
|
||||
public static String normaliseLabel(String text) {
|
||||
return removeSpecialCharacters(text, Math.min(32, text.length()));
|
||||
private static byte unicodeToCraftOsFallback(int c) {
|
||||
return switch (c) {
|
||||
case 0x263A -> 1;
|
||||
case 0x263B -> 2;
|
||||
case 0x2665 -> 3;
|
||||
case 0x2666 -> 4;
|
||||
case 0x2663 -> 5;
|
||||
case 0x2660 -> 6;
|
||||
case 0x2022 -> 7;
|
||||
case 0x25D8 -> 8;
|
||||
case 0x2642 -> 11;
|
||||
case 0x2640 -> 12;
|
||||
case 0x266A -> 14;
|
||||
case 0x266B -> 15;
|
||||
case 0x25BA -> 16;
|
||||
case 0x25C4 -> 17;
|
||||
case 0x2195 -> 18;
|
||||
case 0x203C -> 19;
|
||||
case 0x25AC -> 22;
|
||||
case 0x21A8 -> 23;
|
||||
case 0x2191 -> 24;
|
||||
case 0x2193 -> 25;
|
||||
case 0x2192 -> 26;
|
||||
case 0x2190 -> 27;
|
||||
case 0x221F -> 28;
|
||||
case 0x2194 -> 29;
|
||||
case 0x25B2 -> 30;
|
||||
case 0x25BC -> 31;
|
||||
case 0x1FB99 -> 127;
|
||||
case 0x258C -> (byte) 149;
|
||||
default -> '?';
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalise a string from the clipboard, suitable for pasting into a computer.
|
||||
* Check if a character is capable of being input and passed to a {@linkplain ComputerEvents#charTyped(ComputerEvents.Receiver, byte)
|
||||
* "char" event}.
|
||||
*
|
||||
* @param chr The character to check.
|
||||
* @return Whether this character can be typed.
|
||||
*/
|
||||
public static boolean isTypableChar(byte chr) {
|
||||
return chr != 0 && chr != '\r' && chr != '\n';
|
||||
}
|
||||
|
||||
private static boolean isAllowedInLabel(char c) {
|
||||
// Limit to ASCII and latin1, excluding '§' (Minecraft's formatting character).
|
||||
return (c >= ' ' && c <= '~') || (c >= 161 && c <= 255 && c != 167);
|
||||
}
|
||||
|
||||
public static String normaliseLabel(String text) {
|
||||
var length = Math.min(32, text.length());
|
||||
var builder = new StringBuilder(length);
|
||||
for (var i = 0; i < length; i++) {
|
||||
var c = text.charAt(i);
|
||||
builder.append(isAllowedInLabel(c) ? c : '?');
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Java string to a Lua one (using the terminal charset), suitable for pasting into a computer.
|
||||
* <p>
|
||||
* This removes special characters and strips to the first line of text.
|
||||
*
|
||||
* @param clipboard The text from the clipboard.
|
||||
* @return The normalised clipboard text.
|
||||
* @return The encoded clipboard text.
|
||||
*/
|
||||
public static String normaliseClipboardString(String clipboard) {
|
||||
// Clip to the first occurrence of \r or \n
|
||||
var newLineIndex1 = clipboard.indexOf('\r');
|
||||
var newLineIndex2 = clipboard.indexOf('\n');
|
||||
public static ByteBuffer getClipboardString(String clipboard) {
|
||||
var output = new byte[Math.min(MAX_PASTE_LENGTH, clipboard.length())];
|
||||
var idx = 0;
|
||||
|
||||
int length;
|
||||
if (newLineIndex1 >= 0 && newLineIndex2 >= 0) {
|
||||
length = Math.min(newLineIndex1, newLineIndex2);
|
||||
} else if (newLineIndex1 >= 0) {
|
||||
length = newLineIndex1;
|
||||
} else if (newLineIndex2 >= 0) {
|
||||
length = newLineIndex2;
|
||||
} else {
|
||||
length = clipboard.length();
|
||||
var iterator = clipboard.codePoints().iterator();
|
||||
while (iterator.hasNext() && idx <= output.length) {
|
||||
var chr = unicodeToTerminal(iterator.next());
|
||||
if (!isTypableChar(chr)) break;
|
||||
output[idx++] = chr;
|
||||
}
|
||||
|
||||
return removeSpecialCharacters(clipboard, Math.min(length, 512));
|
||||
return ByteBuffer.wrap(output, 0, idx).asReadOnlyBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user