tcircv3/tcircv3.py

259 lines
9.9 KiB
Python
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/python3
# tcirc.py
# Copyright (C) 2022 oneseveneight/sose
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Email: oneseveneight@airmail.cc
import socket
import re
import mcrcon.mcrcon as mcrcon
import tomli
import time
import threading
settings = ""
with open('settings.toml', 'rb') as f:
settings = tomli.load(f)
server = settings["irc"]["settings"]["server"]
channel = settings["irc"]["settings"]["channel"]
botnick = settings["irc"]["settings"]["nick"]
irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print('IRC bot connected')
irc.connect((server, 6667))
irc.send(bytes('USER ' + botnick + ' '
+ botnick + ' ' + botnick
+ 'tcirc bot\n', 'utf8'))
irc.send(bytes('NICK ' + botnick + '\n', 'utf8'))
#irc.send(bytes('PRIVMSG nickserv :iNOOPE\r\n', 'utf8'))
print("JOINING CHANNEL")
irc.send(bytes('JOIN ' + channel + '\n', 'utf8'))
print("JOINED CHANNEL")
irc_mc_color_mapping = {}
mc_irc_color_mapping = {}
def define_mapping(irc,mc):
global irc_mc_color_mapping, mc_irc_color_mapping
irc_mc_color_mapping[irc]=mc
mc_irc_color_mapping[mc]=irc
define_mapping(0,"f") # white
define_mapping(1,"0") # black
define_mapping(2,"1") # dark blue
define_mapping(3,"2") # dark green
define_mapping(4,"c") # light red
define_mapping(5,"4") # "brown" (dark red is closest)
define_mapping(6,"5") # purple
define_mapping(7,"6") # orange
define_mapping(8,"e") # yellow
define_mapping(9,"a") # green
define_mapping(10,"3") # dark aqua/cyan
define_mapping(11,"b") # aqua/cyan
define_mapping(12,"9") # light blue
define_mapping(13,"d") # pink (light purple is closest)
define_mapping(14,"8") # gray
define_mapping(15,"7") # light gray
def safeint(v):
try:
return int(v)
except:
return v
def irc_to_mc_colors(m):
if m.group(1)=="\x0f":
return "\xa7r" # reset
else:
return "\xa7"+irc_mc_color_mapping.get(safeint(m.group(2)),"f")
def mc_to_irc():
print('started mc thread')
death_messages_file = open('death_messages', 'r')
death_messages = death_messages_file.readlines()
death_messages_file.close()
death_messages = [s.replace('\n', '') for s in death_messages]
file = open('mc_remote_file')
file.readlines()
print('reading from file ' + file.name)
while 1:
time.sleep(1)
latest_lines = file.readlines()
for line in latest_lines:
print("got line " + line)
if line is None:
continue
line = re.sub(r'', r'^[', line)
for matchlist in settings["game"].keys():
if matchlist == 'settings':
continue
match = []
dontmatch = []
replace = []
if "match" in settings["game"][matchlist].keys():
match = settings["game"][matchlist]["match"]
if "dont_match" in settings["game"][matchlist].keys():
dontmatch = settings["game"][matchlist]["dont_match"]
if "replace" in settings["game"][matchlist].keys():
replace = settings["game"][matchlist]["replace"]
line_does_match = True
for match_line in match:
if re.search(match_line, line) is None:
print("line didn't match " + match_line + ", dumping")
print("line was " + line)
line_does_match = False
break
if line_does_match == False:
continue
for match_line in dontmatch:
if re.search(match_line, line) is not None:
print("line matched " + match_line + ", dumping")
line_does_match = False
break
if line_does_match == False:
continue
print('received ' + ''.join(line))
for rule in replace:
if len(rule) > 2:
if len(rule) == 4:
if rule[3] == 'MULTILINE':
line = re.sub(rule[0], rule[1], line, rule[2], re.M)
else:
line = re.sub(rule[0], rule[1], line, rule[2])
else:
line = re.sub(rule[0], rule[1], line)
if matchlist == "misc":
if ('@' + settings["bot"]["from"] + ':') not in line:
irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8'))
elif any(' ' + death + ' ' in line for death in death_messages) and 'Villager EntityVillager[\'' not in line:
line = re.sub(r'^\[.*\]: ', '', line, 1)
irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8'))
else:
irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8'))
file.close()
def irc_to_mc():
print('started irc thread')
rcon = mcrcon.MCRcon()
rcon_password_file = open(settings["game"]["settings"]["rcon_password_file"], 'r')
rcon_password = rcon_password_file.readline().strip()
rcon_password_file.close()
rcon.connect(settings["game"]["settings"]["server"], settings["game"]["settings"]["rcon_port"], rcon_password)
print('initiated rcon connection')
while 1:
time.sleep(1)
text = irc.recv(1024)
if len(text) == 0:
print('Disconnected, attempting to recconect')
irc.close()
irc.connect((server, 6667))
irc.send(bytes('USER ' + botnick + ' '
+ botnick + ' ' + botnick
+ 'tcirc bot\n', 'utf8'))
irc.send(bytes('NICK ' + botnick + '\n', 'utf8'))
time.sleep(5)
irc.send(bytes('PRIVMSG nickserv :iNOOPE\r\n', 'utf8'))
irc.send(bytes('JOIN ' + channel + '\n', 'utf8'))
print('IDENTIFIED')
text = irc.recv(1024)
text = text.decode('utf-8')
print('received ' + text)
if 'PRIVMSG ' + channel in text:
text = re.sub(r':.*?\!', r'', text, 1)
text = re.sub(r' PRIVMSG ' + channel, r'', text, 1)
text = re.sub(r' :', r':', text, 1)
text = re.sub(r'@.*?:', r'@tilde.town: ', text, 1)
if '!uptime' in text:
print('seen uptime')
response = rcon.command('uptime')
response = response.split('\n')[0]
response = response.replace('\n', '')
response = re.sub('§.', '', response)
irc.send(bytes('PRIVMSG ' + channel + ' :' + response + '\n', 'utf8'))
print('PRIVMSG ' + channel + ' :' + response)
if '!online' in text:
print('seen online')
response = rcon.command('who')
response = response.replace('\n', '')
response = re.sub('§.', '', response)
response = re.sub(r'There are.*?: ', '', response, 1)
irc.send(bytes('PRIVMSG ' + channel + ' :' + response + '\n', 'utf8'))
print('PRIVMSG ' + channel + ' :' + response)
elif '!fsgiven' in text:
print('fsgiven called')
fsgiven_file = open('fsgiven', 'r')
fsgiven = int(fsgiven_file.readline().strip())
fsgiven_file.close()
response = str(fsgiven) + ' fs given.'
irc.send(bytes('PRIVMSG ' + channel + ' :' + response + '\n', 'utf8'))
else:
text = re.sub("([\x03\x0f])([0-9A-Fa-f]{1,2}(?:,[0-9A-Fa-f]{1,2})?)?",irc_to_mc_colors,text)
rcon.command('say ' + text[:-2])
if re.search(' (f|F) .*', text) is not None:
print('someone paid respects.')
fsgiven_file = open('fsgiven', 'r+')
fsgiven = fsgiven_file.readline().strip()
fsgiven = int(fsgiven) + 1
print(str(fsgiven) + ' total respects paid')
fsgiven_file.seek(0)
fsgiven_file.write(str(fsgiven))
fsgiven_file.truncate()
fsgiven_file.close()
response = 'Respects paid.'
irc.send(bytes('PRIVMSG ' + channel + ' :' + response + '\n', 'utf8'))
elif 'JOIN' in text or 'PART' in text:
print("-- JOIN EVENT --")
print(text)
if 'PART' in text or 'QUIT' in text:
text = re.search(r':.*!', text).group(0)
text = text[:-1]
text = text[1:]
text = text + ' left irc'
elif 'JOIN' in text:
text = re.search(r':.*!', text).group(0)
text = text[:-1]
text = text[1:]
text = text + ' joined irc'
# rcon.command('say ' + text)
elif 'PING' in text:
print('pinged by server, returning pong')
irc.send(b'PONG ' + text.split()[1].encode() + b'\r\n')
print('sent PONG ' + text.split()[1] + '\r\n')
rcon.disconnect()
mc_thread = threading.Thread(target=mc_to_irc)
mc_thread.daemon = True
irc_thread = threading.Thread(target=irc_to_mc)
irc_thread.daemon = True
irc_thread.start()
mc_thread.start()
while 1:
time.sleep(1)