def console_command(self, parameters): wanted = " ".join(parameters) if wanted == "spring": season = Spring() elif wanted == "winter": season = Winter() else: yield "Couldn't find season %s" % wanted return msg = "Changing season to %s..." % wanted yield msg self.factory.day = season.day self.factory.update_season() yield "Season successfully changed!"
class TestWinter(unittest.TestCase): def setUp(self): self.hook = Winter() self.c = Chunk(0, 0) def test_trivial(self): pass def test_spring_to_ice(self): self.c.set_block((0, 0, 0), blocks["spring"].slot) self.hook.transform(self.c) self.assertEqual(self.c.get_block((0, 0, 0)), blocks["ice"].slot) def test_snow_on_stone(self): self.c.set_block((0, 0, 0), blocks["stone"].slot) self.hook.transform(self.c) self.assertEqual(self.c.get_block((0, 1, 0)), blocks["snow"].slot) def test_no_snow_on_snow(self): """ Test whether snow is spawned on top of other snow. """ self.c.set_block((0, 0, 0), blocks["snow"].slot) self.hook.transform(self.c) self.assertNotEqual(self.c.get_block((0, 1, 0)), blocks["snow"].slot) def test_no_floating_snow(self): """ Test whether snow is spawned in the correct y-level over populated chunks. """ self.c.set_block((0, 0, 0), blocks["grass"].slot) self.c.populated = True self.c.dirty = False self.c.clear_damage() self.hook.transform(self.c) self.assertEqual(self.c.get_block((0, 1, 0)), blocks["snow"].slot) self.assertNotEqual(self.c.get_block((0, 2, 0)), blocks["snow"].slot) def test_bad_heightmap_floating_snow(self): """ Test whether snow is spawned in the correct y-level over populated chunks, if the heightmap is incorrect. """ self.c.set_block((0, 0, 0), blocks["grass"].slot) self.c.populated = True self.c.dirty = False self.c.clear_damage() self.c.heightmap[0 * 16 + 0] = 2 self.hook.transform(self.c) self.assertEqual(self.c.get_block((0, 1, 0)), blocks["snow"].slot) self.assertNotEqual(self.c.get_block((0, 2, 0)), blocks["snow"].slot) def test_top_of_world_snow(self): """ Blocks at the top of the world should not cause exceptions when snow is placed on them. """ self.c.set_block((0, 127, 0), blocks["stone"].slot) self.hook.transform(self.c)
def setUp(self): self.hook = Winter() self.c = Chunk(0, 0)
class BravoFactory(Factory): """ A ``Factory`` that creates ``BravoProtocol`` objects when connected to. """ implements(IPushProducer) protocol = BravoProtocol timestamp = None time = 0 day = 0 eid = 1 interfaces = [] def __init__(self, config, name): """ Create a factory and world. ``name`` is the string used to look up factory-specific settings from the configuration. :param str name: internal name of this factory """ self.name = name self.config = config self.config_name = "world %s" % name self.world = World(self.config, self.name) self.world.factory = self self.protocols = dict() self.connectedIPs = defaultdict(int) self.mode = self.config.get(self.config_name, "mode") if self.mode not in ("creative", "survival"): raise Exception("Unsupported mode %s" % self.mode) self.limitConnections = self.config.getintdefault( self.config_name, "limitConnections", 0) self.limitPerIP = self.config.getintdefault(self.config_name, "limitPerIP", 0) self.vane = WeatherVane(self) def startFactory(self): log.msg("Initializing factory for world '%s'..." % self.name) # Get our plugins set up. self.register_plugins() log.msg("Starting world...") self.world.start() # Start up the permanent cache. # has_option() is not exactly desirable, but it's appropriate here # because we don't want to take any action if the key is unset. if self.config.has_option(self.config_name, "perm_cache"): cache_level = self.config.getint(self.config_name, "perm_cache") self.world.enable_cache(cache_level) log.msg("Starting timekeeping...") self.timestamp = reactor.seconds() self.time = self.world.level.time self.update_season() self.time_loop = LoopingCall(self.update_time) self.time_loop.start(2) log.msg("Starting entity updates...") # Start automatons. for automaton in self.automatons: automaton.start() self.chat_consumers = set() log.msg("Factory successfully initialized for world '%s'!" % self.name) def stopFactory(self): """ Called before factory stops listening on ports. Used to perform shutdown tasks. """ log.msg("Shutting down world...") # Stop automatons. Technically, they may not actually halt until their # next iteration, but that is close enough for us, probably. # Automatons are contracted to not access the world after stop() is # called. for automaton in self.automatons: automaton.stop() # Evict plugins as soon as possible. Can't be done before stopping # automatons. self.unregister_plugins() self.time_loop.stop() # Write back current world time. This must be done before stopping the # world. self.world.time = self.time # And now stop the world. self.world.stop() log.msg("World data saved!") def buildProtocol(self, addr): """ Create a protocol. This overriden method provides early player entity registration, as a solution to the username/entity race that occurs on login. """ banned = self.world.serializer.load_plugin_data("banned_ips") # Do IP bans first. for ip in banned.split(): if addr.host == ip: # Use KickedProtocol with extreme prejudice. log.msg("Kicking banned IP %s" % addr.host) p = KickedProtocol("Sorry, but your IP address is banned.") p.factory = self return p # We are ignoring values less that 1, but making sure not to go over # the connection limit. if (self.limitConnections and len(self.protocols) >= self.limitConnections): log.msg("Reached maximum players, turning %s away." % addr.host) p = KickedProtocol("The player limit has already been reached." " Please try again later.") p.factory = self return p # Do our connection-per-IP check. if (self.limitPerIP and self.connectedIPs[addr.host] >= self.limitPerIP): log.msg("At maximum connections for %s already, dropping." % addr.host) p = KickedProtocol( "There are too many players connected from this IP.") p.factory = self return p else: self.connectedIPs[addr.host] += 1 # If the player wasn't kicked, let's continue! log.msg("Starting connection for %s" % addr) p = self.protocol(self.config, self.name) p.host = addr.host p.factory = self self.register_entity(p) # Copy our hooks to the protocol. p.register_hooks() return p def teardown_protocol(self, protocol): """ Do internal bookkeeping on behalf of a protocol which has been disconnected. Did you know that "bookkeeping" is one of the few words in English which has three pairs of double letters in a row? """ username = protocol.username host = protocol.host if username in self.protocols: del self.protocols[username] self.connectedIPs[host] -= 1 def set_username(self, protocol, username): """ Attempt to set a new username for a protocol. :returns: whether the username was changed """ # If the username's already taken, refuse it. if username in self.protocols: return False if protocol.username in self.protocols: # This protocol's known under another name, so remove it. del self.protocols[protocol.username] # Set the username. self.protocols[username] = protocol protocol.username = username return True def register_plugins(self): """ Setup plugin hooks. """ log.msg("Registering client plugin hooks...") plugin_types = { "automatons": IAutomaton, "generators": ITerrainGenerator, "open_hooks": IWindowOpenHook, "click_hooks": IWindowClickHook, "close_hooks": IWindowCloseHook, "pre_build_hooks": IPreBuildHook, "post_build_hooks": IPostBuildHook, "pre_dig_hooks": IPreDigHook, "dig_hooks": IDigHook, "sign_hooks": ISignHook, "use_hooks": IUseHook, } packs = self.config.getlistdefault(self.config_name, "packs", []) try: packs = [available_packs[pack] for pack in packs] except KeyError, e: raise Exception("Couldn't find plugin pack %s" % e.args) for t, interface in plugin_types.iteritems(): l = self.config.getlistdefault(self.config_name, t, []) # Grab extra plugins from the pack. Order doesn't really matter # since the plugin loader sorts things anyway. for pack in packs: if t in pack: l += pack[t] # Hax. :T if t == "generators": plugins = retrieve_sorted_plugins(interface, l) elif issubclass(interface, ISortedPlugin): plugins = retrieve_sorted_plugins(interface, l, factory=self) else: plugins = retrieve_named_plugins(interface, l, factory=self) log.msg("Using %s: %s" % (t.replace("_", " "), ", ".join(plugin.name for plugin in plugins))) setattr(self, t, plugins) # Deal with seasons. seasons = self.config.getlistdefault(self.config_name, "seasons", []) for pack in packs: if "seasons" in pack: seasons += pack["seasons"] self.seasons = [] if "spring" in seasons: self.seasons.append(Spring()) if "winter" in seasons: self.seasons.append(Winter()) # Assign generators to the world pipeline. self.world.pipeline = self.generators # Use hooks have special funkiness. uh = self.use_hooks self.use_hooks = defaultdict(list) for plugin in uh: for target in plugin.targets: self.use_hooks[target].append(plugin)