Config refactor part 2

main
Bram van den Heuvel 2023-10-01 14:07:13 +02:00
parent 947b454faf
commit a1a7bf69ff
4 changed files with 56 additions and 68 deletions

View File

@ -39,46 +39,4 @@ MATRIX_ROOM = at(['matrix', 'room_id']) or "!channel_id:example.org"
SERVER_IP = os.getenv('SERVER_ADDRESS') or 'unknown ip' SERVER_IP = os.getenv('SERVER_ADDRESS') or 'unknown ip'
# Matrix users who are allowed to run OP commands in Minecraft through Matrix MATRIX_ADMINS = at(['matrix', 'mc-admins']) or []
MC_ADMINS = [
"@bramvdnheuvel:nltrix.net", # Bram on Matrix (example, feel free to remove)
"@_discord_625632515314548736:t2bot.io" # Bram on Discord (example, feel free to remove)
# Your username on Matrix
]
if os.getenv('MATRIX_ADMINS') is not None:
MC_ADMINS = os.getenv('MATRIX_ADMINS').split(',')
make_bool = lambda os_value, default_value : default_value if not os_value else (
False if os_value.lower() == 'false' else True
)
SERVER_SETTINGS = {
'level-name': os.getenv('WORLD') or 'world',
# Server settings
'port' : 25565 if os.getenv('PORT') == None else int(os.getenv('PORT')),
'query.port' : 25565 if os.getenv('PORT') == None else int(os.getenv('PORT')),
'max-players' : 7 if os.getenv('MAX_PLAYERS') == None else int(os.getenv('MAX_PLAYERS')),
# Server temperature >:3
'view-distance' : 10 if os.getenv('RENDER_DISTANCE') == None else int(os.getenv('RENDER_DISTANCE')),
'enable-command-block' : make_bool(os.getenv('COMMAND_BLOCKS'), True),
# Environment
'allow-nether' : make_bool(os.getenv('NETHER'), True),
'spawn-npcs' : make_bool(os.getenv('NPCS'), True),
'spawn-animals' : make_bool(os.getenv('ANIMALS'), True),
'spawn-monsters' : make_bool(os.getenv('MONSTERS'), True),
# Gamemode
'pvp' : make_bool(os.getenv('PVP'), True),
'gamemode' : os.getenv('GAMEMODE') or 'survival',
'difficulty': os.getenv('DIFFICULTY') or 'medium',
'hardcore' : make_bool(os.getenv('HARDCORE'), False),
# Grief protection
'online-mode' : make_bool(os.getenv('VERIFY_ACCOUNTS'), True),
'white-list' : make_bool(os.getenv('WHITELIST'), True),
'enforce-whitelist' : make_bool(os.getenv('WHITELIST'), True),
'spawn-protection' : 16 if os.getenv('SPAWN_PROTECTION') == None else os.getenv('SPAWN_PROTECTION'),
}

View File

@ -1,3 +1,12 @@
config:
# How much memory the Minecraft server is allowed to take up
# Number in megabytes. Defaults to 1024. (= 1 GB)
ram: 1024
# File location of the server jar.
# To be downloaded at: https://www.minecraft.net/en-us/download/server
server_jar: server.jar
# Matrix bridge configurations # Matrix bridge configurations
matrix: matrix:
# Homeserver URL # Homeserver URL
@ -14,14 +23,16 @@ matrix:
server_address: unknown ip server_address: unknown ip
# List of Matrix users that can send commands to the bridge. # List of Matrix users that can send commands to the bridge.
# When a message starts with a slash, (/) the bridge will interpret it as a # When a message starts with an exclamation mark, (!) the bridge will
# Minecraft command and will put that as a command into the console. # interpret it as a Minecraft command and will put that as a command
# into the console.
mc-admins: mc-admins:
- "@bram:matrix.directory" - "@bram:matrix.directory"
# - "@alice:example.org" # - "@alice:example.org"
# - # -
# When users have bridged from other platforms, you can indicate accordingly. # When users have bridged from other platforms, you can indicate accordingly.
# When multiple RegEx strings apply, all are included.
alternative_platforms: alternative_platforms:
Discord: Discord:
match: "@_?discord_\d+:.+" match: "@_?discord_\d+:.+"

18
main.py
View File

@ -20,11 +20,6 @@ async def message_callback(room: MatrixRoom, event: RoomMessageText) -> None:
if int(event.server_timestamp) < STARTUP_TIME: if int(event.server_timestamp) < STARTUP_TIME:
return return
# Determine platform
platform = 'Matrix'
if re.fullmatch(r"@_discord_\d+:t2bot\.io", event.sender):
platform = 'Discord'
# Determine how to display username # Determine how to display username
name = room.users[event.sender].display_name name = room.users[event.sender].display_name
for user in room.users: for user in room.users:
@ -35,11 +30,7 @@ async def message_callback(room: MatrixRoom, event: RoomMessageText) -> None:
name = room.users[event.sender].disambiguated_name name = room.users[event.sender].disambiguated_name
break break
mc_wrapper.reply_to_mc( mc_wrapper.reply_to_mc(event.body, name, event.sender)
event.body, name,
admin=(event.sender in config.MC_ADMINS),
platform=platform
)
client.add_event_callback(message_callback, RoomMessageText) client.add_event_callback(message_callback, RoomMessageText)
@ -47,7 +38,7 @@ async def activate_client() -> None:
print(await client.login(config.MATRIX_PASSWORD)) print(await client.login(config.MATRIX_PASSWORD))
await client.room_send( await client.room_send(
room_id=config.MC_CHANNEL, room_id=config.MATRIX_ROOM,
message_type="m.room.message", message_type="m.room.message",
content = { content = {
"msgtype": "m.text", "msgtype": "m.text",
@ -60,8 +51,11 @@ async def activate_client() -> None:
async def start(): async def start():
await asyncio.gather( await asyncio.gather(
# Start the Matrix client
activate_client(), activate_client(),
mc_wrapper.start(client, config.MC_CHANNEL)
# Start the Minecraft subprocess
mc_wrapper.start(client, config.MATRIX_ROOM)
) )
asyncio.run(start()) asyncio.run(start())

View File

@ -14,6 +14,9 @@ p = Popen(sys.argv[1:],
nbsr = NBSR(p.stdout) nbsr = NBSR(p.stdout)
async def start(client, mc_channel): async def start(client, mc_channel):
"""
Start reading from the Minecraft subprocess.
"""
await asyncio.sleep(3) await asyncio.sleep(3)
while True: while True:
@ -49,6 +52,12 @@ async def start(client, mc_channel):
server_live = False server_live = False
def process_message(sentence : str) -> Union[str, None]: def process_message(sentence : str) -> Union[str, None]:
"""
Process a message that is sent to stdout in the Minecraft terminal.
If this function deems it relevant, it returns a string that can be
sent to Matrix.
"""
global server_live global server_live
if (match := re.fullmatch( if (match := re.fullmatch(
@ -83,7 +92,8 @@ def process_message(sentence : str) -> Union[str, None]:
sentence)): sentence)):
username, = match.groups() username, = match.groups()
return username + " left the Minecraft server", ( return username + " left the Minecraft server", (
"<strong>" + username + " left the Minecraft server</strong>") "<strong>" + username + " left the Minecraft server</strong>"
)
if (match := re.fullmatch( if (match := re.fullmatch(
r"\[[\d:]+\] \[Server thread\/INFO\]: <([A-Za-z0-9_]{3,16})> (.+)", r"\[[\d:]+\] \[Server thread\/INFO\]: <([A-Za-z0-9_]{3,16})> (.+)",
@ -101,24 +111,39 @@ def process_message(sentence : str) -> Union[str, None]:
return None, None return None, None
def reply_to_mc(message : str, author : str, def reply_to_mc(message : str, display_name : str, sender : str):
admin : bool = False, platform : str = 'Matrix'):
""" """
Send something back to the Minecraft terminal. Send something back to the Minecraft terminal.
""" """
if admin and message.startswith('!'): if sender in config.MATRIX_ADMINS and message.startswith('!'):
p.stdin.write((message[1:] + "\r\n").encode()) p.stdin.write((message[1:] + "\r\n").encode())
else: else:
msg = [
"",
dict(text="M", color="red"),
dict(text="D", color="aqua") if platform == 'Discord' else None,
dict(text=f" <{author}> {message}")
]
p.stdin.write( p.stdin.write(
("execute as @a run tellraw @s " + json.dumps([m for m in msg if m is not None]) + "\r\n").encode() ("execute as @a run tellraw @s " + format(sender, display_name, message) + "\r\n").encode()
) )
p.stdin.flush() p.stdin.flush()
def format(sender : str, display_name : str, message : str) -> str:
"""
Create a string used to format the user's message.
"""
start = [ "", dict(text="M", color="red" ) ]
end = [ dict(text=f" <{display_name}> {message}") ]
options = config.at(['matrix', 'alternative_platforms']) or {}
for platform, details in options.items():
try:
regex = details['match']
text = details['text']
color = details['color']
except KeyError:
print("WARNING: Platform `" + platform + "` is missing some configurations.")
else:
if re.fullmatch(regex, sender):
start.append(dict(text=text, color=color))
return json.dumps(start + end)
if __name__ == '__main__': if __name__ == '__main__':
asyncio.run(start()) asyncio.run(start())