def posChanged(self, x, y, z, h, p): "Hook trigger for when the player moves" rx = x >> 5 ry = y >> 5 rz = z >> 5 if hasattr(self.client.world.blockstore, "raw_blocks"): try: check_offset = self.client.world.blockstore.get_offset(rx, ry, rz) try: block = self.client.world.blockstore.raw_blocks[check_offset] except (IndexError): return check_offset = self.client.world.blockstore.get_offset(rx, ry-1, rz) blockbelow = self.client.world.blockstore.raw_blocks[check_offset] except (KeyError, AssertionError): pass else: if block == chr(BLOCK_LAVA) or blockbelow == chr(BLOCK_LAVA): #or block == chr(BLOCK_STILLLAVA) or blockbelow == chr(BLOCK_STILLLAVA): #Ok, so they touched lava, THEY MUST DIE. Warp them to the spawn, timer to stop spam. if self.died is False: self.died = True self.client.teleportTo(self.client.world.spawn[0], self.client.world.spawn[1], self.client.world.spawn[2], self.client.world.spawn[3]) self.client.factory.queue.put ((self.client.world,TASK_WORLDMESSAGE, (255, self.client.world, COLOUR_DARKRED+self.client.username+" has died from lava."))) reactor.callLater(1, self.unDie)
def posChanged(self, x, y, z, h, p): "Hook trigger for when the player moves" rx = x >> 5 ry = y >> 5 rz = z >> 5 if hasattr(self.client.world.blockstore, "raw_blocks"): try: check_offset = self.client.world.blockstore.get_offset( rx, ry, rz) try: block = self.client.world.blockstore.raw_blocks[ check_offset] except (IndexError): return check_offset = self.client.world.blockstore.get_offset( rx, ry - 1, rz) blockbelow = self.client.world.blockstore.raw_blocks[ check_offset] except (KeyError, AssertionError): pass else: if block == chr(BLOCK_LAVA) or blockbelow == chr(BLOCK_LAVA): #or block == chr(BLOCK_STILLLAVA) or blockbelow == chr(BLOCK_STILLLAVA): #Ok, so they touched lava, THEY MUST DIE. Warp them to the spawn, timer to stop spam. if self.died is False: self.died = True self.client.teleportTo(self.client.world.spawn[0], self.client.world.spawn[1], self.client.world.spawn[2], self.client.world.spawn[3]) self.client.factory.queue.put( (self.client.world, TASK_WORLDMESSAGE, (255, self.client.world, COLOUR_DARKRED + self.client.username + " has died from lava."))) reactor.callLater(1, self.unDie)
def commandRestore(self, parts, fromloc, overriderank): "/restore worldname number|backupname - Op\nRestore map to indicated number or backup name." if len(parts) < 2: self.client.sendServerMessage("Please specify at least a world ID!") else: world_id = parts[1].lower() world_dir = "mapdata/worlds/%s/" % world_id if len(parts) < 3: try: backups = os.listdir(world_dir + "backup/") except: self.client.sendServerMessage("Syntax: /restore worldname number") return backups.sort(lambda x, y: int(x) - int(y)) backup_number = str(int(backups[-1])) else: backup_number = parts[2] if not os.path.exists(world_dir + "backup/%s/" % backup_number): self.client.sendServerMessage("Backup %s does not exist." % backup_number) else: old_clients = self.client.factory.worlds[world_id].clients if not os.path.exists(world_dir + "blocks.gz.new"): shutil.copy(world_dir + "backup/%s/blocks.gz" % backup_number, world_dir) shutil.copy(world_dir + "backup/%s/world.meta" % backup_number, world_dir) else: reactor.callLater(1, self.commandRestore(self, parts, overriderank)) self.client.factory.loadWorld("mapdata/worlds/%s" % world_id, world_id) self.client.sendServerMessage("%s has been restored to %s and booted." % (world_id, backup_number)) self.client.factory.worlds[world_id].clients = old_clients for client in self.client.factory.worlds[world_id].clients: client.changeToWorld(world_id)
def reload(self, username): try: self.ini.read("persist/%s.ini" % username.lower()) except: pass else: reactor.callLater(10, self.reload, username)
def reload(self, username): try: self.ini.read("persist/%s.ini" % username.lower()) except: pass else: reactor.callLater(10, self.reload, username)
block_iter = iter(generate_changes()) def do_step(): # Do 10 blocks try: for x in range(10):#10 blocks at a time, 10 blocks per tenths of a second, 100 blocks a second block_iter.next() reactor.callLater(0.01, do_step) #This is how long(in seconds) it waits to run another 10 blocks except StopIteration:
def do_step(): # Do 10 blocks try: for x in range(10): # 10 blocks at a time, 10 blocks per tenths of a second, 100 blocks a second block_iter.next() reactor.callLater(0.01, do_step) # This is how long (in seconds) it waits to run another 10 blocks except StopIteration: if fromloc == 'user': self.client.finalizeMassCMD('bwb', self.client.total) pass
self.client.total += 1 except AssertionError: self.client.sendServerMessage("Out of bounds creplace error.") return yield # Now, set up a loop delayed by the reactor block_iter = iter(generate_changes()) def do_step(): # Do 50 blocks try: for x in range(50):
def do_step(): # Do 10 blocks try: for x in range(10): block_iter.next() reactor.callLater(0.01, do_step) except StopIteration: if fromloc == 'user': self.client.finalizeMassCMD('copy', self.client.total) self.client.total = 0 pass
def saveWorlds(self): "Saves the worlds, one at a time, with a 1 second delay." if not self.saving: if not self.world_save_stack: self.world_save_stack = list(self.worlds) key = self.world_save_stack.pop() self.saveWorld(key) if not self.world_save_stack: self.saveMeta() else: reactor.callLater(1, self.saveWorlds)
def do_step(): # Do 10 blocks try: for x in range( 10 ): #10 blocks at a time, 10 blocks per tenths of a second, 100 blocks a second block_iter.next() reactor.callLater( 0.01, do_step ) #This is how long(in seconds) it waits to run another 10 blocks except StopIteration: pass
def run(self): """ Execute pending WX events followed by WX idle events and reschedule. """ # run wx events while self.app.Pending(): self.app.Dispatch() # run wx idle events self.app.ProcessIdle() reactor.callLater(0.02, self.run)
def do_step(): # Do 10 blocks try: for x in range(10):#10 blocks at a time, 10 blocks per tenths of a second, 100 blocks a second block_iter.next() reactor.callLater(0.01, do_step) #This is how long(in seconds) it waits to run another 10 blocks except StopIteration: if fromloc == 'user': self.client.finalizeMassCMD('bhcb', self.client.total) self.client.sendServerMessage("%i %s, %i %s" % (self.total_a, block, self.total_b, block2)) self.total_a = 0 self.total_b = 0 pass
def sendLevelChunk(self): if not hasattr(self, 'chunk'): self.logger.error("Cannot send chunk, there isn't one! %r %r" % (self, self.__dict__)) return if self.chunk: self.sendPacked(TYPE_CHUNK, len(self.chunk), self.chunk, chr(int(100*(self.zipped_level.tell()/float(self.zipped_size))))) self.chunk = self.zipped_level.read(1024) reactor.callLater(0.001, self.sendLevelChunk) else: self.zipped_level.close() del self.zipped_level del self.chunk del self.zipped_size self.endSendLevel()
def blockChanged(self, x, y, z, block, selected_block, fromloc): if fromloc != 'user': #People shouldnt be blbing mines :P return if self.client.world.has_mine(x, y, z): self.client.sendServerMessage("You defused a mine!") self.client.world.delete_mine(x, y, z) if self.placingmines and block==BLOCK_BLACK: self.client.sendServerMessage("You placed a mine") self.placingmines = False def ActivateMine(): self.client.world.add_mine(x, y, z) self.client.sendServerMessage("Your mine is now active!") reactor.callLater(2, ActivateMine)
def sendLevelChunk(self): if not hasattr(self, 'chunk'): self.logger.error("Cannot send chunk, there isn't one! %r %r" % (self, self.__dict__)) return if self.chunk: self.sendPacked(TYPE_CHUNK, len(self.chunk), self.chunk, chr(int(100*(self.zipped_level.tell()/float(self.zipped_size))))) self.chunk = self.zipped_level.read(1024) reactor.callLater(0.001, self.sendLevelChunk) else: self.zipped_level.close() del self.zipped_level del self.chunk del self.zipped_size self.endSendLevel()
def do_step(): # Do 10 blocks try: for x in range( 10 ): # 10 blocks at a time, 10 blocks per tenths of a second, 100 blocks a second block_iter.next() reactor.callLater( 0.01, do_step ) # This is how long (in seconds) it waits to run another 10 blocks except StopIteration: if fromloc == 'user': self.client.finalizeMassCMD('bwb', self.client.total) pass
def blockChanged(self, x, y, z, block, selected_block, fromloc): "Hook trigger for block changes." world = self.client.world if block is BLOCK_AIR and self.in_publicworld: if ord(world.blockstore.raw_blocks[world.blockstore.get_offset(x, y, z)]) != 3: worldname = world.id username = self.client.username def griefcheck(): if self.var_blockchcount >= 35: self.client.factory.queue.put( ( self.client, TASK_STAFFMESSAGE, ( "#%s%s: %s%s" % ( COLOUR_DARKGREEN, "SERVER", COLOUR_DARKGREEN, "ALERT! Possible Griefer behavior detected in", ) ), ) ) self.client.factory.queue.put( ( self.client, TASK_STAFFMESSAGE, ( "#%s%s: %s%s" % ( COLOUR_DARKGREEN, "SERVER", COLOUR_DARKGREEN, "'" + worldname + "'! Username: "******" was detected as a possible griefer in '" + worldname + "'") self.client.adlog.write( datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M") + " | STAFF | " + username + " was detected as a possible griefer in '" + worldname + "'" + "\n" ) self.client.adlog.flush() self.var_blockchcount = 0 if self.var_blockchcount == 0: self.client.factory.loops["antigrief"] = reactor.callLater(5, griefcheck) self.var_blockchcount += 1
def do_step(): # Do 10 blocks try: for x in range( 10 ): #10 blocks at a time, 10 blocks per tenths of a second, 100 blocks a second block_iter.next() reactor.callLater( 0.01, do_step ) #This is how long(in seconds) it waits to run another 10 blocks except StopIteration: if fromloc == 'user': self.client.finalizeMassCMD('bhcb', self.client.total) self.client.sendServerMessage( "%i %s, %i %s" % (self.total_a, block, self.total_b, block2)) self.total_a = 0 self.total_b = 0 pass
def posChanged(self, x, y, z, h, p): "Hook trigger for when the player moves" rx = x >> 5 ry = y >> 5 rz = z >> 5 try: if self.client.world.has_command(rx, ry, rz) and (rx, ry, rz) != self.last_block_position: if self.listeningforpay: self.client.sendServerMessage("Please confirm or cancel payment before using a cmdblock.") return False if self.inputvar is not None or self.inputnum is not None or self.inputblock is not None or self.inputyn is not None: self.client.sendServerMessage("Please give input before using a cmdblock") return False self.runningcmdlist = list(self.client.world.get_command(rx, ry, rz)) self.runningsensor = True reactor.callLater(0.01, self.runcommands) except AssertionError: pass self.last_block_position = (rx, ry, rz)
def blockChanged(self, x, y, z, block, fromloc): "Hook trigger for block changes." #avoid infinite loops by making blocks unaffected by commands #if fromloc != 'user': # return False if self.client.world.has_command(x, y, z): if self.cmdinfo: cmdlist = self.client.world.get_command(x, y, z) if len(cmdlist)<11: self.client.sendServerMessage("Page 1 of 1:") for x in cmdlist: self.client.sendServerMessage(x) else: self.client.sendServerMessage("Page 1 of %s:" %int((len(cmdlist)/10)+1)) for x in cmdlist[:9]: self.client.sendServerMessage(x) self.infoindex = 0 self.cmdinfolines = cmdlist return False if self.command_remove is True: self.client.world.delete_command(x, y, z) self.client.sendServerMessage("You deleted a command block.") else: if self.listeningforpay: self.client.sendServerMessage("Please confirm or cancel payment before using a cmdblock.") return False if self.inputvar is not None or self.inputnum is not None or self.inputblock is not None or self.inputyn is not None: self.client.sendServerMessage("Please give input before using a cmdblock") return False if self.cmdinfolines is not None: self.client.sendServerMessage("Please complete the cmdinfo before using a cmdblock.") return False self.runningcmdlist = list(self.client.world.get_command(x, y, z)) self.runningsensor = False reactor.callLater(0.01, self.runcommands) return False if self.command_cmd: if self.placing_cmd: self.client.sendServerMessage("You placed a command block. Type /cmdend to stop.") self.client.world.add_command(x, y, z, self.command_cmd)
def blockChanged(self, x, y, z, block, selected_block, fromloc): "Hook trigger for block changes." tobuild = [] # Randomise the variables fanout = self.explosion_radius if self.build_tnt and block == BLOCK_DIRT: def explode(): # Clear the explosion radius for i in range(-fanout, fanout+1): for j in range(-fanout, fanout+1): for k in range(-fanout, fanout+1): tobuild.append((i, j, k, BLOCK_DIRT)) # OK, send the build changes for dx, dy, dz, block in tobuild: try: self.client.world[x+dx, y+dy, z+dz] = chr(block) self.client.sendBlock(x+dx, y+dy, z+dz, block) self.client.factory.queue.put((self.client, TASK_BLOCKSET, (x+dx, y+dy, z+dz, block))) except AssertionError: # OOB pass # Explode in 2 seconds reactor.callLater(self.delay, explode)
def blockChanged(self, x, y, z, block, selected_block, fromloc): "Hook trigger for block changes." world = self.client.world if block is BLOCK_AIR and self.in_publicworld: if ord(world.blockstore.raw_blocks[world.blockstore.get_offset(x, y, z)]) != 3: worldname = world.id username = self.client.username def griefcheck(): if self.var_blockchcount >= 35: self.client.factory.queue.put((self.client, TASK_STAFFMESSAGE, ("#%s%s: %s%s" % (COLOUR_DARKGREEN, 'SERVER', COLOUR_DARKGREEN, "ALERT! Possible Griefer behavior detected in")))) self.client.factory.queue.put((self.client, TASK_STAFFMESSAGE, ("#%s%s: %s%s" % (COLOUR_DARKGREEN, 'SERVER', COLOUR_DARKGREEN, "'" + worldname + "'! Username: "******" was detected as a possible griefer in '" + worldname + "'") self.client.adlog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" | STAFF | "+username + " was detected as a possible griefer in '" + worldname + "'" + "\n") self.client.adlog.flush() self.var_blockchcount = 0 if self.var_blockchcount == 0: self.client.factory.loops["antigrief"] = reactor.callLater(5, griefcheck) self.var_blockchcount += 1
def registerAddress(self, domainURL, logicalURL, physicalURL): if domainURL.host != self.domain: log.msg("Registration for domain we don't handle.") return defer.fail(RegistrationError(404)) if logicalURL.host != self.domain: log.msg("Registration for domain we don't handle.") return defer.fail(RegistrationError(404)) if self.users.has_key(logicalURL.username): dc, old = self.users[logicalURL.username] dc.reset(3600) else: dc = reactor.callLater(3600, self._expireRegistration, logicalURL.username) log.msg("Registered %s at %s" % (logicalURL.toString(), physicalURL.toString())) self.users[logicalURL.username] = (dc, physicalURL) return defer.succeed( Registration(int(dc.getTime() - time.time()), physicalURL))
def initLoops(self): # Set up tasks to run during execution reactor.callLater(0.1, self.sendMessages) self.loops["printinfo"] = task.LoopingCall(self.printInfo) self.loops["printinfo"].start(60) # Initial startup is instant, but it updates every 10 minutes. self.world_save_stack = [] reactor.callLater(60, self.saveWorlds) if self.enable_archives: if "archives" not in protocol_plugins: self.loadPlugin("archives") #self.loops["loadarchives"] = task.LoopingCall(self.loadArchives) #self.loops["loadarchives"].start(60) reactor.callLater(60, self.loadArchives) gc.disable()
def sendMessages(self): "Sends all queued messages, and lets worlds recieve theirs." try: while True: # Get the next task source_client, task, data = self.queue.get_nowait() if source_client == None: # Client is None pass try: if isinstance(source_client, World): world = source_client elif str(source_client).startswith("<StdinPlugin"): world = self.worlds["main"] else: try: world = source_client.world except AttributeError: if not source_client.connected: continue else: self.logger.warning("Source client for message has no world. Ignoring.") continue # Someone built/deleted a block if task is TASK_BLOCKSET: # Only run it for clients who weren't the source. for client in world.clients: if client is not source_client: client.sendBlock(*data) # Someone moved elif task is TASK_PLAYERPOS: # Only run it for clients who weren't the source. for client in world.clients: if client != source_client: client.sendPlayerPos(*data) # Someone moved only their direction elif task is TASK_PLAYERDIR: # Only run it for clients who weren't the source. for client in world.clients: if client != source_client: client.sendPlayerDir(*data) # Someone spoke! elif task is TASK_MESSAGE: #LOL MOAR WORD FILTER id, colour, username, text = data text = self.messagestrip(text) data = (id,colour,username,text) for client in self.clients.values(): if not client.console: if (client.world.global_chat or client.world is source_client.world): client.sendMessage(*data) id, colour, username, text = data self.logger.info("%s: %s" % (username, text)) self.chatlog.write("%s - %s: %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M"), username, text)) self.chatlog.flush() if self.irc_relay and world: self.irc_relay.sendMessage(username, text) # Someone spoke! elif task is TASK_IRCMESSAGE: # Word Filter id, colour, username, text = data text = self.messagestrip(text) data = (id, colour, username, text) for client in self.clients.values(): client.sendIrcMessage(*data) self.logger.info("<%s> %s" % (username, text)) self.chatlog.write("[%s] <%s> %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M"), username, text)) self.chatlog.flush() if self.irc_relay and world: self.irc_relay.sendMessage(username, text) # Someone actioned! elif task is TASK_ACTION: #WORD FALTER id, colour, username, text = data text = self.messagestrip(text) data = (id, colour, username, text) for client in self.clients.values(): client.sendAction(*data) id, colour, username, text = data self.logger.info("ACTION - *%s %s" % (username, text)) self.chatlog.write("%s *%s %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M"), username, text)) self.chatlog.flush() if self.irc_relay and world: self.irc_relay.sendAction(username, text) # Someone connected to the server elif task is TASK_PLAYERCONNECT: for client in self.usernames: self.usernames[client].sendNewPlayer(*data) self.usernames[client].sendServerMessage("%s has come online." % source_client.username) if self.irc_relay and world: self.irc_relay.sendServerMessage("%s has come online." % source_client.username) # Someone joined a world! elif task is TASK_NEWPLAYER: for client in world.clients: if client != source_client: client.sendNewPlayer(*data) client.sendServerMessage("%s has joined the map." % source_client.username) # Someone left! elif task is TASK_PLAYERLEAVE: # Only run it for clients who weren't the source. for client in self.clients.values(): client.sendPlayerLeave(*data) if not source_client.username is None: client.sendServerMessage("%s has quit! (%s%s%s)" % (source_client.username, COLOUR_RED, source_client.quitmsg, COLOUR_YELLOW)) else: source_client.logger.info("Pinged the server.") if not source_client.username is None: if self.irc_relay and world: self.irc_relay.sendServerMessage("%s has quit! (%s%s%s)" % (source_client.username, COLOUR_RED, source_client.quitmsg, COLOUR_BLACK)) self.logger.info("%s has quit! (%s)" % (source_client.username, source_client.quitmsg)) # Someone changed worlds! elif task is TASK_WORLDCHANGE: # Only run it for clients who weren't the source. for client in data[1].clients: client.sendPlayerLeave(data[0]) client.sendServerMessage("%s joined '%s'" % (source_client.username, world.id)) if self.irc_relay and world: self.irc_relay.sendServerMessage("%s joined '%s'" % (source_client.username, world.id)) self.logger.info("%s has now joined '%s'" % (source_client.username, world.id)) elif task == TASK_STAFFMESSAGE: # Give all staff the message id, colour, username, text = data message = self.messagestrip(text) for user, client in self.usernames.items(): if self.isMod(user): client.sendMessage(100, COLOUR_YELLOW+"#"+colour, username, message, False, False) if self.irc_relay and len(data)>3: self.irc_relay.sendServerMessage("#"+username+": "+text,True,username) self.logger.info("#"+username+": "+text) self.adlog = open("logs/server.log", "a") self.adlog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" - "+username+": "+text+"\n") self.adlog.flush() elif task == TASK_GLOBALMESSAGE: # Give all world people the message id, world, message = data message = self.messagestrip(message); for client in world.clients: client.sendNormalMessage(message) elif task == TASK_WORLDMESSAGE: # Give all world people the message id, world, message = data for client in world.clients: client.sendNormalMessage(message) elif task == TASK_SERVERMESSAGE: # Give all people the message message = data message = self.messagestrip(message); for client in self.clients.values(): client.sendNormalMessage(COLOUR_DARKBLUE + message) self.logger.info(message) if self.irc_relay and world: self.irc_relay.sendServerMessage(message) elif task == TASK_ONMESSAGE: # Give all people the message message = data message = self.messagestrip(message); for client in self.clients.values(): client.sendNormalMessage(COLOUR_YELLOW + message) if self.irc_relay and world: self.irc_relay.sendServerMessage(message) elif task == TASK_PLAYERRESPAWN: # We need to immediately respawn the player to update their nick. for client in world.clients: if client != source_client: id, username, x, y, z, h, p = data client.sendPlayerLeave(id) client.sendNewPlayer(id, username, x, y, z, h, p) elif task == TASK_SERVERURGENTMESSAGE: # Give all people the message message = data for client in self.clients.values(): client.sendNormalMessage(COLOUR_DARKRED + message) self.logger.info(message) if self.irc_relay and world: self.irc_relay.sendServerMessage(message) elif task == TASK_AWAYMESSAGE: # Give all world people the message id, colour, username, text = data message = self.messagestrip(text) data = (id, colour, username, text) for client in world.clients: client.sendNormalMessage(COLOUR_DARKPURPLE + message) self.logger.info("AWAY - %s %s" % (username, text)) self.chatlog.write("%s %s %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M"), username, text)) self.chatlog.flush() if self.irc_relay and world: self.irc_relay.sendAction(username, text) except Exception, e: self.logger.error(traceback.format_exc()) except Empty: pass # OK, now, for every world, let them read their queues for world in self.worlds.values(): world.read_queue() # Come back soon! reactor.callLater(0.1, self.sendMessages)
# blockBox is copyright 2009-2011 the Archives Team, the blockBox Team, and the iCraft team.
def turl(self): try: threading.Thread(target=self.get_url).start() except: self.logger.error(traceback.format_exc()) reactor.callLater(1, self.turl)
def dataReceived(self, data): # First, add the data we got onto our internal buffer self.buffer += data # While there's still data there... while self.buffer: # Examine the first byte, to see what the command is type = ord(self.buffer[0]) try: format = TYPE_FORMATS[type] except KeyError: #it's a weird data packet, probably a ping. reactor.callLater(0.2, self.transport.loseConnection) return # See if we have all its data if len(self.buffer) - 1 < len(format): # Nope, wait a bit break # OK, decode the data parts = list(format.decode(self.buffer[1:])) self.buffer = self.buffer[len(format)+1:] if type == TYPE_INITIAL: # Get the client's details protocol, self.username, mppass, utype = parts self.logger = logging.getLogger(self.username) if self.identified == True: self.logger.info("Kicked '%s'; already logged in to server" % (self.username)) self.sendError("You already logged in! Foolish bot owners.") # Check their password correct_pass = hashlib.md5(self.factory.salt + self.username).hexdigest()[-32:].strip("0") mppass = mppass.strip("0") if not self.transport.getHost().host.split(".")[0:2] == self.transport.getPeer().host.split(".")[0:2]: if self.factory.verify_names and mppass != correct_pass: self.logger.info("Kicked '%s'; invalid password (%s, %s)" % (self.username, mppass, correct_pass)) self.sendError("Incorrect authentication. (try again in 60s?)") return self.logger.info("Connected, as '%s'" % self.username) self.identified = True # Are they banned? if self.factory.isBanned(self.username): self.sendError("Banned: %s" % self.factory.banReason(self.username)) return # OK, see if there's anyone else with that username if not self.factory.duplicate_logins and self.username.lower() in self.factory.usernames: self.factory.usernames[self.username.lower()].duplicateKick() self.factory.usernames[self.username.lower()] = self # Right protocol? if protocol != 7: self.sendError("Wrong protocol.") break # Send them back our info. breakable_admins = self.runHook("canbreakadmin") self.persist = Persist(self.username.lower()) reactor.callLater(0.1, self.setPersist) self.sendPacked( TYPE_INITIAL, 7, # Protocol version self.packString(self.factory.server_name), self.packString(self.factory.server_message), 100 if breakable_admins else 0, ) # Then... stuff for client in self.factory.usernames.values(): client.sendServerMessage("%s has come online." %self.username) if self.factory.irc_relay: self.factory.irc_relay.sendServerMessage("%s has come online." % self.username) # Are they IP specced? if self.factory.isIpSpecced(self.ip): self.factory.spectators.add(self.username) self.sendSpectatorUpdate() self.sendServerMessage("Your IP has been spectated for: %s" % self.factory.ipSpecReason(self.ip)) self.logger.info("User %s autospecced due to its IP being on the IPSpec list." % self.username) reactor.callLater(0.1, self.sendLevel) self.factory.loops[self.username]["sendkeepalive"] = task.LoopingCall(self.sendKeepAlive) self.factory.loops[self.username]["sendkeepalive"].start(1) elif type == TYPE_BLOCKCHANGE: x, y, z, created, block = parts if block == 255: block = 0 if block > 49: self.logger.info("Kicked '%s'; Tried to place an invalid block.; Block: '%s'" % (self.transport.getPeer().host, block)) self.sendError("Invalid blocks are not allowed!") return if 6 < block < 12: if not block == 9 and not block == 11: self.logger.info("Kicked '%s'; Tried to place an invalid block.; Block: '%s'" % (self.transport.getPeer().host, block)) self.sendError("Invalid blocks are not allowed!") return if self.identified == False: self.logger.info("Kicked '%s'; did not send a login before building" % (self.transport.getPeer().host)) self.sendError("Provide an authentication before building.") return try: # If we're read-only, reverse the change if self.isSpectator(): self.sendBlock(x, y, z) self.sendServerMessage("Spectators cannot edit maps.") return allowbuild = self.runHook("blockclick", x, y, z, block, True) if allowbuild is False: self.sendBlock(x, y, z) return elif not self.AllowedToBuild(x,y,z): self.sendBlock(x, y, z) return # This try prevents out-of-range errors on the world storage # Track if we need to send back the block change overridden = False selected_block = block # If we're deleting, block is actually air # (note the selected block is still stored as selected_block) if not created: block = 0 # Pre-hook, for stuff like /paint new_block = self.runHook("preblockchange", x, y, z, block, selected_block, True) if new_block is not None: block = new_block overridden = True # Call hooks new_block = self.runHook("blockchange", x, y, z, block, selected_block, True) if new_block is False: # They weren't allowed to build here! self.sendBlock(x, y, z) continue elif new_block is True: # Someone else handled building, just continue continue elif new_block is not None: block = new_block overridden = True # OK, save the block self.world[x, y, z] = chr(block) # Now, send the custom block back if we need to if overridden: self.sendBlock(x, y, z, block) # Out of bounds! except (KeyError, AssertionError): self.sendPacked(TYPE_BLOCKSET, x, y, z, "\0") # OK, replay changes to others else: self.factory.queue.put((self, TASK_BLOCKSET, (x, y, z, block))) if len(self.last_block_changes) >= 3: self.last_block_changes = [(x, y, z)] + self.last_block_changes[:1]+self.last_block_changes[1:3] else: self.last_block_changes = [(x, y, z)] + self.last_block_changes[:2] elif type == TYPE_PLAYERPOS: # If we're loading a world, ignore these. if self.loading_world: continue naff, x, y, z, h, p = parts pos_change = not (x == self.x and y == self.y and z == self.z) dir_change = not (h == self.h and p == self.p) if self.frozen: newx = self.x >> 5 newy = self.y >> 5 newz = self.z >> 5 self.teleportTo(newx, newy, newz, h, p) return override = self.runHook("poschange", x, y, z, h, p) # Only send changes if the hook didn't say no if override is not False: if pos_change: # Send everything to the other clients self.factory.queue.put((self, TASK_PLAYERPOS, (self.id, self.x, self.y, self.z, self.h, self.p))) elif dir_change: self.factory.queue.put((self, TASK_PLAYERDIR, (self.id, self.h, self.p))) self.x, self.y, self.z, self.h, self.p = x, y, z, h, p elif type == TYPE_MESSAGE: byte, message = parts user = self.username.lower() t = self.persist.string("misc", "title", "") if t is "": self.title = "" else: self.title = "\""+t+"\" " self.usertitlename = self.title + self.username override = self.runHook("chatmsg", message) goodchars = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " ", "!", "@", "#", "$", "%", "*", "(", ")", "-", "_", "+", "=", "{", "[", "}", "]", ":", ";", "\"", "\'", "<", ",", ">", ".", "?", "/", "\\", "|"] for c in message.lower(): if not c in goodchars: self.logger.info("Kicked '%s'; Tried to use invalid characters; Message: '%s'" % (self.transport.getPeer().host, message)) self.sendError("Invalid characters are not allowed!") return message = message.replace("%0", "&0") message = message.replace("%1", "&1") message = message.replace("%2", "&2") message = message.replace("%3", "&3") message = message.replace("%4", "&4") message = message.replace("%5", "&5") message = message.replace("%6", "&6") message = message.replace("%7", "&7") message = message.replace("%8", "&8") message = message.replace("%9", "&9") message = message.replace("%a", "&a") message = message.replace("%b", "&b") message = message.replace("%c", "&c") message = message.replace("%d", "&d") message = message.replace("%e", "&e") message = message.replace("%f", "&f") message = message.replace("0", "&f") message = message.replace("00", "&f") message = message.replace("1", "&0") message = message.replace("01", "&0") message = message.replace("2", "&1") message = message.replace("02", "&1") message = message.replace("3", "&2") message = message.replace("03", "&2") message = message.replace("4", "&c") message = message.replace("04", "&c") message = message.replace("5", "&4") message = message.replace("05", "&4") message = message.replace("6", "&5") message = message.replace("06", "&5") message = message.replace("7", "&6") message = message.replace("07", "&6") message = message.replace("8", "&e") message = message.replace("08", "&e") message = message.replace("9", "&a") message = message.replace("09", "&a") message = message.replace("10", "&3") message = message.replace("11", "&b") message = message.replace("12", "&9") message = message.replace("13", "&d") message = message.replace("14", "&8") message = message.replace("15", "&7") message = message.replace("./", " /") message = message.replace(".!", " !") message = message.replace(".@", " @") message = message.replace(".#", " #") message = message.replace("%$rnd", "&$rnd") if message[len(message)-2] == "&": self.sendServerMessage("You can not use a color at the end of a message") return if len(message) > 51: moddedmsg = message[:51].replace(" ", "") if moddedmsg[len(moddedmsg)-2] == "&": message = message.replace("&", "*") if self.identified == False: self.logger.info("Kicked '%s'; did not send a login before chatting; Message: '%s'" % (self.transport.getPeer().host, message)) self.sendError("Provide an authentication before chatting.") return if message.startswith("/"): # It's a command #message = message.lower() parts = [x.strip() for x in message.split() if x.strip()] command = parts[0].strip("/") if not message.startswith("/tlog "): self.logger.info("%s just used: %s" % (self.username," ".join(parts))) #for command logging to IRC if self.factory.irc_relay: if self.factory.irc_cmdlogs: self.factory.irc_relay.sendServerMessage("%s just used: %s" % (self.username," ".join(parts))) # See if we can handle it internally try: func = getattr(self, "command%s" % command.title()) except AttributeError: # Can we find it from a plugin? try: try: func = self.commands[command.lower()] except KeyError: self.sendServerMessage("Unknown command '%s'" % command) return except AttributeError: self.logger.error("Cannot find plugin %s, please report to blockBox team." % func) self.sendSplitServerMessage("Command code not found, please report to server staff or blockBox team.") return if (self.isSpectator() and (getattr(func, "admin_only", False) or getattr(func, "mod_only", False) or getattr(func, "op_only", False) or getattr(func, "advbuilder_only", False) or getattr(func, "worldowner_only", False) or getattr(func, "writer_only", False))): self.sendServerMessage("'%s' is not available to specs." % command) return if getattr(func, "owner_only", False) and not self.isOwner(): self.sendServerMessage("'%s' is a Owner-only command!" % command) return if getattr(func, "director_only", False) and not self.isDirector(): self.sendServerMessage("'%s' is a Director-only command!" % command) return if getattr(func, "admin_only", False) and not self.isAdmin(): self.sendServerMessage("'%s' is an Admin-only command!" % command) return if getattr(func, "mod_only", False) and not (self.isMod() or self.isAdmin()): self.sendServerMessage("'%s' is a Mod-only command!" % command) return if getattr(func, "worldowner_only", False) and not (self.isMod() or self.isAdmin()): self.sendServerMessage("'%s' is a WorldOwner-only command!" % command) return if getattr(func, "advbuilder_only", False) and not (self.isAdvBuilder() or self.isOp() or self.isMod()): self.sendServerMessage("'%s' is an Advanced Builder-only command!" % command) return if getattr(func, "op_only", False) and not (self.isOp() or self.isMod()): self.sendServerMessage("'%s' is an Op-only command!" % command) return if getattr(func, "writer_only", False) and not (self.isWriter() or self.isOp() or self.isMod()): self.sendServerMessage("'%s' is a Builder-only command!" % command) return try: func(parts, 'user', False) #fromloc is user, overriderank is false except Exception, e: self.sendSplitServerMessage(traceback.format_exc().replace("Traceback (most recent call last):", "")) self.sendSplitServerMessage("Internal Server Error - Traceback (Please report this to the Server Staff or the blockBox Team, see /about for contact info)") self.logger.error(traceback.format_exc()) elif message.startswith("@"): # It's a whisper try: username, text = message[1:].strip().split(" ", 1) except ValueError: self.sendServerMessage("Please include a username and a message to send.") else: username = username.lower() if username in self.factory.usernames: self.factory.usernames[username].sendWhisper(self.username, text) self.sendWhisper(self.username, text) self.logger.info("@"+self.username+" (from "+self.username+"): "+text) self.whisperlog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" - "+self.username+" (from "+self.usertitlename+"): "+text+"\n") self.whisperlog.flush() else: self.sendServerMessage("%s is currently offline." % self.username) elif message.startswith("!"): #It's a world message. if len(message) == 1: self.sendServerMessage("Please include a message to send.") else: try: text = message[1:] except ValueError: self.sendServerMessage("Please include a message to send.") else: if self.world.global_chat: if self.world.highlight_ops: self.sendWorldMessage ("!"+self.userColour()+self.usertitlename+":"+COLOUR_WHITE+" "+text) else: self.sendWorldMessage ("!"+COLOUR_WHITE+self.usertitlename+":"+COLOUR_WHITE+" "+text) self.logger.info("!"+self.usertitlename+" in "+str(self.world.id)+": "+text) self.wclog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" - "+self.usertitlename+" in "+str(self.world.id)+": "+text+"\n") self.wclog.flush() else: if self.world.highlight_ops: self.sendWorldMessage (" "+self.userColour()+self.usertitlename+":"+COLOUR_WHITE+" "+text) else: self.sendWorldMessage (" "+COLOUR_WHITE+self.usertitlename+":"+COLOUR_WHITE+" "+text) if self.factory.irc_relay: self.factory.irc_relay.sendServerMessage("!"+self.usertitlename+" in "+str(self.world.id)+": "+text) elif message.startswith("#"): #It's an staff-only message. if len(message) == 1: self.sendServerMessage("Please include a message to send.") else: try: text = message[1:] except ValueError: if self.isMod(): self.sendServerMessage("Please include a message to send.") else: self.factory.queue.put((self, TASK_MESSAGE, (self.id, self.userColour(), self.username, message))) if self.isMod(): self.factory.queue.put((self, TASK_STAFFMESSAGE, (0, self.userColour(), self.username, text))) else: self.factory.queue.put((self, TASK_MESSAGE, (self.id, self.userColour(), self.usertitlename, message))) else: if self.isSilenced(): self.sendServerMessage("You are Silenced and lost your tongue.") else: if override is not True: if not self.world.global_chat: if self.world.highlight_ops: self.sendWorldMessage ("!"+self.userColour()+self.usertitlename+":"+COLOUR_WHITE+" "+message) else: self.sendWorldMessage ("!"+COLOUR_WHITE+self.usertitlename+":"+COLOUR_WHITE+" "+message) self.logger.info("!"+self.usertitlename+" in "+str(self.world.id)+": "+message) self.wclog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" - "+self.usertitlename+" in "+str(self.world.id)+": "+message+"\n") self.wclog.flush() else: self.factory.queue.put((self, TASK_MESSAGE, (self.id, self.userColour(), self.usertitlename, message))) else: if type == 2: self.logger.warn("Alpha Client attempted to connect.") self.sendPacked( 255, self.packString("This server is only compatible with Minecraft Classic!") ) self.transport.loseConnection() else: self.log("Unhandleable type %s" % type, logging.WARN)
def sendOverloadChunk(self): "Sends a level chunk full of 1s." if self.connected: self.sendPacked(TYPE_CHUNK, 1024, "\1"*1024, 50) reactor.callLater(0.001, self.sendOverloadChunk)
def sendError(self, error): self.logger.info("Sending error: %s" % error) self.sendPacked(TYPE_ERROR, error) reactor.callLater(0.2, self.transport.loseConnection)
def setKeepAlive(self, t): self.keepAliveDelay = t self.stopKeepAlive() self.stopKeepAliveID = reactor.callLater(t, self.sendKeepAlive)
def blockChanged(self, x, y, z, block, selected_block, fromloc): "Hook trigger for block changes." tobuild = [] world = self.client.world # Randomise the variables fanout = self.explosion_radius if self.build_dynamite and block == BLOCK_TNT: def explode(): # Clear the explosion radius for i in range(-fanout, fanout + 1): for j in range(-fanout, fanout + 1): for k in range(-fanout, fanout + 1): if (i**2 + j**2 + k**2)**0.5 + 0.691 < fanout: try: if not self.client.AllowedToBuild( x + i, y + j, z + k): return check_offset = world.blockstore.get_offset( x + i, y + j, z + k) blocktype = world.blockstore.raw_blocks[ check_offset] unbreakables = [ chr(BLOCK_SOLID), chr(BLOCK_IRON), chr(BLOCK_GOLD), chr(BLOCK_TNT) ] strongblocks = [ chr(BLOCK_ROCK), chr(BLOCK_STONE), chr(BLOCK_OBSIDIAN), chr(BLOCK_WATER), chr(BLOCK_STILLWATER), chr(BLOCK_LAVA), chr(BLOCK_STILLLAVA), chr(BLOCK_BRICK), chr(BLOCK_GOLDORE), chr(BLOCK_IRONORE), chr(BLOCK_COAL), chr(BLOCK_SPONGE) ] if blocktype not in unbreakables and blocktype not in strongblocks: if not world.has_mine( x + i, y + j, z + k): tobuild.append( (i, j, k, BLOCK_STILLLAVA)) if (i**2 + j**2 + k**2)**0.5 + 0.691 < fanout - 1: if blocktype not in unbreakables: if not world.has_mine( x + i, y + j, z + k): tobuild.append( (i, j, k, BLOCK_STILLLAVA)) except AssertionError: # OOB pass # OK, send the build changes for dx, dy, dz, block in tobuild: try: world[x + dx, y + dy, z + dz] = chr(block) self.client.sendBlock(x + dx, y + dy, z + dz, block) self.client.factory.queue.put( (self.client, TASK_BLOCKSET, (x + dx, y + dy, z + dz, block))) except AssertionError: # OOB pass def explode2(): # Clear the explosion radius for i in range(-fanout, fanout + 1): for j in range(-fanout, fanout + 1): for k in range(-fanout, fanout + 1): if (i**2 + j**2 + k**2)**0.5 + 0.691 < fanout: try: if not self.client.AllowedToBuild( x + i, y + j, z + k): return check_offset = world.blockstore.get_offset( x + i, y + j, z + k) blocktype = world.blockstore.raw_blocks[ check_offset] unbreakables = [ chr(BLOCK_SOLID), chr(BLOCK_IRON), chr(BLOCK_GOLD) ] strongblocks = [ chr(BLOCK_ROCK), chr(BLOCK_STONE), chr(BLOCK_OBSIDIAN), chr(BLOCK_WATER), chr(BLOCK_STILLWATER), chr(BLOCK_LAVA), chr(BLOCK_BRICK), chr(BLOCK_GOLDORE), chr(BLOCK_IRONORE), chr(BLOCK_COAL), chr(BLOCK_SPONGE) ] if blocktype not in unbreakables and blocktype not in strongblocks: if not world.has_mine( x + i, y + j, z + k): tobuild.append( (i, j, k, BLOCK_AIR)) if (i**2 + j**2 + k**2)**0.5 + 0.691 < fanout - 1: if blocktype not in unbreakables: if not world.has_mine( x + i, y + j, z + k): tobuild.append( (i, j, k, BLOCK_AIR)) except AssertionError: # OOB pass # OK, send the build changes for dx, dy, dz, block in tobuild: try: world[x + dx, y + dy, z + dz] = chr(block) self.client.sendBlock(x + dx, y + dy, z + dz, block) self.client.factory.queue.put( (self.client, TASK_BLOCKSET, (x + dx, y + dy, z + dz, block))) except AssertionError: # OOB pass # Explode in 2 seconds reactor.callLater(self.delay, explode) # Explode2 in 3 seconds reactor.callLater(self.delay + 0.5, explode2)
def sendOverload(self): "Sends an overload - a fake map designed to use as much memory as it can." self.sendPacked(TYPE_INITIAL, 7, "Loading...", "Entering world main", 0) self.sendPacked(TYPE_PRECHUNK) reactor.callLater(0.001, self.sendOverloadChunk)
def callLater(self, period, func): """ Wrapper around L{reactor.callLater} for test purpose. """ from lib.twisted.internet import reactor return reactor.callLater(period, func)
def __init__(self, username): self.username = username self.ini = ConfigParser() reactor.callLater(0.1, self.reload, username)
def _loseConnection(self): self.stopReading() self.reactor.removeActiveHandle(self) if self.connected: # actually means if we are *listening* from lib.twisted.internet import reactor reactor.callLater(0, self.connectionLost)
def _loseConnection(self): self.stopReading() if self.connected: # actually means if we are *listening* from lib.twisted.internet import reactor reactor.callLater(0, self.connectionLost)
def _defaultScheduler(x): from lib.twisted.internet import reactor return reactor.callLater(_EPSILON, x)
def AutoBackup(self): for world in self.worlds: self.Backup(world, "server") if self.backup_auto: reactor.callLater(float(self.backup_freq * 60), self.AutoBackup)
def __init__(self, username): self.username = username self.ini = ConfigParser() reactor.callLater(.1, self.reload, username)
def sendLevel(self): "Starts the process of sending a level to the client." self.factory.recordPresence(self.username) # Ask the World to flush the level and get a gzip handle back to us. if hasattr(self, "world"): self.world.get_gzip_handle().addCallback(self.sendLevelStart) def sendLevelStart(self, (gzip_handle, zipped_size)): "Called when the world is flushed and the gzip is ready to read." # Store that handle and size self.zipped_level, self.zipped_size = gzip_handle, zipped_size # Preload our first chunk, send a level stream header, and go! self.chunk = self.zipped_level.read(1024) self.logger.debug("Sending level...") self.sendPacked(TYPE_PRECHUNK) reactor.callLater(0.001, self.sendLevelChunk) def sendLevelChunk(self): if not hasattr(self, 'chunk'): self.logger.error("Cannot send chunk, there isn't one! %r %r" % (self, self.__dict__)) return if self.chunk: self.sendPacked(TYPE_CHUNK, len(self.chunk), self.chunk, chr(int(100*(self.zipped_level.tell()/float(self.zipped_size))))) self.chunk = self.zipped_level.read(1024) reactor.callLater(0.001, self.sendLevelChunk) else: self.zipped_level.close() del self.zipped_level del self.chunk del self.zipped_size self.endSendLevel()
def sendLevel(self): "Starts the process of sending a level to the client." self.factory.recordPresence(self.username) # Ask the World to flush the level and get a gzip handle back to us. if hasattr(self, "world"): self.world.get_gzip_handle().addCallback(self.sendLevelStart) def sendLevelStart(self, (gzip_handle, zipped_size)): "Called when the world is flushed and the gzip is ready to read." # Store that handle and size self.zipped_level, self.zipped_size = gzip_handle, zipped_size # Preload our first chunk, send a level stream header, and go! self.chunk = self.zipped_level.read(1024) self.logger.debug("Sending level...") self.sendPacked(TYPE_PRECHUNK) reactor.callLater(0.001, self.sendLevelChunk) def sendLevelChunk(self): if not hasattr(self, 'chunk'): self.logger.error("Cannot send chunk, there isn't one! %r %r" % (self, self.__dict__)) return if self.chunk: self.sendPacked(TYPE_CHUNK, len(self.chunk), self.chunk, chr(int(100*(self.zipped_level.tell()/float(self.zipped_size))))) self.chunk = self.zipped_level.read(1024) reactor.callLater(0.001, self.sendLevelChunk) else: self.zipped_level.close() del self.zipped_level del self.chunk del self.zipped_size self.endSendLevel()
def dataReceived(self, data): # First, add the data we got onto our internal buffer self.buffer += data # While there's still data there... while self.buffer: # Examine the first byte, to see what the command is type = ord(self.buffer[0]) try: format = TYPE_FORMATS[type] except KeyError: #it's a weird data packet, probably a ping. reactor.callLater(0.2, self.transport.loseConnection) return # See if we have all its data if len(self.buffer) - 1 < len(format): # Nope, wait a bit break # OK, decode the data parts = list(format.decode(self.buffer[1:])) self.buffer = self.buffer[len(format)+1:] if type == TYPE_INITIAL: # Get the client's details protocol, self.username, mppass, utype = parts self.logger = logging.getLogger(self.username) if self.identified == True: self.logger.info("Kicked '%s'; already logged in to server" % (self.username)) self.sendError("You already logged in! Foolish bot owners.") # Check their password correct_pass = hashlib.md5(self.factory.salt + self.username).hexdigest()[-32:].strip("0") mppass = mppass.strip("0") if not self.transport.getHost().host.split(".")[0:2] == self.transport.getPeer().host.split(".")[0:2]: if self.factory.verify_names and mppass != correct_pass: self.logger.info("Kicked '%s'; invalid password (%s, %s)" % (self.username, mppass, correct_pass)) self.sendError("Incorrect authentication. (try again in 60s?)") return self.logger.info("Connected, as '%s'" % self.username) self.identified = True # Are they banned? if self.factory.isBanned(self.username): self.sendError("Banned: %s" % self.factory.banReason(self.username)) return # OK, see if there's anyone else with that username if not self.factory.duplicate_logins and self.username.lower() in self.factory.usernames: self.factory.usernames[self.username.lower()].duplicateKick() self.factory.usernames[self.username.lower()] = self # Right protocol? if protocol != 7: self.sendError("Wrong protocol.") break # Send them back our info. breakable_admins = self.runHook("canbreakadmin") self.persist = Persist(self.username.lower()) reactor.callLater(0.1, self.setPersist) self.sendPacked( TYPE_INITIAL, 7, # Protocol version self.packString(self.factory.server_name), self.packString(self.factory.server_message), 100 if breakable_admins else 0, ) # Then... stuff for client in self.factory.usernames.values(): client.sendServerMessage("%s has come online." %self.username) if self.factory.irc_relay: self.factory.irc_relay.sendServerMessage("%s has come online." % self.username) reactor.callLater(0.1, self.sendLevel) self.loops["sendkeepalive"] = task.LoopingCall(self.sendKeepAlive) self.loops["sendkeepalive"].start(1) elif type == TYPE_BLOCKCHANGE: x, y, z, created, block = parts if block == 255: block = 0 if block > 49: self.logger.info("Kicked '%s'; Tried to place an invalid block.; Block: '%s'" % (self.transport.getPeer().host, block)) self.sendError("Invalid blocks are not allowed!") return if 6 < block < 12: if not block == 9 and not block == 11: self.logger.info("Kicked '%s'; Tried to place an invalid block.; Block: '%s'" % (self.transport.getPeer().host, block)) self.sendError("Invalid blocks are not allowed!") return if self.identified == False: self.logger.info("Kicked '%s'; did not send a login before building" % (self.transport.getPeer().host)) self.sendError("Provide an authentication before building.") return try: # If we're read-only, reverse the change if self.isSpectator(): self.sendBlock(x, y, z) self.sendServerMessage("Spectators cannot edit maps.") return allowbuild = self.runHook("blockclick", x, y, z, block, True) if allowbuild is False: self.sendBlock(x, y, z) return elif not self.AllowedToBuild(x,y,z): self.sendBlock(x, y, z) return # This try prevents out-of-range errors on the world storage # Track if we need to send back the block change overridden = False selected_block = block # If we're deleting, block is actually air # (note the selected block is still stored as selected_block) if not created: block = 0 # Pre-hook, for stuff like /paint new_block = self.runHook("preblockchange", x, y, z, block, selected_block, True) if new_block is not None: block = new_block overridden = True # Call hooks new_block = self.runHook("blockchange", x, y, z, block, selected_block, True) if new_block is False: # They weren't allowed to build here! self.sendBlock(x, y, z) continue elif new_block is True: # Someone else handled building, just continue continue elif new_block is not None: block = new_block overridden = True # OK, save the block self.world[x, y, z] = chr(block) # Now, send the custom block back if we need to if overridden: self.sendBlock(x, y, z, block) # Out of bounds! except (KeyError, AssertionError): self.sendPacked(TYPE_BLOCKSET, x, y, z, "\0") # OK, replay changes to others else: self.factory.queue.put((self, TASK_BLOCKSET, (x, y, z, block))) if len(self.last_block_changes) >= 3: self.last_block_changes = [(x, y, z)] + self.last_block_changes[:1]+self.last_block_changes[1:3] else: self.last_block_changes = [(x, y, z)] + self.last_block_changes[:2] elif type == TYPE_PLAYERPOS: # If we're loading a world, ignore these. if self.loading_world: continue naff, x, y, z, h, p = parts pos_change = not (x == self.x and y == self.y and z == self.z) dir_change = not (h == self.h and p == self.p) if self.frozen: newx = self.x >> 5 newy = self.y >> 5 newz = self.z >> 5 self.teleportTo(newx, newy, newz, h, p) return override = self.runHook("poschange", x, y, z, h, p) # Only send changes if the hook didn't say no if override is not False: if pos_change: # Send everything to the other clients self.factory.queue.put((self, TASK_PLAYERPOS, (self.id, self.x, self.y, self.z, self.h, self.p))) elif dir_change: self.factory.queue.put((self, TASK_PLAYERDIR, (self.id, self.h, self.p))) self.x, self.y, self.z, self.h, self.p = x, y, z, h, p elif type == TYPE_MESSAGE: byte, message = parts user = self.username.lower() t = self.persist.string("misc", "title", "") if t is "": self.title = "" else: self.title = "\""+t+"\" " self.usertitlename = self.title + self.username override = self.runHook("chatmsg", message) goodchars = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", " ", "!", "@", "#", "$", "%", "*", "(", ")", "-", "_", "+", "=", "{", "[", "}", "]", ":", ";", "\"", "\'", "<", ",", ">", ".", "?", "/", "\\", "|"] for c in message.lower(): if not c in goodchars: self.logger.info("Kicked '%s'; Tried to use invalid characters; Message: '%s'" % (self.transport.getPeer().host, message)) self.sendError("Invalid characters are not allowed!") return message = message.replace("%0", "&0") message = message.replace("%1", "&1") message = message.replace("%2", "&2") message = message.replace("%3", "&3") message = message.replace("%4", "&4") message = message.replace("%5", "&5") message = message.replace("%6", "&6") message = message.replace("%7", "&7") message = message.replace("%8", "&8") message = message.replace("%9", "&9") message = message.replace("%a", "&a") message = message.replace("%b", "&b") message = message.replace("%c", "&c") message = message.replace("%d", "&d") message = message.replace("%e", "&e") message = message.replace("%f", "&f") message = message.replace("0", "&f") message = message.replace("00", "&f") message = message.replace("1", "&0") message = message.replace("01", "&0") message = message.replace("2", "&1") message = message.replace("02", "&1") message = message.replace("3", "&2") message = message.replace("03", "&2") message = message.replace("4", "&c") message = message.replace("04", "&c") message = message.replace("5", "&4") message = message.replace("05", "&4") message = message.replace("6", "&5") message = message.replace("06", "&5") message = message.replace("7", "&6") message = message.replace("07", "&6") message = message.replace("8", "&e") message = message.replace("08", "&e") message = message.replace("9", "&a") message = message.replace("09", "&a") message = message.replace("10", "&3") message = message.replace("11", "&b") message = message.replace("12", "&9") message = message.replace("13", "&d") message = message.replace("14", "&8") message = message.replace("15", "&7") message = message.replace("./", " /") message = message.replace(".!", " !") message = message.replace(".@", " @") message = message.replace(".#", " #") message = message.replace("%$rnd", "&$rnd") if message[len(message)-2] == "&": self.sendServerMessage("You can not use a color at the end of a message") return if len(message) > 51: moddedmsg = message[:51].replace(" ", "") if moddedmsg[len(moddedmsg)-2] == "&": message = message.replace("&", "*") if self.identified == False: self.logger.info("Kicked '%s'; did not send a login before chatting; Message: '%s'" % (self.transport.getPeer().host, message)) self.sendError("Provide an authentication before chatting.") return if message.startswith("/"): # It's a command #message = message.lower() parts = [x.strip() for x in message.split() if x.strip()] command = parts[0].strip("/") if not message.startswith("/tlog "): self.logger.info("%s just used: %s" % (self.username," ".join(parts))) #for command logging to IRC if self.factory.irc_relay: if self.factory.irc_cmdlogs: self.factory.irc_relay.sendServerMessage("%s just used: %s" % (self.username," ".join(parts))) # See if we can handle it internally try: func = getattr(self, "command%s" % command.title()) except AttributeError: # Can we find it from a plugin? try: try: func = self.commands[command.lower()] except KeyError: self.sendServerMessage("Unknown command '%s'" % command) return except AttributeError: self.logger.error("Cannot find plugin %s, please report to blockBox team." % func) self.sendSplitServerMessage("Command code not found, please report to server staff or blockBox team.") return if (self.isSpectator() and (getattr(func, "admin_only", False) or getattr(func, "mod_only", False) or getattr(func, "op_only", False) or getattr(func, "advbuilder_only", False) or getattr(func, "worldowner_only", False) or getattr(func, "writer_only", False))): self.sendServerMessage("'%s' is not available to specs." % command) return if getattr(func, "owner_only", False) and not self.isOwner(): self.sendServerMessage("'%s' is a Owner-only command!" % command) return if getattr(func, "director_only", False) and not self.isDirector(): self.sendServerMessage("'%s' is a Director-only command!" % command) return if getattr(func, "admin_only", False) and not self.isAdmin(): self.sendServerMessage("'%s' is an Admin-only command!" % command) return if getattr(func, "mod_only", False) and not (self.isMod() or self.isAdmin()): self.sendServerMessage("'%s' is a Mod-only command!" % command) return if getattr(func, "worldowner_only", False) and not (self.isMod() or self.isAdmin()): self.sendServerMessage("'%s' is a WorldOwner-only command!" % command) return if getattr(func, "advbuilder_only", False) and not (self.isAdvBuilder() or self.isOp() or self.isMod()): self.sendServerMessage("'%s' is an Advanced Builder-only command!" % command) return if getattr(func, "op_only", False) and not (self.isOp() or self.isMod()): self.sendServerMessage("'%s' is an Op-only command!" % command) return if getattr(func, "writer_only", False) and not (self.isWriter() or self.isOp() or self.isMod()): self.sendServerMessage("'%s' is a Builder-only command!" % command) return try: func(parts, 'user', False) #fromloc is user, overriderank is false except Exception, e: self.sendSplitServerMessage(traceback.format_exc().replace("Traceback (most recent call last):", "")) self.sendSplitServerMessage("Internal Server Error - Traceback (Please report this to the Server Staff or the blockBox Team, see /about for contact info)") self.logger.error(traceback.format_exc()) elif message.startswith("@"): # It's a whisper try: username, text = message[1:].strip().split(" ", 1) except ValueError: self.sendServerMessage("Please include a username and a message to send.") else: username = username.lower() if username in self.factory.usernames: self.factory.usernames[username].sendWhisper(self.username, text) self.sendWhisper(self.username, text) self.logger.info("@"+self.username+" (from "+self.username+"): "+text) self.whisperlog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" - "+self.username+" (from "+self.usertitlename+"): "+text+"\n") self.whisperlog.flush() else: self.sendServerMessage("%s is currently offline." % self.username) elif message.startswith("!"): #It's a world message. if len(message) == 1: self.sendServerMessage("Please include a message to send.") else: try: text = message[1:] except ValueError: self.sendServerMessage("Please include a message to send.") else: if self.world.global_chat: if self.world.highlight_ops: self.sendWorldMessage ("!"+self.userColour()+self.usertitlename+":"+COLOUR_WHITE+" "+text) else: self.sendWorldMessage ("!"+COLOUR_WHITE+self.usertitlename+":"+COLOUR_WHITE+" "+text) self.logger.info("!"+self.usertitlename+" in "+str(self.world.id)+": "+text) self.wclog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" - "+self.usertitlename+" in "+str(self.world.id)+": "+text+"\n") self.wclog.flush() else: if self.world.highlight_ops: self.sendWorldMessage (" "+self.userColour()+self.usertitlename+":"+COLOUR_WHITE+" "+text) else: self.sendWorldMessage (" "+COLOUR_WHITE+self.usertitlename+":"+COLOUR_WHITE+" "+text) if self.factory.irc_relay: self.factory.irc_relay.sendServerMessage("!"+self.usertitlename+" in "+str(self.world.id)+": "+text) elif message.startswith("#"): #It's an staff-only message. if len(message) == 1: self.sendServerMessage("Please include a message to send.") else: try: text = message[1:] except ValueError: if self.isMod(): self.sendServerMessage("Please include a message to send.") else: self.factory.queue.put((self, TASK_MESSAGE, (self.id, self.userColour(), self.username, message))) if self.isMod(): self.factory.queue.put((self, TASK_STAFFMESSAGE, (0, self.userColour(), self.username, text))) else: self.factory.queue.put((self, TASK_MESSAGE, (self.id, self.userColour(), self.usertitlename, message))) else: if self.isSilenced(): self.sendServerMessage("You are Silenced and lost your tongue.") else: if override is not True: if not self.world.global_chat: if self.world.highlight_ops: self.sendWorldMessage ("!"+self.userColour()+self.usertitlename+":"+COLOUR_WHITE+" "+message) else: self.sendWorldMessage ("!"+COLOUR_WHITE+self.usertitlename+":"+COLOUR_WHITE+" "+message) self.logger.info("!"+self.usertitlename+" in "+str(self.world.id)+": "+message) self.wclog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M")+" - "+self.usertitlename+" in "+str(self.world.id)+": "+message+"\n") self.wclog.flush() else: self.factory.queue.put((self, TASK_MESSAGE, (self.id, self.userColour(), self.usertitlename, message))) else: if type == 2: self.logger.warn("Alpha Client attempted to connect.") self.sendPacked( 255, self.packString("This server is only compatible with Minecraft Classic!") ) self.transport.loseConnection() else: self.log("Unhandleable type %s" % type, logging.WARN)
def callLater(self, period, func): """ Wrapper around L{reactor.callLater} for test purpose. """ from lib.twisted.internet import reactor return reactor.callLater(period, func)
def sendOverloadChunk(self): "Sends a level chunk full of 1s." if self.connected: self.sendPacked(TYPE_CHUNK, 1024, "\1"*1024, 50) reactor.callLater(0.001, self.sendOverloadChunk)
def _callLater(self, *args, **kwargs): from lib.twisted.internet import reactor return reactor.callLater(*args, **kwargs)
def posChanged(self, x, y, z, h, p): "Hook trigger for when the player moves" rx = x >> 5 ry = y >> 5 rz = z >> 5 mx = rx mz = rz my = ry - 2 try: if self.client.world.has_mine(mx, my, mz) or self.client.world.has_mine(mx, my-1, mz): if self.client.world.has_mine(mx, my-1, mz): self.client.world.delete_mine(mx, my-1, mz) my = ry - 3 if self.client.world.has_mine(mx, my, mz): my = ry - 2 self.client.world.delete_mine(mx, my, mz) tobuild = [] # Randomise the variables fanout = self.explosion_radius def explode(): # Clear the explosion radius for i in range(-fanout, fanout+1): for j in range(-fanout, fanout+1): for k in range(-fanout, fanout+1): if (i**2+j**2+k**2)**0.5 + 0.691 < fanout: if not self.client.AllowedToBuild(mx+i, my+j, mz+k): return check_offset = self.client.world.blockstore.get_offset(mx+i, my+j, mz+k) blocktype = self.client.world.blockstore.raw_blocks[check_offset] unbreakables = [chr(BLOCK_SOLID), chr(BLOCK_IRON), chr(BLOCK_GOLD)] if blocktype not in unbreakables: if not self.client.world.has_mine(mx+i, my+j, mz+k): tobuild.append((i, j, k, BLOCK_STILLLAVA)) # OK, send the build changes for dx, dy, dz, block in tobuild: try: self.client.world[mx+dx, my+dy, mz+dz] = chr(block) self.client.sendBlock(mx+dx, my+dy, mz+dz, block) self.client.factory.queue.put((self.client, TASK_BLOCKSET, (mx+dx, my+dy, mz+dz, block))) except AssertionError: # OOB pass def explode2(): # Clear the explosion radius for i in range(-fanout, fanout+1): for j in range(-fanout, fanout+1): for k in range(-fanout, fanout+1): if (i**2+j**2+k**2)**0.5 + 0.691 < fanout: if not self.client.AllowedToBuild(mx+i, my+j, mz+k): return check_offset = self.client.world.blockstore.get_offset(mx+i, my+j, mz+k) blocktype = self.client.world.blockstore.raw_blocks[check_offset] unbreakables = [chr(BLOCK_SOLID), chr(BLOCK_IRON), chr(BLOCK_GOLD)] if blocktype not in unbreakables: if not self.client.world.has_mine(mx+i, my+j, mz+k): tobuild.append((i, j, k, BLOCK_AIR)) # OK, send the build changes for dx, dy, dz, block in tobuild: try: self.client.world[mx+dx, my+dy, mz+dz] = chr(block) self.client.sendBlock(mx+dx, my+dy, mz+dz, block) self.client.factory.queue.put((self.client, TASK_BLOCKSET, (mx+dx, my+dy, mz+dz, block))) except AssertionError: # OOB pass # Explode in 2 seconds self.client.sendServerMessage("*CLICK*") reactor.callLater(self.delay, explode) # Explode2 in 3 seconds reactor.callLater(self.delay+0.5, explode2) except AssertionError: #oob pass
def install(app): """Install the wxPython support, given a wxApp instance""" runner = wxRunner(app) reactor.callLater(0.02, runner.run)
def sendError(self, error): self.logger.info("Sending error: %s" % error) self.sendPacked(TYPE_ERROR, error) reactor.callLater(0.2, self.transport.loseConnection)
def _callLater(self, *args, **kwargs): from lib.twisted.internet import reactor return reactor.callLater(*args, **kwargs)
def sendOverload(self): "Sends an overload - a fake map designed to use as much memory as it can." self.sendPacked(TYPE_INITIAL, 7, "Loading...", "Entering world main", 0) self.sendPacked(TYPE_PRECHUNK) reactor.callLater(0.001, self.sendOverloadChunk)
self.logger.debug("%s" % self.url) #self.logger.info("Saved URL to url.txt.") open('data/url.txt', 'w').write(self.url) if not self.factory.console.is_alive(): self.factory.console.run() except IOError, SystemExit: pass except: self.logger.error("Minecraft.net seems to be offline.") except IOError, SystemExit: pass except: self.logger.error(traceback.format_exc()) finally: if not onetime: reactor.callLater(60, self.turl) def bb_get_url(self, onetime=False): if self.factory.config.getboolean("options", "use_blockbeat"): try: try: self.factory.last_heartbeat = time.time() fh = urllib.urlopen("http://blockbeat.bradness.info/announce.php", urllib.urlencode({ "users": len(self.factory.clients), "hash": self.hash, "max": self.factory.max_clients, "port": self.factory.config.getint("network", "port"), "name": self.factory.server_name, "software": 'blockbox', "public": self.factory.public, "motd": self.factory.config.get("server", "description"),
def sendKeepAlive(self): self.sendFLAP("", 0x05) self.stopKeepAliveID = reactor.callLater(self.keepAliveDelay, self.sendKeepAlive)
# blockBox is copyright 2009-2011 the Archives Team, the blockBox Team, and the iCraft team.