Compare commits

..

2 commits

Author SHA1 Message Date
Malasaur
ceccdf818b Replaced Minecraft command with tellraw and Server with ./start.sh 2025-08-28 20:40:44 +02:00
Malasaur
49a9964ec5 Rewritten and finished framework and bot 2025-08-28 20:39:20 +02:00
7 changed files with 150 additions and 33 deletions

2
.gitignore vendored
View file

@ -1,3 +1,3 @@
__pycache__ __pycache__
modules venv
program.py program.py

12
data.py
View file

@ -1,12 +0,0 @@
from subprocess import PIPE, STDOUT, Popen
from typing import Callable, List, Tuple
from re import Pattern
output_binds: List[Tuple[Pattern, Callable]] = []
proc = None
def initializeProc(cmd):
global proc
proc = Popen(cmd.split(), stdin=PIPE, stdout=PIPE,
stderr=STDOUT, text=True, bufsize=1)

31
libcommon.py Normal file
View file

@ -0,0 +1,31 @@
from subprocess import PIPE, STDOUT, Popen, run
from typing import Callable, List, Optional, Tuple
from re import Pattern
minecraftOutputBinds: List[Tuple[Pattern, Callable]] = []
minecraftProc = None
def minecraftInit(cmd: str) -> None:
global minecraftProc
minecraftProc = Popen(cmd.split(), stdin=PIPE, stdout=PIPE,
stderr=STDOUT, text=True, bufsize=1)
class Group:
def __init__(self, name: str, id: str):
self.name = name
self.id = id
def __repr__(self) -> str:
return f'<Group "{self.name}" at "{self.id}">'
signalMessageBinds: List[Tuple[Optional[Group], Callable]] = []
signalProc = None
def signalInit(cmd: str) -> None:
global signalProc
signalProc = run(cmd.split(), stdout=PIPE)

View file

@ -1,19 +1,16 @@
from subprocess import PIPE, STDOUT, Popen
from importlib import import_module
from threading import Thread from threading import Thread
from typing import Callable from typing import Callable
from pathlib import Path
from re import compile from re import compile
import data import libcommon
def reader() -> None: def reader() -> None:
if data.proc.stdout: if libcommon.minecraftProc.stdout:
for line in data.proc.stdout: for line in libcommon.minecraftProc.stdout:
line = line.rstrip("\n") line = line.rstrip("\n")
print(line) print(line)
for pattern, func in data.output_binds: for pattern, func in libcommon.minecraftOutputBinds:
match = pattern.match(line) match = pattern.match(line)
if match: if match:
func(*match.groups()) func(*match.groups())
@ -22,30 +19,30 @@ def reader() -> None:
def onConsoleOutput(pattern: str) -> Callable: def onConsoleOutput(pattern: str) -> Callable:
def decorator(func: Callable) -> Callable: def decorator(func: Callable) -> Callable:
data.output_binds.append((compile(pattern), func)) libcommon.minecraftOutputBinds.append((compile(pattern), func))
return func return func
return decorator return decorator
def sendCommand(cmd: str) -> None: def sendCommand(cmd: str) -> None:
if data.proc.stdin: if libcommon.minecraftProc.stdin:
data.proc.stdin.write(cmd+"\n") libcommon.minecraftProc.stdin.write(cmd+"\n")
data.proc.stdin.flush() libcommon.minecraftProc.stdin.flush()
if __name__ == "__main__": def main() -> None:
data.initializeProc("python -u program.py") libcommon.minecraftInit("sudo ./start.sh")
for file in Path("modules").iterdir():
if file.name.endswith(".py"):
import_module("modules."+file.name[:-3])
t = Thread(target=reader, daemon=True) t = Thread(target=reader, daemon=True)
t.start() t.start()
try: try:
while data.proc.poll() is None: while libcommon.minecraftProc.poll() is None:
sendCommand(input()) sendCommand(input())
except KeyboardInterrupt: except KeyboardInterrupt:
sendCommand("stop") sendCommand("stop")
data.proc.wait() libcommon.minecraftProc.wait()
if __name__ == "__main__":
main()

63
libsignal.py Normal file
View file

@ -0,0 +1,63 @@
from typing import Callable, List, Optional
from requests import post as _post
from sseclient import SSEClient
from threading import Thread
from time import sleep
from json import loads
from uuid import uuid4
import libcommon
url = "http://localhost:42069"
def post(method: str, **params):
return _post(url+"/api/v1/rpc", json={"jsonrpc": "2.0", "method": method, "params": params, "id": str(uuid4())}).json()
def sendMessage(message: str, recipient: str | libcommon.Group):
if isinstance(recipient, libcommon.Group):
return post("send", message=message, groupId=recipient.id)
return post("send", message=message, recipient=recipient)
def listGroups() -> List[libcommon.Group]:
grps = post("listGroups")["result"]
groups = []
for group in grps:
groups.append(libcommon.Group(group["name"], group["id"]))
return groups
def onMessage(group: Optional[libcommon.Group] = None) -> Callable:
def decorator(func: Callable) -> Callable:
libcommon.signalMessageBinds.append((group, func))
return func
return decorator
def main():
cli = Thread(target=libcommon.signalInit, args=(
"signal-cli daemon --http localhost:42069",))
cli.start()
sleep(5)
for msg in SSEClient(url+"/api/v1/events"):
data = loads(msg.data)
envelope = data.get("envelope", None)
if envelope:
dataMessage = envelope.get("dataMessage", None)
if dataMessage:
name = envelope["sourceName"]
body = dataMessage["message"]
groupId = dataMessage["groupInfo"]["groupId"]
if body is not None:
for group, func in libcommon.signalMessageBinds:
if group is None or group.id == groupId:
func(name, body)
break
if __name__ == "__main__":
main()

21
main.py Normal file
View file

@ -0,0 +1,21 @@
from importlib import import_module
from threading import Thread
from subprocess import run
from pathlib import Path
import libminecraft
import libsignal
minecraftThread = Thread(target=libminecraft.main)
signalThread = Thread(target=libsignal.main)
minecraftThread.start()
signalThread.start()
for file in Path("modules").iterdir():
if file.name.endswith(".py"):
import_module("modules."+file.name[:-3])
minecraftThread.join()
signalThread.join()

View file

@ -0,0 +1,17 @@
import libminecraft
import libsignal
import libcommon
RSBeta = libcommon.Group(
"RS Beta", "25a58sEeccxAs7Ka27HZW5Sm3R8zJQcyndLKR6FO7sM=")
@libminecraft.onConsoleOutput(r"\[.*\] \[Server thread\/INFO\]: <(.*)> (.*)")
def minecraftToSignal(usr: str, msg: str):
libsignal.sendMessage(f"[{usr}] {msg}", RSBeta)
@libsignal.onMessage(RSBeta)
def signalToMinecraft(usr: str, msg: str):
print(usr, msg)
libminecraft.sendCommand(f"tellraw @a [{usr}] {msg}")