111 lines
3.3 KiB
JavaScript
111 lines
3.3 KiB
JavaScript
import {MatrixClient, SimpleFsStorageProvider} from "@vector-im/matrix-bot-sdk";
|
|
import {matrix} from "./config.js";
|
|
import "colors";
|
|
import {spawn} from "child_process";
|
|
import escapeHTML from "escape-html";
|
|
|
|
|
|
// matrix
|
|
|
|
var storage = new SimpleFsStorageProvider("matrix-data.json");
|
|
var client = new MatrixClient(matrix.homeserver_url, matrix.access_token, storage);
|
|
var sendmsg = body => client.sendMessage(matrix.room_id, {body, msgtype: "m.text", format: "org.matrix.custom.html", formatted_body: escapeHTML(body), "m.mentions": {}});
|
|
await client.start();
|
|
console.log("matrix ready");
|
|
|
|
|
|
|
|
// minecraft
|
|
|
|
var mc_ready = false;
|
|
var mc = spawn("java", ["-Xmx16G", "-Xms16G", "-jar", "server.jar"], {
|
|
cwd: "server"
|
|
});
|
|
mc.stdout.on("data", data => {
|
|
var line = data.toString().trim();
|
|
console.log(line.green);
|
|
if (line.endsWith(`[Server thread/INFO]: No player was found`)) return;
|
|
if (/^\[\d\d:\d\d:\d\d\] \[Server thread\/INFO\]: Done/gm.test(line)) {
|
|
mc_ready = true;
|
|
return;
|
|
}
|
|
if (/^\[\d\d:\d\d:\d\d\] \[Server thread\/INFO\]: Stopping (?:the )?server/gm.test(line)) {
|
|
mc_ready = false;
|
|
return;
|
|
}
|
|
if (!mc_ready) return;
|
|
if (/^\[\d\d:\d\d:\d\d\] \[Netty (?:Server|Epoll|Kqueue) IO #\d+\/ERROR]:/.test(line)) return;
|
|
line = line.replace(/^\[\d\d:\d\d:\d\d\] \[(?:Server thread|ServerMain)\/(?:INFO|WARN)\]: (?:\[Not Secure\] )?/gm, '');
|
|
if (line.startsWith("Can't keep up!")) return;
|
|
sendmsg(line).catch(console.error);
|
|
});
|
|
mc.stderr.on("data", data => {
|
|
var line = data.toString().trim();
|
|
console.log(line.yellow);
|
|
});
|
|
mc.on("close", code => {
|
|
mc_ready = false;
|
|
console.log("mc exit", code);
|
|
process.exit(code);
|
|
})
|
|
process.stdin.on("data", data => {
|
|
mc.stdin.write(data);
|
|
});
|
|
|
|
|
|
|
|
// matrix to minecraft
|
|
client.on("room.message", async (roomId, event) => {
|
|
if (roomId != matrix.room_id) return;
|
|
if (event.sender == await client.getUserId()) return;
|
|
var msg = event.content?.body;
|
|
if (typeof msg !== "string") return;
|
|
|
|
if (event.content.filename && event.content.filename != event.content.body) msg += `\n${event.content.filename}`;
|
|
|
|
let displayname = await getDisplayName(event.sender);
|
|
msg = `§b§l${displayname}:§r§b ${msg}`;
|
|
|
|
var replied_event_id = event.content["m.relates_to"]?.["m.in_reply_to"]?.event_id;
|
|
if (replied_event_id) {
|
|
try {
|
|
var replied_event = await client.getEvent(roomId, replied_event_id);
|
|
let displayname = await getDisplayName(replied_event.sender);
|
|
msg = `§3> §l${displayname}:§r§3 §o${replied_event.content?.body || ''}§r\n${msg}`;
|
|
} catch(error) {
|
|
console.error(error.message);
|
|
msg = `§3> §o§4failed to load replied message: ${error.message}§r\n${msg}`;
|
|
}
|
|
}
|
|
|
|
console.log("[matrix]", msg.blue);
|
|
|
|
if (!mc_ready) return;
|
|
mc.stdin.write(`tellraw @a ${JSON.stringify({text: msg, color: "aqua"})}\n`);
|
|
if (event.content.body.toLowerCase() == "list") mc.stdin.write("list\n");
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// util
|
|
|
|
var displaynames = new Map();
|
|
async function getDisplayName(userId) {
|
|
var displayname = displaynames.get(userId);
|
|
if (!displayname) {
|
|
try {
|
|
var {displayname} = await client.getUserProfile(userId);
|
|
} catch (error) {
|
|
console.error(error.message);
|
|
}
|
|
if (!displayname) displayname = userId.match(/^@(.+):/)?.[1] || userId;
|
|
displaynames.set(userId, displayname);
|
|
setTimeout(() => {
|
|
displaynames.delete(userId);
|
|
}, 60000);
|
|
}
|
|
return displayname;
|
|
}
|