259 lines
9.9 KiB
Python
Executable File
259 lines
9.9 KiB
Python
Executable File
#!/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)
|