diff --git a/evennia/commands/cmdhandler.py b/evennia/commands/cmdhandler.py index a4f04af016..76cd3985eb 100644 --- a/evennia/commands/cmdhandler.py +++ b/evennia/commands/cmdhandler.py @@ -36,6 +36,7 @@ command line. The processing of a command works as follows: from collections import defaultdict from weakref import WeakValueDictionary from traceback import format_exc +from itertools import chain from copy import copy from twisted.internet.defer import inlineCallbacks, returnValue from django.conf import settings @@ -223,7 +224,7 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype): location = obj.location except Exception: location = None - if location:# and not obj_cmdset.no_objs: #TODO + if location: # Gather all cmdsets stored on objects in the room and # also in the caller's inventory and the location itself local_objlist = yield (location.contents_get(exclude=obj) + @@ -239,9 +240,10 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype): # is not seeing e.g. the commands on a fellow player (which is why # the no_superuser_bypass must be True) local_obj_cmdsets = \ - yield [lobj.cmdset.current for lobj in local_objlist - if (lobj.cmdset.current and - lobj.access(caller, access_type='call', no_superuser_bypass=True))] + yield list(chain.from_iterable( + lobj.cmdset.cmdset_stack for lobj in local_objlist + if (lobj.cmdset.current and + lobj.access(caller, access_type='call', no_superuser_bypass=True)))) for cset in local_obj_cmdsets: #This is necessary for object sets, or we won't be able to # separate the command sets from each other in a busy room. We @@ -267,8 +269,7 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype): _msg_err(caller, _ERROR_CMDSETS) raise ErrorReported try: - # we don't return the 'duplicates' option since this happens per-merge - returnValue((obj.cmdset.current, obj.cmdset.cmdset_stack)) + returnValue((obj.cmdset.current, list(obj.cmdset.cmdset_stack))) except AttributeError: returnValue(((None, None, None), [])) @@ -299,12 +300,13 @@ def get_and_merge_cmdsets(caller, session, player, obj, callertype): if not current.no_channels: # also objs may have channels channel_cmdsets = yield _get_channel_cmdset(obj) - print "obj channel cmdsets:", len(channel_cmdsets), [cmdset.key for cmdset in channel_cmdsets] + print "obj channel cmdsets:", len(channel_cmdsets), [cmdset.key if cmdset else cmdset for cmdset in channel_cmdsets] cmdsets += channel_cmdsets - if not current.no_channels: - channel_cmdsets = yield _get_channel_cmdset(obj) - print "player channel cmdsets:", len(channel_cmdsets), [cmdset.key for cmdset in channel_cmdsets] - cmdsets += channel_cmdsets + if not current.no_channels: + channel_cmdsets = yield _get_channel_cmdset(player) + print "player channel cmdsets:", len(channel_cmdsets), [cmdset.key for cmdset in channel_cmdsets] + print channel_cmdsets[0].commands + cmdsets += channel_cmdsets elif callertype == "player": # we are calling the command from the player level diff --git a/evennia/comms/channelhandler.py b/evennia/comms/channelhandler.py index 271d898600..55da9293fe 100644 --- a/evennia/comms/channelhandler.py +++ b/evennia/comms/channelhandler.py @@ -145,7 +145,7 @@ class ChannelHandler(object): Initializes the channel handler's internal state. """ - self.cached_channel_cmds = [] + self.cached_channel_cmds = {} self.cached_cmdsets = {} def __str__(self): @@ -160,7 +160,8 @@ class ChannelHandler(object): Reset the cache storage. """ - self.cached_channel_cmds = [] + self.cached_channel_cmds = {} + self.cached_cmdsets = {} def add(self, channel): """ @@ -195,7 +196,7 @@ class ChannelHandler(object): cmd.__doc__ = cmd.__doc__.format(channelkey=key, lower_channelkey=key.strip().lower(), channeldesc=channel.attributes.get("desc", default="").strip()) - self.cached_channel_cmds.append(cmd) + self.cached_channel_cmds[channel] = cmd self.cached_cmdsets = {} add_channel = add # legacy alias @@ -208,10 +209,10 @@ class ChannelHandler(object): global _CHANNELDB if not _CHANNELDB: from evennia.comms.models import ChannelDB as _CHANNELDB - self.cached_channel_cmds = [] + self.cached_channel_cmds = {} self.cached_cmdsets = {} for channel in _CHANNELDB.objects.get_all_channels(): - self.add_channel(channel) + self.add(channel) def get_cmdset(self, source_object): """ @@ -221,7 +222,7 @@ class ChannelHandler(object): Args: source_object (Object): An object subscribing to one or more channels. -hannelhandler import CHANNEL_HANDLER + Returns: cmdsets (list): The Channel-Cmdsets `source_object` has access to. @@ -230,14 +231,18 @@ hannelhandler import CHANNEL_HANDLER if source_object in self.cached_cmdsets: return self.cached_cmdsets[source_object] else: - # create a new cmdset holding all channels - chan_cmdset = cmdset.CmdSet() - chan_cmdset.key = 'ChannelCmdSet' - chan_cmdset.priority = 101 - chan_cmdset.duplicates = True - for cmd in [cmd for cmd in self.cached_channel_cmds - if cmd.access(source_object, 'send')]: - chan_cmdset.add(cmd) + # create a new cmdset holding all viable channels + chan_cmdset = None + chan_cmds = [channelcmd for channel, channelcmd in self.cached_channel_cmds.iteritems() + if channel.subscriptions.has(source_object) + and channelcmd.access(source_object, 'send')] + if chan_cmds: + chan_cmdset = cmdset.CmdSet() + chan_cmdset.key = 'ChannelCmdSet' + chan_cmdset.priority = 101 + chan_cmdset.duplicates = True + for cmd in chan_cmds: + chan_cmdset.add(cmd) self.cached_cmdsets[source_object] = chan_cmdset return chan_cmdset diff --git a/evennia/comms/models.py b/evennia/comms/models.py index 3e56f8e1fc..81304f7faa 100644 --- a/evennia/comms/models.py +++ b/evennia/comms/models.py @@ -109,7 +109,7 @@ class Msg(SharedMemoryModel): db_hide_from_objects = models.ManyToManyField("objects.ObjectDB", related_name='hide_from_objects_set', null=True, blank=True) db_hide_from_channels = models.ManyToManyField("ChannelDB", related_name='hide_from_channels_set', null=True, blank=True) - db_tags = models.ManyToManyField(Tag, null=True, blank=True, + db_tags = models.ManyToManyField(Tag, null=True, blank=True, help_text='tags on this message. Tags are simple string markers to identify, group and alias messages.') # Database manager @@ -331,7 +331,7 @@ class Msg(SharedMemoryModel): """ return self.locks.check(accessing_obj, access_type=access_type, default=default) - + #------------------------------------------------------------ # # TempMsg @@ -448,6 +448,11 @@ class SubscriptionHandler(object): """ self.obj = obj + self._cache = None + + def _recache(self): + self._cache = {player : True for player in self.obj.db_subscriptions.all()} + self._cache.update({obj : True for obj in self.obj.db_object_subscriptions.all()}) def has(self, entity): """ @@ -463,12 +468,9 @@ class SubscriptionHandler(object): subscriber. """ - clsname = entity.__dbclass__.__name__ - if clsname == "PlayerDB": - return entity in self.obj.db_subscriptions.all() - elif clsname == "ObjectDB": - return entity in self.obj.db_object_subscriptions.all() - + if self._cache is None: + self._recache() + return entity in self._cache def add(self, entity): """ @@ -492,10 +494,11 @@ class SubscriptionHandler(object): self.obj.db_object_subscriptions.add(subscriber) elif clsname == "PlayerDB": self.obj.db_subscriptions.add(subscriber) + self._recache() def remove(self, entity): """ - Remove a subecriber from the channel. + Remove a subscriber from the channel. Args: entity (Player, Object or list): The entity or @@ -510,6 +513,7 @@ class SubscriptionHandler(object): self.obj.db_subscriptions.remove(entity) elif clsname == "ObjectDB": self.obj.db_object_subscriptions.remove(entity) + self._recache() def all(self): """ @@ -520,8 +524,9 @@ class SubscriptionHandler(object): may be a mix of Players and Objects! """ - return list(self.obj.db_subscriptions.all()) + \ - list(self.obj.db_object_subscriptions.all()) + if self._cache is None: + self._recache() + return self._cache def clear(self): """ @@ -530,6 +535,7 @@ class SubscriptionHandler(object): """ self.obj.db_subscriptions.clear() self.obj.db_object_subscriptions.clear() + self._cache = None class ChannelDB(TypedObject): diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 13824e5a7a..a9a6ce7c21 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -875,24 +875,6 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)): self.at_access(result, accessing_obj, access_type, **kwargs) return result - def __eq__(self, other): - """ - Checks for equality against an id string or another object or - user. - - Args: - other (Object): object to compare to. - - """ - try: - return self.dbid == other.dbid - except AttributeError: - # compare players instead - try: - return self.player.uid == other.player.uid - except AttributeError: - return False - # # Hook methods #