Update prototype example module

This commit is contained in:
Griatch 2020-09-06 13:09:43 +02:00
parent b086e95e19
commit c051d15f5c
3 changed files with 104 additions and 52 deletions

View file

@ -2,40 +2,56 @@
Prototypes
A prototype is a simple way to create individualized instances of a
given `Typeclass`. For example, you might have a Sword typeclass that
implements everything a Sword would need to do. The only difference
between different individual Swords would be their key, description
and some Attributes. The Prototype system allows to create a range of
such Swords with only minor variations. Prototypes can also inherit
and combine together to form entire hierarchies (such as giving all
Sabres and all Broadswords some common properties). Note that bigger
variations, such as custom commands or functionality belong in a
hierarchy of typeclasses instead.
given typeclass. It is dictionary with specific key names.
Example prototypes are read by the `@spawn` command but is also easily
available to use from code via `evennia.spawn` or `evennia.utils.spawner`.
Each prototype should be a dictionary. Use the same name as the
variable to refer to other prototypes.
For example, you might have a Sword typeclass that implements everything a
Sword would need to do. The only difference between different individual Swords
would be their key, description and some Attributes. The Prototype system
allows to create a range of such Swords with only minor variations. Prototypes
can also inherit and combine together to form entire hierarchies (such as
giving all Sabres and all Broadswords some common properties). Note that bigger
variations, such as custom commands or functionality belong in a hierarchy of
typeclasses instead.
A prototype can either be a dictionary placed into a global variable in a
python module (a 'module-prototype') or stored in the database as a dict on a
special Script (a db-prototype). The former can be created just by adding dicts
to modules Evennia looks at for prototypes, the latter is easiest created
in-game via the `olc` command/menu.
Prototypes are read and used to create new objects with the `spawn` command
or directly via `evennia.spawn` or the full path `evennia.prototypes.spawner.spawn`.
A prototype dictionary have the following keywords:
Possible keywords are:
prototype_parent - string pointing to parent prototype of this structure.
key - string, the main object identifier.
typeclass - string, if not set, will use `settings.BASE_OBJECT_TYPECLASS`.
location - this should be a valid object or #dbref.
home - valid object or #dbref.
destination - only valid for exits (object or dbref).
- `prototype_key` - the name of the prototype. This is required for db-prototypes,
for module-prototypes, the global variable name of the dict is used instead
- `prototype_parent` - string pointing to parent prototype if any. Prototype inherits
in a similar way as classes, with children overriding values in their partents.
- `key` - string, the main object identifier.
- `typeclass` - string, if not set, will use `settings.BASE_OBJECT_TYPECLASS`.
- `location` - this should be a valid object or #dbref.
- `home` - valid object or #dbref.
- `destination` - only valid for exits (object or #dbref).
- `permissions` - string or list of permission strings.
- `locks` - a lock-string to use for the spawned object.
- `aliases` - string or list of strings.
- `attrs` - Attributes, expressed as a list of tuples on the form `(attrname, value)`,
`(attrname, value, category)`, or `(attrname, value, category, locks)`. If using one
of the shorter forms, defaults are used for the rest.
- `tags` - Tags, as a list of tuples `(tag,)`, `(tag, category)` or `(tag, category, data)`.
- Any other keywords are interpreted as Attributes with no category or lock.
These will internally be added to `attrs` (eqivalent to `(attrname, value)`.
permissions - string or list of permission strings.
locks - a lock-string.
aliases - string or list of strings.
ndb_<name> - value of a nattribute (the "ndb_" part is ignored).
any other keywords are interpreted as Attributes and their values.
See the `@spawn` command and `evennia.utils.spawner` for more info.
See the `spawn` command and `evennia.prototypes.spawner.spawn` for more info.
"""
## example of module-based prototypes using
## the variable name as `prototype_key` and
## simple Attributes
# from random import randint
#
# GOBLIN = {
@ -43,7 +59,8 @@ See the `@spawn` command and `evennia.utils.spawner` for more info.
# "health": lambda: randint(20,30),
# "resists": ["cold", "poison"],
# "attacks": ["fists"],
# "weaknesses": ["fire", "light"]
# "weaknesses": ["fire", "light"],
# "tags": = [("greenskin", "monster"), ("humanoid", "monster")]
# }
#
# GOBLIN_WIZARD = {

View file

@ -592,7 +592,7 @@ def validate_prototype(
protparent = protparents.get(protstring)
if not protparent:
_flags["errors"].append(
"Prototype {}'s prototype_parent '{}' was not found.".format((protkey, protstring))
"Prototype {}'s prototype_parent '{}' was not found.".format(protkey, protstring)
)
if id(prototype) in _flags["visited"]:
_flags["errors"].append(

View file

@ -29,6 +29,7 @@ caller.msg() construct every time the page is updated.
"""
from django.conf import settings
from django.db.models.query import QuerySet
from django.core.paginator import Paginator
from evennia import Command, CmdSet
from evennia.commands import cmdhandler
from evennia.utils.utils import make_iter, inherits_from, justify
@ -131,7 +132,7 @@ class EvMore(object):
def __init__(
self,
caller,
text,
inp,
always_page=False,
session=None,
justify=False,
@ -143,28 +144,28 @@ class EvMore(object):
):
"""
Initialization of the text handler.
Initialization of the inp handler.
Args:
caller (Object or Account): Entity reading the text.
text (str, EvTable or iterator): The text or data to put under paging.
inp (str, EvTable, Paginator or iterator): The text or data to put under paging.
- If a string, paginage normally. If this text contains
one or more `\f` format symbol, automatic pagination and justification
are force-disabled and page-breaks will only happen after each `\f`.
- If `EvTable`, the EvTable will be paginated with the same
setting on each page if it is too long. The table
decorations will be considered in the size of the page.
- Otherwise `text` is converted to an iterator, where each step is
- Otherwise `inp` is converted to an iterator, where each step is
expected to be a line in the final display. Each line
will be run through `iter_callable`.
always_page (bool, optional): If `False`, the
pager will only kick in if `text` is too big
pager will only kick in if `inp` is too big
to fit the screen.
session (Session, optional): If given, this session will be used
to determine the screen width and will receive all output.
justify (bool, optional): If set, auto-justify long lines. This must be turned
off for fixed-width or formatted output, like tables. It's force-disabled
if `text` is an EvTable.
if `inp` is an EvTable.
justify_kwargs (dict, optional): Keywords for the justifiy function. Used only
if `justify` is True. If this is not set, default arguments will be used.
exit_on_lastpage (bool, optional): If reaching the last page without the
@ -230,31 +231,51 @@ class EvMore(object):
# always limit number of chars to 10 000 per page
self.height = min(10000 // max(1, self.width), height)
if inherits_from(text, "evennia.utils.evtable.EvTable"):
# an EvTable
self.init_evtable(text)
elif isinstance(text, QuerySet):
# a queryset
self.init_queryset(text)
elif not isinstance(text, str):
# anything else not a str
self.init_iterable(text)
elif "\f" in text:
# string with \f line-break markers in it
self.init_f_str(text)
else:
# a string
self.init_str(text)
# does initial parsing of input
self.parse_input(inp)
# kick things into gear
self.start()
# page formatter
# Hooks for customizing input handling and formatting (use if overriding this class)
def parse_input(self, inp):
"""
Parse the input to figure out the size of the data, how many pages it
consist of and pick the correct paginator mechanism. Override this if
you want to support a new type of input.
Each initializer should set self._paginator and optionally self._page_formatter
for properly handling the input data.
"""
if inherits_from(inp, "evennia.utils.evtable.EvTable"):
# an EvTable
self.init_evtable(inp)
elif isinstance(inp, QuerySet):
# a queryset
self.init_queryset(inp)
elif isinstance(inp, Paginator):
self.init_django_paginator(inp)
elif not isinstance(inp, str):
# anything else not a str
self.init_iterable(inp)
elif "\f" in inp:
# string with \f line-break markers in it
self.init_f_str(inp)
else:
# a string
self.init_str(inp)
def format_page(self, page):
"""
Page formatter. Uses the page_formatter callable by default.
This allows to easier override the class if needed.
Args:
page (any): A piece of data representing one page to display. This must
be poss
Returns:
"""
return self._page_formatter(page)
@ -269,7 +290,13 @@ class EvMore(object):
Paginate by slice. This is done with an eye on memory efficiency (usually for
querysets); to avoid fetching all objects at the same time.
"""
return self._data[pageno * self.height : pageno * self.height + self.height]
return self._data[pageno * self.height: pageno * self.height + self.height]
def paginator_django(self, pageno):
"""
Paginate using the django queryset Paginator API. Note that his is indexed from 1.
"""
return self._data.page(pageno + 1)
# inits for different input types
@ -292,6 +319,14 @@ class EvMore(object):
self._data = qs
self._paginator = self.paginator_slice
def init_django_paginator(self, pages):
"""
The input is a django Paginator object.
"""
self._npages = pages.num_pages
self._data = pages
self._paginator = self.paginator_django
def init_iterable(self, inp):
"""The input is something other than a string - convert to iterable of strings"""
inp = make_iter(inp)