evennia.prototypes.spawner

Spawner

The spawner takes input files containing object definitions in dictionary forms. These use a prototype architecture to define unique objects without having to make a Typeclass for each.

There main function is spawn(*prototype), where the prototype is a dictionary like this:

from evennia.prototypes import prototypes, spawner

prot = {
 "prototype_key": "goblin",
 "typeclass": "types.objects.Monster",
 "key": "goblin grunt",
 "health": lambda: randint(20,30),
 "resists": ["cold", "poison"],
 "attacks": ["fists"],
 "weaknesses": ["fire", "light"]
 "tags": ["mob", "evil", ('greenskin','mob')]
 "attrs": [("weapon", "sword")]
}
# spawn something with the prototype
goblin = spawner.spawn(prot)

# make this into a db-saved prototype (optional)
prot = prototypes.create_prototype(prot)
Possible keywords are:
prototype_key (str): name of this prototype. This is used when storing prototypes and should

be unique. This should always be defined but for prototypes defined in modules, the variable holding the prototype dict will become the prototype_key if it’s not explicitly given.

prototype_desc (str, optional): describes prototype in listings prototype_locks (str, optional): locks for restricting access to this prototype. Locktypes

supported are ‘edit’ and ‘use’.

prototype_tags(list, optional): List of tags or tuples (tag, category) used to group prototype

in listings

prototype_parent (str, tuple or callable, optional): name (prototype_key) of eventual parent prototype, or

a list of parents, for multiple left-to-right inheritance.

prototype: Deprecated. Same meaning as ‘parent’.

typeclass (str or callable, optional): if not set, will use typeclass of parent prototype or use

settings.BASE_OBJECT_TYPECLASS

key (str or callable, optional): the name of the spawned object. If not given this will set to a

random hash

location (obj, str or callable, optional): location of the object - a valid object or #dbref home (obj, str or callable, optional): valid object or #dbref destination (obj, str or callable, optional): only valid for exits (object or #dbref)

permissions (str, list or callable, optional): which permissions for spawned object to have locks (str or callable, optional): lock-string for the spawned object aliases (str, list or callable, optional): Aliases for the spawned object exec (str or callable, optional): this is a string of python code to execute or a list of such

codes. This can be used e.g. to trigger custom handlers on the object. The execution namespace contains ‘evennia’ for the library and ‘obj’. All default spawn commands limit this functionality to Developer/superusers. Usually it’s better to use callables or prototypefuncs instead of this.

tags (str, tuple, list or callable, optional): string or list of strings or tuples

(tagstr, category). Plain strings will be result in tags with no category (default tags).

attrs (tuple, list or callable, optional): tuple or list of tuples of Attributes to add. This

form allows more complex Attributes to be set. Tuples at least specify (key, value) but can also specify up to (key, value, category, lockstring). If you want to specify a lockstring but not a category, set the category to None.

ndb_<name> (any): value of a nattribute (ndb_ is stripped) - this is of limited use. other (any): any other name is interpreted as the key of an Attribute with

its value. Such Attributes have no categories.

Each value can also be a callable that takes no arguments. It should return the value to enter into the field and will be called every time the prototype is used to spawn an object. Note, if you want to store a callable in an Attribute, embed it in a tuple to the args keyword.

By specifying the “prototype_parent” key, the prototype becomes a child of the given prototype, inheritng all prototype slots it does not explicitly define itself, while overloading those that it does specify.

import random


{
 "prototype_key": "goblin_wizard",
 "prototype_parent": "GOBLIN",
 "key": "goblin wizard",
 "spells": ["fire ball", "lighting bolt"]
 }

GOBLIN_ARCHER = {
 "prototype_parent": "GOBLIN",
 "key": "goblin archer",
 "attack_skill": (random, (5, 10))"
 "attacks": ["short bow"]
}

One can also have multiple prototypes. These are inherited from the left, with the ones further to the right taking precedence.

ARCHWIZARD = {
 "attack": ["archwizard staff", "eye of doom"]

GOBLIN_ARCHWIZARD = {
 "key" : "goblin archwizard"
 "prototype_parent": ("GOBLIN_WIZARD", "ARCHWIZARD"),
}

The goblin archwizard will have some different attacks, but will otherwise have the same spells as a goblin wizard who in turn shares many traits with a normal goblin.

Storage 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.

This system also takes into consideration prototypes defined and stored in modules. Such prototypes are considered ‘read-only’ to the system and can only be modified in code. To replace a default prototype, add the same-name prototype in a custom module read later in the settings.PROTOTYPE_MODULES list. To remove a default prototype, override its name with an empty dict.

class evennia.prototypes.spawner.Unset[source]

Bases: object

Helper class representing a non-set diff element.

evennia.prototypes.spawner.flatten_prototype(prototype, validate=False)[source]

Produce a ‘flattened’ prototype, where all prototype parents in the inheritance tree have been merged into a final prototype.

Parameters
  • prototype (dict) – Prototype to flatten. Its prototype_parent field will be parsed.

  • validate (bool, optional) – Validate for valid keys etc.

Returns

flattened (dict) – The final, flattened prototype.

evennia.prototypes.spawner.prototype_from_object(obj)[source]

Guess a minimal prototype from an existing object.

Parameters

obj (Object) – An object to analyze.

Returns

prototype (dict) – A prototype estimating the current state of the object.

evennia.prototypes.spawner.prototype_diff(prototype1, prototype2, maxdepth=2, homogenize=False, implicit_keep=False)[source]

A ‘detailed’ diff specifies differences down to individual sub-sections of the prototype, like individual attributes, permissions etc. It is used by the menu to allow a user to customize what should be kept.

Parameters
  • prototype1 (dict) – Original prototype.

  • prototype2 (dict) – Comparison prototype.

  • maxdepth (int, optional) – The maximum depth into the diff we go before treating the elements of iterables as individual entities to compare. This is important since a single attr/tag (for example) are represented by a tuple.

  • homogenize (bool, optional) – Auto-homogenize both prototypes for the best comparison. This is most useful for displaying.

  • implicit_keep (bool, optional) – If set, the resulting diff will assume KEEP unless the new prototype explicitly change them. That is, if a key exists in prototype1 and not in prototype2, it will not be REMOVEd but set to KEEP instead. This is particularly useful for auto-generated prototypes when updating objects.

Returns

diff (dict)

A structure detailing how to convert prototype1 to prototype2. All

nested structures are dicts with keys matching either the prototype’s matching key or the first element in the tuple describing the prototype value (so for a tag tuple (tagname, category) the second-level key in the diff would be tagname). The the bottom level of the diff consist of tuples (old, new, instruction), where instruction can be one of “REMOVE”, “ADD”, “UPDATE” or “KEEP”.

evennia.prototypes.spawner.flatten_diff(diff)[source]

For spawning, a ‘detailed’ diff is not necessary, rather we just want instructions on how to handle each root key.

Parameters

diff (dict) – Diff produced by prototype_diff and possibly modified by the user. Note that also a pre-flattened diff will come out unchanged by this function.

Returns

flattened_diff (dict)

A flat structure detailing how to operate on each

root component of the prototype.

Notes

The flattened diff has the following possible instructions:

UPDATE, REPLACE, REMOVE

Many of the detailed diff’s values can hold nested structures with their own individual instructions. A detailed diff can have the following instructions:

REMOVE, ADD, UPDATE, KEEP

Here’s how they are translated:
  • All REMOVE -> REMOVE

  • All ADD|UPDATE -> UPDATE

  • All KEEP -> KEEP

  • Mix KEEP, UPDATE, ADD -> UPDATE

  • Mix REMOVE, KEEP, UPDATE, ADD -> REPLACE

evennia.prototypes.spawner.prototype_diff_from_object(prototype, obj, implicit_keep=True)[source]

Get a simple diff for a prototype compared to an object which may or may not already have a prototype (or has one but changed locally). For more complex migratations a manual diff may be needed.

Parameters
  • prototype (dict) – New prototype.

  • obj (Object) – Object to compare prototype against.

Returns

diff (dict) – Mapping for every prototype key: {“keyname”: “REMOVE|UPDATE|KEEP”, …} obj_prototype (dict): The prototype calculated for the given object. The diff is how to

convert this prototype into the new prototype.

implicit_keep (bool, optional): This is usually what one wants for object updating. When

set, this means the prototype diff will assume KEEP on differences between the object-generated prototype and that which is not explicitly set in the new prototype. This means e.g. that even though the object has a location, and the prototype does not specify the location, it will not be unset.

Notes

The diff is on the following form:

{“key”: (old, new, “KEEP|REPLACE|UPDATE|REMOVE”),
“attrs”: {“attrkey”: (old, new, “KEEP|REPLACE|UPDATE|REMOVE”),

“attrkey”: (old, new, “KEEP|REPLACE|UPDATE|REMOVE”), …},

“aliases”: {“aliasname”: (old, new, “KEEP…”, …}, … }

evennia.prototypes.spawner.format_diff(diff, minimal=True)[source]

Reformat a diff for presentation. This is a shortened version of the olc _format_diff_text_and_options without the options.

Parameters
  • diff (dict) – A diff as produced by prototype_diff.

  • minimal (bool, optional) – Only show changes (remove KEEPs)

Returns

texts (str) – The formatted text.

evennia.prototypes.spawner.batch_update_objects_with_prototype(prototype, diff=None, objects=None, exact=False)[source]

Update existing objects with the latest version of the prototype.

Parameters
  • prototype (str or dict) – Either the prototype_key to use or the prototype dict itself.

  • diff (dict, optional) – This a diff structure that describes how to update the protototype. If not given this will be constructed from the first object found.

  • objects (list, optional) – List of objects to update. If not given, query for these objects using the prototype’s prototype_key.

  • exact (bool, optional) – By default (False), keys not explicitly in the prototype will not be applied to the object, but will be retained as-is. This is usually what is expected - for example, one usually do not want to remove the object’s location even if it’s not set in the prototype. With exact=True, all un-specified properties of the objects will be removed if they exist. This will lead to a more accurate 1:1 correlation between the object and the prototype but is usually impractical.

Returns

changed (int) – The number of objects that had changes applied to them.

evennia.prototypes.spawner.batch_create_object(*objparams)[source]

This is a cut-down version of the create_object() function, optimized for speed. It does NOT check and convert various input so make sure the spawned Typeclass works before using this!

Parameters

objsparams (tuple) –

Each paremter tuple will create one object instance using the parameters within. The parameters should be given in the following order:

  • create_kwargs (dict): For use as new_obj = ObjectDB(**create_kwargs).

  • permissions (str): Permission string used with new_obj.batch_add(permission).

  • lockstring (str): Lockstring used with new_obj.locks.add(lockstring).

  • aliases (list): A list of alias strings for

    adding with new_object.aliases.batch_add(*aliases).

  • nattributes (list): list of tuples (key, value) to be loop-added to

    add with new_obj.nattributes.add(*tuple).

  • attributes (list): list of tuples (key, value[,category[,lockstring]]) for

    adding with new_obj.attributes.batch_add(*attributes).

  • tags (list): list of tuples (key, category) for adding

    with new_obj.tags.batch_add(*tags).

  • execs (list): Code strings to execute together with the creation
    of each object. They will be executed with evennia and obj

    (the newly created object) available in the namespace. Execution will happend after all other properties have been assigned and is intended for calling custom handlers etc.

Returns

objects (list) – A list of created objects

Notes

The exec list will execute arbitrary python code so don’t allow this to be available to unprivileged users!

evennia.prototypes.spawner.spawn(*prototypes, **kwargs)[source]

Spawn a number of prototyped objects.

Parameters

prototypes (str or dict) – Each argument should either be a prototype_key (will be used to find the prototype) or a full prototype dictionary. These will be batched-spawned as one object each.

Keyword Arguments
  • prototype_modules (str or list) – A python-path to a prototype module, or a list of such paths. These will be used to build the global protparents dictionary accessible by the input prototypes. If not given, it will instead look for modules defined by settings.PROTOTYPE_MODULES.

  • prototype_parents (dict) – A dictionary holding a custom prototype-parent dictionary. Will overload same-named prototypes from prototype_modules.

  • return_parents (bool) – Return a dict of the entire prototype-parent tree available to this prototype (no object creation happens). This is a merged result between the globally found protparents and whatever custom prototype_parents are given to this function.

  • only_validate (bool) – Only run validation of prototype/parents (no object creation) and return the create-kwargs.

Returns

object (Object, dict or list)

Spawned object(s). If only_validate is given, return

a list of the creation kwargs to build the object(s) without actually creating it. If return_parents is set, instead return dict of prototype parents.