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.
- Using `lunr` search indexing for better `help` matching and suggestions. Also improve
the main help command's default listing output.
- Added `content_types` indexing to DefaultObject's ContentsHandler. (volund)
### Already in master
- `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
transparently through the decorating TypeClass.
"""
from collections import defaultdict
from django.conf import settings
from django.db import models
from django.core.exceptions import ObjectDoesNotExist
@ -42,34 +43,49 @@ class ContentsHandler(object):
"""
self.obj = obj
self._pkcache = {}
self._pkcache = set()
self._idcache = obj.__class__.__instance_cache__
self._typecache = defaultdict(set)
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):
"""
Re-initialize the content cache
"""
self._pkcache.update(
dict((obj.pk, None) for obj in ObjectDB.objects.filter(db_location=self.obj) if obj.pk)
)
objects = self.load()
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.
Args:
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:
objects (list): the Objects inside this location
"""
if exclude:
pks = [pk for pk in self._pkcache if pk not in [excl.pk for excl in make_iter(exclude)]]
if content_type is not None:
pks = self._typecache[content_type]
else:
pks = self._pkcache
if exclude:
pks = pks - {excl.pk for excl in make_iter(exclude)}
try:
return [self._idcache[pk] for pk in pks]
except KeyError:
@ -81,7 +97,7 @@ class ContentsHandler(object):
except KeyError:
# this means an actual failure of caching. Return real database match.
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):
"""
@ -91,7 +107,9 @@ class ContentsHandler(object):
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):
"""
@ -101,7 +119,10 @@ class ContentsHandler(object):
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):
"""
@ -109,6 +130,7 @@ class ContentsHandler(object):
"""
self._pkcache = {}
self._typecache = defaultdict(set)
self.init()

View file

@ -203,6 +203,8 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
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.
# Will be formatted with the appropriate attributes.
@ -257,7 +259,7 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
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
objects that has this object set as its location.
@ -266,17 +268,18 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
Args:
exclude (Object): Object to exclude from returned
contents list
content_type (str): A content_type to filter by. None for no
filtering.
Returns:
contents (list): List of contents of this Object.
Notes:
Also available as the `contents` property.
Also available as the `contents` property, minus exclusion
and filtering.
"""
con = self.contents_cache.get(exclude=exclude)
# print "contents_get:", self, con, id(self), calledby() # DEBUG
return con
return self.contents_cache.get(exclude=exclude, content_type=content_type)
def contents_set(self, *args):
"You cannot replace this property"
@ -1656,20 +1659,25 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase):
**kwargs (dict): Arbitrary, optional arguments for users
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:
return ""
# get and identify all objects
visible = (con for con in self.contents if con != looker and con.access(looker, "view"))
exits, users, things = [], [], defaultdict(list)
for con in visible:
key = con.get_display_name(looker)
if con.destination:
exits.append(key)
elif con.has_account:
users.append("|c%s|n" % key)
else:
# things can be pluralized
things[key].append(con)
exits_list = filter_visible(self.contents_get(content_type='exit'))
users_list = filter_visible(self.contents_get(content_type='character'))
things_list = filter_visible(self.contents_get(content_type="object"))
things = defaultdict(list)
for thing in things_list:
things[thing.key].append(thing)
users = [f"|c{user.key}|n" for user in users_list]
exits = [ex.key for ex in exits_list]
# get description, build string
string = "|c%s|n\n" % self.get_display_name(looker)
desc = self.db.desc
@ -2026,7 +2034,9 @@ class DefaultCharacter(DefaultObject):
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.
# 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)"
@ -2278,6 +2288,9 @@ class DefaultRoom(DefaultObject):
This is the base room object. It's just like any Object except its
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.
# 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.
"""
_content_types = ("exit",)
exit_command = ExitCommand
priority = 101