From 7f0e0d5ef8a38ed2c497647cb1b49775b5eeddff Mon Sep 17 00:00:00 2001 From: Griatch Date: Sun, 22 Feb 2015 11:35:16 +0100 Subject: [PATCH] Added at_init() call in idmapper and made sure to not deprecate it. Fixed bugs in search and continued work on tutorial world. --- evennia/commands/cmdsethandler.py | 8 ++++++-- evennia/commands/default/building.py | 5 ++++- evennia/contrib/tutorial_world/mob.py | 14 +++++++++----- evennia/contrib/tutorial_world/objects.py | 4 ++-- evennia/contrib/tutorial_world/rooms.py | 22 ++++++++++++---------- evennia/objects/objects.py | 6 ++---- evennia/scripts/tickerhandler.py | 15 ++++++++++++--- evennia/utils/idmapper/base.py | 18 ++++++++++++++++-- 8 files changed, 63 insertions(+), 29 deletions(-) diff --git a/evennia/commands/cmdsethandler.py b/evennia/commands/cmdsethandler.py index 6c2f0a7174..b10e15dd1c 100644 --- a/evennia/commands/cmdsethandler.py +++ b/evennia/commands/cmdsethandler.py @@ -357,7 +357,7 @@ class CmdSetHandler(object): cmdset.permanent = False self.update() - def delete(self, cmdset=None): + def remove(self, cmdset=None): """ Remove a cmdset from the handler. @@ -409,8 +409,10 @@ class CmdSetHandler(object): pass # re-sync the cmdsethandler. self.update() + # legacy alias + delete = remove - def delete_default(self): + def remove_default(self): """ This explicitly deletes the default cmdset. It's the only command that can. @@ -428,6 +430,8 @@ class CmdSetHandler(object): else: self.cmdset_stack = [_EmptyCmdSet(cmdsetobj=self.obj)] self.update() + # legacy alias + delete_default = remove_default def all(self): """ diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index 336689fd3b..83d7fdeeb8 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1714,9 +1714,12 @@ class CmdExamine(ObjManipCommand): """ Formats a single attribute line. """ - if crop and isinstance(value, basestring): + if crop: + if not isinstance(value, basestring): + value = utils.to_str(value, force_string=True) value = utils.crop(value) value = utils.to_unicode(value) + string = "\n %s = %s" % (attr, value) string = raw(string) return string diff --git a/evennia/contrib/tutorial_world/mob.py b/evennia/contrib/tutorial_world/mob.py index 9583ba7cdb..6882365aba 100644 --- a/evennia/contrib/tutorial_world/mob.py +++ b/evennia/contrib/tutorial_world/mob.py @@ -10,6 +10,7 @@ import random from evennia import TICKER_HANDLER from evennia import search_object from evennia import Command, CmdSet +from evennia import logger from evennia.contrib.tutorial_world import objects as tut_objects @@ -276,7 +277,7 @@ class Mob(tut_objects.TutorialObject): if not self.db.aggressive: self.start_hunting() return - self._set_ticker(self.db.attacking_pace, "do_attack") + self._set_ticker(self.db.aggressive_pace, "do_attack") self.ndb.is_patrolling = False self.ndb.is_hunting = False self.ndb.is_attacking = True @@ -346,7 +347,7 @@ class Mob(tut_objects.TutorialObject): # no exits! teleport to home to get away. self.move_to(self.home) - def do_attacking(self, *args, **kwargs): + def do_attack(self, *args, **kwargs): """ Called regularly when in attacking mode. In attacking mode the mob will bring its weapons to bear on any targets @@ -373,9 +374,12 @@ class Mob(tut_objects.TutorialObject): # defeated room target.msg(self.db.defeat_msg) self.location.msg_contents(self.db.defeat_msg_room % target.key, exclude=target) - defeat_location = search_object(self.db.defeat_location) - if defeat_location: - target.move_to(defeat_location, quiet=True) + send_defeated_to = search_object(self.db.send_defeated_to) + if send_defeated_to: + target.move_to(send_defeated_to[0], quiet=True) + else: + logger.log_err("Mob: mob.db.send_defeated_to not found: %s" % self.db.send_defeated_to) + # response methods - called by other objects diff --git a/evennia/contrib/tutorial_world/objects.py b/evennia/contrib/tutorial_world/objects.py index b65cb49f34..bf6c4447d7 100644 --- a/evennia/contrib/tutorial_world/objects.py +++ b/evennia/contrib/tutorial_world/objects.py @@ -297,7 +297,7 @@ class LightSource(TutorialObject): When burned out, the object will be deleted. """ - def __init__(self): + def at_init(self): """ If this is called with the Attribute is_giving_light already set, we know that the timer got killed by a server @@ -795,7 +795,7 @@ class CmdAttack(Command): self.caller.db.combat_parry_mode = False else: self.caller.msg("You fumble with your weapon, unsure of whether to stab, slash or parry ...") - self.caller.location.msg_contents("%s fumbles with their weapon." % self.obj.key) + self.caller.location.msg_contents("%s fumbles with their weapon." % self.caller, exclude=self.caller) self.caller.db.combat_parry_mode = False return diff --git a/evennia/contrib/tutorial_world/rooms.py b/evennia/contrib/tutorial_world/rooms.py index 56411fc2bb..0aab853b9f 100644 --- a/evennia/contrib/tutorial_world/rooms.py +++ b/evennia/contrib/tutorial_world/rooms.py @@ -440,6 +440,7 @@ class DarkCmdSet(CmdSet): """ key = "darkroom_cmdset" mergetype = "Replace" + priority = 2 def at_cmdset_creation(self): "populate the cmdset." @@ -472,6 +473,7 @@ class DarkRoom(TutorialRoom): self.db.tutorial_info = "This is a room with custom command sets on itself." # the room starts dark. self.db.is_lit = False + self.cmdsets.add(DarkCmdSet, permanent=True) def _carries_light(self, obj): """ @@ -502,22 +504,22 @@ class DarkRoom(TutorialRoom): if any(self._carries_light(obj) for obj in self.contents): # people are carrying lights if not self.db.is_lit: + self.cmdset.remove(DarkCmdSet) self.db.is_lit = True for char in (obj for obj in self.contents if obj.has_player): # this won't do anything if it is already removed - char.cmdset.delete(DarkCmdSet) char.msg("The room is lit up.") else: # noone is carrying light - darken the room + if self.db.is_lit: + self.db.is_lit = False + self.cmdset.add(DarkCmdSet, permanent=True) for char in (obj for obj in self.contents if obj.has_player): - if self.db.is_lit: - self.db.is_lit = False - if char.is_superuser: - char.msg("You are Superuser, so you are not affected by the dark state.") - else: - # put players in darkness - char.cmdset.add(DarkCmdSet) - char.msg("The room is completely dark.") + if char.is_superuser: + char.msg("You are Superuser, so you are not affected by the dark state.") + else: + # put players in darkness + char.msg("The room is completely dark.") def at_object_receive(self, obj, source_location): """ @@ -535,8 +537,8 @@ class DarkRoom(TutorialRoom): DarkCmdSet if necessary. This also works if they are teleported away. """ - obj.cmdset.delete(DarkCmdSet) self.check_light_state() + obj.cmdset.delete(DarkCmdSet) #------------------------------------------------------------ # diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 3e2013520f..651bb74e29 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -386,9 +386,9 @@ class DefaultObject(ObjectDB): if is_string: # searchdata is a string; wrap some common self-references if searchdata.lower() in ("here", ): - return self.location + return [self.location] if quiet else self.location if searchdata.lower() in ("me", "self",): - return self + return [self] if quiet else self if use_nicks: # do nick-replacement on search @@ -961,8 +961,6 @@ class DefaultObject(ObjectDB): def at_init(self): """ - DEPRECATED: Use __init__ instead. - This is always called whenever this object is initiated -- that is, whenever it its typeclass is cached from memory. This happens on-demand first time the object is used or activated diff --git a/evennia/scripts/tickerhandler.py b/evennia/scripts/tickerhandler.py index 8449fc910c..5b13cf54a1 100644 --- a/evennia/scripts/tickerhandler.py +++ b/evennia/scripts/tickerhandler.py @@ -51,13 +51,19 @@ call the handler's save() and restore() methods when the server reboots. from twisted.internet.defer import inlineCallbacks from evennia.scripts.scripts import ExtendedLoopingCall from evennia.server.models import ServerConfig -from evennia.utils.logger import log_trace +from evennia.utils.logger import log_trace, log_err from evennia.utils.dbserialize import dbserialize, dbunserialize, pack_dbobj, unpack_dbobj _GA = object.__getattribute__ _SA = object.__setattr__ +_ERROR_ADD_INTERVAL = \ +"""TickerHandler: Tried to add a ticker with invalid interval: +obj={obj}, interval={interval}, args={args}, kwargs={kwargs} +store_key={store_key} +Ticker was not added.""" + class Ticker(object): """ Represents a repeatedly running task that calls @@ -93,7 +99,6 @@ class Ticker(object): """ Set up the ticker """ - print "Ticker __init__", interval self.interval = interval self.subscriptions = {} # set up a twisted asynchronous repeat call @@ -113,7 +118,6 @@ class Ticker(object): if not subs: self.task.stop() elif subs: - print "validating tickerhandler:", subs, start_delay, self.interval self.task.start(self.interval, now=False, start_delay=start_delay) def add(self, store_key, obj, *args, **kwargs): @@ -156,6 +160,11 @@ class TickerPool(object): """ Add new ticker subscriber """ + if not interval: + log_err(_ERROR_ADD_INTERVAL.format(store_key=store_key, obj=obj, + interval=interval, args=args, kwargs=kwargs)) + return + if interval not in self.tickers: self.tickers[interval] = self.ticker_class(interval) self.tickers[interval].add(store_key, obj, *args, **kwargs) diff --git a/evennia/utils/idmapper/base.py b/evennia/utils/idmapper/base.py index 7cdcec28ab..6e0d6078f8 100755 --- a/evennia/utils/idmapper/base.py +++ b/evennia/utils/idmapper/base.py @@ -65,7 +65,7 @@ class SharedMemoryModelBase(ModelBase): cached_instance = cls.get_cached_instance(instance_key) if cached_instance is None: cached_instance = new_instance() - cls.cache_instance(cached_instance) + cls.cache_instance(cached_instance, new=True) return cached_instance @@ -246,12 +246,26 @@ class SharedMemoryModel(Model): return cls.__dbclass__.__instance_cache__.get(id) @classmethod - def cache_instance(cls, instance): + def cache_instance(cls, instance, new=False): """ Method to store an instance in the cache. + + Args: + instance (Class instance): the instance to cache + new (bool, optional): this is the first time this + instance is cached (i.e. this is not an update + operation). + """ if instance._get_pk_val() is not None: cls.__dbclass__.__instance_cache__[instance._get_pk_val()] = instance + if new: + try: + # trigger the at_init hook only + # at first initialization + instance.at_init() + except AttributeError: + pass @classmethod def get_all_cached_instances(cls):