#!/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_mc_bot_v1' irc = socket.socket(socket.AF_INET, socket.SOCK_STREAM) print('IRC bot connected') irc.connect((server, 6667)) 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 elif m.group(1)=="\x02": return "\xa7l" # bold elif m.group(1)=="\x1d": return "\xa7o" # italic elif m.group(1)=="\x1f": return "\xa7n" # underline elif m.group(1)=="\x1e" return "\xa7m" # strikethrough 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: if re.search('\[Async Chat Thread -.*?/INFO', line) is not None and ': [GriefPrevention] ' not in line: 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 + ' :' + line, 'utf8')) 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) irc.send(bytes('PRIVMSG ' + channel + ' :' + 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: 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: 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) print('sent ' + line) irc.send(bytes('PRIVMSG ' + channel + ' :' + line, 'utf8')) file.close() def irc_to_mc(): print('started irc thread') rcon = mcrcon.MCRcon() rcon_password_file = open('rcon_password', 'r') rcon_password = rcon_password_file.readline().strip() rcon_password_file.close() rcon.connect('0.0.0.0', 6668, 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'@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')) else: text = re.sub("([\x02\x03\x0f\x1d\x1e\x1f])([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: text = re.search(r':.*!', text).group(0) text = text[:-1] text = text[1:] text = text + ' left irc' if '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)