def __init__(self, blocks_path, sx, sy, sz): Thread.__init__(self) self.x, self.y, self.z = sx, sy, sz self.blocks_path = blocks_path self.world_name = os.path.basename(os.path.dirname(blocks_path)) self.in_queue = Queue() self.out_queue = Queue() self.logger = ColouredLogger()
def connectionMade(self): self.logger = ColouredLogger(debug) self.ops = [] self.nickname = self.factory.main_factory.irc_nick self.password = self.factory.main_factory.irc_pass irc.IRCClient.connectionMade(self) self.factory.instance = self self.factory, self.controller_factory = self.factory.main_factory, self.factory self.world = None self.sendLine('NAMES ' + self.factory.irc_channel)
def __init__(self, blockstore): Thread.__init__(self) self.blockstore = blockstore #self.setDaemon(True) # means that python can terminate even if still active #self.work = Event() # TODO use event to start and stop self.last_lag = 0 self.running = True self.was_physics = False self.was_unflooding = False self.changed = set() self.working = set() # could be a list or a sorted list but why bother (world updates may appear in random order but most of the time so many get updated it should be unnoticable) self.sponge_locations = set() self.logger = ColouredLogger(debug)
class ControllerProtocol(LineReceiver): """ Protocol for dealing with controller requests. """ def connectionMade(self): self.logger = ColouredLogger(debug) peer = self.transport.getPeer() self.logger.debug("Control connection made from %s:%s" % (peer.host, peer.port)) self.factory, self.controller_factory = self.factory.main_factory, self.factory def connectionLost(self, reason): peer = self.transport.getPeer() self.logger.debug("Control connection lost from %s:%s" % (peer.host, peer.port)) def sendJson(self, data): self.sendLine(simplejson.dumps(data)) def lineReceived(self, line): data = simplejson.loads(line) peer = self.transport.getPeer() if data['password'] != self.factory.controller_password: self.sendJson({"error": "invalid password"}) self.logger.info("Control: Invalid password %s (%s:%s)" % (data, peer.host, peer.port)) else: command = data['command'].lower() try: func = getattr(self, "command%s" % command.title()) except AttributeError: self.sendJson({"error": "unknown command %s" % command}) else: self.logger.debug("Control: %s %s (%s:%s)" % (command.upper(), data, peer.host, peer.port)) try: func(data) except Exception, e: self.sendJson({"error": "%s" % e}) traceback.print_exc()
def connectionMade(self): self.logger = ColouredLogger(debug) peer = self.transport.getPeer() self.logger.debug("Control connection made from %s:%s" % (peer.host, peer.port)) self.factory, self.controller_factory = self.factory.main_factory, self.factory
class ChatBot(irc.IRCClient): """An IRC-server chat integration bot.""" ocommands = ["help", "cmdlist", "banreason", "banned", "kick", "ban", "shutdown", "rank", "derank", "spec", "boot"] ncommands = ["who", "worlds", "staff", "credits", "help", "rules", "cmdlist", "about", "lastseen", "roll"] def connectionMade(self): self.logger = ColouredLogger(debug) self.ops = [] self.nickname = self.factory.main_factory.irc_nick self.password = self.factory.main_factory.irc_pass irc.IRCClient.connectionMade(self) self.factory.instance = self self.factory, self.controller_factory = self.factory.main_factory, self.factory self.world = None self.sendLine('NAMES ' + self.factory.irc_channel) def connectionLost(self, reason): irc.IRCClient.connectionLost(self, reason) self.logger.info("IRC client disconnected. (%s)" % reason) # callbacks for events def ctcpQuery_VERSION(self, user, channel, data): """Called when received a CTCP VERSION request.""" nick = user.split("!")[0] self.ctcpMakeReply(nick, [('VERSION', 'The Archives %s - a Minecraft server written in Python.' % VERSION)]) def signedOn(self): """Called when bot has succesfully signed on to server.""" self.logger.info("IRC client connected.") self.msg("NickServ", "IDENTIFY %s %s" % (self.nickname, self.password)) self.msg("ChanServ", "INVITE %s" % self.factory.irc_channel) self.join(self.factory.irc_channel) def joined(self, channel): """This will get called when the bot joins the channel.""" self.logger.info("IRC client joined %s." % channel) def sendError(self, error): self.logger.error("Sending error: %s" % error) self.sendPacked(TYPE_ERROR, error) reactor.callLater(0.2, self.transport.loseConnection) def lineReceived(self, line): # use instead of query line = irc.lowDequote(line) try: prefix, command, params = irc.parsemsg(line) if irc.numeric_to_symbolic.has_key(command): command = irc.numeric_to_symbolic[command] self.handleCommand(command, prefix, params) except irc.IRCBadMessage: self.badMessage(line, *sys.exc_info()) try: if command == "RPL_NAMREPLY": names = params[3].split() for name in names: if name.startswith("@"): self.ops.append(name[1:]) except: self.logger.error(traceback.format_exc()) def AdminCommand(self, command): try: user = command[0] if user in self.ops: if len(command) > 1: if command[1].startswith("#"): if self.factory.staffchat: # It's an staff-only message. if len(command[1]) < 1: self.msg(user, "07Please include a message to send.") else: text = " ".join(command[1:])[1:] self.factory.sendMessageToAll(text, "staff", user=(COLOUR_PURPLE + user)) elif command[1].lower() in self.ocommands and len(command) > 1: theCommand = command[1].lower() if theCommand == ("help"): self.msg(user, "07Admin Help") self.msg(user, "07Commands: Use 'cmdlist'") if self.factory.staffchat: self.msg(user, "07StaffChat: Use '#message'") elif theCommand == ("cmdlist"): self.msg(user, "07Here are your Admin Commands:") self.msg(user, "07ban banned banreason boot derank kick rank shutdown spec") self.msg(user, "07Use 'command arguments' to do it.") elif theCommand == ("banreason"): if len(command) == 3: username = command[2] if not self.factory.isBanned(username): self.msg(user, "07%s is not Banned." % username) else: self.msg(user, "07Reason: %s" % self.factory.banReason(username)) else: self.msg(user, "07You must provide a name.") elif theCommand == ("banned"): self.msg(user, ", ".join(self.factory.banned)) elif theCommand == ("kick"): theUser = command[2] if user.lower() in self.factory.usernames: if len(command) > 2: self.factory.usernames[theUser.lower()].sendError( "You were kicked by %s: %s" % (user, " ".join(command[3:]))) else: self.factory.usernames[theUser.lower()].sendError("You were kicked by %s!" % user) self.msg(user, "%s has been kicked from the server%s." % ( str(command[2], (" for %s" % " ".join(command[3:]) if len(command) > 2 else "")))) return self.msg(user, "%s is not online." % command[2]) elif theCommand == ("ban"): if command > 3: if self.factory.isBanned(command[2]): self.msg(user, "07%s is already Banned." % command[2]) else: self.factory.addBan(command[2], " ".join(command[3:])) if command[2] in self.factory.usernames: self.factory.usernames[command[2]].sendError("You got banned!") self.msg(user, "07%s has been Banned for %s." % (command[2], " ".join(command[3:]))) else: self.msg(user, "07Please give a username and reason.") elif theCommand == ("shutdown"): world = str(command[2]).lower() if world in self.factory.worlds: self.factory.unloadWorld(world) self.msg(user, "07World '" + world + "' shutdown.") else: self.msg(user, "07World '" + world + "' is not loaded.") elif theCommand == ("rank"): if not len(command) > 2: self.msg(user, "07You must provide a username.") else: self.msg(user, Rank(self, command[1:] + [user], "irc", True, self.factory)) elif theCommand == ("derank"): if not len(command) > 2: self.msg(user, "07You must provide a username.") else: self.msg(user, DeRank(self, command[1:] + [user], "irc", True, self.factory)) elif theCommand == ("spec"): if not len(command) > 2: self.msg(user, "07You must provide a username.") else: self.msg(user, Spec(self, command[1], "irc", True, self.factory)) elif theCommand == "despec": if not len(command) > 2: self.msg(user, "07You must provide a username.") else: self.msg(user, DeSpec(self, command[1], "irc", True, self.factory)) elif theCommand == ("boot"): world = str(command[2]).lower() returned = self.factory.loadWorld("worlds/" + world, world) if returned == False: self.msg(user, "07 World %s loading failed." % world) else: self.msg(user, "07World %s booted." % world) else: self.msg(user, "07Sorry, %s is not a command!" % theCommand) else: self.msg(user, "07%s is not a command!" % command[1].lower()) else: self.msg(user, "07You must provide a valid command to use the IRC bot.") else: if command[1].startswith("#"): if self.factory.staffchat: self.msg(user, "07You must be an op to use StaffChat.") elif command[1].lower() in self.ocommands: self.msg(user, "07You must be an op to use %s." % command[1]) else: self.msg(user, "07%s is not a command!" % command[1]) if not command[1].startswith("#"): self.logger.info("%s just used: %s" % (user, " ".join(command[1:]))) except: self.logger.error(traceback.format_exc()) self.msg(user, "Internal Server Error (See the Console for more details)") def privmsg(self, user, channel, msg): """This will get called when the bot receives a message.""" try: user = user.split('!', 1)[0] msg = self.factory.messagestrip(msg) if channel == self.nickname: if not (self.nickname == user or "Serv" in user): msg_command = msg.split() self.AdminCommand([user] + msg_command) elif channel.lower() == self.factory.irc_channel.lower(): if msg.lower().lstrip(self.nickname.lower()).startswith("$" + self.nickname.lower()): msg_command = msg.split() msg_command[1] = msg_command[1].lower() if len(msg_command) > 1: if msg_command[1] in self.ncommands and len(msg_command) > 1: if msg_command[1] == "who": self.msg(self.factory.irc_channel, "07Who's Online?") none = True for key in self.factory.worlds: users = ", ".join(str(c.username) for c in self.factory.worlds[key].clients) if users: whois = ("07%s: %s" % (key, users)) self.msg(self.factory.irc_channel, whois) users = None none = False if none: self.msg(self.factory.irc_channel, "07No users are online.") elif msg_command[1] == "worlds": self.msg(self.factory.irc_channel, "07Worlds Booted:") worlds = ", ".join([id for id, world in self.factory.worlds.items()]) self.msg(self.factory.irc_channel, "07Online Worlds: " + worlds) elif msg_command[1] == "staff": self.msg(self.factory.irc_channel, "07Please see your PM for the Staff List.") self.msg(user, "The Server Staff") list = Staff(self, self.factory) for each in list: self.msg(user, " ".join(each)) elif msg_command[1] == "credits": self.msg(self.factory.irc_channel, "07Please see your PM for the Credits.") self.msg(user, "The Credits") list = Credits() for each in list: self.msg(user, "".join(each)) elif msg_command[1] == "help": self.msg(self.factory.irc_channel, "07Help Center") self.msg(self.factory.irc_channel, "07Commands: Use '$" + self.nickname + " cmdlist'") self.msg(self.factory.irc_channel, "07WorldChat: Use '!world message'") self.msg(self.factory.irc_channel, "07IRCChat: Use '$message'") self.msg(self.factory.irc_channel, "07About: Use '$" + self.nickname + " about'") self.msg(self.factory.irc_channel, "07Credits: Use '$" + self.nickname + " credits'") elif msg_command[1] == "rules": self.msg(self.factory.irc_channel, "07Please see your PM for the Rules.") self.msg(user, "The Rules") try: r = open('config/rules.txt', 'r') except IOError: self.msg(user, "07There are no rules for this server.") return for line in r: line = line.replace("\n", "") self.msg(user, line) elif msg_command[1] == "cmdlist": self.msg(self.factory.irc_channel, "07Command List") self.msg(self.factory.irc_channel, "07about cmdlist credits help rules staff who worlds") self.msg(self.factory.irc_channel, "07Use '$" + self.nickname + " command arguments' to do it.") self.msg(self.factory.irc_channel, "07NOTE: Admin Commands are by PMing " + self.nickname + " - only for ops.") elif msg_command[1] == "about": self.msg(self.factory.irc_channel, "07About the Server, powered by The Archives %s | Credits: Use '$%s credits'" % ( VERSION, self.nickname)) self.msg(self.factory.irc_channel, "07Name: %s; Owners: %s" % ( self.factory.server_name, ", ".join(self.factory.owners))) try: self.msg(self.factory.irc_channel, "07URL: " + self.factory.heartbeat.url) except: self.msg(self.factory.irc_channel, "07URL: N/A (minecraft.net is offline)") self.msg(self.factory.irc_channel, "07Site: " + self.factory.info_url) elif msg_command[1] == "lastseen": if len(msg_command) < 2: self.msg(self.factory.irc_channel, "07Please enter a username to look for.") else: if msg_command[2].lower() not in self.factory.lastseen: self.msg(self.factory.irc_channel, "07There are no records of %s." % msg_command[2]) else: t = time.time() - self.factory.lastseen[msg_command[2].lower()] days = t // 86400 hours = (t % 86400) // 3600 mins = (t % 3600) // 60 desc = "%id, %ih, %im" % (days, hours, mins) self.msg(self.factory.irc_channel, "07%s was last seen %s ago." % (msg_command[2], desc)) else: self.msg(self.factory.irc_channel, "07Sorry, %s is not a command!" % msg_command[1]) self.logger.info("%s just used: %s" % (user, " ".join(msg_command[1:]))) elif msg_command[1] in self.ocommands and len(msg_command) > 1: if user in self.ops: self.msg(self.factory.irc_channel, "07Please do not use %s in the channel; use a query instead!" % msg_command[1]) else: self.msg(self.factory.irc_channel, "07You must be an op to use %s." % msg_command[1]) else: self.msg(self.factory.irc_channel, "07You must provide a valid command to use the IRC bot - try the help command.") else: self.msg(self.factory.irc_channel, "07You must provide a valid command to use the IRC bot - try the help command.") elif msg.startswith("$"): self.logger.info("<$%s> %s" % (user, msg)) elif msg.startswith("!"): # It's a world message. message = msg.split(" ") if len(message) == 1: self.msg(self.factory.irc_channel, "07Please include a message to send.") else: try: world = message[0][1:len(message[0])] out = "\n ".join(message[1:]) except ValueError: self.msg(self.factory.irc_channel, "07Please include a message to send.") else: if world in self.factory.worlds: self.factory.sendMessageToAll(out, "world", user=user, world=world) else: self.msg(self.factory.irc_channel, "07That world does not exist. Try !world message") else: for character in msg: if not character.lower() in PRINTABLE: msg = msg.replace("&0", "&0") msg = msg.replace("&1", "&1") msg = msg.replace("&2", "&2") msg = msg.replace("&3", "&3") msg = msg.replace("&4", "&4") msg = msg.replace("&5", "&5") msg = msg.replace("&6", "&6") msg = msg.replace("&7", "&7") msg = msg.replace("&8", "&8") msg = msg.replace("&9", "&9") msg = msg.replace("&a", "&a") msg = msg.replace("&b", "&b") msg = msg.replace("&c", "&c") msg = msg.replace("&d", "&d") msg = msg.replace("&e", "&e") msg = msg.replace("&f", "&f") msg = msg.replace("0", "&f") msg = msg.replace("00", "&f") msg = msg.replace("1", "&0") msg = msg.replace("01", "&0") msg = msg.replace("2", "&1") msg = msg.replace("02", "&1") msg = msg.replace("3", "&2") msg = msg.replace("03", "&2") msg = msg.replace("4", "&c") msg = msg.replace("04", "&c") msg = msg.replace("5", "&4") msg = msg.replace("05", "&4") msg = msg.replace("6", "&5") msg = msg.replace("06", "&5") msg = msg.replace("7", "&6") msg = msg.replace("07", "&6") msg = msg.replace("8", "&e") msg = msg.replace("08", "&e") msg = msg.replace("9", "&a") msg = msg.replace("09", "&a") msg = msg.replace("10", "&3") msg = msg.replace("11", "&b") msg = msg.replace("12", "&9") msg = msg.replace("13", "&d") msg = msg.replace("14", "&8") msg = msg.replace("15", "&7") msg = msg.replace(character, "*") msg = msg.replace("%0", "&0") msg = msg.replace("%1", "&1") msg = msg.replace("%2", "&2") msg = msg.replace("%3", "&3") msg = msg.replace("%4", "&4") msg = msg.replace("%5", "&5") msg = msg.replace("%6", "&6") msg = msg.replace("%7", "&7") msg = msg.replace("%8", "&8") msg = msg.replace("%9", "&9") msg = msg.replace("%a", "&a") msg = msg.replace("%b", "&b") msg = msg.replace("%c", "&c") msg = msg.replace("%d", "&d") msg = msg.replace("%e", "&e") msg = msg.replace("%f", "&f") msg = msg.replace("./", " /") msg = msg.replace(".!", " !") if msg[len(msg) - 2] == "&": self.msg(self.factory.irc_channel, "07You cannot use a color at the end of a message.") return if len(msg) > 51: moddedmsg = msg[:51].replace(" ", "") if moddedmsg[len(moddedmsg) - 2] == "&": msg = msg.replace("&", "*") self.factory.sendMessageToAll(msg, "irc", user=user) except: self.logger.error(traceback.format_exc()) self.msg(self.factory.irc_channel, "Internal Server Error (See the Console for more details)") def action(self, user, channel, msg): """This will get called when the bot sees someone do an action.""" msg = msg.replace("./", " /") msg = msg.replace(".!", " !") user = user.split('!', 1)[0] msg = "".join([char for char in msg if ord(char) < 128 and char != "" or "0"]) self.factory.sendMessageToAll("%s* %s %s" % (COLOUR_YELLOW, COLOUR_WHITE + user, msg), "irc", user="") self.logger.info("* %s %s" % (user, msg)) self.factory.chatlog.write( "[%s] * %s %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"), user, msg)) self.factory.chatlog.flush() def sendMessage(self, username, message): message = message.replace("&0", "01") message = message.replace("&1", "02") message = message.replace("&2", "03") message = message.replace("&3", "10") message = message.replace("&4", "05") message = message.replace("&5", "06") message = message.replace("&6", "07") message = message.replace("&7", "15") message = message.replace("&8", "14") message = message.replace("&9", "12") message = message.replace("&a", "09") message = message.replace("&b", "11") message = message.replace("&c", "04") message = message.replace("&d", "13") message = message.replace("&e", "08") message = message.replace("&f", "14") username = username.replace("&0", "01") username = username.replace("&1", "02") username = username.replace("&2", "03") username = username.replace("&3", "10") username = username.replace("&4", "05") username = username.replace("&5", "06") username = username.replace("&6", "07") username = username.replace("&7", "15") username = username.replace("&8", "14") username = username.replace("&9", "12") username = username.replace("&a", "09") username = username.replace("&b", "11") username = username.replace("&c", "04") username = username.replace("&d", "13") username = username.replace("&e", "08") username = username.replace("&f", "14") self.msg(self.factory.irc_channel, "%s: %s" % (username, message)) def sendServerMessage(self, message, admin=False, user=""): message = message.replace("./", " /") message = message.replace(".!", " !") message = message.replace("&0", "01") message = message.replace("&1", "02") message = message.replace("&2", "03") message = message.replace("&3", "10") message = message.replace("&4", "05") message = message.replace("&5", "06") message = message.replace("&6", "07") message = message.replace("&7", "15") message = message.replace("&8", "14") message = message.replace("&9", "12") message = message.replace("&a", "09") message = message.replace("&b", "11") message = message.replace("&c", "04") message = message.replace("&d", "13") message = message.replace("&e", "08") message = message.replace("&f", "14") if admin: for op in self.ops: if not op == user or not IRC: self.msg(op, "%s" % message) else: self.msg(self.factory.irc_channel, "%s" % message) def sendAction(self, username, message): message = message.replace("&0", "01") message = message.replace("&1", "02") message = message.replace("&2", "03") message = message.replace("&3", "10") message = message.replace("&4", "05") message = message.replace("&5", "06") message = message.replace("&6", "07") message = message.replace("&7", "15") message = message.replace("&8", "14") message = message.replace("&9", "12") message = message.replace("&a", "09") message = message.replace("&b", "11") message = message.replace("&c", "04") message = message.replace("&d", "13") message = message.replace("&e", "08") message = message.replace("&f", "14") self.msg(self.factory.irc_channel, "* %s %s" % (username, message)) # irc callbacks def irc_NICK(self, prefix, params): "Called when an IRC user changes their nickname." old_nick = prefix.split('!')[0] new_nick = params[0] if old_nick in self.ops: self.ops.remove(old_nick) self.ops.append(new_nick) msg = "%s%s is now known as %s" % (COLOUR_YELLOW, old_nick, new_nick) self.factory.sendMessageToAll(msg, "irc", user="") def userKicked(self, kickee, channel, kicker, message): "Called when I observe someone else being kicked from a channel." if kickee in self.ops: self.ops.remove(kickee) msg = "%s%s was kicked from %s by %s" % (COLOUR_YELLOW, kickee, channel, kicker) self.factory.sendMessageToAll(msg, "irc", user="") if not kickee == message: msg = "%sReason: %s" % (COLOUR_YELLOW, message) self.factory.sendMessageToAll(msg, "irc", user="") def userLeft(self, user, channel): "Called when I see another user leaving a channel." if user in self.ops: self.ops.remove(user) msg = "%s%s has left %s" % (COLOUR_YELLOW, user.split("!")[0], channel) self.factory.sendMessageToAll(msg, "irc", user="") def userJoined(self, user, channel): "Called when I see another user joining a channel." if user in self.ops: self.ops.remove(user) msg = "%s%s has joined %s" % (COLOUR_YELLOW, user.split("!")[0], channel) self.factory.sendMessageToAll(msg, "irc", user="") def modeChanged(self, user, channel, set, modes, args): "Called when someone changes a mode." setUser = user.split("!")[0] arguments = [] for element in args: if element: arguments.append(element.split("!")[0]) if set and modes.startswith("o"): if len(arguments) < 2: msg = "%s%s was opped on %s by %s" % (COLOUR_YELLOW, arguments[0], channel, setUser) else: msg = "%sUsers opped on %s by %s: %s (%s)" % ( COLOUR_YELLOW, channel, setUser, ", ".join(arguments), len(arguments)) self.factory.sendMessageToAll(msg, "irc", user="") for name in args: if not name in self.ops: self.ops.append(name) elif not set and modes.startswith("o"): done = [] for name in args: done.append(name.split("!")[0]) if len(arguments) < 2: msg = "%s%s was deopped on %s by %s" % (COLOUR_YELLOW, arguments[0], channel, setUser) else: msg = "%sUsers deopped on %s by %s: %s (%s)" % ( COLOUR_YELLOW, channel, setUser, ", ".join(arguments), len(arguments)) self.factory.sendMessageToAll(msg, "irc", user="") for name in args: if name in self.ops: self.ops.remove(name) elif set and modes.startswith("v"): if len(arguments) < 2: msg = "%s%s was voiced on %s by %s" % (COLOUR_YELLOW, arguments[0], channel, setUser) else: msg = "%sUsers voiced on %s by %s: %s (%s)" % ( COLOUR_YELLOW, channel, setUser, ", ".join(arguments), len(arguments)) self.factory.sendMessageToAll(msg, "irc", user="") for name in args: if not name in self.ops: self.ops.append(name) elif not set and modes.startswith("v"): done = [] for name in args: done.append(name.split("!")[0]) if len(arguments) < 2: msg = "%s%s was devoiced on %s by %s" % (COLOUR_YELLOW, arguments[0], channel, setUser) else: msg = "%sUsers devoiced on %s by %s: %s (%s)" % ( COLOUR_YELLOW, channel, setUser, ", ".join(arguments), len(arguments)) self.factory.sendMessageToAll(msg, "irc", user="") for name in args: if name in self.ops: self.ops.remove(name) elif set and modes.startswith("b"): msg = "%sBan set in %s by %s" % (COLOUR_YELLOW, channel, setUser) self.factory.sendMessageToAll(msg, "irc", user="") msg = "%s(%s)" % (COLOUR_YELLOW, " ".join(args)) self.factory.sendMessageToAll(msg, "irc", user="") elif not set and modes.startswith("b"): msg = "%sBan lifted in %s by %s" % (COLOUR_YELLOW, channel, setUser) self.factory.sendMessageToAll(msg, "irc", user="") msg = "%s(%s)" % (COLOUR_YELLOW, " ".join(args)) self.factory.sendMessageToAll(msg, "irc", user="") def irc_QUIT(self, user, params): userhost = user user = user.split('!')[0] quitMessage = params[0] if userhost in self.ops: self.ops.remove(userhost) msg = "%s%s has quit IRC." % (COLOUR_YELLOW, user) self.factory.sendMessageToAll(msg, "irc", user=user) for character in msg: if not character.lower() in PRINTABLE: msg = msg.replace("&0", "&0") msg = msg.replace("&1", "&1") msg = msg.replace("&2", "&2") msg = msg.replace("&3", "&3") msg = msg.replace("&4", "&4") msg = msg.replace("&5", "&5") msg = msg.replace("&6", "&6") msg = msg.replace("&7", "&7") msg = msg.replace("&8", "&8") msg = msg.replace("&9", "&9") msg = msg.replace("&a", "&a") msg = msg.replace("&b", "&b") msg = msg.replace("&c", "&c") msg = msg.replace("&d", "&d") msg = msg.replace("&e", "&e") msg = msg.replace("&f", "&f") msg = msg.replace("0", "&f") msg = msg.replace("00", "&f") msg = msg.replace("1", "&0") msg = msg.replace("01", "&0") msg = msg.replace("2", "&1") msg = msg.replace("02", "&1") msg = msg.replace("3", "&2") msg = msg.replace("03", "&2") msg = msg.replace("4", "&c") msg = msg.replace("04", "&c") msg = msg.replace("5", "&4") msg = msg.replace("05", "&4") msg = msg.replace("6", "&5") msg = msg.replace("06", "&5") msg = msg.replace("7", "&6") msg = msg.replace("07", "&6") msg = msg.replace("8", "&e") msg = msg.replace("08", "&e") msg = msg.replace("9", "&a") msg = msg.replace("09", "&a") msg = msg.replace("10", "&3") msg = msg.replace("11", "&b") msg = msg.replace("12", "&9") msg = msg.replace("13", "&d") msg = msg.replace("14", "&8") msg = msg.replace("15", "&7") msg = msg.replace(character, "*") msg = msg.replace("%0", "&0") msg = msg.replace("%1", "&1") msg = msg.replace("%2", "&2") msg = msg.replace("%3", "&3") msg = msg.replace("%4", "&4") msg = msg.replace("%5", "&5") msg = msg.replace("%6", "&6") msg = msg.replace("%7", "&7") msg = msg.replace("%8", "&8") msg = msg.replace("%9", "&9") msg = msg.replace("%a", "&a") msg = msg.replace("%b", "&b") msg = msg.replace("%c", "&c") msg = msg.replace("%d", "&d") msg = msg.replace("%e", "&e") msg = msg.replace("%f", "&f") msg = msg.replace("./", " /") msg = msg.replace(".!", " !") if msg[len(msg) - 2] == "&": return if len(msg) > 51: moddedmsg = msg[:51].replace(" ", "") if moddedmsg[len(moddedmsg) - 2] == "&": msg = msg.replace("&", "*") msg = "%s(%s%s)" % (COLOUR_YELLOW, quitMessage, COLOUR_YELLOW) self.factory.sendMessageToAll(msg, "irc", user="")
class BlockStore(Thread): """ A class which deals with storing the block worlds, flushing them, etc. """ def __init__(self, blocks_path, sx, sy, sz): Thread.__init__(self) self.x, self.y, self.z = sx, sy, sz self.blocks_path = blocks_path self.world_name = os.path.basename(os.path.dirname(blocks_path)) self.in_queue = Queue() self.out_queue = Queue() self.logger = ColouredLogger() def run(self): # Initialise variables self.physics = False self.physics_engine = Physics(self) self.raw_blocks = None # Read this from any thread but please update through TASK_BLOCKSET so queued_blocks is updated self.running = True self.unflooding = False self.finite_water = False self.queued_blocks = {} # Blocks which need to be flushed into the file. self.create_raw_blocks() # Start physics engine self.physics_engine.start() # Main eval loop while self.running: try: # Pop something off the queue task = self.in_queue.get() # If we've been asked to flush, do so, and say we did. if task[0] is TASK_FLUSH: self.flush() self.out_queue.put([TASK_FLUSH]) # New block? elif task[0] is TASK_BLOCKSET: try: self[task[1]] = task[2] if len(task) == 4 and task[3] == True: # Tells the server to update the given block for clients. self.out_queue.put([TASK_BLOCKSET, (task[1][0], task[1][1], task[1][2], task[2])]) except AssertionError: self.logger.warning("Tried to set a block at %s in %s!" % (task[1], self.world_name)) # Asking for a block? elif task[0] is TASK_BLOCKGET: self.out_queue.put([TASK_BLOCKGET, task[1], self[task[1]]]) # Perhaps physics was enabled? elif task[0] is TASK_PHYSICSOFF: self.logger.debug("Disabling physics on '%s'..." % self.world_name) self.disable_physics() # Or disabled? elif task[0] is TASK_PHYSICSON: self.logger.debug("Enabling physics on '%s'..." % self.world_name) self.enable_physics() # I can haz finite water tiem? elif task[0] is TASK_FWATERON: self.logger.debug("Enabling finite water on '%s'..." % self.world_name) self.finite_water = True # Noes, no more finite water. elif task[0] is TASK_FWATEROFF: self.logger.debug("Disabling finite water on '%s'..." % self.world_name) self.finite_water = False # Do they need to do a Moses? elif task[0] is TASK_UNFLOOD: self.logger.debug("Unflood started on '%s'..." % self.world_name) self.unflooding = True # Perhaps that's it, and we need to stop? elif task[0] is TASK_STOP: self.logger.debug("Stopping block store '%s'..." % self.world_name) self.physics_engine.stop() self.flush() self.logger.debug("Stopped block store '%s'." % self.world_name) return # ??? else: raise ValueError("Unknown BlockStore task: %s" % task) except (KeyboardInterrupt, IOError): pass def enable_physics(self): "Turns on physics" self.physics = True def disable_physics(self): "Disables physics, and clears the in-memory store." self.physics = False def create_raw_blocks(self): "Reads in the gzipped data into a raw array" # Open the blocks file fh = gzip.GzipFile(self.blocks_path) self.raw_blocks = array('c') # Read off the size header fh.read(4) # Copy into the array in chunks chunk = fh.read(2048) while chunk: self.raw_blocks.extend(chunk) chunk = fh.read(2048) fh.close() def get_offset(self, x, y, z): "Turns block coordinates into a data offset" assert 0 <= x < self.x assert 0 <= y < self.y assert 0 <= z < self.z return y * (self.x * self.z) + z * (self.x) + x def get_coords(self, offset): "Turns a data offset into coordinates" x = offset % self.x z = (offset // self.x) % self.z y = offset // (self.x * self.z) return x, y, z def message(self, message): "Sends a message out to users about this World." self.out_queue.put([TASK_MESSAGE, message]) def __setitem__(self, (x, y, z), block): "Set a block in this level to the given value." assert isinstance(block, str) and len(block) == 1 # Save to queued blocks offset = self.get_offset(x, y, z) self.queued_blocks[offset] = block # And directly to raw blocks, if we must if self.raw_blocks: self.raw_blocks[offset] = block # Ask the physics engine if they'd like a look at that self.physics_engine.handle_change(offset, block)
# Arc is copyright 2009-2011 the Arc team and other contributors. # Arc is licensed under the BSD 2-Clause modified License. # To view more details, please see the "LICENSING" file in the "docs" folder of the Arc Package. import sys from arc.logger import ColouredLogger debug = (True if "--debug" in sys.argv else False) logger = ColouredLogger() logger.debug("Imported arc/ folder.") del logger del ColouredLogger del sys
class Physics(Thread): """ Given a BlockStore, works out what needs doing (water, grass etc.) and send the changes back to the BlockStore. """ # This thread: # * Receives changes by ATOMIC updates to 'changed' eg. self.changed.add(offset) # * Sends changes by queueing updates in the blockstore # * Reads but doesn't modify self.blockstore.raw_blocks[] # Optimised by only checking blocks near changes, advantages are a small work set and very up-to-date def __init__(self, blockstore): Thread.__init__(self) self.blockstore = blockstore #self.setDaemon(True) # means that python can terminate even if still active #self.work = Event() # TODO use event to start and stop self.last_lag = 0 self.running = True self.was_physics = False self.was_unflooding = False self.changed = set() self.working = set() # could be a list or a sorted list but why bother (world updates may appear in random order but most of the time so many get updated it should be unnoticable) self.sponge_locations = set() self.logger = ColouredLogger(debug) def stop(self): self.running = False self.join() def run(self): while self.running: if self.blockstore.physics: if self.blockstore.unflooding: # Do n fluid removals updates = 0 for offset, block in enumerate(self.blockstore.raw_blocks): if block == CHR_LAVA or block == CHR_WATER or block == CHR_SPOUT or block == CHR_LAVA_SPOUT: x, y, z = self.blockstore.get_coords(offset) self.set_block((x, y, z), BLOCK_AIR) updates += 1 if updates >= LIMIT_UNFLOOD: break else: # Unflooding complete. self.blockstore.unflooding = False self.blockstore.message(COLOUR_YELLOW + "Unflooding complete.") self.changed.clear() self.working = set() else: # If this is the first of a physics run, redo the queues from scratch if not self.was_physics or self.was_unflooding: self.logger.debug("Queue everything for '%s'." % self.blockstore.world_name) self.changed.clear() self.working = Popxrange(0, (self.blockstore.x * self.blockstore.y * self.blockstore.z)) # if working list is empty then copy changed set to working set # otherwise keep using the working set till empty elif len(self.working) == 0: self.logger.debug("Performing expand checks for '%s' with %d changes." % ( self.blockstore.world_name, len(self.changed))) changedfixed = self.changed # 'changedfixed' is 'changed' so gets all updates self.changed = set() # until 'changed' is a new set. This and the above statment are ATOMIC self.working = set() # changes from a Popxrange to a set while len(changedfixed) > 0: self.expand_checks(changedfixed.pop()) self.logger.debug("Starting physics run for '%s' with %d checks." % ( self.blockstore.world_name, len(self.working))) updates = 0 try: for x in xrange(LIMIT_CHECKS): offset = self.working.pop() updates += self.handle(offset) except KeyError: pass #if overflow and (time.time() - self.last_lag > self.LAG_INTERVAL): #self.blockstore.message("Physics is currently lagging in %(id)s.") #self.last_lag = time.time() self.logger.debug("Ended physics run for '%s' with %d updates and %d checks remaining." % ( self.blockstore.world_name, updates, len(self.working))) else: if self.was_physics: self.blockstore.unflooding = False self.changed.clear() self.working = set() self.was_physics = self.blockstore.physics self.was_unflooding = self.blockstore.unflooding # Wait till next iter time.sleep(0.7) # TODO change this so takes into account run time def handle_change(self, offset, block): # must be ATOMIC "Gets called when a block is changed, with its offset and type." self.changed.add(offset) def set_block(self, (x, y, z), block): # only place blockstore is updated "Call to queue a block change, with its position and type." self.blockstore.in_queue.put([TASK_BLOCKSET, (x, y, z), chr(block), True])
from arc.constants import * from arc.globals import * from arc.logger import ColouredLogger from arc.server import ArcFactory FILES_TO_MAKE = ["logs/", "logs/console/", "logs/levels/", # Log folders "arc/archives/", # Archives "config/data/"] # Config data makefiles(FILES_TO_MAKE) makedatfile("config/data/balances.dat") makedatfile("config/data/inbox.dat") makedatfile("config/data/jail.dat") makedatfile("config/data/titles.dat") debug = (True if "--debug" in sys.argv else False) logger = ColouredLogger(debug) try: from colorama import init except ImportError: logger.warn("Colorama is not installed - console colours DISABLED.") except Exception as e: logger.warn("Unable to import colorama: %s" % e) logger.warn("Console colours DISABLED.") else: init() logger.stdout("&f") logger.debug("&fIf you see this, debug mode is &eon&f!") logger.info("&fColorama &ainstalled&f - Console colours &cENABLED&f.") def doExit():
class ChatBot(irc.IRCClient): """An IRC-server chat integration bot.""" def connectionMade(self): self.logger = ColouredLogger(debug) self.ops = [] self.nickname = self.factory.main_factory.irc_nick self.password = self.factory.main_factory.irc_pass irc.IRCClient.connectionMade(self) self.factory.instance = self self.factory, self.irc_factory = self.factory.main_factory, self.factory self.world = None self.sendLine('NAMES ' + self.factory.irc_channel) def connectionLost(self, reason): irc.IRCClient.connectionLost(self, reason) self.logger.info("IRC client disconnected. (%s)" % reason) # callbacks for events def ctcpQuery_VERSION(self, user, channel, data): """Called when received a CTCP VERSION request.""" nick = user.split("!")[0] self.ctcpMakeReply(nick, [('VERSION', 'The Archives %s - a Minecraft server written in Python.' % VERSION)]) def signedOn(self): """Called when bot has succesfully signed on to server.""" self.logger.info("IRC client connected.") self.msg("NickServ", "IDENTIFY %s %s" % (self.nickname, self.password)) self.msg("ChanServ", "INVITE %s" % self.factory.irc_channel) self.join(self.factory.irc_channel) def joined(self, channel): """This will get called when the bot joins the channel.""" self.logger.info("IRC client joined %s." % channel) def sendError(self, error): self.logger.error("Sending error: %s" % error) self.sendPacked(TYPE_ERROR, error) reactor.callLater(0.2, self.transport.loseConnection) def lineReceived(self, line): # use instead of query line = irc.lowDequote(line) try: prefix, command, params = irc.parsemsg(line) if irc.numeric_to_symbolic.has_key(command): command = irc.numeric_to_symbolic[command] self.handleCommand(command, prefix, params) except irc.IRCBadMessage: self.badMessage(line, *sys.exc_info()) try: if command == "RPL_NAMREPLY": names = params[3].split() for name in names: if name.startswith("@"): self.ops.append(name[1:]) except: self.logger.error(traceback.format_exc()) def privmsg(self, user, channel, msg): """This will get called when the bot receives a message.""" try: user = user.split('!', 1)[0] if channel == self.nickname: if not (self.nickname == user or "Serv" in user): msg_command = msg.split() self.factory.runCommand(msg_command[0], msg_command, "irc_query", (True if user in self.ops else False), client=self, username=user) elif channel.lower() == self.factory.irc_channel.lower(): if msg.lower().lstrip(self.nickname.lower()).startswith("$" + self.nickname.lower()): msg_command = msg.split() msg_command[1] = msg_command[1].lower() self.factory.runCommand(msg_command[1], msg_command, "irc", (True if user in self.ops else False), client=self) elif msg.startswith("$"): self.logger.info("<$%s> %s" % (user, msg)) elif msg.startswith("!"): # It's a world message. message = msg.split(" ") if len(message) == 1: self.msg(self.factory.irc_channel, "Please include a message to send.") else: try: world = message[0][1:len(message[0])] out = "\n ".join(message[1:]) except ValueError: self.msg(self.factory.irc_channel, "07Please include a message to send.") else: if world in self.factory.worlds: self.factory.sendMessageToAll(out, "world", user=user, world=world, fromloc="irc") else: self.msg(self.factory.irc_channel, "07That world does not exist. Try !world message") else: msg = sanitizeMessage(msg, [MSGREPLACE["text_colour_to_game"], MSGREPLACE["irc_colour_to_game"], MSGREPLACE["escape_commands"]]) for character in msg: if not character.lower() in PRINTABLE: msg = msg.replace(character, "*") if msg[len(msg) - 2] == "&": self.msg(self.factory.irc_channel, "07You cannot use a color at the end of a message.") return self.factory.sendMessageToAll(msg, "irc", user=user, fromloc="irc") except: self.logger.error(traceback.format_exc()) self.msg(self.factory.irc_channel, "Internal Server Error (See the Console for more details)") def action(self, user, channel, msg): """This will get called when the bot sees someone do an action.""" msg = msg.replace("./", " /") msg = msg.replace(".!", " !") user = user.split('!', 1)[0] msg = "".join([char for char in msg if ord(char) < 128 and char != "" or "0"]) self.factory.sendMessageToAll("%s* %s %s" % (COLOUR_YELLOW, COLOUR_WHITE + user, msg), "irc", user="", fromloc="irc") self.logger.info("* %s %s" % (user, msg)) self.factory.chatlog.write( "[%s] * %s %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"), user, msg)) self.factory.chatlog.flush() def sendMessage(self, username, message): sanitizeMessage(username, MSGREPLACE["game_colour_to_irc"]) sanitizeMessage(message, [MSGREPLACE["game_colour_to_irc"], MSGREPLACE["escape_commands"]]) self.msg(self.factory.irc_channel, "%s: %s" % (username, message)) def sendServerMessage(self, message, user=None): sanitizeMessage(message, [MSGREPLACE["game_colour_to_irc"], MSGREPLACE["escape_commands"]]) if user != None: self.msg(user, "%s" % message) else: self.msg(self.factory.irc_channel, "%s" % message) def sendAction(self, username, message): sanitizeMessage(message, MSGREPLACE["game_colour_to_irc"]) sanitizeMessage(message, [MSGREPLACE["game_colour_to_irc"], MSGREPLACE["escape_commands"]]) self.msg(self.factory.irc_channel, "* %s %s" % (username, message)) sendSplitServerMessage = sendWorldMessage = sendPlainWorldMessage = sendNormalMessage = sendServerMessage def sendServerList(self, items, wrap_at=63, plain=False, username=None): "Sends the items as server messages, wrapping them correctly." done = " ".join(items) self.irc_factory.sendServerMessage(done) # irc callbacks def irc_NICK(self, prefix, params): "Called when an IRC user changes their nickname." old_nick = prefix.split('!')[0] new_nick = params[0] if old_nick in self.ops: self.ops.remove(old_nick) self.ops.append(new_nick) msg = "%s%s is now known as %s" % (COLOUR_YELLOW, old_nick, new_nick) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") def userKicked(self, kickee, channel, kicker, message): "Called when I observe someone else being kicked from a channel." if kickee in self.ops: self.ops.remove(kickee) msg = "%s%s was kicked from %s by %s" % (COLOUR_YELLOW, kickee, channel, kicker) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") if not kickee == message: msg = "%sReason: %s" % (COLOUR_YELLOW, message) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") def userLeft(self, user, channel): "Called when I see another user leaving a channel." if user in self.ops: self.ops.remove(user) msg = "%s%s has left %s" % (COLOUR_YELLOW, user.split("!")[0], channel) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") def userJoined(self, user, channel): "Called when I see another user joining a channel." if user in self.ops: self.ops.remove(user) msg = "%s%s has joined %s" % (COLOUR_YELLOW, user.split("!")[0], channel) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") def modeChanged(self, user, channel, set, modes, args): "Called when someone changes a mode." setUser = user.split("!")[0] arguments = [] for element in args: if element: arguments.append(element.split("!")[0]) if set and modes.startswith("o"): if len(arguments) < 2: msg = "%s%s was opped on %s by %s" % (COLOUR_YELLOW, arguments[0], channel, setUser) else: msg = "%sUsers opped on %s by %s: %s (%s)" % ( COLOUR_YELLOW, channel, setUser, ", ".join(arguments), len(arguments)) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") for name in args: if not name in self.ops: self.ops.append(name) elif not set and modes.startswith("o"): done = [] for name in args: done.append(name.split("!")[0]) if len(arguments) < 2: msg = "%s%s was deopped on %s by %s" % (COLOUR_YELLOW, arguments[0], channel, setUser) else: msg = "%sUsers deopped on %s by %s: %s (%s)" % ( COLOUR_YELLOW, channel, setUser, ", ".join(arguments), len(arguments)) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") for name in args: if name in self.ops: self.ops.remove(name) def irc_QUIT(self, user, params): userhost = user user = user.split('!')[0] quitMessage = params[0] if userhost in self.ops: self.ops.remove(userhost) msg = "%s%s has quit IRC." % (COLOUR_YELLOW, user) self.factory.sendMessageToAll(msg, "irc", user=user) sanitizeMessage(msg, [MSGREPLACE["irc_colour_to_game"], MSGREPLACE["escape_commands"]]) for character in msg: if not character.lower() in PRINTABLE: msg = msg.replace(character, "*") if msg[len(msg) - 2] == "&": return msg = "%s(%s%s)" % (COLOUR_YELLOW, quitMessage, COLOUR_YELLOW) self.factory.sendMessageToAll(msg, "irc", user="", fromloc="irc") def isRank(self): return False # For whatever rank, just return False. overriderank is turned on for query so doesn't matter isSpectator = isBuilder = isOp = isWorldOwner = isHelper = isMod = isAdmin = isDirector = isOwner = isSilenced = alloweToBuild = canBreakAdminBlocks = isRank def getBlockValue(self, value): # Try getting the block as a direct integer type. try: block = chr(int(value)) except ValueError: # OK, try a symbolic type. try: block = chr(globals()['BLOCK_%s' % value.upper()]) except KeyError: return None # Check the block is valid if ord(block) > 49: return None return block def send(self, *args, **kwargs): pass canBreakAdminBlocks = sendPacked = sendError = sendRankUpdate = respawn = sendBlock = sendPlayerPos = sendPlayerDir = sendNewPlayer = sendPlayerLeave = sendKeepAlive = sendOverload =\ sendOverloadChunk = sendLevel = sendLevelStart = sendLevelChunk = endSendLevel = sendAllNew = sendWelcome = send def getBlbLimit(self): return 0