feat: use text displays for vm bot

This commit is contained in:
Chayapak 2025-05-02 17:46:38 +07:00
parent cf51fdfb9d
commit b5e7929123
Signed by: ChomeNS
SSH key fingerprint: SHA256:0YoxhdyXsgbc0nfeB2N6FYE60mxMU7DS4uCUMaw2mvA
2 changed files with 163 additions and 21 deletions
src/main/java/me/chayapak1/testingbot

View file

@ -6,6 +6,8 @@ import net.kyori.adventure.text.format.NamedTextColor;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.ByteBuffer;
import java.util.UUID;
// all in 1 class unlike ChomeNS Bot because laziness
public class Utilities {
@ -40,7 +42,7 @@ public class Utilities {
character == '\u007f' ||
// check if character is a control code, also space is the first character after
// the control characters so this is why we can do `character < ' '`
// the control characters so this is why we can do `character < ' '
character < ' '
) continue;
@ -50,4 +52,30 @@ public class Utilities {
return replaced.toString();
}
// uuid
public static int[] intArray (final UUID uuid) {
final ByteBuffer buffer = ByteBuffer.wrap(new byte[16]);
buffer.putLong(0, uuid.getMostSignificantBits());
buffer.putLong(8, uuid.getLeastSignificantBits());
final int[] intArray = new int[4];
for (int i = 0; i < intArray.length; i++) intArray[i] = buffer.getInt();
return intArray;
}
public static String snbt (final UUID uuid) {
final int[] array = intArray(uuid);
return String.format(
"[I;%d,%d,%d,%d]",
array[0],
array[1],
array[2],
array[3]
);
}
public static String selector (final UUID uuid) { return "@n[nbt={UUID:" + snbt(uuid) + "}]"; }
}

View file

@ -1,9 +1,10 @@
package me.chayapak1.testingbot.bots;
import me.chayapak1.testingbot.ComponentParser;
import me.chayapak1.testingbot.Utilities;
import me.chayapak1.testingbot.base.BaseBot;
import me.chayapak1.testingbot.base.Core;
import net.kyori.adventure.text.Component;
import org.cloudburstmc.math.vector.Vector3i;
import org.geysermc.mcprotocollib.network.Session;
import org.geysermc.mcprotocollib.network.event.session.SessionAdapter;
import org.geysermc.mcprotocollib.network.packet.Packet;
@ -13,6 +14,7 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.*;
// requires qemu-system-x86_64 in /usr/bin/
// image.iso = cdrom, you can just `touch image.iso` if you don't want it
@ -24,14 +26,44 @@ public class VMBot extends SessionAdapter {
private Process process;
private final TruncatingStringBuilder buffer = new TruncatingStringBuilder(128);
private final UUID textDisplayUUID = UUID.randomUUID();
private String lastOutput = "";
private final Vector3i position = Vector3i.from(
Integer.parseInt(System.getProperty("x")),
Integer.parseInt(System.getProperty("y")),
Integer.parseInt(System.getProperty("z"))
);
public VMBot () {
Runtime.getRuntime().addShutdownHook(new Thread(this::cleanup));
this.bot = new BaseBot("vm");
final Timer timer = new Timer();
final TimerTask recreateTask = new TimerTask() {
@Override
public void run () {
recreate();
}
};
final TimerTask tickTask = new TimerTask() {
@Override
public void run () {
tick();
}
};
timer.schedule(recreateTask, 500, 2 * 1000);
timer.schedule(tickTask, 50, 50);
bot.session.addListener(this);
bot.core.addListener(new Core.Listener() {
@Override
public void refilled() {
public void refilled () {
VMBot.this.coreRefilled();
}
});
@ -39,11 +71,54 @@ public class VMBot extends SessionAdapter {
bot.connect();
}
private void recreate () {
if (!bot.loggedIn) return;
bot.core.run(String.format(
"summon text_display %d %d %d {UUID:%s}",
position.getX(),
position.getY(),
position.getZ(),
Utilities.snbt(textDisplayUUID)
));
bot.core.run(String.format(
"minecraft:data merge entity %s {alignment:left,line_width:1024,shadow:1b,background:-16777216}",
Utilities.selector(textDisplayUUID)
));
}
private void tick () {
if (!bot.loggedIn) return;
final String output = buffer.getString();
if (output.equals(lastOutput)) return;
lastOutput = output;
bot.core.run(String.format(
"data modify entity %s text set value '\"%s\"'",
Utilities.selector(textDisplayUUID),
output
// insane regex
.replaceAll("[\\u001B\\u009B][\\[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", "")
.replace("\r", "")
.replace("\\", "\\\\\\\\")
.replace("'", "\\'")
.replace("\"", "\\\\")
));
}
private void coreRefilled () {
if (started) return;
started = true;
tick(); // creates the text display
new Thread(() -> {
try {
process = new ProcessBuilder(
@ -72,25 +147,31 @@ public class VMBot extends SessionAdapter {
final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String output;
int character;
while ((output = reader.readLine()) != null) {
if (output.isBlank()) continue;
System.out.println(output);
bot.chat.tellraw(
Component.text(
output
// INSANE regex.
.replaceAll("[\\u001B\\u009B][\\[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?(?:\\u0007|\\u001B\\u005C|\\u009C))|(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))", "")
)
);
while ((character = reader.read()) != -1) {
final char[] chars = Character.toChars(character);
final String string = new String(chars);
System.out.print(string);
buffer.append(string);
}
} catch (final IOException e) {
bot.chat.tellraw(Utilities.getErrorComponent(e));
}
}).start();
}, "VM Process Thread").start();
}
private void cleanup () {
System.out.println("\n\nCleaning up...");
bot.core.run(String.format(
"kill %s",
Utilities.selector(textDisplayUUID)
));
try {
Thread.sleep(500);
} catch (final InterruptedException ignored) { }
}
@Override
@ -107,10 +188,6 @@ public class VMBot extends SessionAdapter {
final OutputStream output = process.getOutputStream();
if (content.trim().equalsIgnoreCase("sendc")) {
// ALSO clear the core queue
bot.core.clearQueue();
output.write("\u0003".getBytes());
output.flush();
@ -127,4 +204,41 @@ public class VMBot extends SessionAdapter {
bot.chat.tellraw(Utilities.getErrorComponent(e));
}
}
// chatgpt ahh code
private final static class TruncatingStringBuilder {
private final StringBuilder sb = new StringBuilder();
private final Deque<Integer> newlineIndices = new ArrayDeque<>();
private final int maxNewlines;
public TruncatingStringBuilder (final int maxNewlines) {
this.maxNewlines = maxNewlines;
}
public void append (final String str) {
for (int i = 0; i < str.length(); i++) {
final char c = str.charAt(i);
sb.append(c);
if (c == '\n') {
newlineIndices.addLast(sb.length() - 1);
if (newlineIndices.size() > maxNewlines) {
final Integer cutoffIndex = newlineIndices.pollFirst(); // remove the oldest newline
if (cutoffIndex == null) continue;
sb.delete(0, cutoffIndex + 1);
// Shift all stored newline indices accordingly
for (int j = 0; j < newlineIndices.size(); j++) {
newlineIndices.addLast(newlineIndices.pollFirst() - (cutoffIndex + 1));
}
}
}
}
}
public String getString () {
return sb.toString();
}
}
}