OLC systen. Create olc_storage mechanism

This commit is contained in:
Griatch 2018-02-28 19:17:26 +01:00
parent 5810fa11fe
commit 43185d8f17
7 changed files with 205 additions and 9 deletions

View file

@ -631,10 +631,31 @@ class DefaultAccount(with_metaclass(TypeclassBase, AccountDB)):
# this will only be set if the utils.create_account
# function was used to create the object.
cdict = self._createdict
updates = []
if not cdict.get("key"):
if not self.db_key:
self.db_key = "#%i" % self.dbid
updates.append("db_key")
elif self.key != cdict.get("key"):
updates.append("db_key")
self.db_key = cdict["key"]
if updates:
self.save(update_fields=updates)
if cdict.get("locks"):
self.locks.add(cdict["locks"])
if cdict.get("permissions"):
permissions = cdict["permissions"]
if cdict.get("tags"):
# this should be a list of tags, tuples (key, category) or (key, category, data)
self.tags.batch_add(*cdict["tags"])
if cdict.get("attributes"):
# this should be tuples (key, val, ...)
self.attributes.batch_add(*cdict["attributes"])
if cdict.get("nattributes"):
# this should be a dict of nattrname:value
for key, value in cdict["nattributes"]:
self.nattributes.add(key, value)
del self._createdict
self.permissions.batch_add(*permissions)

View file

@ -1002,14 +1002,14 @@ class DefaultObject(with_metaclass(TypeclassBase, ObjectDB)):
cdict["location"].at_object_receive(self, None)
self.at_after_move(None)
if cdict.get("tags"):
# this should be a list of tags
# this should be a list of tags, tuples (key, category) or (key, category, data)
self.tags.batch_add(*cdict["tags"])
if cdict.get("attributes"):
# this should be a dict of attrname:value
# this should be tuples (key, val, ...)
self.attributes.batch_add(*cdict["attributes"])
if cdict.get("nattributes"):
# this should be a dict of nattrname:value
for key, value in cdict["nattributes"].items():
for key, value in cdict["nattributes"]:
self.nattributes.add(key, value)
del self._createdict

View file

@ -513,6 +513,22 @@ class DefaultScript(ScriptBase):
updates.append("db_persistent")
if updates:
self.save(update_fields=updates)
if cdict.get("permissions"):
self.permissions.batch_add(*cdict["permissions"])
if cdict.get("locks"):
self.locks.add(cdict["locks"])
if cdict.get("tags"):
# this should be a list of tags, tuples (key, category) or (key, category, data)
self.tags.batch_add(*cdict["tags"])
if cdict.get("attributes"):
# this should be tuples (key, val, ...)
self.attributes.batch_add(*cdict["attributes"])
if cdict.get("nattributes"):
# this should be a dict of nattrname:value
for key, value in cdict["nattributes"]:
self.nattributes.add(key, value)
if not cdict.get("autostart"):
# don't auto-start the script
return

View file

@ -530,8 +530,8 @@ class AttributeHandler(object):
repeat-calling add when having many Attributes to add.
Args:
indata (tuple): Tuples of varying length representing the
Attribute to add to this object.
indata (list): List of tuples of varying length representing the
Attribute to add to this object. Supported tuples are
- `(key, value)`
- `(key, value, category)`
- `(key, value, category, lockstring)`

View file

@ -54,7 +54,8 @@ _GA = object.__getattribute__
def create_object(typeclass=None, key=None, location=None, home=None,
permissions=None, locks=None, aliases=None, tags=None,
destination=None, report_to=None, nohome=False):
destination=None, report_to=None, nohome=False, attributes=None,
nattributes=None):
"""
Create a new in-game object.
@ -68,13 +69,18 @@ def create_object(typeclass=None, key=None, location=None, home=None,
permissions (list): A list of permission strings or tuples (permstring, category).
locks (str): one or more lockstrings, separated by semicolons.
aliases (list): A list of alternative keys or tuples (aliasstring, category).
tags (list): List of tag keys or tuples (tagkey, category).
tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data).
destination (Object or str): Obj or #dbref to use as an Exit's
target.
report_to (Object): The object to return error messages to.
nohome (bool): This allows the creation of objects without a
default home location; only used when creating the default
location itself or during unittests.
attributes (list): Tuples on the form (key, value) or (key, value, category),
(key, value, lockstring) or (key, value, lockstring, default_access).
to set as Attributes on the new object.
nattributes (list): Non-persistent tuples on the form (key, value). Note that
adding this rarely makes sense since this data will not survive a reload.
Returns:
object (Object): A newly created object of the given typeclass.
@ -122,7 +128,8 @@ def create_object(typeclass=None, key=None, location=None, home=None,
# store the call signature for the signal
new_object._createdict = dict(key=key, location=location, destination=destination, home=home,
typeclass=typeclass.path, permissions=permissions, locks=locks,
aliases=aliases, tags=tags, report_to=report_to, nohome=nohome)
aliases=aliases, tags=tags, report_to=report_to, nohome=nohome,
attributes=attributes, nattributes=nattributes)
# this will trigger the save signal which in turn calls the
# at_first_save hook on the typeclass, where the _createdict can be
# used.
@ -139,7 +146,8 @@ object = create_object
def create_script(typeclass=None, key=None, obj=None, account=None, locks=None,
interval=None, start_delay=None, repeats=None,
persistent=None, autostart=True, report_to=None, desc=None):
persistent=None, autostart=True, report_to=None, desc=None,
tags=None, attributes=None):
"""
Create a new script. All scripts are a combination of a database
object that communicates with the database, and an typeclass that

View file

View file

@ -0,0 +1,151 @@
"""
OLC storage and sharing mechanism.
This sets up a central storage for prototypes. The idea is to make these
available in a repository for buildiers to use. Each prototype is stored
in a Script so that it can be tagged for quick sorting/finding and locked for limiting
access.
"""
from evennia.scripts.scripts import DefaultScript
from evennia.utils.create import create_script
from evennia.utils.utils import make_iter
from evennia.utils.evtable import EvTable
class PersistentPrototype(DefaultScript):
"""
This stores a single prototype
"""
key = "persistent_prototype"
desc = "Stores a prototoype"
def store_prototype(caller, key, prototype, desc="", tags=None, locks="", delete=False):
"""
Store a prototype persistently.
Args:
caller (Account or Object): Caller aiming to store prototype. At this point
the caller should have permission to 'add' new prototypes, but to edit
an existing prototype, the 'edit' lock must be passed on that prototype.
key (str): Name of prototype to store.
prototype (dict): Prototype dict.
desc (str, optional): Description of prototype, to use in listing.
tags (list, optional): Tag-strings to apply to prototype. These are always
applied with the 'persistent_prototype' category.
locks (str, optional): Locks to apply to this prototype. Used locks
are 'use' and 'edit'
delete (bool, optional): Delete an existing prototype identified by 'key'.
This requires `caller` to pass the 'edit' lock of the prototype.
Returns:
stored (StoredPrototype or None): The resulting prototype (new or edited),
or None if deleting.
Raises:
PermissionError: If edit lock was not passed by caller.
"""
key = key.lower()
locks = locks if locks else "use:all();edit:id({}) or edit:perm(Admin)".format(caller.id)
tags = [(tag, "persistent_prototype") for tag in make_iter(tags)]
stored_prototype = PersistentPrototype.objects.filter(db_key=key)
if stored_prototype:
stored_prototype = stored_prototype[0]
if not stored_prototype.access(caller, 'edit'):
PermissionError("{} does not have permission to edit prototype {}".format(caller, key))
if delete:
stored_prototype.delete()
return
if desc:
stored_prototype.desc = desc
if tags:
stored_prototype.tags.add(tags)
if locks:
stored_prototype.locks.add(locks)
if prototype:
stored_prototype.attributes.add("prototype", prototype)
else:
stored_prototype = create_script(
PersistentPrototype, key=key, desc=desc, persistent=True,
locks=locks, tags=tags, attributes=[("prototype", prototype)])
return stored_prototype
def search_prototype(key=None, tags=None):
"""
Find prototypes based on key and/or tags.
Kwargs:
key (str): An exact or partial key to query for.
tags (str or list): Tag key or keys to query for. These
will always be applied with the 'persistent_protototype'
tag category.
Return:
matches (queryset): All found PersistentPrototypes. This will
be all prototypes if no arguments are given.
Note:
This will use the tags to make a subselection before attempting
to match on the key. So if key/tags don't match up nothing will
be found.
"""
matches = PersistentPrototype.objects.all()
if tags:
# exact match on tag(s)
tags = make_iter(tags)
tag_categories = ("persistent_prototype" for _ in tags)
matches = matches.get_by_tag(tags, tag_categories)
if key:
# partial match on key
matches = matches.filter(db_key=key) or matches.filter(db_key__icontains=key)
return matches
def get_prototype_list(caller, key=None, tags=None, show_non_use=False, show_non_edit=True):
"""
Collate a list of found prototypes based on search criteria and access.
Args:
caller (Account or Object): The object requesting the list.
key (str, optional): Exact or partial key to query for.
tags (str or list, optional): Tag key or keys to query for.
show_non_use (bool, optional): Show also prototypes the caller may not use.
show_non_edit (bool, optional): Show also prototypes the caller may not edit.
Returns:
table (EvTable or None): An EvTable representation of the prototypes. None
if no prototypes were found.
"""
prototypes = search_prototype(key, tags)
if not prototypes:
return None
# gather access permissions as (key, desc, can_use, can_edit)
prototypes = [(prototype.key, prototype.desc,
prototype.access(caller, "use"), prototype.access(caller, "edit"))
for prototype in prototypes]
if not show_non_use:
prototypes = [tup for tup in prototypes if tup[2]]
if not show_non_edit:
prototypes = [tup for tup in prototypes if tup[3]]
if not prototypes:
return None
table = []
for i in range(len(prototypes[0])):
table.append([tup[i] for tup in prototypes])
table = EvTable("Key", "Desc", "Use", "Edit", table, crop=True, width=78)
table.reformat_column(0, width=28)
table.reformat_column(1, width=40)
table.reformat_column(2, width=5)
table.reformat_column(3, width=5)
return table