def reloadConfig(self): try: # TODO: Figure out which of these would work dynamically, otherwise delete them from this area. self.owner = self.config.get("main", "owner").lower() self.duplicate_logins = self.options_config.getboolean("options", "duplicate_logins") self.info_url = self.options_config.get("options", "info_url") self.away_kick = self.options_config.getboolean("options", "away_kick") self.away_time = self.options_config.getint("options", "away_time") self.colors = self.options_config.getboolean("options", "colors") self.physics_limit = self.options_config.getint("worlds", "physics_limit") self.default_backup = self.options_config.get("worlds", "default_backup") self.asd_delay = self.options_config.getint("worlds", "asd_delay") self.gchat = self.options_config.getboolean("worlds", "gchat") self.grief_blocks = self.ploptions_config.getint("antigrief", "blocks") self.grief_time = self.ploptions_config.getint("antigrief", "time") self.backup_freq = self.ploptions_config.getint("backups", "backup_freq") self.backup_default = self.ploptions_config.getboolean("backups", "backup_default") self.backup_max = self.ploptions_config.getint("backups", "backup_max") self.backup_auto = self.ploptions_config.getboolean("backups", "backup_auto") self.enable_archives = self.ploptions_config.getboolean("archiver", "enable_archiver") self.currency = self.ploptions_config.get("bank", "currency") self.build_director = self.ploptions_config.get("build", "director") self.build_admin = self.ploptions_config.get("build", "admin") self.build_mod = self.ploptions_config.get("build", "mod") self.build_op = self.ploptions_config.get("build", "op") self.build_other = self.ploptions_config.get("build", "other") if self.backup_auto: reactor.callLater(float(self.backup_freq * 60),self.AutoBackup) except: return False
def commandRestore(self, parts, byuser, overriderank): "/restore worldname number - Op\nRestore world to indicated number." if len(parts) < 2: self.client.sendServerMessage("Please specify at least a world ID!") else: world_id = parts[1].lower() world_dir = ("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: if not os.path.exists(world_dir+"blocks.gz.new"): shutil.copy(world_dir+"backup/%s/blocks.gz" % backup_number, world_dir) try: shutil.copy(world_dir+"backup/%s/world.meta" % backup_number, world_dir) except: pass else: reactor.callLater(1, self.commandRestore(parts, byuser, overriderank)) default_name = self.client.factory.default_name self.client.factory.unloadWorld("worlds/%s" % world_id, world_id) self.client.sendServerMessage("%s has been restored to %s and booted." % (world_id, backup_number)) for client in self.client.factory.worlds[world_id].clients: client.changeToWorld(world_id)
def posChanged(self, x, y, z, h, p): "Hook trigger for when the user 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. 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 _callback(wp, filename, mask): # We are notified before we actually process new # directories, so we need to defer this check. def _(): try: self.assertTrue(self.inotify._isWatched(subdir)) subdir.remove() except Exception: d.errback() def _eb(): # second call, we have just removed the subdir try: self.assertTrue(not self.inotify._isWatched(subdir)) d.callback(None) except Exception: d.errback() if not calls: # first call, it's the create subdir calls.append(filename) reactor.callLater(0, _) else: reactor.callLater(0, _eb)
def get_url(self): host = 'www.classicube.net' path = '/server/heartbeat' proto = 'http' try: self.factory.last_heartbeat = time.time() fh = urllib2.urlopen("%s://%s%s?%s" % (proto,host,path,urlencode({ "port": self.factory.config.getint("network", "port"), "users": len(self.factory.clients), "max": self.factory.max_clients, "name": self.factory.server_name, "public": self.factory.public, "version": 7, "salt": hashlib.md5("self.factory.salt").hexdigest(), }))) self.url = fh.read().strip() logging.log(logging.INFO, "Heartbeat Sent. Your URL (saved to docs/SERVERURL): %s" % self.url) open('docs/SERVERURL', 'w').write(self.url) if not self.factory.console.is_alive(): self.factory.console.run() except urllib2.URLError as r: logging.log(logging.ERROR, "%s seems to be offline: %s" % (host,r)) except: logging.log(logging.ERROR, traceback.format_exc()) finally: reactor.callLater(60, self.get_url)
def flush(self): """ Flushes queued blocks into the .gz file. Needed before sending gzipped block data to clients. """ # Don't flush if there's nothing to do if not self.saving: try: if not self.queued_blocks: return self.logger.debug("Flushing %s..." % self.blocks_path) # Open the old and the new file if os.path.exists(self.blocks_path + ".new"): os.remove(self.blocks_path + ".new") gz = gzip.GzipFile(self.blocks_path) new_gz = gzip.GzipFile(self.blocks_path + ".new", 'wb', compresslevel=4) # Copy over the size header new_gz.write(gz.read(4)) # Order the blocks we're going to write ordered_blocks = sorted(self.queued_blocks.items()) # Start writing out the blocks in chunks, replacing as we go. chunk_size = 1024 chunk = list(gz.read(chunk_size)) pos = 0 blocks_pos = 0 chunk_end = len(chunk) while chunk: while blocks_pos < len(ordered_blocks) and ordered_blocks[ blocks_pos][0] < chunk_end: offset, value = ordered_blocks[blocks_pos] chunk[offset - pos] = value blocks_pos += 1 chunk_str = "".join(chunk) new_gz.write(chunk_str) pos += len(chunk) chunk = list(gz.read(chunk_size)) chunk_end = pos + len(chunk) # Safety first. If this isn't true, there's a bug. assert blocks_pos == len(ordered_blocks) # OK, close up shop. gz.close() new_gz.close() # Copy the new level over the old. os.remove(self.blocks_path) os.rename(self.blocks_path + ".new", self.blocks_path) self.queued_blocks = {} except: self.logger.error("Problem saving world %s" % self.blocks_path) self.saving = True reactor.callLater(3, self.flush) else: try: os.remove(self.blocks_path) os.rename(self.blocks_path + ".new", self.blocks_path) self.saving = False except: self.saving = True reactor.callLater(3, self.flush)
def LogTimestamp(): if os.path.exists("logs/console/console.log"): shutil.copy( "logs/console/console.log", "logs/console/console." + time.strftime("%m-%d-%Y_%H", time.localtime(time.time())) + ".log") f = open("logs/console/console.log", 'w') f.close() reactor.callLater(6 * 60 * 60, LogTimestamp) # 24hours*60minutes*60seconds
def do_step(): # Do 10 blocks try: for x in range(10): block_iter.next() reactor.callLater(0.01, do_step) except StopIteration: self.client.sendServerMessage("Your undo just completed.")
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 printInfo(self): logging.log(logging.INFO, "There are %s users on the server" % len(self.clients)) for key in self.worlds: logging.log(logging.INFO, "%s: %s" % (key, ", ".join(str(c.username) for c in self.worlds[key].clients))) if (time.time() - self.last_heartbeat) > 180: self.heartbeat = None self.heartbeat = Heartbeat(self) reactor.callLater(60, self.printInfo)
def flush(self): """ Flushes queued blocks into the .gz file. Needed before sending gzipped block data to clients. """ # Don't flush if there's nothing to do if not self.saving: try: if not self.queued_blocks: return logging.log(logging.DEBUG, "Flushing %s..." % self.blocks_path) # Open the old and the new file if os.path.exists(self.blocks_path + ".new"): os.remove(self.blocks_path + ".new") gz = gzip.GzipFile(self.blocks_path) new_gz = gzip.GzipFile(self.blocks_path + ".new", 'wb', compresslevel=4) # Copy over the size header new_gz.write(gz.read(4)) # Order the blocks we're going to write ordered_blocks = sorted(self.queued_blocks.items()) # Start writing out the blocks in chunks, replacing as we go. chunk_size = 1024 chunk = list(gz.read(chunk_size)) pos = 0 blocks_pos = 0 chunk_end = len(chunk) while chunk: while blocks_pos < len(ordered_blocks) and ordered_blocks[blocks_pos][0] < chunk_end: offset, value = ordered_blocks[blocks_pos] chunk[offset - pos] = value blocks_pos += 1 chunk_str = "".join(chunk) new_gz.write(chunk_str) pos += len(chunk) chunk = list(gz.read(chunk_size)) chunk_end = pos + len(chunk) # Safety first. If this isn't true, there's a bug. assert blocks_pos == len(ordered_blocks) # OK, close up shop. gz.close() new_gz.close() # Copy the new level over the old. os.remove(self.blocks_path) os.rename(self.blocks_path + ".new", self.blocks_path) self.queued_blocks = {} except: logging.log(logging.ERROR, "Problem saving world %s" %self.blocks_path) self.saving = True reactor.callLater(3, self.flush) else: try: os.remove(self.blocks_path) os.rename(self.blocks_path + ".new", self.blocks_path) self.saving = False except: self.saving = True reactor.callLater(3, self.flush)
def do_step(): try: for x in range(10): block_iter.next() reactor.callLater(0.01, do_step) except StopIteration: if fromloc == "user": self.client.sendServerMessage("Your replacenear just completed.") pass
def turl(self): #self.logger.info("Main Thread ID = %s" % threading.currentThread().ident) # for debugging purposes try: hbThread = threading.Thread(target=self.threadFunc) hbThread.daemon = True # don't let this thread cause shutting down to hang hbThread.start() except: self.logger.error(traceback.format_exc()) reactor.callLater(1, self.turl)
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.sendServerMessage("Your redo just completed.") pass
def test_delayedCall(self): """ If there is a delayed call, C{doIteration} is called with a timeout which is the difference between the current time and the time at which that call is to run. """ reactor = TimeoutReportReactor() reactor.callLater(100, lambda: None) timeout = self._checkIterationTimeout(reactor) self.assertEquals(timeout, 100)
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 byuser: self.client.sendServerMessage("Your fill just completed.") pass
def test_timePasses(self): """ If a delayed call is scheduled and then some time passes, the timeout passed to C{doIteration} is reduced by the amount of time which passed. """ reactor = TimeoutReportReactor() reactor.callLater(100, lambda: None) reactor.now += 25 timeout = self._checkIterationTimeout(reactor) self.assertEquals(timeout, 75)
def _callback(wp, fp, mask): # We are notified before we actually process new # directories, so we need to defer this check. def _(): try: self.assertFalse(self.inotify._isWatched(subdir.path)) d.callback(None) except Exception: d.errback() reactor.callLater(0, _)
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 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: reactor.callLater(60, self.saveWorlds) self.saveMeta() else: reactor.callLater(1, self.saveWorlds)
def commandRestore(self, parts, fromloc, overriderank): "/restore worldname number - Op\nRestore world to indicated number." if len(parts) < 2: self.client.sendServerMessage("Please specify at least a world ID!") else: world_id = parts[1].lower() world_dir = ("worlds/%s/" % world_id) if not self.client.isModPlus(): # ensure user has proper rank in the target world (the check to run this command only counts the world they're currently in) canRestore = False config = ConfigParser() config.read(world_dir+"world.meta") # this still has an issue: it won't pick up recent rank changes that haven't been flushed to the file yet. but it's good enough in geneal. if config.has_section("owner"): print config.get("owner", "owner") if config.get("owner", "owner").lower() == self.client.username.lower(): canRestore = True if config.has_section("ops"): for op in config.options("ops"): print op if op.lower() == self.client.username.lower(): canRestore = True if not canRestore: self.client.sendServerMessage("You are not allowed to restore that world!") return 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: if not os.path.exists(world_dir+"blocks.gz.new"): shutil.copy(world_dir+"backup/%s/blocks.gz" % backup_number, world_dir) try: shutil.copy(world_dir+"backup/%s/world.meta" % backup_number, world_dir) os.remove(world_dir+"blocks.db") # remove blocktracker data since it's no longer valid except: pass else: reactor.callLater(1, self.commandRestore(self, parts, fromloc, overriderank)) default_name = self.client.factory.default_name self.client.factory.unloadWorld("worlds/%s" % world_id, world_id) self.client.sendServerMessage("%s has been restored to %s and booted." % (world_id, backup_number)) if world_id in self.client.factory.worlds: for client in self.client.factory.worlds[world_id].clients: client.changeToWorld(world_id)
def blockChanged(self, x, y, z, block, selected_block, fromloc): if fromloc != "user": # People shouldn't be blbing mines 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 setTimeout(self, seconds, timeoutFunc=timeout, *args, **kw): """ Set a timeout function to be triggered if I am not called. @param seconds: How long to wait (from now) before firing the C{timeoutFunc}. @param timeoutFunc: will receive the L{Deferred} and *args, **kw as its arguments. The default C{timeoutFunc} will call the errback with a L{TimeoutError}. """ warnings.warn( "Deferred.setTimeout is deprecated. Look for timeout " "support specific to the API you are using instead.", DeprecationWarning, stacklevel=2) if self.called: return assert not self.timeoutCall, "Don't call setTimeout twice on the same Deferred." from reqs.twisted.internet import reactor self.timeoutCall = reactor.callLater( seconds, lambda: self.called or timeoutFunc(self, *args, **kw)) return self.timeoutCall
def blockChanged(self, x, y, z, block, selected_block, byuser): "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 >= self.client.factory.grief_blocks: self.client.factory.queue.put((self.client, TASK_STAFFMESSAGE, ("#%s%s: %s%s" % (COLOUR_DARKGREEN, 'Console ALERT', COLOUR_DARKRED, "Possible grief behavior was detected;", False)))) self.client.factory.queue.put((self.client, TASK_STAFFMESSAGE, ("#%s%s: %s%s" % (COLOUR_DARKGREEN, 'Console ALERT', COLOUR_DARKRED, "World: "+worldname+" | User: "******" was detected as a possible griefer in '" + worldname + "'") self.client.adlog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S")+" | #Console ALERT: Possible grief behavior was detected; World: "+worldname+" | User: "******"\n") self.client.adlog.flush() self.var_blockchcount = 0 if self.var_blockchcount == 0: reactor.callLater(self.client.factory.grief_time, griefcheck) self.var_blockchcount += 1
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 >= self.client.factory.grief_blocks: self.client.factory.queue.put((self.client, TASK_STAFFMESSAGE, ("#%s%s: %s%s" % (COLOUR_DARKGREEN, 'Console ALERT', COLOUR_DARKRED, "Possible grief behavior was detected;", False)))) self.client.factory.queue.put((self.client, TASK_STAFFMESSAGE, ("#%s%s: %s%s" % (COLOUR_DARKGREEN, 'Console ALERT', COLOUR_DARKRED, "World: "+worldname+" | User: "******"%s was detected as a possible griefer in world %s." % (username, worldname)) self.client.adlog.write(datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S")+" | #Console ALERT: Possible grief behavior was detected; World: "+worldname+" | User: "******"\n") self.client.adlog.flush() self.var_blockchcount = 0 if self.var_blockchcount == 0: reactor.callLater(self.client.factory.grief_time, griefcheck) self.var_blockchcount += 1
def commandRestore(self, parts, byuser, overriderank): "/restore worldname number - Op\nRestore world to indicated number." if len(parts) < 2: self.client.sendServerMessage( "Please specify at least a world ID!") else: world_id = parts[1].lower() world_dir = ("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: if not os.path.exists(world_dir + "blocks.gz.new"): shutil.copy( world_dir + "backup/%s/blocks.gz" % backup_number, world_dir) try: shutil.copy( world_dir + "backup/%s/world.meta" % backup_number, world_dir) except: pass else: reactor.callLater( 1, self.commandRestore(parts, byuser, overriderank)) default_name = self.client.factory.default_name self.client.factory.unloadWorld("worlds/%s" % world_id, world_id) self.client.sendServerMessage( "%s has been restored to %s and booted." % (world_id, backup_number)) for client in self.client.factory.worlds[world_id].clients: client.changeToWorld(world_id)
def test_cancelDelayedCall(self): """ If the only delayed call is canceled, C{None} is the timeout passed to C{doIteration}. """ reactor = TimeoutReportReactor() call = reactor.callLater(50, lambda: None) call.cancel() timeout = self._checkIterationTimeout(reactor) self.assertEquals(timeout, None)
def test_resetDelayedCall(self): """ If a delayed call is reset, the timeout passed to C{doIteration} is based on the interval between the time when reset is called and the new delay of the call. """ reactor = TimeoutReportReactor() call = reactor.callLater(50, lambda: None) reactor.now += 25 call.reset(15) timeout = self._checkIterationTimeout(reactor) self.assertEquals(timeout, 15)
def test_delayDelayedCall(self): """ If a delayed call is re-delayed, the timeout passed to C{doIteration} is based on the remaining time before the call would have been made and the additional amount of time passed to the delay method. """ reactor = TimeoutReportReactor() call = reactor.callLater(50, lambda: None) reactor.now += 10 call.delay(20) timeout = self._checkIterationTimeout(reactor) self.assertEquals(timeout, 60)
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 test_multipleDelayedCalls(self): """ If there are several delayed calls, C{doIteration} is called with a timeout which is the difference between the current time and the time at which the earlier of the two calls is to run. """ reactor = TimeoutReportReactor() reactor.callLater(50, lambda: None) reactor.callLater(10, lambda: None) reactor.callLater(100, lambda: None) timeout = self._checkIterationTimeout(reactor) self.assertEquals(timeout, 10)
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 AutoBackup(self): for world in self.worlds: self.Backup(world) if self.backup_auto: reactor.callLater(float(self.backup_freq * 60),self.AutoBackup)
def sendKeepAlive(self): self.sendFLAP("",0x05) self.stopKeepAliveID = reactor.callLater(self.keepAliveDelay, self.sendKeepAlive)
def _loseConnection(self): self.stopReading() self.reactor.removeActiveHandle(self) if self.connected: # actually means if we are *listening* from reqs.twisted.internet import reactor reactor.callLater(0, self.connectionLost)
def setKeepAlive(self,t): self.keepAliveDelay=t self.stopKeepAlive() self.stopKeepAliveID = reactor.callLater(t, self.sendKeepAlive)
def sendKeepAlive(self): self.sendFLAP("", 0x05) self.stopKeepAliveID = reactor.callLater(self.keepAliveDelay, self.sendKeepAlive)
def setKeepAlive(self, t): self.keepAliveDelay = t self.stopKeepAlive() self.stopKeepAliveID = reactor.callLater(t, self.sendKeepAlive)
def _callLater(self, *args, **kwargs): from reqs.twisted.internet import reactor return reactor.callLater(*args, **kwargs)
def posChanged(self, x, y, z, h, p): "Hook trigger for when the user 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 callLater(self, period, func): """ Wrapper around L{reactor.callLater} for test purpose. """ from reqs.twisted.internet import reactor return reactor.callLater(period, func)
def callLater(self, period, func): from reqs.twisted.internet import reactor return reactor.callLater(period, func)
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() try: if isinstance(source_client, World): world = source_client elif str(source_client).startswith("<StdinPlugin"): world = self.worlds[self.default_name] else: try: world = source_client.world except AttributeError: logging.log(logging.WARN, "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: # More Word Filter id, colour, username, text = data text = self.messagestrip(text) data = (id,colour,username,text) for client in self.clients.values(): client.sendMessage(*data) id, colour, username, text = data logging.log(logging.INFO, "%s: %s" % (username, text)) self.chatlog.write("[%s] %s: %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"), username, text)) self.chatlog.flush() if self.irc_relay and world: self.irc_relay.sendMessage(username, text) # Someone spoke! elif task is TASK_IRCMESSAGE: for client in self.clients.values(): client.sendMessage(*data) id, colour, username, text = data logging.log(logging.INFO, "<%s> %s" % (username, text)) self.chatlog.write("[%s] <%s> %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"), username, text)) self.chatlog.flush() if self.irc_relay and world: self.irc_relay.sendMessage(username, text) # Someone actioned! elif task is TASK_ACTION: # More Word Filter 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 logging.log(logging.INFO, "* %s %s" % (username, text)) self.chatlog.write("[%s] * %s %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"), 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) if self.username.lower() in INFO_VIPLIST and not self.isMod(): self.usernames[client].sendNormalMessage(COLOUR_DARKRED+"iCraft Developer spotted;") self.usernames[client].sendServerMessage("%s has come online." % source_client.username) if self.irc_relay and world: if self.username.lower() in INFO_VIPLIST and not self.isMod(): self.irc_relay.sendServerMessage("04iCraft Developer spotted;") self.irc_relay.sendServerMessage("07%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 world." % 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 gone offline." % source_client.username) else: source_client.log("Pinged the server.") if not source_client.username is None: if self.irc_relay and world: self.irc_relay.sendServerMessage("07%s has gone offline." % source_client.username) # 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("07%s joined '%s'" % (source_client.username, world.id)) logging.log(logging.INFO, "%s has now joined '%s'" % (source_client.username, world.id)) elif task == TASK_STAFFMESSAGE: # Give all staff the message :D id, colour, username, text, IRC = 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.staffchat and self.irc_relay and len(data)>3: self.irc_relay.sendServerMessage("#"+username+": "+text,True,username,IRC) logging.log(logging.INFO, "#"+username+": "+text) self.adlog = open("logs/server.log", "a") self.adlog.write("["+datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S")+"] #"+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) logging.log(logging.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 user 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) logging.log(logging.INFO,message) if self.irc_relay and world: self.irc_relay.sendServerMessage(message) elif task == TASK_AWAYMESSAGE: # Give all world people the message message = data for client in self.clients.values(): client.sendNormalMessage(COLOUR_DARKPURPLE + message) logging.log(logging.INFO, "AWAY - %s" %message) self.chatlog.write("[%s] %s %s\n" % (datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S"), "", message)) self.chatlog.flush() if self.irc_relay and world: self.irc_relay.sendAction("", message) except Exception, e: logging.log(logging.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)
def commandRestore(self, parts, fromloc, overriderank): "/restore worldname number - Op\nRestore world to indicated number." if len(parts) < 2: self.client.sendServerMessage( "Please specify at least a world ID!") else: world_id = parts[1].lower() world_dir = ("worlds/%s/" % world_id) if not self.client.isModPlus(): # ensure user has proper rank in the target world (the check to run this command only counts the world they're currently in) canRestore = False config = ConfigParser() config.read( world_dir + "world.meta" ) # this still has an issue: it won't pick up recent rank changes that haven't been flushed to the file yet. but it's good enough in geneal. if config.has_section("owner"): print config.get("owner", "owner") if config.get( "owner", "owner").lower() == self.client.username.lower(): canRestore = True if config.has_section("ops"): for op in config.options("ops"): print op if op.lower() == self.client.username.lower(): canRestore = True if not canRestore: self.client.sendServerMessage( "You are not allowed to restore that world!") return 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: if not os.path.exists(world_dir + "blocks.gz.new"): shutil.copy( world_dir + "backup/%s/blocks.gz" % backup_number, world_dir) try: shutil.copy( world_dir + "backup/%s/world.meta" % backup_number, world_dir) os.remove( world_dir + "blocks.db" ) # remove blocktracker data since it's no longer valid except: pass else: reactor.callLater( 1, self.commandRestore(self, parts, fromloc, overriderank)) default_name = self.client.factory.default_name self.client.factory.unloadWorld("worlds/%s" % world_id, world_id) self.client.sendServerMessage( "%s has been restored to %s and booted." % (world_id, backup_number)) if world_id in self.client.factory.worlds: for client in self.client.factory.worlds[world_id].clients: client.changeToWorld(world_id)