mirror of
https://github.com/evennia/evennia.git
synced 2026-04-05 07:27:17 +02:00
Updated ReST docs.
This commit is contained in:
parent
3aeec1298a
commit
64a30c655d
29 changed files with 1391 additions and 1186 deletions
|
|
@ -20,9 +20,9 @@ new additional commands of your own.
|
|||
but in this example we assume you don't.
|
||||
#. Edit ``game/settings.py``, adding the following line:
|
||||
|
||||
``CMDSET_DEFAULT="game.gamesrc.commands.cmdset.DefaultCmdSet"``
|
||||
``CMDSET_CHARACTER="game.gamesrc.commands.cmdset.CharacterCmdSet"``
|
||||
|
||||
Evennia will now look for default commands in the ``DefaultCmdSet``
|
||||
Evennia will now look for default commands in the ``CharacterCmdSet``
|
||||
class of your newly copied module. You only need to do this once.
|
||||
|
||||
Creating a custom command
|
||||
|
|
@ -45,6 +45,7 @@ Creating a custom command
|
|||
|
||||
# file game/gamesrc/commands/command.py
|
||||
#[...]
|
||||
from ev import default_cmds
|
||||
class CmdEcho(default_cmds.MuxCommand):
|
||||
"""
|
||||
Simple command example
|
||||
|
|
@ -65,30 +66,30 @@ Creating a custom command
|
|||
else:
|
||||
self.caller.msg("You gave the string: '%s'" % self.args)
|
||||
|
||||
Adding the Command to a Cmdset
|
||||
------------------------------
|
||||
Adding the Command to a default Cmdset
|
||||
--------------------------------------
|
||||
|
||||
The command is not available to use until it is part of a Command Set.
|
||||
In this example we will go the easiest route and add it to the default
|
||||
command set we already prepared.
|
||||
Character command set we already prepared.
|
||||
|
||||
#. Edit your recently copied ``game/gamesrc/commands/cmdset.py``
|
||||
#. In this copied module you will find the ``DefaultCmdSet`` class
|
||||
already imported and prepared for you. Import your new command module
|
||||
here with ``from game.gamesrc.commands.command import CmdEcho``.
|
||||
#. Add a line ``self.add(CmdEcho())`` to ``DefaultCmdSet``, in the
|
||||
#. Add a line ``self.add(CmdEcho())`` to ``CharacterCmdSet``, in the
|
||||
``at_cmdset_creation`` method (the template tells you where). This is
|
||||
approximately how it should look at this point:
|
||||
|
||||
::
|
||||
|
||||
# file gamesrc/commands/examples/cmdset.py
|
||||
# file gamesrc/commands/cmdset.py
|
||||
#[...]
|
||||
from game.gamesrc.commands.command import CmdEcho
|
||||
#[...]
|
||||
class DefaultCmdSet(default_cmds.DefaultCmdSet):
|
||||
class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
||||
|
||||
key = DefaultMUX
|
||||
key = DefaultCharacter
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
|
||||
|
|
@ -115,3 +116,73 @@ old one - it will overload the default one. Just remember that you must
|
|||
|
||||
See `Commands <Commands.html>`_ for many more details and possibilities
|
||||
when defining Commands and using Cmdsets in various ways.
|
||||
|
||||
Adding the command to specific object types
|
||||
-------------------------------------------
|
||||
|
||||
You do not *have* to expand the ``CharacterCmdSet``, it's just the
|
||||
easiest example. The cmdset system is very generic. You can create your
|
||||
own cmdsets and add them to objects as you please (just how to control
|
||||
how they merge with the existing set is described in detail in the
|
||||
[Commands#Command\_Sets Command Set documentation]).
|
||||
|
||||
::
|
||||
|
||||
# file gamesrc/commands/cmdset.py
|
||||
#[...]
|
||||
from game.gamesrc.commands.command import CmdEcho
|
||||
#[...]
|
||||
class MyCmdSet(default_cmds.CmdSet):
|
||||
|
||||
key = MyCmdSet
|
||||
|
||||
def at_cmdset_creation(self):
|
||||
self.add(CmdEcho())
|
||||
|
||||
Now you just need to add this to an object. To test things (as
|
||||
superuser) you can do
|
||||
|
||||
::
|
||||
|
||||
@py self.cmdset.add("cmdset.MyCmdSet")
|
||||
|
||||
This will add the cmdset (and the echo command) to yourself so you can
|
||||
test it. This is not permanent though, if you do a ``@reload`` the
|
||||
merger will be gone. You *can* add the ``permanent=True`` keyword to the
|
||||
``cmdset.add`` call. This will however only make the new merged cmdset
|
||||
permanent on that single object, not on other objects of that type,
|
||||
which is usually what you want.
|
||||
|
||||
To make sure all new created objects get your new merged set, put the
|
||||
``cmdset.add`` call in your custom `Typeclass <Typeclasses.html>`_'
|
||||
``at_object_creation`` method:
|
||||
|
||||
::
|
||||
|
||||
from ev import Object
|
||||
class MyObject(Object):
|
||||
|
||||
def at_object_creation(self):
|
||||
"called when the object is first created"
|
||||
self.cmdset.add("cmdset.MyCmdSet")
|
||||
|
||||
|
||||
All new objects of this typeclass will now start with this cmdset.
|
||||
|
||||
*Note:* An important caveat with this is that ``at_object_creation`` is
|
||||
only called *once*, when the object is first created. This means that if
|
||||
you already have existing objects in your databases using that
|
||||
typeclass, they will not have been initiated the same way. There are
|
||||
many ways to update them; since it's a one-time update you can usually
|
||||
just simply loop through them. As superuser, try the following:
|
||||
|
||||
::
|
||||
|
||||
@py [obj.cmdset.add("cmdset.MyCmdSet") for obj in
|
||||
ev.managers.typeclass_search("game.gamesrc.objects.objects.mytypeclass.MyTypeClass"]
|
||||
|
||||
This goes through all objects in your database having the right
|
||||
typeclass, adding the new cmdset to each. The good news is that you only
|
||||
have to do this if you want to post-add cmdsets. If you just want to add
|
||||
a new command, you can just add that command to the cmdset's
|
||||
``at_cmdset_creation`` and @reload.
|
||||
|
|
|
|||
|
|
@ -66,16 +66,19 @@ that characters should not have the ability to pick up.
|
|||
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.
|
||||
so this is a *very* simple example. We also add a custom
|
||||
[Commands#Command\_Sets Command set] to it.
|
||||
|
||||
::
|
||||
|
||||
# file game/gamesrc/objects/heavy.py
|
||||
from ev import Object
|
||||
# let's assume we defined our own cmdset earlier
|
||||
from game.gamesrc.commands.mycmdsets import HeavySet
|
||||
|
||||
class Heavy(Object):
|
||||
"Heavy object"
|
||||
at_object_creation(self):
|
||||
def at_object_creation(self):
|
||||
"Called whenever a new object is created"
|
||||
# lock the object down by default
|
||||
self.locks.add("get:false()")
|
||||
|
|
@ -84,6 +87,8 @@ so this is a *very* simple example.
|
|||
# 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."
|
||||
# expand the default cmdset with your own custom set (defined elsewhere)
|
||||
self.cmdset.add(HeavySet)
|
||||
|
||||
Change Default Rooms, Exits, Character Typeclass
|
||||
------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ Installation and Early Life
|
|||
Customizing the server
|
||||
----------------------
|
||||
|
||||
- `Changing the Settings <SettingsDefault.html>`_
|
||||
- `Change Evennia's language <Internationalization.html>`_
|
||||
- `Apache webserver configuration <ApacheConfig.html>`_ (optional)
|
||||
- `Changing text encodings used by the server <TextEncodings.html>`_
|
||||
|
|
@ -34,4 +35,5 @@ Working with Evennia
|
|||
|
||||
- `Setting up your work environment with version
|
||||
control <VersionControl.html>`_
|
||||
- `First steps coding with Evennia <FirstStepsCoding.html>`_
|
||||
|
||||
|
|
|
|||
|
|
@ -62,19 +62,84 @@ will for example delete an ``Attribute``:
|
|||
|
||||
del rose.db.has_thorns
|
||||
|
||||
Both ``db`` and ``ndb`` defaults to offering an ``all`` property on
|
||||
Both ``db`` and ``ndb`` defaults to offering an ``all()`` method on
|
||||
themselves. This returns all associated attributes or non-persistent
|
||||
properties.
|
||||
|
||||
::
|
||||
|
||||
list_of_all_rose_attributes = rose.db.all
|
||||
list_of_all_rose_ndb_attrs = rose.ndb.all
|
||||
list_of_all_rose_attributes = rose.db.all()
|
||||
list_of_all_rose_ndb_attrs = rose.ndb.all()
|
||||
|
||||
If you use ``all`` as the name of an attribute, this will be used
|
||||
instead. Later deleting your custom ``all`` will return the default
|
||||
behaviour.
|
||||
|
||||
Properties of Attributes
|
||||
------------------------
|
||||
|
||||
An Attribute object is stored in the database. It has the following
|
||||
properties:
|
||||
|
||||
- ``key`` - the name of the Attribute. When doing e.g.
|
||||
``obj.db.attrname = value``, this property is set to ``attrname``.
|
||||
- ``value`` - this is the value of the Attribute. This value can be
|
||||
anything which can be pickled - objects, lists, numbers or what have
|
||||
you (see
|
||||
[Attributes#What\_types\_of\_data\_can\_I\_save\_in\_an\_Attribute
|
||||
this section] for more info). In the example
|
||||
``obj.db.attrname = value``, the ``value`` is stored here.
|
||||
- ``category`` - this is an optional property that is set to None for
|
||||
most Attributes. Setting this allows to use Attributes for different
|
||||
functionality. This is usually not needed unless you want to use
|
||||
Attributes for very different functionality (`Nicks <Nicks.html>`_ is
|
||||
an example of using Attributes in this way). To modify this property
|
||||
you need to use the [Attributes#The\_Attribute\_Handler Attribute
|
||||
Handler].
|
||||
- ``strvalue`` - this is a separate value field that only accepts
|
||||
strings. This severaly limits the data possible to store, but allows
|
||||
for easier database lookups. This property is usually not used except
|
||||
when re-using Attributes for some other purpose
|
||||
(`Nicks <Nicks.html>`_ use it). It is only accessible via the
|
||||
[Attributes#The\_Attribute\_Handler Attribute Handler].
|
||||
|
||||
Non-database attributes have no equivalence to category nor strvalue.
|
||||
|
||||
The Attribute Handler
|
||||
---------------------
|
||||
|
||||
The Attribute handler is what is used under the hood to manage the
|
||||
Attributes on an object. It is accessible as ``obj.attributes``. For
|
||||
most operations, the ``db`` or ``ndb`` wrappers are enough. But
|
||||
sometimes you won't know the attribute name beforehand or you need to
|
||||
manipulate your Attributes in more detail. The Attribute handler has the
|
||||
following methods (the argument lists are mostly shortened; you can see
|
||||
the full call signatures in ``src.typeclasses.models``):
|
||||
|
||||
- ``attributes.has(...)`` - this checks if the object has an Attribute
|
||||
with this key. This is equivalent to doing ``obj.db.key``.
|
||||
- ``get(...)`` - this retrieves the given Attribute. Normally the
|
||||
``value`` property of the Attribute is returned, but the method takes
|
||||
keywords for returning the Attribute object itself. By supplying an
|
||||
``accessing_object`` oto the call one can also make sure to check
|
||||
permissions before modifying anything.
|
||||
- ``add(...)`` - this adds a new Attribute to the object. An optional
|
||||
`lockstring <Locks.html>`_ can be supplied here to restrict future
|
||||
access and also the call itself may be checked against locks.
|
||||
- ``remove(...)`` - Remove the given Attribute. This can optionally be
|
||||
made to check for permission before performing the deletion.
|
||||
- ``clear(...)`` - removes all Attributes from object.
|
||||
- ``all(...)`` - returns all Attributes (of the given category)
|
||||
attached to this object.
|
||||
|
||||
See [Attributes#Locking\_and\_checking\_Attributes this section] for
|
||||
more about locking down Attribute access and editing.
|
||||
|
||||
There is an equivalent ``nattribute`` handler for managing non-database
|
||||
Attributes. This has the same methods but is much simpler since it does
|
||||
not concern itself with category nor strvalue. It also offers no concept
|
||||
of access control.
|
||||
|
||||
Persistent vs non-persistent
|
||||
----------------------------
|
||||
|
||||
|
|
@ -248,15 +313,15 @@ 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:
|
||||
You cannot use the ``db`` handler to modify Attribute object (such as
|
||||
setting a lock on them) - The ``db`` handler will return the Attribute's
|
||||
*value*, not the Attribute object itself. Instead you use
|
||||
``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)")
|
||||
obj.attributes.get("myattr", return_obj=True).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
|
||||
|
|
@ -266,60 +331,12 @@ 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)):
|
||||
attr = obj.attributes.get(attrname, return_obj=True, accessing_obj=caller, default=None, default_access=False)
|
||||
if not attr:
|
||||
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 normal case). 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.
|
||||
|
||||
The same keywords are available to use with ``obj.attributes.set()`` and
|
||||
``obj.attributes.remove()``, those will check for the *attredit* lock
|
||||
type.
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ To temporarily step down from your superuser position you can use the
|
|||
|
||||
::
|
||||
|
||||
@quell
|
||||
> @quell
|
||||
|
||||
This will make you start using the permission of your current
|
||||
`Character <Objects.html>`_ instead of your superuser level. If you
|
||||
|
|
@ -64,19 +64,18 @@ rather short name, let's is give a few aliases.
|
|||
|
||||
::
|
||||
|
||||
> @name box = very large box;box;very;bo;crate
|
||||
> @name box = very large box;box;very;crate
|
||||
|
||||
We now actually renamed the box to *very large box* (and this is what we
|
||||
will see when looking at the room), but we will also recognize it by any
|
||||
of the other names we give - like *crate* or simply *box* as before. We
|
||||
will see when looking at it), but we will also recognize it by any of
|
||||
the other names we give - like *crate* or simply *box* as before. We
|
||||
could have given these aliases directly after the name in the
|
||||
``@create`` command, this is true for all creation commands - you can
|
||||
always tag on a list of ;-separated aliases to the name of your new
|
||||
object. If you had wanted to not change the name itself, but to only add
|
||||
aliases, you could have used the ``@alias`` command.
|
||||
|
||||
We are currently carrying the box, which you can see if you give the
|
||||
command ``inventory`` (or ``i``). Let's drop it.
|
||||
We are currently carrying the box. Let's drop it.
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -118,8 +117,7 @@ box was dropped in the room, then try this:
|
|||
Locks are a rather `big topic <Locks.html>`_, but for now that will do
|
||||
what we want. This will lock the box so noone can lift it. The exception
|
||||
is superusers, they override all locks and will pick it up anyway. Make
|
||||
sure you are using your builder account and not the superuser account
|
||||
and try to get the box now:
|
||||
sure you are quelling your superuser powers and try to get the box now:
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -134,7 +132,7 @@ attributes using the ``@set`` command:
|
|||
|
||||
::
|
||||
|
||||
> @set box/get_err_msg = The box is way too heavy for you to lift.
|
||||
> @set box/get_err_msg = It's way too heavy for you to lift.
|
||||
|
||||
Try to get it now and you should see a nicer error message echoed back
|
||||
to you.
|
||||
|
|
@ -178,7 +176,7 @@ Pushing your buttons
|
|||
|
||||
If we get back to the box we made, there is only so much fun you can do
|
||||
with it at this point. It's just a dumb generic object. If you renamed
|
||||
it ``carpet`` and changed its description noone would be the wiser.
|
||||
it to ``stone`` and changed its description noone would be the wiser.
|
||||
However, with the combined use of custom
|
||||
`Typeclasses <Typeclasses.html>`_, `Scripts <Scripts.html>`_ and
|
||||
object-based `Commands <Commands.html>`_, you could expand it and other
|
||||
|
|
@ -201,7 +199,7 @@ Python except Evennia defaults to looking in ``game/gamesrc/objects/``
|
|||
so you don't have to write the full path every time. There you go - one
|
||||
red button.
|
||||
|
||||
The RedButton is an example object intended to show off many of
|
||||
The RedButton is an example object intended to show off a few of
|
||||
Evennia's features. You will find that the `Scripts <Scripts.html>`_ and
|
||||
`Commands <Commands.html>`_ controlling it are scattered in
|
||||
``examples``-folders all across ``game/gamesrc/``.
|
||||
|
|
@ -210,8 +208,8 @@ If you wait for a while (make sure you dropped it!) the button will
|
|||
blink invitingly. Why don't you try to push it ...? Surely a big red
|
||||
button is meant to be pushed. You know you want to.
|
||||
|
||||
Creating a room called 'house'
|
||||
------------------------------
|
||||
Making yourself a house
|
||||
-----------------------
|
||||
|
||||
The main command for shaping the game world is ``@dig``. For example, if
|
||||
you are standing in Limbo you can dig a route to your new house location
|
||||
|
|
@ -240,8 +238,7 @@ This will create a new room "cliff" with an exit "southwest" leading
|
|||
there and a path "northeast" leading back from the cliff to your current
|
||||
location.
|
||||
|
||||
You can create exits from anywhere at any time using the ``@open``
|
||||
command:
|
||||
You can create new exits from where you are using the ``@open`` command:
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -251,9 +248,9 @@ This opens an exit ``north`` to the previously created room ``house``.
|
|||
|
||||
If you have many rooms named ``house`` you will get a list of matches
|
||||
and have to select which one you want to link to. You can also give its
|
||||
database ref number, which is unique to every object. This can be found
|
||||
with the ``examine`` command or by looking at the latest constructions
|
||||
with ``@objects``.
|
||||
database (#dbref) number, which is unique to every object. This can be
|
||||
found with the ``examine`` command or by looking at the latest
|
||||
constructions with ``@objects``.
|
||||
|
||||
Follow the north exit to your 'house' or ``@teleport`` to it:
|
||||
|
||||
|
|
@ -276,37 +273,46 @@ To manually open an exit back to Limbo (if you didn't do so with the
|
|||
|
||||
(or give limbo's dbref which is #2)
|
||||
|
||||
Finding and manipulating existing objects
|
||||
-----------------------------------------
|
||||
Reshuffling the world
|
||||
---------------------
|
||||
|
||||
To re-point an exit at another room or object, you can use
|
||||
You can find things using the ``@find`` command. Assuming you are back
|
||||
at ``Limbo``, let's teleport the *large box to our house*.
|
||||
|
||||
::
|
||||
|
||||
> @link <room name> = <new_target name>
|
||||
> @teleport box = house
|
||||
very large box is leaving Limbo, heading for house.
|
||||
Teleported very large box -> house.
|
||||
|
||||
To find something, use
|
||||
We can still find the box by using @find:
|
||||
|
||||
::
|
||||
|
||||
> @find <name>
|
||||
> @find box
|
||||
One Match(#1-#8):
|
||||
very large box(#8) - src.objects.objects.Object
|
||||
|
||||
This will return a list of dbrefs that have a similar name.
|
||||
|
||||
To teleport something somewhere, one uses
|
||||
Knowing the #dbref of the box (#8 in this example), you can grab the box
|
||||
and get it back here without actually yourself going to ``house`` first:
|
||||
|
||||
::
|
||||
|
||||
> @teleport <object> = <destination>
|
||||
> @teleport #8 = here
|
||||
|
||||
To destroy something existing, use
|
||||
(You can usually use ``here`` to refer to your current location. To
|
||||
refer to yourself you can use ``self`` or ``me``). The box should now be
|
||||
back in Limbo with you.
|
||||
|
||||
We are getting tired of the box. Let's destroy it.
|
||||
|
||||
::
|
||||
|
||||
> @destroy <object>
|
||||
> @destroy box
|
||||
|
||||
You can destroy many objects in one go by giving a comma-separated list
|
||||
of objects to the command.
|
||||
of objects (or their #dbrefs, if they are not in the same location) to
|
||||
the command.
|
||||
|
||||
Adding a help entry
|
||||
-------------------
|
||||
|
|
@ -322,16 +328,27 @@ command.
|
|||
Adding a World
|
||||
--------------
|
||||
|
||||
Evennia comes with a tutorial world for you to build. To build this you
|
||||
need to log back in as *superuser*. Place yourself in Limbo and do:
|
||||
After this brief introduction to building you may be ready to see a more
|
||||
fleshed-out example. Evennia comes with a tutorial world for you to
|
||||
explore.
|
||||
|
||||
First you need to switch back to *superuser* by using the ``@unquell``
|
||||
command. Next, place yourself in ``Limbo`` and run the following
|
||||
command:
|
||||
|
||||
::
|
||||
|
||||
@batchcommand contrib.tutorial_world.build
|
||||
> @batchcommand contrib.tutorial_world.build
|
||||
|
||||
This will take a while, but you will see a lot of messages as the world
|
||||
is built for you. You will end up with a new exit from Limbo named
|
||||
*tutorial*. See more info about the tutorial world
|
||||
`here <TutorialWorldIntroduction.html>`_. Read
|
||||
``contrib/tutorial_world/build.ev`` to see exactly how it's built, step
|
||||
by step.
|
||||
This will take a while (be patient and don't re-run the command). You
|
||||
will see all the commands used to build the world scroll by as the world
|
||||
is built for you.
|
||||
|
||||
You will end up with a new exit from Limbo named *tutorial*. Apart from
|
||||
being a little solo-adventure in its own right, the tutorial world is a
|
||||
good source for learning Evennia building (and coding).
|
||||
|
||||
Read
|
||||
`contrib/tutorial\_world/build.ev <https://code.google.com/p/evennia/source/browse/contrib/tutorial_world/build.ev>`_
|
||||
to see exactly how it's built, step by step. See also more info about
|
||||
the tutorial world `here <TutorialWorldIntroduction.html>`_.
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ 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
|
||||
makes models work intuitively. It is visible mostly in that many
|
||||
database models in Evennia inherit from
|
||||
``src.utils.idmapper.models.SharedMemoryModel``.
|
||||
|
||||
On-object variable cache
|
||||
|
|
@ -95,24 +95,6 @@ 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
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
|
|
@ -162,6 +144,8 @@ as fast as accessing any normal python property - 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.
|
||||
|
||||
Apart from the lookup, each Attribute object itself caches the values
|
||||
stored in it. Again this means that (after the first time) accessing an
|
||||
attribute is equivalent to accessing any normal Python property.
|
||||
Due to the possibility of storing objects in Attributes, the system
|
||||
cannot cache the value of data stored in the Attribute (this would allow
|
||||
for the system not detecting a stored Object being deleted elsewhere -
|
||||
it would still be accessible from the Attribute). So having to re-access
|
||||
such objects every load does incur a minor speed penalty.
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
*This tutorial requires that you first well understand how
|
||||
`Commands <Commands.html>`_ work.*
|
||||
|
||||
Cooldowns
|
||||
=========
|
||||
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -7,7 +7,9 @@ system. Stock evennia implements a 'MUX-like' system of channels, but
|
|||
there is nothing stopping you from changing things to better suit your
|
||||
taste.
|
||||
|
||||
Comms rely on two main database objects - ``Msg`` and ``Channel``.
|
||||
Comms rely on two main database objects - ``Msg`` and ``Channel``. There
|
||||
is also the ``TempMsg`` which mimics the API of a ``Msg`` but has no
|
||||
connection to the database.
|
||||
|
||||
Msg
|
||||
---
|
||||
|
|
@ -67,10 +69,15 @@ next section).
|
|||
Channels
|
||||
--------
|
||||
|
||||
Channels are `Typeclassed <Typeclass.html>`_ entities, which mean they
|
||||
can be easily extended and their functionality modified. To change which
|
||||
channel typeclass Evennia uses, change
|
||||
settings.BASE\_CHANNEL\_TYPECLASS.
|
||||
|
||||
Channels act as generic distributors of messages. Think of them as
|
||||
"switch boards" redistributing ``Msg`` objects. Internally they hold a
|
||||
list of "listening" objects and any ``Msg`` sent to the channel will be
|
||||
distributed out to all channel listeners. Channels have
|
||||
list of "listening" objects and any ``Msg`` (or ``TempMsg`` sent to the
|
||||
channel will be distributed out to all channel listeners. Channels have
|
||||
`Locks <Locks.html>`_ to limit who may listen and/or send messages
|
||||
through them.
|
||||
|
||||
|
|
@ -92,11 +99,12 @@ methods of channels:
|
|||
|
||||
channel.msg(msgobj, header=None, senders=None, persistent=True)
|
||||
|
||||
The argument ``msgobj`` can be a previously constructed ``Msg`` or
|
||||
``TempMsg`` - in that case all the following keywords are ignored. If
|
||||
``msgobj`` is a string, the other keywords are used for creating a new
|
||||
``Msg`` or ``TempMsg`` on the fly, depending on if ``persistent`` is set
|
||||
or not.
|
||||
The argument ``msgobj`` can be either a string, a previously constructed
|
||||
``Msg`` or a ``TempMsg`` - in the latter cases all the following
|
||||
keywords are ignored. If ``msgobj`` is a string, the other keywords are
|
||||
used for creating a new ``Msg`` or ``TempMsg`` on the fly, depending on
|
||||
if ``persistent`` is set or not. Default is to use ``TempMsg`` for
|
||||
channel communication (i.e. not save everything to the database).
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -108,18 +116,13 @@ or not.
|
|||
# use the Msg object directly, no other keywords are needed
|
||||
mychan.msg(mymsg)
|
||||
|
||||
# create a Msg automatically behind the scenes
|
||||
# Send a non-persistent message to a channel
|
||||
mychan.msg("Hello!", senders=[sender])
|
||||
|
||||
# send a non-persistent TempMsg (note that the senders
|
||||
# keyword can also be used without a list if there is
|
||||
# only one sender)
|
||||
mychan.msg("Hello!", senders=sender, persistent=False)
|
||||
|
||||
# this is a shortcut that always sends a non-persistent TempMsg
|
||||
# also if a full Msg was supplied to it (it also creates TempMsgs
|
||||
# on the fly if given a string).
|
||||
mychan.tempmsg(mymsg)
|
||||
# send a message to list, save it to the database
|
||||
# (note how the senders keyword can also be used
|
||||
# without a list if there is only one sender)
|
||||
mychan.msg("Hello!", senders=sender, persistent=True)
|
||||
|
||||
On a more advanced note, when a player enters something like
|
||||
``ooc Hello!`` (where ``ooc`` is the name/alias of a channel), this is
|
||||
|
|
|
|||
|
|
@ -58,6 +58,12 @@ do this once):
|
|||
|
||||
Once you have an online clone and a local copy of it:
|
||||
|
||||
#. Make sure that you have edited Mercurial's config file (``hgrc``) and
|
||||
under the header ``[ui]`` added the line
|
||||
``username=Yourname <your email>``. This is important for proper
|
||||
crediting and eventual conversions. See the first point of the
|
||||
`Mercurial
|
||||
Quickstart <http://mercurial.selenic.com/wiki/QuickStart>`_.
|
||||
#. Code away on your computer, fixing bugs or whatnot (you can be
|
||||
offline for this). Commit your code to your local clone as you work,
|
||||
as often as you like. There are some suggestions for setting up a
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -26,6 +26,7 @@ General Evennia development information
|
|||
- `Setting up a Mercurial environment for
|
||||
coding <VersionControl.html>`_
|
||||
- `Planning your own Evennia game <GamePlanning.html>`_
|
||||
- `First steps coding Evennia <FirstStepsCoding.html>`_
|
||||
|
||||
Evennia Component Documentation
|
||||
-------------------------------
|
||||
|
|
@ -34,21 +35,25 @@ Evennia Component Documentation
|
|||
|
||||
- `Directory Overview <DirectoryOverview.html>`_
|
||||
- `Portal and Server <PortalAndServer.html>`_
|
||||
- `Session <Session.html>`_
|
||||
- `Commands <Commands.html>`_
|
||||
- `Typeclass system <Typeclasses.html>`_
|
||||
|
||||
- `Objects <Objects.html>`_
|
||||
- `Scripts <Scripts.html>`_
|
||||
- `Players <Players.html>`_
|
||||
- [Communications#Channels Channels]
|
||||
- `Attributes <Attributes.html>`_
|
||||
|
||||
- `Locks and Permissions <Locks.html>`_
|
||||
- `Communications <Communications.html>`_
|
||||
- `Help System <HelpSystem.html>`_
|
||||
- `Nicks <Nicks.html>`_
|
||||
- `Tags <Tags.html>`_
|
||||
- `Sessions and Protocols <SessionProtocols.html>`_
|
||||
- `Caches <Caches.html>`_
|
||||
- `Web features <WebFeatures.html>`_
|
||||
- `Out-of-band communication <OOB.html>`_
|
||||
- `Configuration and module plugins <ServerConf.html>`_
|
||||
|
||||
Programming Evennia
|
||||
|
|
@ -59,6 +64,7 @@ Programming Evennia
|
|||
- `Useful coding utilities <CodingUtils.html>`_
|
||||
- `Running and writing unit tests for Evennia <UnitTesting.html>`_
|
||||
- `Running processes asynchronously <AsyncProcess.html>`_
|
||||
- `Expanding Evennia with new database models <NewModels.html>`_
|
||||
|
||||
Work in Progress - Developer brainstorms and whitepages
|
||||
-------------------------------------------------------
|
||||
|
|
@ -70,6 +76,5 @@ the road.*
|
|||
- `Basic game system implementation <WorkshopDefaultGame.html>`_
|
||||
(inactive)
|
||||
- `Rtclient protocol <Workshop.html>`_ (deprecated)
|
||||
- `Summary of changes <EvenniaDevel.html>`_ of latest version vs old
|
||||
Evennia (implemented in aug2010)
|
||||
- `Change log <EvenniaDevel.html>`_ of big Evennia updates over time
|
||||
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ or features missing, file a bug report or send us a message.
|
|||
players/
|
||||
scripts/
|
||||
server/
|
||||
portal/
|
||||
typeclasses/
|
||||
utils/
|
||||
web/
|
||||
|
|
@ -277,10 +278,10 @@ connection timeouts) are also defined here.
|
|||
~~~~~~~~~~~~~~~
|
||||
|
||||
This directory is the heart of Evennia. It holds the server process
|
||||
itself (started from ``game/evennia.py``), the portal and all `sessions
|
||||
and protocols <SessionProtocols.html>`_ that allow users to connect to
|
||||
the game. It also knows how to store dynamic server info in the
|
||||
database.
|
||||
itself (started from ``game/evennia.py``). Its subfolder ``portal/``
|
||||
holds the portal and all `sessions and
|
||||
protocols <SessionProtocols.html>`_ that allow users to connect to the
|
||||
game.
|
||||
|
||||
\`src/typeclasses/\`
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -17,14 +17,15 @@ Quick start
|
|||
For you who are extremely impatient, here's the gist of getting a
|
||||
vanilla Evennia install running.
|
||||
|
||||
#. *Get the pre-requisites (Python, Django, Twisted and Mercurial)*.
|
||||
#. *Get the pre-requisites (Python, Django, Twisted, South and
|
||||
Mercurial)*.
|
||||
#. *Start a command terminal/dos prompt and change directory to where
|
||||
you want to have your 'evennia' folder appear*.
|
||||
#. ``hg clone https://code.google.com/p/evennia/ evennia``
|
||||
#. *Change directory to evennia/game*.
|
||||
#. ``python manage.py``
|
||||
#. ``python manage.py syncdb``
|
||||
#. ``python manage.py migrate`` (only if using South)
|
||||
#. ``python manage.py migrate``
|
||||
#. ``python evennia.py -i start``
|
||||
|
||||
Evennia should now be running and you can connect to it by pointing a
|
||||
|
|
@ -40,7 +41,7 @@ As far as operating systems go, any system with Python support should
|
|||
work.
|
||||
|
||||
- Linux/Unix
|
||||
- Windows (2000, XP, Vista, Win7)
|
||||
- Windows (2000, XP, Vista, Win7, Win8)
|
||||
- Mac OSX (>=10.5 recommended)
|
||||
|
||||
If you run into problems, or have success running Evennia on another
|
||||
|
|
@ -55,19 +56,19 @@ Evennia:
|
|||
`ActivePython <http://www.activestate.com/activepython/downloads>`_
|
||||
instead.
|
||||
|
||||
- **`Twisted <http://twistedmatrix.com>`_** (v10.0+)
|
||||
- **`Twisted <http://twistedmatrix.com>`_** (v11.0+)
|
||||
|
||||
- `ZopeInterface <http://www.zope.org/Products/ZopeInterface>`_
|
||||
(v3.0+) - usually included in Twisted packages
|
||||
- Windows users might also need
|
||||
`pywin32 <http://sourceforge.net/projects/pywin32>`_.
|
||||
|
||||
- **`Django <http://www.djangoproject.com>`_** (v1.4+)
|
||||
- **`Django <http://www.djangoproject.com>`_** (v1.5+)
|
||||
|
||||
- `PIL <http://www.pythonware.com/products/pil>`_ (Python Image
|
||||
Library) - often distributed with Django.
|
||||
|
||||
- **`South <http://south.aeracode.org/>`_** (v0.7+)
|
||||
- **`South <http://south.aeracode.org/>`_** (v0.8+)
|
||||
|
||||
- South is used to track and apply changes to the database's
|
||||
structure.
|
||||
|
|
@ -145,22 +146,14 @@ Optional:
|
|||
problems compiling the ``PIL`` library on Mac, it's however not
|
||||
strictly required in order to use Django (it's used for images).
|
||||
|
||||
\_Note (June 2012): Some versions of MacOSX does not seem to have
|
||||
a locale setting out of the box, and this causes a traceback
|
||||
during database creation. This is a known upstream bug in Django
|
||||
1.4, described
|
||||
`here <http://code.google.com/p/evennia/wiki/Quirks#Known_upstream_bugs>`_.
|
||||
In the bug comments is also described how to add the locale and
|
||||
circumvent this bug for now. This affects also Unix/Linux systems,
|
||||
but those usually have the locale set out of the box.
|
||||
|
||||
**Windows** users should first and foremost recognize that the Evennia
|
||||
server is run from the command line, something which some might not be
|
||||
familiar with (based on the questions we have received). In the Windows
|
||||
launch menu, just start *All Programs -> Accessories -> command prompt*
|
||||
and you will get the Windows command line interface. There are plenty of
|
||||
online tutorials on using the Windows command line, one example is found
|
||||
`here <http://www.bleepingcomputer.com/tutorials/windows-command-prompt-introduction/>`_.
|
||||
**Windows** users should first and foremost recognize that the
|
||||
Evennia server is run from the command line, something which some
|
||||
might not be familiar with (based on the questions we have
|
||||
received). In the Windows launch menu, just start \_All Programs
|
||||
-> Accessories -> command prompt and you will get the Windows
|
||||
command line interface. There are plenty of online tutorials on
|
||||
using the Windows command line, one example is found
|
||||
`here <http://www.bleepingcomputer.com/tutorials/windows-command-prompt-introduction/>`_.
|
||||
|
||||
Windows users may want to install
|
||||
`ActivePython <http://www.activestate.com/activepython/downloads>`_
|
||||
|
|
@ -169,11 +162,12 @@ one won't let you download any packages without paying for a "Business"
|
|||
license). If ActivePython is installed, you can use
|
||||
`pypm <http://docs.activestate.com/activepython/2.6/pypm.html>`_ in the
|
||||
same manner as ``easy_install``/``pip`` above. This *greatly* simplifies
|
||||
getting started on Windows - that platform defaults to missing many of
|
||||
the sane developer tools that Linux users take for granted.
|
||||
getting started on Windows - this platform defaults to lacking sane
|
||||
developer tools and package management.
|
||||
|
||||
After installing ActivePython you may need to restart the terminal/DOS
|
||||
window to make the pypm command available on the command line:
|
||||
window to make the pypm command available on the command line. Then
|
||||
write:
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -260,24 +254,19 @@ with the standard tables and values:
|
|||
|
||||
python manage.py syncdb
|
||||
|
||||
You should be asked for a superuser username, email, and password. Make
|
||||
**sure** you create a superuser here when asked, this becomes your login
|
||||
name for the superuser account ``#1`` in game. After this you will see a
|
||||
lot of spammy install messages. If all goes well, you're ready to
|
||||
continue to the next step. If not, look at the error messages and
|
||||
double-check your ``settings.py`` file.
|
||||
You will see a lot of spammy install messages. If all goes well, you're
|
||||
ready to continue to the next step. If not, look at the error messages
|
||||
and double-check your ``settings.py`` file.
|
||||
|
||||
If you installed ``South`` for database schema migrations, you will then
|
||||
need to do this:
|
||||
Next you migrate the database to the current revision:
|
||||
|
||||
::
|
||||
|
||||
python manage.py migrate
|
||||
|
||||
This will migrate the server to the latest version. If you don't use
|
||||
``South``, migrations will not be used and your server will already be
|
||||
at the latest version (but your existing database might have to be
|
||||
manually edited to match eventual future schema changes that we do).
|
||||
This can take a while. When we make changes to the database schema in
|
||||
the future (we announce this on the homepage) you just need to re-run
|
||||
this command to have your existing database converted for you.
|
||||
|
||||
Step 3: Starting and Stopping the Server
|
||||
----------------------------------------
|
||||
|
|
@ -289,10 +278,18 @@ and execute ``evennia.py`` like this:
|
|||
|
||||
python evennia.py -i start
|
||||
|
||||
This starts the server and portal. The ``-i`` flag means that the server
|
||||
starts in *interactive mode*, as a foreground process. You will see
|
||||
debug/log messages directly in the terminal window instead of logging
|
||||
them to a file.
|
||||
(The ``-i`` flag means that the server starts in *interactive mode*, as
|
||||
a foreground process. You will see debug/log messages directly in the
|
||||
terminal window instead of logging them to a file.)
|
||||
|
||||
You should be asked to create a superuser. Make **sure** you create a
|
||||
superuser here when asked, this becomes your login name for the
|
||||
superuser (owner) account in game. It will ask for email address and
|
||||
password. The email address does not have to be an existing one.
|
||||
|
||||
After entering the superuser information, the server and portal will
|
||||
start for the first time. Evennia will quickly run some first-time
|
||||
configurations, restart once and then be running.
|
||||
|
||||
To stop Evennia, do:
|
||||
|
||||
|
|
|
|||
|
|
@ -55,10 +55,15 @@ For testing, we choose the *Freenode* network, ``irc.freenode.net``. We
|
|||
will connect to a test channel, let's call it *#myevennia-test* (an IRC
|
||||
channel always begins with ``#``). It's best if you pick an obscure
|
||||
channel name that didn't exist previously - if it didn't exist it will
|
||||
be created for you. *Don't* connect to ``#evennia``, that is Evennia's
|
||||
official chat channel!
|
||||
be created for you. *Don't* connect to ``#evennia`` for testing and
|
||||
debugging, that is Evennia's official chat channel!
|
||||
|
||||
A *port* needed depends on the network. For Freenode this is ``6667``.
|
||||
(By the way, you *are* welcome to connect your game to ``#evennia`` once
|
||||
you have everything working - it can be a good way to get help and
|
||||
ideas. But if you do, please do so with an in-game channel open only to
|
||||
your game admins and developers).
|
||||
|
||||
The *port* needed depends on the network. For Freenode this is ``6667``.
|
||||
|
||||
What will happen is that your Evennia server will connect to this IRC
|
||||
channel as a normal user. This "user" (or "bot") needs a name, which you
|
||||
|
|
|
|||
|
|
@ -40,6 +40,10 @@ Third-party Evennia links
|
|||
- `Latitude <https://github.com/dbenoy/latitude>`_ (MUCK under
|
||||
development, using Evennia)
|
||||
|
||||
- `notimetoplay
|
||||
post <http://notimetoplay.org/2013/08/29/evennia-a-mud-building-toolkit/>`_
|
||||
about Evennia
|
||||
|
||||
General mud/game development ideas and discussions
|
||||
--------------------------------------------------
|
||||
|
||||
|
|
@ -77,7 +81,26 @@ General mud/game development ideas and discussions
|
|||
discussion about rule systems and game balance that could be
|
||||
applicable also for MUDs.
|
||||
|
||||
x
|
||||
Litterature
|
||||
-----------
|
||||
|
||||
- Richard Bartle *Designing Virtual Worlds* (`amazon
|
||||
page <http://www.amazon.com/Designing-Virtual-Worlds-Richard-Bartle/dp/0131018167>`_)
|
||||
- Essential reading for the design of any persistent game world,
|
||||
written by the co-creator of the original game *MUD*. Discusses
|
||||
basically everything you need to think about and more.
|
||||
- Richard Cantillon *An Essay on Economic Theory* (`free
|
||||
pdf <http://mises.org/books/essay_on_economic_theory_cantillon.pdf>`_)
|
||||
- A very good English translation of *Essai sur la Nature du Commerce
|
||||
en Général*, one of the foundations of modern economic theory.
|
||||
Written in 1730 but the translation is annotated and is very easy to
|
||||
follow for a modern reader. Required reading if you think of
|
||||
implementing a sane game economic system.
|
||||
- David M. Beazley *Python Essential Reference (4th ed)* (`amazon
|
||||
page <http://www.amazon.com/Python-Essential-Reference-David-Beazley/dp/0672329786/>`_)
|
||||
- Our recommended book on Python; it not only efficiently summarizes
|
||||
the language but is also an excellent reference to the standard
|
||||
library for more experienced Python coders.
|
||||
|
||||
Frameworks
|
||||
----------
|
||||
|
|
|
|||
|
|
@ -221,6 +221,25 @@ Some useful default lockfuncs (see ``src/locks/lockfuncs.py`` for more):
|
|||
``id/dbref`` but always looks for permissions and dbrefs of
|
||||
*Players*, not on Characters.
|
||||
|
||||
Checking simple strings
|
||||
-----------------------
|
||||
|
||||
Sometimes you don't really need to look up a certain lock, you just want
|
||||
to check a lockstring. A common use is inside Commands, in order to
|
||||
check if a user has a certain permission. The lockhandler has a method
|
||||
``check_lockstring(accessing_obj, lockstring, bypass_superuser=False)``
|
||||
that allows this.
|
||||
|
||||
::
|
||||
|
||||
# inside command definition
|
||||
if not self.caller.locks.check_lockstring(self.caller, "dummy:perm(Wizards)"):
|
||||
self.caller.msg("You must be Wizard or higher to do this!"
|
||||
return
|
||||
|
||||
Note here that the ``access_type`` can be left to a dummy value since
|
||||
this method does not actually do a Lock lookup.
|
||||
|
||||
Default locks
|
||||
-------------
|
||||
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ Coding with nicks
|
|||
|
||||
Nicks are are stored as the ``Nick`` database model and are referred
|
||||
from the normal Evennia `object <Objects.html>`_ through the ``nicks``
|
||||
property. `` nicks`` is a special handler that offers effective error
|
||||
checking, searches and conversion.
|
||||
property - this is known as the NickHandler. The NickHandler offers
|
||||
effective error checking, searches and conversion.
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -87,16 +87,16 @@ checking, searches and conversion.
|
|||
object.nicks.add("greetjack", "tell Jack = Hello pal!")
|
||||
|
||||
# An object nick:
|
||||
object.nicks.add("rose", "The red flower", nick_type="object")
|
||||
obj.nicks.add("rose", "The red flower", nick_type="object")
|
||||
|
||||
# An player nick:
|
||||
object.nicks("tom", "Tommy Hill", nick_type="player")
|
||||
obj.nicks.add("tom", "Tommy Hill", nick_type="player")
|
||||
|
||||
# My own custom nick type (handled by my own game code somehow):
|
||||
object.nicks.add("hood", "The hooded man", nick_type="my_identsystem")
|
||||
obj.nicks.add("hood", "The hooded man", nick_type="my_identsystem")
|
||||
|
||||
# get back the translated nick:
|
||||
full_name = object.nicks.get("rose", nick_type="object")
|
||||
full_name = obj.nicks.get("rose", nick_type="object")
|
||||
|
||||
# delete a previous set nick
|
||||
object.nicks.del("rose", nick_type="object")
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1,11 +1,11 @@
|
|||
Players
|
||||
=======
|
||||
|
||||
All gamers (real people) that opens a game *Session* on Evennia are
|
||||
doing so through an object called *Player*. The Player object has no
|
||||
in-game representation, it represents the account the gamer has on the
|
||||
game. In order to actually get on the game the Player must *puppet* an
|
||||
`Object <Objects.html>`_ (normally a Character).
|
||||
All *gamers* (real people) that opens a game `Session <Session.html>`_
|
||||
on Evennia are doing so through an object called *Player*. The Player
|
||||
object has no in-game representation, it represents the account the
|
||||
gamer has on the game. In order to actually get on the game the Player
|
||||
must *puppet* an `Object <Objects.html>`_ (normally a Character).
|
||||
|
||||
Just how this works depends on the configuration option
|
||||
``MULTISESSION_MODE``. There are three multisession modes, described in
|
||||
|
|
@ -25,7 +25,7 @@ or some of the other protocols Evennia supports.
|
|||
client is doing exactly the same thing as doing so in any other
|
||||
connected client. All sessions will see the same output and e.g.
|
||||
giving the @quit command will kill all sessions.
|
||||
- In mode 2 (right) eeach Player can hold any number of sessions and
|
||||
- In mode 2 (right) each Player can hold any number of sessions and
|
||||
they are kept separate from one another. This allows a single player
|
||||
to puppet any number of Characters and Objects.
|
||||
|
||||
|
|
@ -39,19 +39,18 @@ characters as well as configuration options. Players are
|
|||
`CmdSet <Commands.html>`_ defaulting to the set defined by
|
||||
``settings.CMDSET_PLAYER``.
|
||||
|
||||
If you are logged in into default Evennia under any multisession mode,
|
||||
you can use the ``@ooc`` command to leave your current
|
||||
`Character <Objects.html>`_ and go into OOC mode. You are quite limited
|
||||
in this mode, basically it works like a simple chat program. It acts as
|
||||
a staging area for switching between Characters (if your game supports
|
||||
that) or as a safety mode if your Character gets deleted. . Use ``@ic``
|
||||
attempt to puppet a Character.
|
||||
Logged into default Evennia, you can use the ``@ooc`` command to leave
|
||||
your current `Character <Objects.html>`_ and go into OOC mode. You are
|
||||
quite limited in this mode, basically it works like a simple chat
|
||||
program. It acts as a staging area for switching between Characters (if
|
||||
your game supports that) or as a safety mode if your Character gets
|
||||
deleted. Use ``@ic`` to attempt to puppet a Character.
|
||||
|
||||
Note that the Player object can and often do have a different set of
|
||||
[Locks#Permissions Permissions] from the Character they control.
|
||||
Normally you should put your permissions on the Player level - only if
|
||||
your Player does not have a given permission will the permissions on the
|
||||
Character be checked.
|
||||
Normally you should put your permissions on the Player level - this will
|
||||
overrule permissions set on the Character level (unless ``@quell``-ing
|
||||
is used).
|
||||
|
||||
How to create your own Player types
|
||||
-----------------------------------
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ Evennia Quirks
|
|||
This is a list of various problems or stumbling blocks that people often
|
||||
ask about or report when using (or trying to use) Evennia. These are
|
||||
common stumbling blocks, non-intuitive behaviour and common newbie
|
||||
mistakes when working with Evennia. They are not bugs.
|
||||
mistakes when working with Evennia. They are not Evennia bugs.
|
||||
|
||||
Actual Evennia bugs should be reported in
|
||||
`Issues <https://code.google.com/p/evennia/issues/list>`_.
|
||||
|
|
@ -48,9 +48,10 @@ Web admin to create new Player
|
|||
------------------------------
|
||||
|
||||
If you use the default login system and is trying to use the Web admin
|
||||
to create a new Player account, you need to thread carefully. The
|
||||
default login system *requires* the Player object to already have a
|
||||
connected Character object - there is no character creation screen by
|
||||
to create a new Player account, you need to consider which
|
||||
MULTIPLAYER\_MODE you are in. If you are in MULTIPLAYER\_MODE 0 or 1,
|
||||
the login system expects each Player to also have a Character object
|
||||
named the same as the Player - there is no character creation screen by
|
||||
default. If using the normal mud login screen, a Character with the same
|
||||
name is automatically created and connected to your Player. From the web
|
||||
interface you must do this manually.
|
||||
|
|
@ -62,13 +63,6 @@ property on the Character and the "character" property on the Player to
|
|||
point to each other. You must also set the lockstring of the Character
|
||||
to allow the Player to "puppet" this particular character.
|
||||
|
||||
The default login system is very simple and intended for you to easily
|
||||
get into the game. The more advanced login system in ``contrib/`` along
|
||||
with the example character-creation system does not require such an
|
||||
initial coupling (i.e. you can create the coupling in-game). For your
|
||||
initial experiments, it's easist to create your characters from the
|
||||
normal MUD connection screen instead.
|
||||
|
||||
Mutable attributes and their connection to the database
|
||||
-------------------------------------------------------
|
||||
|
||||
|
|
@ -117,22 +111,4 @@ appreciate getting more input and help.
|
|||
Known upstream bugs
|
||||
===================
|
||||
|
||||
These are known bugs in in the libraries Evennia uses, i.e. things out
|
||||
of our control.
|
||||
|
||||
Error during manage.py syncdb
|
||||
-----------------------------
|
||||
|
||||
This error can be seen using Django 1.4 without a *locale* set. It
|
||||
causes a traceback during the ``manage.py syncdb`` phase, just when
|
||||
trying to create the superuser.
|
||||
|
||||
::
|
||||
|
||||
TypeError: decode() argument 1 must be string, not None
|
||||
|
||||
This opaque error means no locale could be found. Not properly handling
|
||||
this is a bug in Django 1.4 reported
|
||||
`here <https://code.djangoproject.com/ticket/16017>`_. You resolve it by
|
||||
setting your locale (this is a good thing to have in any case). See the
|
||||
comments to that bug report for how to do this.
|
||||
There are no known upstream bugs at this time.
|
||||
|
|
|
|||
|
|
@ -143,10 +143,10 @@ find longer descriptions of these in ``src/scripts/scripts.py``.
|
|||
situations such as reloads. This is also useful for using scripts as
|
||||
state managers. If the method returns ``False``, the script is
|
||||
stopped and cleanly removed.
|
||||
- ``at_start()`` - this is called when the script first starts. For
|
||||
persistent scripts this is at least once ever server startup. Note
|
||||
that this will *always* be called right away, also if ``start_delay``
|
||||
is ``True``.
|
||||
- ``at_start()`` - this is called when the script starts or is
|
||||
unpaused. For persistent scripts this is at least once ever server
|
||||
startup. Note that this will *always* be called right away, also if
|
||||
``start_delay`` is ``True``.
|
||||
- ``at_repeat()`` - this is called every ``interval`` seconds, or not
|
||||
at all. It is called right away at startup, unless ``start_delay`` is
|
||||
``True``, in which case the system will wait ``interval`` seconds
|
||||
|
|
@ -173,10 +173,10 @@ possible to also invoke manually)
|
|||
resumed. This is called automatically when the server reloads. No
|
||||
hooks are called - as far as the script knows, it never stopped -
|
||||
this is a suspension of the script, not a change of state.
|
||||
- ``unpause()`` - resumes a previously paused script. Timers etc are
|
||||
restored to what they were before pause. The server unpauses all
|
||||
paused scripts after a server reload. No hooks are called - as far as
|
||||
the script is concerned, it never stopped running.
|
||||
- ``unpause()`` - resumes a previously paused script. The at\_start()
|
||||
hook will be called to allow it to reclaim its internal state. Timers
|
||||
etc are restored to what they were before pause. The server unpauses
|
||||
all paused scripts after a server reload.
|
||||
- ``time_until_next_repeat()`` - for timed scripts, this returns the
|
||||
time in seconds until it next fires. Returns ``None`` if
|
||||
``interval==0``.
|
||||
|
|
|
|||
|
|
@ -43,11 +43,11 @@ code. The only way to change an Evennia setting is to edit
|
|||
\`game/gamesrc/conf\` directory
|
||||
-------------------------------
|
||||
|
||||
The ``game/gamesrc/conf/`` directory contains module templates for
|
||||
customizing Evennia. Common for all these is that you should *copy* the
|
||||
template up one level (to ``game/gamesrc/conf/``) and edit the copy, not
|
||||
the original. You then need to change your settings file to point the
|
||||
right variable at your new module. Each template header describes
|
||||
The ``game/gamesrc/conf/examples/`` directory contains module templates
|
||||
for customizing Evennia. Common for all these is that you should *copy*
|
||||
the template up one level (to ``game/gamesrc/conf/``) and edit the copy,
|
||||
not the original. You then need to change your settings file to point
|
||||
the right variable at your new module. Each template header describes
|
||||
exactly how to use it and which settings variable needs to be changed
|
||||
for Evennia to be able to locate it.
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,72 @@ MUSH parsers have jumped light years ahead of where they were even seven
|
|||
or eight years ago, they can still stutter under the weight of the more
|
||||
complex systems if not designed properly.
|
||||
|
||||
To further illustrate the lack of readability for building larger
|
||||
systems in softcode, here is another example, PennMush softcode this
|
||||
time, for implementing an "+info" command (it allows you to store pages
|
||||
of extra character info that is later confirmed by admins and can be
|
||||
viewed by other players):
|
||||
|
||||
::
|
||||
|
||||
&INC`SET u(ifo)=@include u(ifo)/INC`TARGET;@include \
|
||||
u(ifo)/INC`FILENAME;@assert strlen(%q<filename>)=@nspemit \
|
||||
%#=announce(INFO)%BERROR: Info file name empty.;@switch/inline \
|
||||
gt(strlen(setr(attr,u(u(ifo)/FUN`FINDFILE,%q<target>,%q<filename>))),0)=1,{@assert \
|
||||
or(isadmin(%#),strmatch(%q<target>,%#))=@nspemit \
|
||||
%#=announce(INFO)%BERROR: You may not change another's Info \
|
||||
files.;@switch/inline \
|
||||
or(getstat(%q<target>/%q<attr>`FLAGS,Hidden),getstat(%q<target>/%q<attr>`FLAGS,Approved))=1,{@assert \
|
||||
isadmin(%#)=@nspemit %#=announce(INFO)%BERROR: That Info File may not \
|
||||
be changed by you.}},0,{@break gt(strlen(%q<filename>),18)=@nspemit \
|
||||
%#=ERROR: Info names are limited to 18 characters or less.;@break \
|
||||
regmatchi(%q<filename>,\\|)=@nspemit %#=ERROR: Pipe symbols are not \
|
||||
allowed in info names.;@break regmatchi(%q<filename>,\/)=@nspemit \
|
||||
%#=ERROR: Slashes symbols are not allowed in info names.;@assert \
|
||||
strlen(%1)=ERROR: Text field empty. To delete an +info file, use \
|
||||
+info/delete.};&[strfirstof(%q<attr>,setr(attr,D`INFOFILE`[nextslot(%q<target>,D`INFOFILE)]))] \
|
||||
%q<target>=%q<filename>;&%q<attr>`CONTENTS %q<target>=%1;th \
|
||||
setstat(%q<target>/%q<attr>`FLAGS,SetBy,%#);th \
|
||||
setstat(%q<target>/%q<attr>`FLAGS,SetOn,secs());@switch/inline \
|
||||
strmatch(%#,%q<target>)=1,{@nspemit %#=announce(INFO)%BYou set your \
|
||||
%q<filename> Info File},{@nspemit %#=announce(INFO)%BYou set \
|
||||
[name(%q<target>)]'s %q<filename> Info File!;@nspemit \
|
||||
%q<target>=announce(INFO)%B%n set your %q<filename> Info File!}
|
||||
|
||||
(Note that the softcode is actually all one line, it was split to be
|
||||
viewable on this wiki). Below is the rough Evennia equivalent
|
||||
functionality as an Evennia command method, written by the same softcode
|
||||
author after a week of learning Evennia:
|
||||
|
||||
::
|
||||
|
||||
def switch_set(self,target,files,rhs,isadmin):
|
||||
if self.caller is not target and not isadmin:
|
||||
self.caller.msg("ERROR: You may not set that person's files.")
|
||||
return
|
||||
if not self.rhs:
|
||||
self.caller.msg("ERROR: No info file contents entered to set.")
|
||||
return
|
||||
for info in files:
|
||||
if not re.match('^[\w-]+$', info.lower().strip()):
|
||||
self.caller.msg("ERROR: File '" + info + \
|
||||
"' could not be set: may only use alphanumeric characters, -, and spaces in info names.")
|
||||
elif self.files.get(info.lower().strip(),{}).get("approved",None) is True:
|
||||
self.caller.msg("ERROR: File '" + info.strip() + "' could not be set: file is approved.")
|
||||
else:
|
||||
self.files[info.lower().strip()] = {"contents":rhs, "setby":self.caller,
|
||||
"seton":"timestamp", "displayname":info.strip()}
|
||||
if target is self.caller:
|
||||
self.caller.msg("Info File '" + info.strip() + "' set!")
|
||||
else:
|
||||
self.caller.msg("Info File '" + info.strip() + "' set!")
|
||||
target.caller.msg(self.caller.key + " set your '" + info.strip() + "' info file!")
|
||||
target.db.infofiles = dict(self.files)
|
||||
return
|
||||
|
||||
The details of the implementation are unimportant, the difference in
|
||||
readability is the main point here.
|
||||
|
||||
Changing Times
|
||||
--------------
|
||||
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ Coding basics
|
|||
More details about coding with Evennia is found in the `Developer
|
||||
Central <DeveloperCentral.html>`_.
|
||||
|
||||
- `First Steps Coding with Evennia <FirstStepsCoding.html>`_ - this is
|
||||
partly duplicated in the following two tutorials using different
|
||||
words.
|
||||
- `Tutorial: Adding a new default
|
||||
command <AddingCommandTutorial.html>`_
|
||||
- `Tutorial: Adding new Object typeclasses and
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -27,23 +27,76 @@ unlimited power to extend the game leveraging the full power of a mature
|
|||
high level programming language. You can find a more elaborate
|
||||
discussion about our take on MUX SoftCode `here <SoftCode.html>`_.
|
||||
|
||||
Documentation policy
|
||||
--------------------
|
||||
|
||||
All the commands in the default command sets have their doc-strings
|
||||
formatted on a similar form:
|
||||
|
||||
::
|
||||
|
||||
"""
|
||||
Short header
|
||||
|
||||
Usage:
|
||||
key[/switches, if any] <mandatory args> [<optional args or types>]
|
||||
|
||||
Switches:
|
||||
switch1 - description
|
||||
switch2 - description
|
||||
|
||||
Examples:
|
||||
usage example and output
|
||||
|
||||
Longer documentation detailing the command.
|
||||
|
||||
"""
|
||||
|
||||
The ``Switches`` and ``Examples`` headers can be skipped if not needed.
|
||||
Here is the ``nick`` command as an example:
|
||||
|
||||
::
|
||||
|
||||
"""
|
||||
Define a personal alias/nick
|
||||
|
||||
Usage:
|
||||
nick[/switches] <nickname> = [<string>]
|
||||
alias ''
|
||||
|
||||
Switches:
|
||||
object - alias an object
|
||||
player - alias a player
|
||||
clearall - clear all your aliases
|
||||
list - show all defined aliases (also "nicks" works)
|
||||
|
||||
Examples:
|
||||
nick hi = say Hello, I'm Sarah!
|
||||
nick/object tom = the tall man
|
||||
|
||||
A 'nick' is a personal shortcut you create for your own use [...]
|
||||
|
||||
"""
|
||||
|
||||
For commands that *require arguments*, the policy is for it to return a
|
||||
``Usage`` string if the command is entered without any arguments. So for
|
||||
such commands, the Command body should contain something to the effect
|
||||
of
|
||||
|
||||
::
|
||||
|
||||
if not self.args:
|
||||
self.caller.msg("Usage: nick[/switches] <nickname> = [<string>]")
|
||||
return
|
||||
|
||||
WWMD - What Would MUX Do?
|
||||
-------------------------
|
||||
|
||||
Our policy for implementing the default commands is as follows - we tend
|
||||
to look at MUX2's implementation before contriving one of our own. This
|
||||
comes with a caveat though - there are many cases where this is
|
||||
impossible without sacrificing the usability and utility of the
|
||||
codebase. In those cases, differences in implementation as well as
|
||||
command syntax is to be expected. Evennia is *not* MUX - we handle all
|
||||
underlying systems very differently and don't use
|
||||
`SoftCode <SoftCode.html>`_. The WWMD policy is only applied to the
|
||||
default commands, not to any other programming paradigms in the
|
||||
codebase.
|
||||
|
||||
If you are an Evennia codebase developer, consider activating
|
||||
``IMPORT_MUX_HELP`` in your ``settings.py`` file. This will import a
|
||||
copy of the MUX2 help database and might come in handy when it comes to
|
||||
adding/implementing new default commands. If you must deviate from
|
||||
MUX2's implementation of something, make sure to document it extensively
|
||||
in the command's docstring.
|
||||
Our original policy for implementing the default commands was to look at
|
||||
MUX2's implementation and base our command syntax on that. This means
|
||||
that many default commands have roughly similar syntax and switches as
|
||||
MUX commands. There are however many differences between the systems and
|
||||
readability and usability has taken priority (frankly, the MUX syntax is
|
||||
outright arcane in places). So the default command sets can be
|
||||
considered to implement a "MUX-like" dialect - whereas the overall feel
|
||||
is familiar, the details may differ considerably.
|
||||
|
|
|
|||
|
|
@ -30,8 +30,36 @@ should be easy to retrieve.
|
|||
|
||||
Many MUD codebases hardcode zones as part of the engine and database.
|
||||
Evennia does no such distinction due to the fact that rooms themselves
|
||||
are meant to be customized to any level anyway. Below is just *one*
|
||||
example of how one could add zone-like functionality to a game.
|
||||
are meant to be customized to any level anyway. Below are two
|
||||
suggestions for how zones could be implemented.
|
||||
|
||||
Zones using Tags
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
*OBS: Placeholder - this section is NOT fully supported by the code at
|
||||
the moment!*
|
||||
|
||||
All objects in Evennia can hold any number of `tags <Tag.html>`_. Tags
|
||||
are short labels that you attach to objects. They make it very easy to
|
||||
retrieve groups of objects. An object can have any number of different
|
||||
tags. So let's attach the relevant tag to our forest:
|
||||
|
||||
::
|
||||
|
||||
forestobj.tags.add("magicalforest", category="zone")
|
||||
|
||||
You could add this manually, or automatically during creation somehow
|
||||
(you'd need to modify your @dig command for this, most likely).
|
||||
|
||||
Henceforth you can then easily retrieve only objects with a given tag:
|
||||
|
||||
::
|
||||
|
||||
import ev
|
||||
rooms = ev.managers.Tags.get_objs_with_tag("magicalforest", category="zone") # (error here)
|
||||
|
||||
Zones using Aliases
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All objects have a *key* property, stored in the database. This is the
|
||||
primary name of the object. But it can also have any number of *Aliases*
|
||||
|
|
@ -41,8 +69,8 @@ alias "door". Aliases are actually separate database entities and are as
|
|||
such very fast to search for in the database, about as fast as searching
|
||||
for the object's primary key in fact.
|
||||
|
||||
This makes Aliases prime candiates for implementing zones. All you need
|
||||
to do is to come up with a consistent aliasing scheme. Here's one
|
||||
This makes Aliases another candidate for implementing zones. All you
|
||||
need to do is to come up with a consistent aliasing scheme. Here's one
|
||||
suggestion:
|
||||
|
||||
::
|
||||
|
|
@ -130,12 +158,12 @@ zone in the typeclass rather than enforce the ``@dig`` command to do it:
|
|||
class MagicalForestRoom(Room)
|
||||
def at_object_creation(self):
|
||||
...
|
||||
self.aliases = "#magicforest|%s" % self.key
|
||||
self.aliases.add("#magicforest|%s" % self.key)
|
||||
...
|
||||
class NormalForestRoom(Room)
|
||||
def at_object_creation(self):
|
||||
...
|
||||
self.aliases = "#normalforest|%s" % self.key
|
||||
self.aliases.add("#normalforest|%s" % self.key)
|
||||
...
|
||||
|
||||
Of course, an alternative way to implement zones themselves is to have
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue