Updated ReST documentation.
This commit is contained in:
parent
d885ef6ab3
commit
b15d1fa683
8 changed files with 518 additions and 61 deletions
|
|
@ -6,6 +6,7 @@ Alphabetical page index
|
||||||
:titlesonly:
|
:titlesonly:
|
||||||
|
|
||||||
wiki/AddingCommandTutorial
|
wiki/AddingCommandTutorial
|
||||||
|
wiki/AddingObjectTypeclassTutorial
|
||||||
wiki/AdminDocs
|
wiki/AdminDocs
|
||||||
wiki/ApacheConfig
|
wiki/ApacheConfig
|
||||||
wiki/AsyncProcess
|
wiki/AsyncProcess
|
||||||
|
|
@ -17,6 +18,7 @@ Alphabetical page index
|
||||||
wiki/BuilderDocs
|
wiki/BuilderDocs
|
||||||
wiki/BuildingPermissions
|
wiki/BuildingPermissions
|
||||||
wiki/BuildingQuickstart
|
wiki/BuildingQuickstart
|
||||||
|
wiki/Caches
|
||||||
wiki/ChoosingAnSQLServer
|
wiki/ChoosingAnSQLServer
|
||||||
wiki/CodingIntroduction
|
wiki/CodingIntroduction
|
||||||
wiki/CodingUtils
|
wiki/CodingUtils
|
||||||
|
|
|
||||||
178
docs/sphinx/source/wiki/AddingObjectTypeclassTutorial.rst
Normal file
178
docs/sphinx/source/wiki/AddingObjectTypeclassTutorial.rst
Normal file
|
|
@ -0,0 +1,178 @@
|
||||||
|
Creating your own object classes
|
||||||
|
================================
|
||||||
|
|
||||||
|
Evennia comes with a few very basic classes of in-game entities:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
Object
|
||||||
|
|
|
||||||
|
Character
|
||||||
|
Room
|
||||||
|
Exit
|
||||||
|
|
||||||
|
So the more specific object-types are just children of the basic
|
||||||
|
``Object`` class (technically these are all
|
||||||
|
`Typeclasses <Typeclassed.html>`_ entities, but for this tutorial, just
|
||||||
|
treat them as normal Python classes).
|
||||||
|
|
||||||
|
For your own game you will most likely want to expand on these very
|
||||||
|
simple beginnings. It's normal to want your Characters to have various
|
||||||
|
attributes. Maybe Rooms should hold extra information or even *all*
|
||||||
|
Objects in your game should have properties not included in basic
|
||||||
|
Evennia.
|
||||||
|
|
||||||
|
First a brief overview of how Evennia handles its object classes. The
|
||||||
|
default classes are defined under ``src/objects/objects.py``. You can
|
||||||
|
look at them there or you can bring up a Python prompt and interactively
|
||||||
|
examine ``ev.Object``, ``ev.Room`` etc.
|
||||||
|
|
||||||
|
You will create your own object classes in ``game/gamesrc/objects``. You
|
||||||
|
should normally inherit from the default classes (normal Python class
|
||||||
|
inheritance) and go from there. Once you have a working new class you
|
||||||
|
can immediately start to create objects in-game inheriting from that
|
||||||
|
class.
|
||||||
|
|
||||||
|
If you want to change the *default* object classes, there is one more
|
||||||
|
step. Evennia's default commands and internal creation mechanisms look
|
||||||
|
at a range of variables in your ``settings.py`` file to determine which
|
||||||
|
are the "default" classes. These defaults are used by the vanilla
|
||||||
|
creation commands if you don't specify the typeclass specifically. They
|
||||||
|
are also used as a fallback by Evennia if there are errors in other
|
||||||
|
typeclasses, so make sure that your new default class is bug-free.
|
||||||
|
|
||||||
|
The following sections spells this out more explicitly.
|
||||||
|
|
||||||
|
Create a new Typeclass
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
This is the simplest case. Say you want to create a new "Heavy" object
|
||||||
|
that characters should not have the ability to pick up.
|
||||||
|
|
||||||
|
#. Go to ``game/gamesrc/objects/``. It should already contain a
|
||||||
|
directory ``examples/``.
|
||||||
|
#. Create a new module here, named ``heavy.py``. Alternatively you can
|
||||||
|
copy ``examples/object.py`` up one level and rename that file to
|
||||||
|
``heavy.py`` instead - you will then have a template to start from.
|
||||||
|
#. Code away in the ``heavy.py`` module, implementing the chair
|
||||||
|
functionality. See `Objects <Objects.html>`_ for more details and the
|
||||||
|
example class below. Let's call the typeclass simply ``Heavy``.
|
||||||
|
#. Once you are done, log into the game with a build-capable account and
|
||||||
|
do ``@create/drop rock:heavy.Heavy`` to drop a new heavy "rock"
|
||||||
|
object in your location. Note that you have to log in as a
|
||||||
|
non-superuser (i.e. not as User #1) when trying to get the rock in
|
||||||
|
order to see its heavy effects.
|
||||||
|
|
||||||
|
That's it. Below is a ``Heavy`` Typeclass that you could try. Note that
|
||||||
|
the `lock <Locks.html>`_ and `Attribute <Attribute.html>`_ here set in
|
||||||
|
the typeclass could just as well have been set using commands in-game,
|
||||||
|
so this is a *very* simple example.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# file game/gamesrc/objects/heavy.py
|
||||||
|
from ev import Object
|
||||||
|
|
||||||
|
class Heavy(Object):
|
||||||
|
"Heavy object"
|
||||||
|
at_object_creation(self):
|
||||||
|
"Called whenever a new object is created"
|
||||||
|
# lock the object down by default
|
||||||
|
self.locks.add("get:false()")
|
||||||
|
# the default "get" command looks for this Attribute in order
|
||||||
|
# return a customized error message (we just happen to know
|
||||||
|
# this, you'd have to look at the code of the 'get' command to
|
||||||
|
# find out).
|
||||||
|
self.db.get_err_msg = "This is too heavy for you to pick up."
|
||||||
|
|
||||||
|
Change Default Rooms, Exits, Character Typeclass
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
This is only slightly more complex than creating any other Typeclass. In
|
||||||
|
fact it only includes one extra step - telling Evennia to use the new
|
||||||
|
default.
|
||||||
|
|
||||||
|
Let's say we want to change Rooms to use our new typeclass ``MyRoom``.
|
||||||
|
|
||||||
|
#. Create a new module in ``game/gamesrc/objects/myroom.py`` and code
|
||||||
|
your ``MyRoom`` typeclass as described in the previous section. Make
|
||||||
|
sure to test it by digging a few rooms of this class (e.g.
|
||||||
|
``@dig Hall:myroom.MyRoom``).
|
||||||
|
#. Once you are sure the new class works as it should, edit
|
||||||
|
``game/settings.py`` and add
|
||||||
|
``BASE_ROOM_TYPECLASS="game.gamesrc.objects.myroom.MyRoom"``.
|
||||||
|
#. Reload Evennia.
|
||||||
|
|
||||||
|
For example the ``@dig`` and ``@tunnel`` commands will henceforth use
|
||||||
|
this new default when digging new rooms whenever you don't give a
|
||||||
|
typeclass explicitly. For the other sub-types, change
|
||||||
|
``BASE_CHARACTER_TYPECLASS`` (used by character creation commands) and
|
||||||
|
``BASE_EXIT_TYPECLASS`` (used by ``@dig``/``@tunnel`` etc) respectively.
|
||||||
|
|
||||||
|
Change the default Object Typeclass
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
Changing the root ``Object`` class works identically to changing the
|
||||||
|
``Character``, ``Room`` or ``Exit`` typeclass. After having created your
|
||||||
|
new typeclass, set ``settings.BASE_EXIT_TYPECLASS`` to point to your new
|
||||||
|
class. Let's say you call your new default ``Object`` class
|
||||||
|
``MyObject``.
|
||||||
|
|
||||||
|
There however one important further thing to remember: ``Characters``,
|
||||||
|
``Rooms`` and ``Exits`` will still inherit from the *old* ``Object`` at
|
||||||
|
this point (not ``MyObject``). This is by design - depending on your
|
||||||
|
type of game, you may not need some or all of these subclasses to
|
||||||
|
inherit any of the new stuff you put in ``MyObject``.
|
||||||
|
|
||||||
|
If you do want that however, you need to also overload these subclasses.
|
||||||
|
For each of the ``Character``, ``Room`` and ``Exit`` you want to
|
||||||
|
customize, do the following:
|
||||||
|
|
||||||
|
#. Create a new module in ``game/gamesrc/``, e.g. ``mycharacter.py``
|
||||||
|
etc. A good flexible solution for overloading only parts of the
|
||||||
|
default is to make inheriting classes *multi-inherited* (see below).
|
||||||
|
As a place-holder you can make the class empty for now (just put
|
||||||
|
``pass`` in it).
|
||||||
|
#. In your ``settings.py`` file, add and define
|
||||||
|
``BASE_CHARACTER_TYPECLASS``, ``BASE_ROOM_TYPECLASS`` and
|
||||||
|
``BASE_EXIT_TYPECLASS`` to point to your new typeclasses.
|
||||||
|
#. Reload Evennia.
|
||||||
|
|
||||||
|
This will give you maximum flexibility with creating and expanding your
|
||||||
|
own types of rooms, characters and exit objects (or not). Below is an
|
||||||
|
example of a new ``myroom.py``:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# file gamesrc/objects/myroom.py
|
||||||
|
from ev import Object
|
||||||
|
from gamesrc.objects.myobject import MyObject
|
||||||
|
# we use multi-inheritance, this will primarily use MyObject,
|
||||||
|
# falling back to the default Object for things MyObject do
|
||||||
|
# not overload
|
||||||
|
class MyRoom(MyObject, Object):
|
||||||
|
"My own expandable room class"
|
||||||
|
pass
|
||||||
|
|
||||||
|
Notes
|
||||||
|
=====
|
||||||
|
|
||||||
|
All above examples puts each class in its own module. This makes it easy
|
||||||
|
to find, but it is really up to you how you organize things. There is
|
||||||
|
nothing stopping you from putting all base classes into one module, for
|
||||||
|
example.
|
||||||
|
|
||||||
|
Also remember that Python may dynamically rename module classes as they
|
||||||
|
are imported. So if you feel it annoying to have to refer to your new
|
||||||
|
default as ``MyObject`` all the time, you can also import them to
|
||||||
|
another name like in the below example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from ev import Object as BaseObject
|
||||||
|
from gamesrc.objects.myobject import MyObject as Object
|
||||||
|
class MyRoom(Object, BaseObject):
|
||||||
|
[...]
|
||||||
|
|
||||||
|
This doesn't actually change the meaning of the code, but might make the
|
||||||
|
relationships clearer inside a module.
|
||||||
|
|
@ -161,10 +161,17 @@ situations though.
|
||||||
What types of data can I save in an Attribute?
|
What types of data can I save in an Attribute?
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
If you store a single object (that is, not an iterable list of objects),
|
Evennia uses the ``pickle`` module to serialize Attribute data into the
|
||||||
you can practically store any Python object that can be
|
database. So if you store a single object (that is, not an iterable list
|
||||||
`pickled <http://docs.python.org/library/pickle.html>`_. Evennia uses
|
of objects), you can practically store any Python object that can be
|
||||||
the ``pickle`` module to serialize Attribute data into the database.
|
`pickled <http://docs.python.org/library/pickle.html>`_.
|
||||||
|
|
||||||
|
If you store many objects however, you can only store them using normal
|
||||||
|
Python structures (i.e. in either a *tuple*, *list*, *dictionary* or
|
||||||
|
*set*). All other iterables (such as custom containers) are converted to
|
||||||
|
*lists* by the Attribute (see next section for the reason for this).
|
||||||
|
Since you can nest dictionaries, sets, lists and tuples together in any
|
||||||
|
combination, this is usually not much of a limitation.
|
||||||
|
|
||||||
There is one notable type of object that cannot be pickled - and that is
|
There is one notable type of object that cannot be pickled - and that is
|
||||||
a Django database object. These will instead be stored as a wrapper
|
a Django database object. These will instead be stored as a wrapper
|
||||||
|
|
@ -177,19 +184,12 @@ recursively traverse all iterables to make sure all database objects in
|
||||||
them are stored safely. So for efficiency, it can be a good idea to
|
them are stored safely. So for efficiency, it can be a good idea to
|
||||||
avoid deeply nested lists with objects if you can.
|
avoid deeply nested lists with objects if you can.
|
||||||
|
|
||||||
To store several objects, you may only use python *lists*,
|
|
||||||
*dictionaries* or *tuples* to store them. If you try to save any other
|
|
||||||
form of iterable (like a ``set`` or a home-made class), the Attribute
|
|
||||||
will convert, store and retrieve it as a list instead. Since you can
|
|
||||||
nest dictionaries, lists and tuples together in any combination, this is
|
|
||||||
usually not a limitation you need to worry about.
|
|
||||||
|
|
||||||
*Note that you could fool the safety check if you for example created
|
*Note that you could fool the safety check if you for example created
|
||||||
custom, non-iterable classes and stored database objects in them. So to
|
custom, non-iterable classes and stored database objects in them. So to
|
||||||
make this clear - saving such an object is **not supported** and will
|
make this clear - saving such an object is **not supported** and will
|
||||||
probably make your game unstable. Store your database objects using
|
probably make your game unstable. Store your database objects using
|
||||||
lists, tuples, dictionaries or a combination of the three and you should
|
lists, tuples, dictionaries, sets or a combination of the four and you
|
||||||
be fine.*
|
should be fine.*
|
||||||
|
|
||||||
Examples of valid attribute data:
|
Examples of valid attribute data:
|
||||||
|
|
||||||
|
|
@ -232,13 +232,13 @@ Example of non-supported save:
|
||||||
Retrieving Mutable objects
|
Retrieving Mutable objects
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
||||||
A side effect of the way Evennia stores Attributes is that Python Lists
|
A side effect of the way Evennia stores Attributes is that Python Lists,
|
||||||
and Dictionaries (only) are handled by custom objects called PackedLists
|
Dictionaries and Sets are handled by custom objects called PackedLists,
|
||||||
and PackedDicts. These behave just like normal lists and dicts except
|
PackedDicts and PackedSets. These behave just like normal lists and
|
||||||
they have the special property that they save to the database whenever
|
dicts except they have the special property that they save to the
|
||||||
new data gets assigned to them. This allows you to do things like
|
database whenever new data gets assigned to them. This allows you to do
|
||||||
``self.db.mylist[4]`` = val without having to extract the mylist
|
things like ``self.db.mylist[4]`` = val without having to extract the
|
||||||
Attribute into a temporary variable first.
|
mylist Attribute into a temporary variable first.
|
||||||
|
|
||||||
There is however an important thing to remember. If you retrieve this
|
There is however an important thing to remember. If you retrieve this
|
||||||
data into another variable, e.g. ``mylist2 = obj.db.mylist``, your new
|
data into another variable, e.g. ``mylist2 = obj.db.mylist``, your new
|
||||||
|
|
@ -287,9 +287,92 @@ stop any changes to the structure from updating the database.
|
||||||
# iterable is a tuple, so we can edit the internal list as we want
|
# iterable is a tuple, so we can edit the internal list as we want
|
||||||
# without affecting the database.
|
# without affecting the database.
|
||||||
|
|
||||||
Notes
|
Locking and checking Attributes
|
||||||
-----
|
-------------------------------
|
||||||
|
|
||||||
|
Attributes are normally not locked down by default, but you can easily
|
||||||
|
change that for individual Attributes (like those that may be
|
||||||
|
game-sensitive in games with user-level building).
|
||||||
|
|
||||||
|
First you need to set a *lock string* on your Attribute. Lock strings
|
||||||
|
are specified `here <Locks.html>`_. The relevant lock types are
|
||||||
|
|
||||||
|
- *attrread* - limits who may read the value of the Attribute
|
||||||
|
- *attredit* - limits who may set/change this Attribute
|
||||||
|
|
||||||
|
You cannot use e.g. ``obj.db.attrname`` handler to modify Attribute
|
||||||
|
objects (such as setting a lock on them - you will only get the
|
||||||
|
Attribute *value* that way, not the actual Attribute *object*. You get
|
||||||
|
the latter with ``get_attribute_obj`` (see next section) which allows
|
||||||
|
you to set the lock something like this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
obj.get_attribute_obj.locks.add("attread:all();attredit:perm(Wizards)")
|
||||||
|
|
||||||
|
A lock is no good if nothing checks it -- and by default Evennia does
|
||||||
|
not check locks on Attributes. You have to add a check to your
|
||||||
|
commands/code wherever it fits (such as before setting an Attribute).
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# in some command code where we want to limit
|
||||||
|
# setting of a given attribute name on an object
|
||||||
|
attr = obj.get_attribute_obj(attrname, default=None)
|
||||||
|
if not (attr and attr.locks.check(caller, 'attredit', default=True)):
|
||||||
|
caller.msg("You cannot edit that Attribute!")
|
||||||
|
return
|
||||||
|
# edit the Attribute here
|
||||||
|
|
||||||
|
Note that in this example this lock check will default to ``True`` if no
|
||||||
|
lock was defined on the Attribute (which is the case by default). You
|
||||||
|
can set this to False if you know all your Attributes always check
|
||||||
|
access in all situations. If you want some special control over what the
|
||||||
|
default Attribute access is (such as allowing everyone to view, but
|
||||||
|
never allowing anyone to edit unless explicitly allowing it with a
|
||||||
|
lock), you can use the ``secure_attr`` method on Typeclassed objects
|
||||||
|
like this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
obj.secure_attr(caller, attrname, value=None,
|
||||||
|
delete=False,
|
||||||
|
default_access_read=True,
|
||||||
|
default_access_edit=False,
|
||||||
|
default_access_create=True)
|
||||||
|
|
||||||
|
The secure\_attr will try to retrieve the attribute value of an existing
|
||||||
|
Attribute if the ``value`` keyword is not set and create/set/delete it
|
||||||
|
otherwise. The *default\_access* keywords specify what should be the
|
||||||
|
default policy for each operation if no appropriate lock string is set
|
||||||
|
on the Attribute.
|
||||||
|
|
||||||
|
Other ways to access Attributes
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
|
Normally ``db`` is all you need. But there there are also several other
|
||||||
|
ways to access information about Attributes, some of which cannot be
|
||||||
|
replicated by ``db``. These are available on all Typeclassed objects:
|
||||||
|
|
||||||
|
- ``has_attribute(attrname)`` - checks if the object has an attribute
|
||||||
|
with the given name. This is equivalent to doing ``obj.db.attrname``.
|
||||||
|
- ``set_attribute(attrname, value)`` - equivalent to
|
||||||
|
``obj.db.attrname = value``.
|
||||||
|
- ``get_attribute(attrname)`` - returns the attribute value. Equivalent
|
||||||
|
to ``obj.db.attrname``.
|
||||||
|
- ``get_attribute_raise(attrname)`` - returns the attribute value, but
|
||||||
|
instead of returning ``None`` if no such attribute is found, this
|
||||||
|
method raises ``AttributeError``.
|
||||||
|
- ``get_attribute_obj(attrname)`` - returns the attribute *object*
|
||||||
|
itself rather than the value stored in it.
|
||||||
|
- ``del_attribute(attrname)`` - equivalent to ``del obj.db.attrname``.
|
||||||
|
Quietly fails if ``attrname`` is not found.
|
||||||
|
- ``del_attribute_raise(attrname)`` - deletes attribute, raising
|
||||||
|
``AttributeError`` if no matching Attribute is found.
|
||||||
|
- ``get_all_attributes`` - equivalent to ``obj.db.all``
|
||||||
|
- ``attr(attrname, value=None, delete=False)`` - this is a convenience
|
||||||
|
function for getting, setting and deleting Attributes. It's
|
||||||
|
recommended to use ``db`` instead.
|
||||||
|
- ``secure_attr(...)`` - lock-checking version of ``attr``. See example
|
||||||
|
in previous section.
|
||||||
|
|
||||||
There are several other ways to assign Attributes to be found on the
|
|
||||||
typeclassed objects, all being more 'low-level' underpinnings to
|
|
||||||
``db``/``ndb``. Read their descriptions in the respective modules.
|
|
||||||
|
|
|
||||||
169
docs/sphinx/source/wiki/Caches.rst
Normal file
169
docs/sphinx/source/wiki/Caches.rst
Normal file
|
|
@ -0,0 +1,169 @@
|
||||||
|
Caches
|
||||||
|
======
|
||||||
|
|
||||||
|
*Note: This is an advanced topic. You might want to skip it on a first
|
||||||
|
read-through.*
|
||||||
|
|
||||||
|
Evennia is a fully persistent system, which means that it will store
|
||||||
|
things in the database whenever its state changes. Since accessing the
|
||||||
|
database i comparably expensive, Evennia uses an extensive *caching*
|
||||||
|
scheme. Caching normally means that once data is read from the database,
|
||||||
|
it is stored in memory for quick retrieval henceforth. Only when data
|
||||||
|
changes will the database be accessed again (and the cache updated).
|
||||||
|
|
||||||
|
With a few exceptions, caching are primarily motivated by speed and to
|
||||||
|
minimize bottlenecks found by profiling the server. Some systems must
|
||||||
|
access certain pieces of data often, and going through the django API
|
||||||
|
over and over builds up. Depending on operation, individual speedups of
|
||||||
|
hundreds of times can be achieved by clever caching.
|
||||||
|
|
||||||
|
The price for extended caching is memory consumption and added
|
||||||
|
complexity. This page tries to explain the various cache strategies in
|
||||||
|
place. Most users should not have to worry about them, but if you ever
|
||||||
|
try to "bang the metal" with Evennia, you should know what you are
|
||||||
|
seeing.
|
||||||
|
|
||||||
|
The default ``@server`` command will give a brief listing of the memory
|
||||||
|
usage of most relevant caches.
|
||||||
|
|
||||||
|
Idmapper
|
||||||
|
--------
|
||||||
|
|
||||||
|
Evennia's django object model is extended by *idmapper* functionality.
|
||||||
|
The idmapper is an external third-party system that sits in
|
||||||
|
``src/utils/idmapper``. The idmapper is an on-demand memory mapper for
|
||||||
|
all database models in the game. This means that a given database object
|
||||||
|
is represented by the same memory area whenever it is accessed. This may
|
||||||
|
sound trivial but it is not - in plain Django there is no such
|
||||||
|
guarantee. Doing something like ``objdb.test = "Test"`` (were objdb is a
|
||||||
|
django model instance) would be unsafe and most likely the ``test``
|
||||||
|
variable would be lost next time the model is retrieved from the
|
||||||
|
database. As Evennia ties `Typeclasses <Typeclasses.html>`_ to django
|
||||||
|
models, this would be a catastophy.
|
||||||
|
|
||||||
|
Idmapper is originally a memory saver for django websites. In the case
|
||||||
|
of a website, object access is brief and fleeting - not so for us. So we
|
||||||
|
have extended idmapper to never loose its reference to a stored object
|
||||||
|
(not doing this was the cause of a very long-standing, very hard-to-find
|
||||||
|
bug).
|
||||||
|
|
||||||
|
Idmapper is an on-demand cache, meaning that it will only cache objects
|
||||||
|
that are actually accessed. Whereas it is possible to clean the idmapper
|
||||||
|
cache via on-model methods, this does not necessarily mean its memory
|
||||||
|
will be freed - this depends on any lingering references in the system
|
||||||
|
(this is how Python's reference counting works). If you ever need to
|
||||||
|
clean the idmapper cache, the safest way is therefore a soft-reload of
|
||||||
|
the server (via e.g. the ``@reload`` command).
|
||||||
|
|
||||||
|
Most developers will not need to care with the idmapper cache - it just
|
||||||
|
makes models work intuitively. It is visible mostly in that all database
|
||||||
|
models in Evennia inherits from
|
||||||
|
``src.utils.idmapper.models.SharedMemoryModel``.
|
||||||
|
|
||||||
|
On-object variable cache
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
All database fields on all objects in Evennia are cached by use of
|
||||||
|
`Python
|
||||||
|
properties <http://docs.python.org/library/functions.html#property>`_.
|
||||||
|
So when you do ``name = obj.key``, you are actually *not* directly
|
||||||
|
accessing a database field "key" on the object. What you are doing is
|
||||||
|
actually to access a handler. This handler looks for hidden variable
|
||||||
|
named ``_cached_db_key``. If that can be found, it is what is returned.
|
||||||
|
If not, the actual database field, named ``db_key`` are accessed. The
|
||||||
|
result is returned and cached for next time.
|
||||||
|
|
||||||
|
The naming scheme is consistent, so a given property ``obj.foo`` is a
|
||||||
|
handler with a cache named ``obj._cached_db_foo`` and a database field
|
||||||
|
``obj.db_key.`` The handler methods for the property are always named
|
||||||
|
``obj.foo_get()``, ``obj.foo_set()`` and ``obj.foo_del()`` (all are not
|
||||||
|
always needed).
|
||||||
|
|
||||||
|
Apart from caching, property handlers also serves another function -
|
||||||
|
they hide away Django administration. So doing ``obj.key = "Peter"``
|
||||||
|
will not only assign (and cache) the string "Peter" in the database
|
||||||
|
field ``obj.db_key``, it will also call ``obj.save()`` for you in order
|
||||||
|
to update the database.
|
||||||
|
|
||||||
|
Hiding away the model fields presents one complication for developers,
|
||||||
|
and that is searching using normal django methods. Basically, if you
|
||||||
|
search using e.g. the standard django ``filter`` method, you must search
|
||||||
|
for ``db_key``, not ``key``. Only the former is known by django, the
|
||||||
|
latter will give an invalid-field error. If you use Evennia's own search
|
||||||
|
methods you don't need to worry about this, they look for the right
|
||||||
|
things behind the scenes for you.
|
||||||
|
|
||||||
|
Mutable variable caches
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Some object properties may appear mutable - that is, they return lists.
|
||||||
|
One such example is the ``permissions`` property. This is however not
|
||||||
|
actually a list - it's just a handler that *returns* and *accepts*
|
||||||
|
lists. ``db_permissions`` is actually stored as a comma-separated
|
||||||
|
string. The uptake of this is that you cannot do list operations on the
|
||||||
|
handler. So ``obj.permissions.append('Immortals')`` will not work.
|
||||||
|
Rather, you will have to do such operations on what is returned. Like
|
||||||
|
this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
perms = obj.permissions # this returns a list!
|
||||||
|
perms.append("Immortals")
|
||||||
|
obj.permissions = perms # overwrites with new list
|
||||||
|
|
||||||
|
Content cache
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
A special case of on-object caching is the *content* cache. Finding the
|
||||||
|
"contents" of a particular location turns out to be a very common and
|
||||||
|
pretty expensive operation. Whenever a person moves, says something or
|
||||||
|
does other things, "everyone else" in a given location must be informed.
|
||||||
|
This means a database search for which objects share the location.
|
||||||
|
|
||||||
|
``obj.contents`` is a convenient container that at every moment contains
|
||||||
|
a cached list of all objects "inside" that particular object. It is
|
||||||
|
updated by the ``location`` property. So ``obj1.location = obj2`` will
|
||||||
|
update ``obj2.contents`` on the fly to contain ``obj1``. It will also
|
||||||
|
remove ``obj1`` from the ``contents`` list of its previous location.
|
||||||
|
Testing shows that when moving from one room to another, finding and
|
||||||
|
messaging everyone in the room took up as much as *25%* of the total
|
||||||
|
computer time needed for the operation. After caching ``contents``,
|
||||||
|
messaging now takes up *0.25%* instead ...
|
||||||
|
|
||||||
|
The contents cache should be used at all times. The main thing to
|
||||||
|
remember is that if you were to somehow bypass the ``location`` handler
|
||||||
|
(such as by setting the ``db_location`` field manually), you will bring
|
||||||
|
the cache and database out of sync until you reload the server.
|
||||||
|
|
||||||
|
Typeclass cache
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
All typeclasses are cached on the database model. This allows for quick
|
||||||
|
access to the typeclass through ``dbobj.typeclass``. Behind the scenes
|
||||||
|
this operation will import the typeclass definition from a path stored
|
||||||
|
in ``db_typeclass_path`` (available via the property handler
|
||||||
|
``typeclass_path``). All checks and eventual debug messages will be
|
||||||
|
handled, and the result cached.
|
||||||
|
|
||||||
|
The only exception to the caching is if the typeclass module had some
|
||||||
|
sort of syntax error or other show-stopping bug. The default typeclass
|
||||||
|
(as defined in ``settings``) will then be loaded instead. The error will
|
||||||
|
be reported and *no* caching will take place. This is in order to keep
|
||||||
|
reloading the typeclass also next try, until it is fixed.
|
||||||
|
|
||||||
|
On-object Attribute cache
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
`Attribute <Attributes.html>`_ lookups are cached by use of hidden
|
||||||
|
dictionaries on all `Typeclassed <Typeclasses.html>`_ objects - this
|
||||||
|
removes the necessity for subsequent database look-ups in order to
|
||||||
|
retrieve attributes. Both ``db`` and ``ndn`` work the same way in this
|
||||||
|
regard.
|
||||||
|
|
||||||
|
Attribute value cache
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Each Attribute object also caches the values stored in it. Whenever
|
||||||
|
retrieving an attribute value, it is also cached for future accesses. In
|
||||||
|
effect this means that (after the first time) accessing an attribute is
|
||||||
|
equivalent to accessing any normal property.
|
||||||
|
|
@ -27,7 +27,7 @@ defined on.
|
||||||
DefaultCmdset and available in the game.
|
DefaultCmdset and available in the game.
|
||||||
|
|
||||||
The full set of available commands (all three sub-sets above) currently
|
The full set of available commands (all three sub-sets above) currently
|
||||||
contains 85 commands in 6 categories. More information about how
|
contains 86 commands in 6 categories. More information about how
|
||||||
commands work can be found in the `Command <Commands.html>`_
|
commands work can be found in the `Command <Commands.html>`_
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
|
|
@ -666,7 +666,7 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
|
||||||
~~~~~
|
~~~~~
|
||||||
|
|
||||||
- ``key`` = ``@home``
|
- ``key`` = ``@home``
|
||||||
- ``aliases`` = ``<None>``
|
- ``aliases`` = ``@sethome``
|
||||||
- `locks <Locks.html>`_ = ``cmd:perm(@home) or perm(Builders)``
|
- `locks <Locks.html>`_ = ``cmd:perm(@home) or perm(Builders)``
|
||||||
- `help\_category <HelpSystem.html>`_ = ``Building``
|
- `help\_category <HelpSystem.html>`_ = ``Building``
|
||||||
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
|
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
|
||||||
|
|
@ -910,19 +910,29 @@ module <https://code.google.com/p/evennia/source/browse/src/commands/default/bui
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
teleport
|
teleport object to another location
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@tel/switch [<object> =] <location>
|
@tel/switch [<object> =] <target location>
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
@tel Limbo
|
||||||
|
@tel/quiet box Limbo
|
||||||
|
@tel/tonone box
|
||||||
|
|
||||||
Switches:
|
Switches:
|
||||||
quiet - don't echo leave/arrive messages to the source/target
|
quiet - don't echo leave/arrive messages to the source/target
|
||||||
locations for the move.
|
locations for the move.
|
||||||
intoexit - if target is an exit, teleport INTO
|
intoexit - if target is an exit, teleport INTO
|
||||||
the exit object instead of to its destination
|
the exit object instead of to its destination
|
||||||
|
tonone - if set, teleport the object to a None-location. If this
|
||||||
|
switch is set, <target location> is ignored.
|
||||||
|
Note that the only way to retrieve
|
||||||
|
an object from a None location is by direct #dbref
|
||||||
|
reference.
|
||||||
|
|
||||||
Teleports an object or yourself somewhere.
|
Teleports an object somewhere. If no object is given, you yourself
|
||||||
|
is teleported to the target location.
|
||||||
|
|
||||||
@tunnel
|
@tunnel
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
@ -1487,6 +1497,29 @@ General
|
||||||
`Link to Python
|
`Link to Python
|
||||||
module <https://code.google.com/p/evennia/source/browse/src/commands/default/general.py>`_
|
module <https://code.google.com/p/evennia/source/browse/src/commands/default/general.py>`_
|
||||||
|
|
||||||
|
@color
|
||||||
|
~~~~~~
|
||||||
|
|
||||||
|
- ``key`` = ``@color``
|
||||||
|
- ``aliases`` = ``<None>``
|
||||||
|
- `locks <Locks.html>`_ = ``cmd:all()``
|
||||||
|
- `help\_category <HelpSystem.html>`_ = ``General``
|
||||||
|
- [`HelpSystem <HelpSystem.html>`_\ #Auto-help\_system Auto-help]
|
||||||
|
(``__doc__ string``) =
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
testing colors
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
@color ansi|xterm256
|
||||||
|
|
||||||
|
Print a color map along with in-mud color codes, while testing what is supported in your client.
|
||||||
|
Choices are 16-color ansi (supported in most muds) or the 256-color xterm256 standard.
|
||||||
|
No checking is done to determine your client supports color - if not you will
|
||||||
|
see rubbish appear.
|
||||||
|
|
||||||
|
|
||||||
@encoding (OOC command)
|
@encoding (OOC command)
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,33 @@
|
||||||
Evennia Licence FAQ
|
Evennia Licence FAQ
|
||||||
===================
|
===================
|
||||||
|
|
||||||
Evennia is licensed under the very friendly *Modified Clarified Artistic
|
Evennia is licensed under the very friendly BSD License. You can find
|
||||||
License*. You can find the license as ``LICENCE`` in the Evennia root
|
the license as ``LICENCE.txt`` in the Evennia root directory. You can
|
||||||
directory. You can also read the full license file
|
also read the full license file
|
||||||
`here <http://code.google.com/p/evennia/source/browse/LICENSE.txt>`_.
|
`here <http://code.google.com/p/evennia/source/browse/LICENSE.txt>`_.
|
||||||
|
|
||||||
You should read the full license text to know what it says exactly, but
|
|
||||||
here are some answers to common questions.
|
|
||||||
|
|
||||||
Q: When creating a game using Evennia, what does the licence permit me to do with it?
|
Q: When creating a game using Evennia, what does the licence permit me to do with it?
|
||||||
-------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------
|
||||||
|
|
||||||
**A:** It's your own game world to do with as you please! To summarize,
|
**A:** It's your own game world to do with as you please! Keep it to
|
||||||
a MUD world you create using Evennia (i.e. the files you create in
|
yourself or re-distribute it under any license of your choice - or sell
|
||||||
``/game/``) falls under **§6** of the license (it's a sort of
|
it and become filthy rich for all we care.
|
||||||
"library"). So your game world and all its contents belongs to you (as
|
|
||||||
it should be). Keep it to yourself or re-distribute it under any license
|
|
||||||
of your choice - or sell it and become filthy rich for all we care.
|
|
||||||
|
|
||||||
Q: I have modified Evennia itself, what does the license say about that?
|
Q: I have modified Evennia itself, what does the license say about that?
|
||||||
------------------------------------------------------------------------
|
------------------------------------------------------------------------
|
||||||
|
|
||||||
**A:** The Evennia package itself (i.e. the stuff you download from us)
|
**A:** The License allows you to do whatever you want with your modified
|
||||||
is referred to as "The Package, Standard version" in the license.
|
Evennia, including re-distributing or selling it, as long as you include
|
||||||
|
our license and copyright info in the ``LICENSE.txt`` file along with
|
||||||
|
your distribution.
|
||||||
|
|
||||||
- If you just fixed a typo or bug, that falls under **§2** - that is,
|
... Of course, if you add bug fixes or add some new snazzy features we
|
||||||
you don't *have* to do anything to appease the license. Regardless,
|
still *softly nudge* you to make those changes available upstream so
|
||||||
we'd of course appreciate it if you submitted bugs/fixes to us so
|
they could be added to the core Evennia package. The license don't
|
||||||
Evennia becomes more complete!.
|
require you to do it, but that doesn't mean we can't still greatly
|
||||||
- If you made bigger modifications or added new features to the server,
|
appreciate it if you do!
|
||||||
that's also ok, but falls under **§3** - you must make a clear note
|
|
||||||
of the changes you did and put those changes into public domain
|
|
||||||
(since it's then no longer a "Standard version"). You could also
|
|
||||||
contact the Evennia developers to make separate arrangements ... but
|
|
||||||
of course, if you plan to add new features to the server, the easiest
|
|
||||||
way to do so is to simply become an Evennia developer!
|
|
||||||
|
|
||||||
Q: Can I re-distribute the Evennia server package along with my custom game implementation?
|
Q: Can I re-distribute the Evennia server package along with my custom game implementation?
|
||||||
-------------------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
**A:** Sure. This is covered in **§4** - just package the "Standard
|
**A:** Sure. As long as the text in LICENSE.txt is included.
|
||||||
version" (that is, the one you download from us) with your game files.
|
|
||||||
Also make sure to include the original license and disclaimers and note
|
|
||||||
where users may get "plain" Evennia should they want to download it of
|
|
||||||
their own.
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,10 @@ Third-party Evennia links
|
||||||
|
|
||||||
- `Avaloria <http://code.google.com/p/avaloria/>`_ (MUD under
|
- `Avaloria <http://code.google.com/p/avaloria/>`_ (MUD under
|
||||||
development, using Evennia)
|
development, using Evennia)
|
||||||
|
- `Winter's Oasis <http://blog.wintersoasis.com/>`_ (MUCK under
|
||||||
|
development, using Evennia)
|
||||||
|
- `Latitude <https://github.com/dbenoy/latitude>`_ (MUCK under
|
||||||
|
development, using Evennia)
|
||||||
|
|
||||||
General mud/game development ideas and discussions
|
General mud/game development ideas and discussions
|
||||||
--------------------------------------------------
|
--------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,8 @@ Central <DeveloperCentral.html>`_.
|
||||||
|
|
||||||
- `Tutorial: Adding a new default
|
- `Tutorial: Adding a new default
|
||||||
command <AddingCommandTutorial.html>`_
|
command <AddingCommandTutorial.html>`_
|
||||||
|
- `Tutorial: Adding new Object typeclasses and
|
||||||
|
defaults <AddingObjectTypeclassTutorial.html>`_
|
||||||
|
|
||||||
Implementation ideas
|
Implementation ideas
|
||||||
--------------------
|
--------------------
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue