Resolve merge conflicts

This commit is contained in:
Griatch 2020-04-13 11:22:19 +02:00
commit 74b73c69f9
3 changed files with 64 additions and 29 deletions

View file

@ -10,7 +10,7 @@
- New `utils.format_grid` for easily displaying long lists of items in a block. - New `utils.format_grid` for easily displaying long lists of items in a block.
- Using `lunr` search indexing for better `help` matching and suggestions. Also improve - Using `lunr` search indexing for better `help` matching and suggestions. Also improve
the main help command's default listing output. the main help command's default listing output.
- Added `content_types` indexing to DefaultObject's ContentsHandler. (volund)
### Already in master ### Already in master
- `is_typeclass(obj (Object), exact (bool))` now defaults to exact=False - `is_typeclass(obj (Object), exact (bool))` now defaults to exact=False

View file

@ -13,6 +13,7 @@ Attributes are separate objects that store values persistently onto
the database object. Like everything else, they can be accessed the database object. Like everything else, they can be accessed
transparently through the decorating TypeClass. transparently through the decorating TypeClass.
""" """
from collections import defaultdict
from django.conf import settings from django.conf import settings
from django.db import models from django.db import models
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
@ -42,34 +43,49 @@ class ContentsHandler(object):
""" """
self.obj = obj self.obj = obj
self._pkcache = {} self._pkcache = set()
self._idcache = obj.__class__.__instance_cache__ self._idcache = obj.__class__.__instance_cache__
self._typecache = defaultdict(set)
self.init() self.init()
def load(self):
"""
Retrieves all objects from database. Used for initializing.
Returns:
Objects (list of ObjectDB)
"""
return list(self.obj.locations_set.all())
def init(self): def init(self):
""" """
Re-initialize the content cache Re-initialize the content cache
""" """
self._pkcache.update( objects = self.load()
dict((obj.pk, None) for obj in ObjectDB.objects.filter(db_location=self.obj) if obj.pk) self._pkcache = {obj.pk for obj in objects}
) for obj in objects:
for ctype in obj._content_types:
self._typecache[ctype].add(obj.pk)
def get(self, exclude=None): def get(self, exclude=None, content_type=None):
""" """
Return the contents of the cache. Return the contents of the cache.
Args: Args:
exclude (Object or list of Object): object(s) to ignore exclude (Object or list of Object): object(s) to ignore
content_type (str or None): Filter list by a content-type. If None, don't filter.
Returns: Returns:
objects (list): the Objects inside this location objects (list): the Objects inside this location
""" """
if exclude: if content_type is not None:
pks = [pk for pk in self._pkcache if pk not in [excl.pk for excl in make_iter(exclude)]] pks = self._typecache[content_type]
else: else:
pks = self._pkcache pks = self._pkcache
if exclude:
pks = pks - {excl.pk for excl in make_iter(exclude)}
try: try:
return [self._idcache[pk] for pk in pks] return [self._idcache[pk] for pk in pks]
except KeyError: except KeyError:
@ -81,7 +97,7 @@ class ContentsHandler(object):
except KeyError: except KeyError:
# this means an actual failure of caching. Return real database match. # this means an actual failure of caching. Return real database match.
logger.log_err("contents cache failed for %s." % self.obj.key) logger.log_err("contents cache failed for %s." % self.obj.key)
return list(ObjectDB.objects.filter(db_location=self.obj)) return self.load()
def add(self, obj): def add(self, obj):
""" """
@ -91,7 +107,9 @@ class ContentsHandler(object):
obj (Object): object to add obj (Object): object to add
""" """
self._pkcache[obj.pk] = None self._pkcache.add(obj.pk)
for ctype in obj._content_types:
self._typecache[ctype].add(obj.pk)
def remove(self, obj): def remove(self, obj):
""" """
@ -101,7 +119,10 @@ class ContentsHandler(object):
obj (Object): object to remove obj (Object): object to remove
""" """
self._pkcache.pop(obj.pk, None) self._pkcache.remove(obj.pk)
for ctype in obj._content_types:
if obj.pk in self._typecache[ctype]:
self._typecache[ctype].remove(obj.pk)
def clear(self): def clear(self):
""" """
@ -109,6 +130,7 @@ class ContentsHandler(object):
""" """
self._pkcache = {} self._pkcache = {}
self._typecache = defaultdict(set)
self.init() self.init()

View file

@ -203,6 +203,8 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
without `obj.save()` having to be called explicitly. without `obj.save()` having to be called explicitly.
""" """
# Used for sorting / filtering in inventories / room contents.
_content_types = ("object",)
# lockstring of newly created objects, for easy overloading. # lockstring of newly created objects, for easy overloading.
# Will be formatted with the appropriate attributes. # Will be formatted with the appropriate attributes.
@ -257,7 +259,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
and not self.db_account.attributes.get("_quell") and not self.db_account.attributes.get("_quell")
) )
def contents_get(self, exclude=None): def contents_get(self, exclude=None, content_type=None):
""" """
Returns the contents of this object, i.e. all Returns the contents of this object, i.e. all
objects that has this object set as its location. objects that has this object set as its location.
@ -266,17 +268,18 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
Args: Args:
exclude (Object): Object to exclude from returned exclude (Object): Object to exclude from returned
contents list contents list
content_type (str): A content_type to filter by. None for no
filtering.
Returns: Returns:
contents (list): List of contents of this Object. contents (list): List of contents of this Object.
Notes: Notes:
Also available as the `contents` property. Also available as the `contents` property, minus exclusion
and filtering.
""" """
con = self.contents_cache.get(exclude=exclude) return self.contents_cache.get(exclude=exclude, content_type=content_type)
# print "contents_get:", self, con, id(self), calledby() # DEBUG
return con
def contents_set(self, *args): def contents_set(self, *args):
"You cannot replace this property" "You cannot replace this property"
@ -1656,20 +1659,25 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
**kwargs (dict): Arbitrary, optional arguments for users **kwargs (dict): Arbitrary, optional arguments for users
overriding the call (unused by default). overriding the call (unused by default).
""" """
def filter_visible(obj_list):
# Helper method to determine if objects are visible to the looker.
return [obj for obj in obj_list if obj != looker and obj.access(looker, "view")]
if not looker: if not looker:
return "" return ""
# get and identify all objects # get and identify all objects
visible = (con for con in self.contents if con != looker and con.access(looker, "view")) exits_list = filter_visible(self.contents_get(content_type='exit'))
exits, users, things = [], [], defaultdict(list) users_list = filter_visible(self.contents_get(content_type='character'))
for con in visible: things_list = filter_visible(self.contents_get(content_type="object"))
key = con.get_display_name(looker)
if con.destination: things = defaultdict(list)
exits.append(key)
elif con.has_account: for thing in things_list:
users.append("|c%s|n" % key) things[thing.key].append(thing)
else: users = [f"|c{user.key}|n" for user in users_list]
# things can be pluralized exits = [ex.key for ex in exits_list]
things[key].append(con)
# get description, build string # get description, build string
string = "|c%s|n\n" % self.get_display_name(looker) string = "|c%s|n\n" % self.get_display_name(looker)
desc = self.db.desc desc = self.db.desc
@ -2026,7 +2034,9 @@ class DefaultCharacter(DefaultObject):
a character avatar controlled by an account. a character avatar controlled by an account.
""" """
# Tuple of types used for indexing inventory contents. Characters generally wouldn't be in
# anyone's inventory, but this also governs displays in room contents.
_content_types = ("character",)
# lockstring of newly created rooms, for easy overloading. # lockstring of newly created rooms, for easy overloading.
# Will be formatted with the appropriate attributes. # Will be formatted with the appropriate attributes.
lockstring = "puppet:id({character_id}) or pid({account_id}) or perm(Developer) or pperm(Developer);delete:id({account_id}) or perm(Admin)" lockstring = "puppet:id({character_id}) or pid({account_id}) or perm(Developer) or pperm(Developer);delete:id({account_id}) or perm(Admin)"
@ -2278,6 +2288,9 @@ class DefaultRoom(DefaultObject):
This is the base room object. It's just like any Object except its This is the base room object. It's just like any Object except its
location is always `None`. location is always `None`.
""" """
# A tuple of strings used for indexing this object inside an inventory.
# Generally, a room isn't expected to HAVE a location, but maybe in some games?
_content_types = ("room",)
# lockstring of newly created rooms, for easy overloading. # lockstring of newly created rooms, for easy overloading.
# Will be formatted with the {id} of the creating object. # Will be formatted with the {id} of the creating object.
@ -2428,7 +2441,7 @@ class DefaultExit(DefaultObject):
exits simply by giving the exit-object's name on its own. exits simply by giving the exit-object's name on its own.
""" """
_content_types = ("exit",)
exit_command = ExitCommand exit_command = ExitCommand
priority = 101 priority = 101