diff --git a/tcirchc.py b/tcirchc.py new file mode 100755 index 0000000..4c996e7 --- /dev/null +++ b/tcirchc.py @@ -0,0 +1,258 @@ +#!/usr/bin/python3 +# tcirc.py +# Copyright (C) 2018 oneseveneight +# +# 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 time +import threading + +server = 'localhost' +channel ='#minecraft' +botnick = 'tildecraft_hardcore_bot_v1' + +irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +print('IRC bot connected') +irc.connect((server, 6667)) +#irc.connect((server, 2345)) +print("connected") +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')) +time.sleep(5) +irc.send(bytes('JOIN ' + channel + '\n', 'utf8')) + +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(): #actually hc to mc but i am very lazy + rcon = mcrcon.MCRcon() + rcon_password_file = open('rcon_password', 'r') + rcon_password = rcon_password_file.readline().strip() + rcon_password_file.close() + rcon.connect('mc.tildeverse.org', 6668, rcon_password) + + print('initiated rcon connection') + 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('hc_remote_file') + file.readlines() + print('reading from file ' + file.name) + while 1: + time.sleep(1) + latest_lines = file.readlines() + for line in latest_lines: + if re.search('\[Async Chat Thread -.*?/INFO', line) is not None : + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'\^.*?m', '', line) + line = re.sub(r'\^.*UUID', '', line) + line = re.sub(r'.*?Async Chat Thread.*?: ', '', line, 1) + line = re.sub(r' :', ':', line, 1) + print(line.split(' ')) + print(line.split(' ')[-1]) + if '[r]' in line.split(' ')[-1]: + line = re.sub(r'^.*?: ', '', line, 1) + line = re.sub(r'\[r\]', '', line, 1) + print('sent ' + line) + rcon.command('say [HARDCORE] ' + line) + + elif '] logged in with entity id' in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'^\[.*?User Authenticator.*\n', '', line, 1, re.M) + line = re.sub(r'\[.*?: ', '', line, 1) + line = re.sub(r'\[/.*?\]', '', line, 1) + line = re.sub(r' with entity id.*', '', line, 1) + print('sent ' + line) + rcon.command('say [HARDCORE] ' + line) + + elif 'left the game' in line and '[Server thread/INFO]: [Rcon] ' not in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'\[.*?: ', '', line, 1) + line = re.sub(r'left the game', 'logged off', line, 1) + line = re.sub(r'\[/.*?\]', '', line, 1) + line = re.sub(r'> ', '', line, 1) + line = re.sub(r'lost connection: Disconnected', 'disconnected', line, 1) + print('sent ' + line) + rcon.command('say [HARDCORE] ' + line) + + elif '[Server thread/INFO]: [' in line and '[LP] LOG' not in line and ': [SavageDeathCompass] ' not in line and ': [GriefPrevention] ' not in line and '[Rcon]' not in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'^.*?: ', '', line, 3) + line = re.sub(r'\^.*?m', '', line) + line = re.sub(r'\[Rcon\].', r'', line) + print('sent ' + line) + if '@tildeverse:' not in line: + rcon.command('say [HARDCORE] ' + line) + # the following applies to the hardcore server + elif '[Server thread/INFO]: <' in line: + print('received ' + ''.join(line)) + if '@tildeverse:' not in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'^.*?: ', '', line, 3) + line = re.sub(r'\^.*?m', '', line) + line = re.sub(r'\[Rcon\].', r'', line) + print('sent ' + line) + rcon.command('say [HARDCORE] ' + line) + + file.close() + + +def irc_to_mc(): + print('started irc thread') + rcon = mcrcon.MCRcon() + rcon_password_file = open('rcon_password_hc', 'r') + rcon_password = rcon_password_file.readline().strip() + rcon_password_file.close() + rcon.connect('mc.bhh.sh', 25575, 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'', text, 1) + text = re.sub(r'@.*?:', r'@tildeverse: ', 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')) + elif '@tildeverse: [HARDCORE]' not in text: + 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: + text = re.sub(r':.*?\!', r'', text, 1) + text = re.sub(r'@localhost', r'', text, 1) + text = re.sub(r':WeeChat.*', r'', text, 1) + text = re.sub(r'JOIN', r'joined', text, 1) + text = re.sub(r'PART', r'left', text, 1) + rcon.command('say ' + text[:-2]) + + 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) diff --git a/tcirchctown.py b/tcirchctown.py new file mode 100755 index 0000000..b3c25da --- /dev/null +++ b/tcirchctown.py @@ -0,0 +1,274 @@ +#!/usr/bin/python3 +# tcirc.py +# Copyright (C) 2018 oneseveneight +# +# 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 time +import threading + +server = 'localhost' +channel ='#minecraft' +botnick = 'tildecraft_hardcore_bot_v1' + +irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +print('IRC bot connected') +#irc.connect((server, 6667)) +irc.connect((server, 2345)) +print("connected") +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')) +time.sleep(5) +irc.send(bytes('JOIN ' + channel + '\n', 'utf8')) + +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('hc_remote_file') + file.readlines() + print('reading from file ' + file.name) + while 1: + time.sleep(1) + latest_lines = file.readlines() + for line in latest_lines: + if re.search('\[Async Chat Thread -.*?/INFO', line) is not None : + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'\^.*?m', '', line) + line = re.sub(r'\^.*UUID', '', line) + line = re.sub(r'.*?Async Chat Thread.*?: ', '', line, 1) + line = re.sub(r' :', ':', line, 1) + print(line.split(' ')) + print(line.split(' ')[-1]) + if '[r]' in line.split(' ')[-1]: + line = re.sub(r'^.*?: ', '', line, 1) + line = re.sub(r'\[r\]', '', line, 1) + print('sent ' + line) + irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8')) + if re.search(': (f|F)( |$)', line) 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 '] logged in with entity id' in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'^\[.*?User Authenticator.*\n', '', line, 1, re.M) + line = re.sub(r'\[.*?: ', '', line, 1) + line = re.sub(r'\[/.*?\]', '', line, 1) + line = re.sub(r' with entity id.*', '', line, 1) + print('sent ' + line) + irc.send(bytes('PRIVMSG ' + channel + ' :[HARDCORE] ' + line, 'utf7')) + + elif 'left the game' in line and 'IRC ' not in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'\[.*?: ', '', line, 1) + line = re.sub(r'left the game', 'left the HARDCORE game', line, 1) + line = re.sub(r'\[/.*?\]', '', line, 1) + line = re.sub(r'> ', '', line, 1) + line = re.sub(r'lost connection: Disconnected', 'disconnected', line, 1) + print('sent ' + line) + irc.send(bytes('PRIVMSG ' + channel + ' :[HARDCORE] ' + line, 'utf8')) + + elif '[WEB]' in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'^.*?: ', '', line, 3) + line = re.sub(r'\^.*?m', '', line) + irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8')) + print('sent ' + line) + #elif '> ' in line and '[LP] LOG' not in line: + elif '[Server thread/INFO]: [' in line and '[LP] LOG' not in line and ': [SavageDeathCompass] ' not in line and ': [GriefPrevention] ' not in line and '[Rcon]' not in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'^.*?: ', '', line, 3) + line = re.sub(r'\^.*?m', '', line) + line = re.sub(r'\[Rcon\].', r'', line) + print('sent ' + line) + if '@tilde.town:' not in line: + irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8')) + elif any(death in line for death in death_messages): + line = re.sub(r'^\[.*\]: ', '', line, 1) + print('sent ' + line) + irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8')) + # the following applies to the hardcore server + elif '[Server thread/INFO]: <' in line: + if '@tilde.town:' not in line: + print('received ' + ''.join(line)) + line = re.sub(r'', r'^[', line) + line = re.sub(r'^.*?: ', '', line, 3) + line = re.sub(r'\^.*?m', '', line) + line = re.sub(r'\[Rcon\].', r'', line) + print('sent ' + line) + irc.send(bytes('PRIVMSG ' + channel + ' :[HARDCORE] ' + line, 'utf8')) + + file.close() + + +def irc_to_mc(): + print('started irc thread') + rcon = mcrcon.MCRcon() + rcon_password_file = open('rcon_password_hc', 'r') + rcon_password = rcon_password_file.readline().strip() + rcon_password_file.close() + rcon.connect('mc.bhh.sh', 25575, 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'', 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: + text = re.sub(r':.*?\!', r'', text, 1) + text = re.sub(r'@localhost', r'', text, 1) + text = re.sub(r':WeeChat.*', r'', text, 1) + text = re.sub(r'JOIN', r'joined', text, 1) + text = re.sub(r'PART', r'left', text, 1) + rcon.command('say ' + text[:-2]) + + 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)