mirror of
https://github.com/evennia/evennia.git
synced 2026-03-26 09:46:32 +01:00
Updated HTML docs.
This commit is contained in:
parent
680d522982
commit
bf918801fd
87 changed files with 2284 additions and 4014 deletions
|
|
@ -1,4 +1,4 @@
|
|||
# Sphinx build info version 1
|
||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: 9adbe4f91e54ddd9ee1242ebb9714806
|
||||
config: 20e6a00accd2c45a252d90d346328ff4
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Objects" href="Objects.html" />
|
||||
<link rel="prev" title="Sessions" href="Sessions.html" />
|
||||
<link rel="prev" title="Typeclasses" href="Typeclasses.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<a href="Objects.html" title="Objects"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -63,15 +63,17 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Accounts</a><ul>
|
||||
<li><a class="reference internal" href="#how-to-customize-your-own-account-types">How to customize your own Account types</a></li>
|
||||
<li><a class="reference internal" href="#working-with-accounts">Working with Accounts</a><ul>
|
||||
<li><a class="reference internal" href="#properties-on-accounts">Properties on Accounts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Sessions.html"
|
||||
title="previous chapter">Sessions</a></p>
|
||||
<p class="topless"><a href="Typeclasses.html"
|
||||
title="previous chapter">Typeclasses</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Objects.html"
|
||||
title="next chapter">Objects</a></p>
|
||||
|
|
@ -116,7 +118,7 @@
|
|||
<p>An <em>Account</em> represents a unique game account - one player playing the game. Whereas a player can potentially connect to the game from several Clients/Sessions, they will normally have only one Account.</p>
|
||||
<p>The Account object has no in-game representation. In order to actually get on the game the Account must <em>puppet</em> an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> (normally a <a class="reference internal" href="Objects.html#characters"><span class="std std-doc">Character</span></a>).</p>
|
||||
<p>Exactly how many Sessions can interact with an Account and its Puppets at once is determined by
|
||||
Evennia’s <a class="reference internal" href="Sessions.html#multisession-mode"><span class="std std-doc">MULTISESSION_MODE</span></a> setting.</p>
|
||||
Evennia’s <span class="xref myst">MULTISESSION_MODE</span></p>
|
||||
<p>Apart from storing login information and other account-specific data, the Account object is what is chatting on Evennia’s default <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>. It is also a good place to store <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Permissions</span></a> to be consistent between different in-game characters. It can also hold player-level configuration options.</p>
|
||||
<p>The Account object has its own default <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">CmdSet</span></a>, the <code class="docutils literal notranslate"><span class="pre">AccountCmdSet</span></code>. The commands in this set are available to the player no matter which character they are puppeting. Most notably the default game’s <code class="docutils literal notranslate"><span class="pre">exit</span></code>, <code class="docutils literal notranslate"><span class="pre">who</span></code> and chat-channel commands are in the Account cmdset.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> ooc
|
||||
|
|
@ -128,8 +130,8 @@ Evennia’s <a class="reference internal" href="Sessions.html#multisession-mode"
|
|||
</div>
|
||||
<p>This re-puppets the latest character.</p>
|
||||
<p>Note that the Account object can have, and often does have, a different set of <a class="reference internal" href="Permissions.html"><span class="doc std std-doc">Permissions</span></a> from the Character they control. Normally you should put your permissions on the Account level - this will overrule permissions set on the Character level. For the permissions of the Character to come into play the default <code class="docutils literal notranslate"><span class="pre">quell</span></code> command can be used. This allows for exploring the game using a different permission set (but you can’t escalate your permissions this way - for hierarchical permissions like <code class="docutils literal notranslate"><span class="pre">Builder</span></code>, <code class="docutils literal notranslate"><span class="pre">Admin</span></code> etc, the <em>lower</em> of the permissions on the Character/Account will always be used).</p>
|
||||
<section id="how-to-customize-your-own-account-types">
|
||||
<h2>How to customize your own Account types<a class="headerlink" href="#how-to-customize-your-own-account-types" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-accounts">
|
||||
<h2>Working with Accounts<a class="headerlink" href="#working-with-accounts" title="Permalink to this headline">¶</a></h2>
|
||||
<p>You will usually not want more than one Account typeclass for all new accounts.</p>
|
||||
<p>An Evennia Account is, per definition, a Python class that includes <code class="docutils literal notranslate"><span class="pre">evennia.DefaultAccount</span></code> among its parents. In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/accounts.py</span></code> there is an empty class ready for you to modify. Evennia defaults to using this (it inherits directly from <code class="docutils literal notranslate"><span class="pre">DefaultAccount</span></code>).</p>
|
||||
<p>Here’s an example of modifying the default Account class in code:</p>
|
||||
|
|
@ -157,9 +159,8 @@ Evennia’s <a class="reference internal" href="Sessions.html#multisession-mode"
|
|||
<blockquote>
|
||||
<div><p>If you wanted Evennia to default to a completely <em>different</em> Account class located elsewhere, you > must point Evennia to it. Add <code class="docutils literal notranslate"><span class="pre">BASE_ACCOUNT_TYPECLASS</span></code> to your settings file, and give the python path to your custom class as its value. By default this points to <code class="docutils literal notranslate"><span class="pre">typeclasses.accounts.Account</span></code>, the empty template we used above.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="properties-on-accounts">
|
||||
<h2>Properties on Accounts<a class="headerlink" href="#properties-on-accounts" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Properties on Accounts<a class="headerlink" href="#properties-on-accounts" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Beyond those properties assigned to all typeclassed objects (see <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclasses</span></a>), the Account also has the following custom properties:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">user</span></code> - a unique link to a <code class="docutils literal notranslate"><span class="pre">User</span></code> Django object, representing the logged-in user.</p></li>
|
||||
|
|
@ -184,6 +185,7 @@ the commands found in the cmdset defined by <code class="docutils literal notran
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">search</span></code> - search for Accounts.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -205,7 +207,7 @@ the commands found in the cmdset defined by <code class="docutils literal notran
|
|||
<a href="Objects.html" title="Objects"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -63,21 +63,21 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Attributes</a><ul>
|
||||
<li><a class="reference internal" href="#managing-attributes-in-code">Managing Attributes in Code</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-attributes">Working with Attributes</a><ul>
|
||||
<li><a class="reference internal" href="#using-db">Using .db</a></li>
|
||||
<li><a class="reference internal" href="#using-attributes">Using .attributes</a></li>
|
||||
<li><a class="reference internal" href="#using-attributeproperty">Using AttributeProperty</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#properties-of-attributes">Properties of Attributes</a></li>
|
||||
<li><a class="reference internal" href="#managing-attributes-in-game">Managing Attributes in-game</a></li>
|
||||
<li><a class="reference internal" href="#locking-and-checking-attributes">Locking and checking Attributes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute">What types of data can I save in an Attribute?</a><ul>
|
||||
<li><a class="reference internal" href="#storing-single-objects">Storing single objects</a></li>
|
||||
<li><a class="reference internal" href="#storing-multiple-objects">Storing multiple objects</a></li>
|
||||
<li><a class="reference internal" href="#retrieving-mutable-objects">Retrieving Mutable objects</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#properties-of-attributes">Properties of Attributes</a></li>
|
||||
<li><a class="reference internal" href="#in-memory-attributes-nattributes">In-memory Attributes (NAttributes)</a><ul>
|
||||
<li><a class="reference internal" href="#persistent-vs-non-persistent">Persistent vs non-persistent</a></li>
|
||||
</ul>
|
||||
|
|
@ -155,27 +155,11 @@
|
|||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<p><em>Attributes</em> allow you to to store arbitrary data on objects and make sure the data survives a server reboot. An Attribute can store pretty much any
|
||||
Python data structure and data type, like numbers, strings, lists, dicts etc. You can also
|
||||
store (references to) database objects like characters and rooms.</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute"><span class="std std-doc">What can be stored in an Attribute</span></a> is a must-read to avoid being surprised, also for experienced developers. Attributes can store <em>almost</em> everything
|
||||
but you need to know the quirks.</p></li>
|
||||
<li><p><a class="reference internal" href="#in-memory-attributes-nattributes"><span class="std std-doc">NAttributes</span></a> are the in-memory, non-persistent
|
||||
siblings of Attributes.</p></li>
|
||||
<li><p><a class="reference internal" href="#managing-attributes-in-game"><span class="std std-doc">Managing Attributes In-game</span></a> for in-game builder commands.</p></li>
|
||||
</ul>
|
||||
<section id="managing-attributes-in-code">
|
||||
<h2>Managing Attributes in Code<a class="headerlink" href="#managing-attributes-in-code" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Attributes are usually handled in code. All <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities
|
||||
(<a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and
|
||||
<a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>) can (and usually do) have Attributes associated with them. There
|
||||
<p><em>Attributes</em> allow you to to store arbitrary data on objects and make sure the data survives a server reboot. An Attribute can store pretty much any Python data structure and data type, like numbers, strings, lists, dicts etc. You can also store (references to) database objects like characters and rooms.</p>
|
||||
<section id="working-with-attributes">
|
||||
<h2>Working with Attributes<a class="headerlink" href="#working-with-attributes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Attributes are usually handled in code. All <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities (<a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>) can (and usually do) have Attributes associated with them. There
|
||||
are three ways to manage Attributes, all of which can be mixed.</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="#using-db"><span class="std std-doc">Using the <code class="docutils literal notranslate"><span class="pre">.db</span></code> property shortcut</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="#using-attributes"><span class="std std-doc">Using the <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> manager (<code class="docutils literal notranslate"><span class="pre">AttributeManager</span></code>)</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="#using-attributeproperty"><span class="std std-doc">Using <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> for assigning Attributes in a way similar to Django fields</span></a></p></li>
|
||||
</ul>
|
||||
<section id="using-db">
|
||||
<h3>Using .db<a class="headerlink" href="#using-db" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The simplest way to get/set Attributes is to use the <code class="docutils literal notranslate"><span class="pre">.db</span></code> shortcut. This allows for setting and getting Attributes that lack a <em>category</em> (having category <code class="docutils literal notranslate"><span class="pre">None</span></code>)</p>
|
||||
|
|
@ -239,8 +223,7 @@ the <a class="reference internal" href="../api/evennia.typeclasses.attributes.ht
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>If you don’t specify a category, the Attribute’s <code class="docutils literal notranslate"><span class="pre">category</span></code> will be <code class="docutils literal notranslate"><span class="pre">None</span></code> and can thus also be found via <code class="docutils literal notranslate"><span class="pre">.db</span></code>. <code class="docutils literal notranslate"><span class="pre">None</span></code> is considered a category of its own, so you won’t find <code class="docutils literal notranslate"><span class="pre">None</span></code>-category Attributes mixed with Attributes having categories.</p>
|
||||
<p>Here are the methods of the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code>. See
|
||||
the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler" title="evennia.typeclasses.attributes.AttributeHandler"><span class="xref myst py py-class">AttributeHandler API</span></a> for more details.</p>
|
||||
<p>Here are the methods of the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code>. See the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler" title="evennia.typeclasses.attributes.AttributeHandler"><span class="xref myst py py-class">AttributeHandler API</span></a> for more details.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">has(...)</span></code> - this checks if the object has an Attribute with this key. This is equivalent
|
||||
to doing <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span></code> except you can also check for a specific `category.</p></li>
|
||||
|
|
@ -330,16 +313,45 @@ The drawback is that without a database precense you can’t find the Attribute
|
|||
<span class="n">char</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"sleepy"</span><span class="p">)</span> <span class="c1"># now returns True</span>
|
||||
|
||||
<span class="n">char</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># now returns True, involves db access</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can e.g. <code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">char.strength</span></code> to set the value back to the default (the value defined
|
||||
in the <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>).</p>
|
||||
<p>You can e.g. <code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">char.strength</span></code> to set the value back to the default (the value defined in the <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>).</p>
|
||||
<p>See the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeProperty" title="evennia.typeclasses.attributes.AttributeProperty"><span class="xref myst py py-class">AttributeProperty API</span></a> for more details on how to create it with special options, like giving access-restrictions.</p>
|
||||
</section>
|
||||
<section id="properties-of-attributes">
|
||||
<h3>Properties of Attributes<a class="headerlink" href="#properties-of-attributes" title="Permalink to this headline">¶</a></h3>
|
||||
<p>An <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object is stored in the database. It has the following properties:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - the name of the Attribute. When doing e.g. <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, this property is set
|
||||
to <code class="docutils literal notranslate"><span class="pre">attrname</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">value</span></code> - this is the value of the Attribute. This value can be anything which can be pickled -
|
||||
objects, lists, numbers or what have you (see
|
||||
<a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute"><span class="std std-doc">this section</span></a> for more info). In the
|
||||
example
|
||||
<code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, the <code class="docutils literal notranslate"><span class="pre">value</span></code> is stored here.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">category</span></code> - 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 (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> is an example of using
|
||||
Attributes in this way). To modify this property you need to use the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">strvalue</span></code> - this is a separate value field that only accepts strings. This severely 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 (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> use it). It is only
|
||||
accessible via the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a>.</p></li>
|
||||
</ul>
|
||||
<p>There are also two special properties:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">attrtype</span></code> - this is used internally by Evennia to separate <a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a>, from Attributes (Nicks
|
||||
use Attributes behind the scenes).</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">model</span></code> - this is a <em>natural-key</em> describing the model this Attribute is attached to. This is on
|
||||
the form <em>appname.modelclass</em>, like <code class="docutils literal notranslate"><span class="pre">objects.objectdb</span></code>. It is used by the Attribute and
|
||||
NickHandler to quickly sort matches in the database. Neither this nor <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> should normally
|
||||
need to be modified.</p></li>
|
||||
</ul>
|
||||
<p>Non-database attributes are not stored in the database and have no equivalence
|
||||
to <code class="docutils literal notranslate"><span class="pre">category</span></code> nor <code class="docutils literal notranslate"><span class="pre">strvalue</span></code>, <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> or <code class="docutils literal notranslate"><span class="pre">model</span></code>.</p>
|
||||
</section>
|
||||
<section id="managing-attributes-in-game">
|
||||
<h2>Managing Attributes in-game<a class="headerlink" href="#managing-attributes-in-game" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Managing Attributes in-game<a class="headerlink" href="#managing-attributes-in-game" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Attributes are mainly used by code. But one can also allow the builder to use Attributes to
|
||||
‘turn knobs’ in-game. For example a builder could want to manually tweak the “level” Attribute of an
|
||||
enemy NPC to lower its difficuly.</p>
|
||||
|
|
@ -375,7 +387,7 @@ set mypobj/mystring = [1, 2, foo] # foo is invalid Python (no quotes)
|
|||
<p>For the last line you’ll get a warning and the value instead will be saved as a string <code class="docutils literal notranslate"><span class="pre">"[1,</span> <span class="pre">2,</span> <span class="pre">foo]"</span></code>.</p>
|
||||
</section>
|
||||
<section id="locking-and-checking-attributes">
|
||||
<h2>Locking and checking Attributes<a class="headerlink" href="#locking-and-checking-attributes" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Locking and checking Attributes<a class="headerlink" href="#locking-and-checking-attributes" title="Permalink to this headline">¶</a></h3>
|
||||
<p>While the <code class="docutils literal notranslate"><span class="pre">set</span></code> command is limited to builders, individual Attributes are usually not
|
||||
locked down. You may want to lock certain sensitive Attributes, in particular for games
|
||||
where you allow player building. You can add such limitations by adding a <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock string</span></a>
|
||||
|
|
@ -418,6 +430,7 @@ To check the <code class="docutils literal notranslate"><span class="pre">lockst
|
|||
<p>The same keywords are available to use with <code class="docutils literal notranslate"><span class="pre">obj.attributes.set()</span></code> and <code class="docutils literal notranslate"><span class="pre">obj.attributes.remove()</span></code>,
|
||||
those will check for the <code class="docutils literal notranslate"><span class="pre">attredit</span></code> lock type.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="what-types-of-data-can-i-save-in-an-attribute">
|
||||
<h2>What types of data can I save in an Attribute?<a class="headerlink" href="#what-types-of-data-can-i-save-in-an-attribute" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The database doesn’t know anything about Python objects, so Evennia must <em>serialize</em> Attribute
|
||||
|
|
@ -613,38 +626,6 @@ instead of <code class="docutils literal notranslate"><span class="pre">_SaverLi
|
|||
explicitly save it back to the Attribute for it to save.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="properties-of-attributes">
|
||||
<h2>Properties of Attributes<a class="headerlink" href="#properties-of-attributes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>An <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object is stored in the database. It has the following properties:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - the name of the Attribute. When doing e.g. <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, this property is set
|
||||
to <code class="docutils literal notranslate"><span class="pre">attrname</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">value</span></code> - this is the value of the Attribute. This value can be anything which can be pickled -
|
||||
objects, lists, numbers or what have you (see
|
||||
<a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute"><span class="std std-doc">this section</span></a> for more info). In the
|
||||
example
|
||||
<code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, the <code class="docutils literal notranslate"><span class="pre">value</span></code> is stored here.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">category</span></code> - 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 (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> is an example of using
|
||||
Attributes in this way). To modify this property you need to use the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">strvalue</span></code> - this is a separate value field that only accepts strings. This severely 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 (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> use it). It is only
|
||||
accessible via the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a>.</p></li>
|
||||
</ul>
|
||||
<p>There are also two special properties:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">attrtype</span></code> - this is used internally by Evennia to separate <a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a>, from Attributes (Nicks
|
||||
use Attributes behind the scenes).</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">model</span></code> - this is a <em>natural-key</em> describing the model this Attribute is attached to. This is on
|
||||
the form <em>appname.modelclass</em>, like <code class="docutils literal notranslate"><span class="pre">objects.objectdb</span></code>. It is used by the Attribute and
|
||||
NickHandler to quickly sort matches in the database. Neither this nor <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> should normally
|
||||
need to be modified.</p></li>
|
||||
</ul>
|
||||
<p>Non-database attributes are not stored in the database and have no equivalence
|
||||
to <code class="docutils literal notranslate"><span class="pre">category</span></code> nor <code class="docutils literal notranslate"><span class="pre">strvalue</span></code>, <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> or <code class="docutils literal notranslate"><span class="pre">model</span></code>.</p>
|
||||
</section>
|
||||
<section id="in-memory-attributes-nattributes">
|
||||
<h2>In-memory Attributes (NAttributes)<a class="headerlink" href="#in-memory-attributes-nattributes" title="Permalink to this headline">¶</a></h2>
|
||||
<p><em>NAttributes</em> (short of Non-database Attributes) mimic Attributes in most things except they
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Batch Command Processor" href="Batch-Command-Processor.html" />
|
||||
<link rel="prev" title="Batch Processors" href="Batch-Processors.html" />
|
||||
<link rel="next" title="Inputfuncs" href="Inputfuncs.html" />
|
||||
<link rel="prev" title="Batch Command Processor" href="Batch-Command-Processor.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,13 +30,14 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
<a href="Inputfuncs.html" title="Inputfuncs"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="Batch-Processors.html" accesskey="U">Batch Processors</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Batch Code Processor</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
|
|
@ -63,7 +64,6 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Batch Code Processor</a><ul>
|
||||
<li><a class="reference internal" href="#basic-usage">Basic Usage</a></li>
|
||||
<li><a class="reference internal" href="#the-batch-file">The batch file</a></li>
|
||||
<li><a class="reference internal" href="#debug-mode">Debug mode</a></li>
|
||||
<li><a class="reference internal" href="#interactive-mode">Interactive mode</a></li>
|
||||
|
|
@ -79,11 +79,11 @@
|
|||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Batch-Processors.html"
|
||||
title="previous chapter">Batch Processors</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Batch-Command-Processor.html"
|
||||
title="next chapter">Batch Command Processor</a></p>
|
||||
title="previous chapter">Batch Command Processor</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Inputfuncs.html"
|
||||
title="next chapter">Inputfuncs</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -116,59 +116,29 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="batch-code-processor">
|
||||
<h1>Batch Code Processor<a class="headerlink" href="#batch-code-processor" title="Permalink to this headline">¶</a></h1>
|
||||
<p>For an introduction and motivation to using batch processors, see <a class="reference internal" href="Batch-Processors.html"><span class="doc std std-doc">here</span></a>. This
|
||||
page describes the Batch-<em>code</em> processor. The Batch-<em>command</em> one is covered [here](Batch-Command-
|
||||
Processor).</p>
|
||||
<section id="basic-usage">
|
||||
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline">¶</a></h2>
|
||||
<p>For an introduction and motivation to using batch processors, see <a class="reference internal" href="Batch-Processors.html"><span class="doc std std-doc">here</span></a>. This page describes the Batch-<em>code</em> processor. The Batch-<em>command</em> one is covered [here](Batch-Command- Processor).</p>
|
||||
<p>The batch-code processor is a superuser-only function, invoked by</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > @batchcode path.to.batchcodefile
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > batchcode path.to.batchcodefile
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Where <code class="docutils literal notranslate"><span class="pre">path.to.batchcodefile</span></code> is the path to a <em>batch-code file</em>. Such a file should have a name
|
||||
ending in “<code class="docutils literal notranslate"><span class="pre">.py</span></code>” (but you shouldn’t include that in the path). The path is given like a python path
|
||||
relative to a folder you define to hold your batch files, set by <code class="docutils literal notranslate"><span class="pre">BATCH_IMPORT_PATH</span></code> in your
|
||||
settings. Default folder is (assuming your game is called “mygame”) <code class="docutils literal notranslate"><span class="pre">mygame/world/</span></code>. So if you want
|
||||
to run the example batch file in <code class="docutils literal notranslate"><span class="pre">mygame/world/batch_code.py</span></code>, you could simply use</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > @batchcode batch_code
|
||||
<p>Where <code class="docutils literal notranslate"><span class="pre">path.to.batchcodefile</span></code> is the path to a <em>batch-code file</em>. Such a file should have a name ending in “<code class="docutils literal notranslate"><span class="pre">.py</span></code>” (but you shouldn’t include that in the path). The path is given like a python path relative to a folder you define to hold your batch files, set by <code class="docutils literal notranslate"><span class="pre">BATCH_IMPORT_PATH</span></code> in your settings. Default folder is (assuming your game is called “mygame”) <code class="docutils literal notranslate"><span class="pre">mygame/world/</span></code>. So if you want to run the example batch file in <code class="docutils literal notranslate"><span class="pre">mygame/world/batch_code.py</span></code>, you could simply use</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > batchcode batch_code
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will try to run through the entire batch file in one go. For more gradual, <em>interactive</em>
|
||||
control you can use the <code class="docutils literal notranslate"><span class="pre">/interactive</span></code> switch. The switch <code class="docutils literal notranslate"><span class="pre">/debug</span></code> will put the processor in
|
||||
<em>debug</em> mode. Read below for more info.</p>
|
||||
</section>
|
||||
<p>This will try to run through the entire batch file in one go. For more gradual, <em>interactive</em> control you can use the <code class="docutils literal notranslate"><span class="pre">/interactive</span></code> switch. The switch <code class="docutils literal notranslate"><span class="pre">/debug</span></code> will put the processor in <em>debug</em> mode. Read below for more info.</p>
|
||||
<section id="the-batch-file">
|
||||
<h2>The batch file<a class="headerlink" href="#the-batch-file" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A batch-code file is a normal Python file. The difference is that since the batch processor loads
|
||||
and executes the file rather than importing it, you can reliably update the file, then call it
|
||||
again, over and over and see your changes without needing to <code class="docutils literal notranslate"><span class="pre">@reload</span></code> the server. This makes for
|
||||
easy testing. In the batch-code file you have also access to the following global variables:</p>
|
||||
<p>A batch-code file is a normal Python file. The difference is that since the batch processor loads and executes the file rather than importing it, you can reliably update the file, then call it again, over and over and see your changes without needing to <code class="docutils literal notranslate"><span class="pre">reload</span></code> the server. This makes for easy testing. In the batch-code file you have also access to the following global variables:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> - This is a reference to the object running the batchprocessor.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code> - This is a boolean that lets you determine if this file is currently being run in debug-
|
||||
mode or not. See below how this can be useful.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">DEBUG</span></code> - This is a boolean that lets you determine if this file is currently being run in debug-mode or not. See below how this can be useful.</p></li>
|
||||
</ul>
|
||||
<p>Running a plain Python file through the processor will just execute the file from beginning to end.
|
||||
If you want to get more control over the execution you can use the processor’s <em>interactive</em> mode.
|
||||
This runs certain code blocks on their own, rerunning only that part until you are happy with it. In
|
||||
order to do this you need to add special markers to your file to divide it up into smaller chunks.
|
||||
These take the form of comments, so the file remains valid Python.</p>
|
||||
<p>Here are the rules of syntax of the batch-code <code class="docutils literal notranslate"><span class="pre">*.py</span></code> file.</p>
|
||||
<p>Running a plain Python file through the processor will just execute the file from beginning to end. If you want to get more control over the execution you can use the processor’s <em>interactive</em> mode. This runs certain code blocks on their own, rerunning only that part until you are happy with it. In order to do this you need to add special markers to your file to divide it up into smaller chunks. These take the form of comments, so the file remains valid Python.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">#CODE</span></code> as the first on a line marks the start of a <em>code</em> block. It will last until the beginning
|
||||
of another marker or the end of the file. Code blocks contain functional python code. Each <code class="docutils literal notranslate"><span class="pre">#CODE</span></code>
|
||||
block will be run in complete isolation from other parts of the file, so make sure it’s self-
|
||||
contained.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> as the first on a line marks the start of a <em>header</em> block. It lasts until the next
|
||||
marker or the end of the file. This is intended to hold imports and variables you will need for all
|
||||
other blocks .All python code defined in a header block will always be inserted at the top of every
|
||||
<code class="docutils literal notranslate"><span class="pre">#CODE</span></code> blocks in the file. You may have more than one <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> block, but that is equivalent to
|
||||
having one big one. Note that you can’t exchange data between code blocks, so editing a header-
|
||||
variable in one code block won’t affect that variable in any other code block!</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">#INSERT</span> <span class="pre">path.to.file</span></code> will insert another batchcode (Python) file at that position.</p></li>
|
||||
<li><p>A <code class="docutils literal notranslate"><span class="pre">#</span></code> that is not starting a <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code>, <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> or <code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> instruction is considered a comment.</p></li>
|
||||
<li><p>Inside a block, normal Python syntax rules apply. For the sake of indentation, each block acts as
|
||||
a separate python module.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">#CODE</span></code> as the first on a line marks the start of a <em>code</em> block. It will last until the beginning of another marker or the end of the file. Code blocks contain functional python code. Each <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block will be run in complete isolation from other parts of the file, so make sure it’s self- contained.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> as the first on a line marks the start of a <em>header</em> block. It lasts until the next marker or the end of the file. This is intended to hold imports and variables you will need for all other blocks .All python code defined in a header block will always be inserted at the top of every <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> blocks in the file. You may have more than one <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> block, but that is equivalent to having one big one. Note that you can’t exchange data between code blocks, so editing a header- variable in one code block won’t affect that variable in any other code block!</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">#INSERT</span> <span class="pre">path.to.file</span></code> will insert another batchcode (Python) file at that position. - A <code class="docutils literal notranslate"><span class="pre">#</span></code> that is not starting a <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code>, <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> or <code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> instruction is considered a comment.</p></li>
|
||||
<li><p>Inside a block, normal Python syntax rules apply. For the sake of indentation, each block acts as a separate python module.</p></li>
|
||||
</ul>
|
||||
<p>Below is a version of the example file found in <code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples/</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1">#</span>
|
||||
|
|
@ -215,36 +185,24 @@ a separate python module.</p></li>
|
|||
<section id="debug-mode">
|
||||
<h2>Debug mode<a class="headerlink" href="#debug-mode" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Try to run the example script with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > @batchcode/debug tutorial_examples.example_batch_code
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > batchcode/debug tutorial_examples.example_batch_code
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The batch script will run to the end and tell you it completed. You will also get messages that the
|
||||
button and the two pieces of furniture were created. Look around and you should see the button
|
||||
there. But you won’t see any chair nor a table! This is because we ran this with the <code class="docutils literal notranslate"><span class="pre">/debug</span></code>
|
||||
switch, which is directly visible as <code class="docutils literal notranslate"><span class="pre">DEBUG==True</span></code> inside the script. In the above example we
|
||||
handled this state by deleting the chair and table again.</p>
|
||||
<p>The debug mode is intended to be used when you test out a batchscript. Maybe you are looking for
|
||||
bugs in your code or try to see if things behave as they should. Running the script over and over
|
||||
would then create an ever-growing stack of chairs and tables, all with the same name. You would have
|
||||
to go back and painstakingly delete them later.</p>
|
||||
<p>The batch script will run to the end and tell you it completed. You will also get messages that the button and the two pieces of furniture were created. Look around and you should see the button there. But you won’t see any chair nor a table! This is because we ran this with the <code class="docutils literal notranslate"><span class="pre">/debug</span></code> switch, which is directly visible as <code class="docutils literal notranslate"><span class="pre">DEBUG==True</span></code> inside the script. In the above example we handled this state by deleting the chair and table again.</p>
|
||||
<p>The debug mode is intended to be used when you test out a batchscript. Maybe you are looking for bugs in your code or try to see if things behave as they should. Running the script over and over would then create an ever-growing stack of chairs and tables, all with the same name. You would have to go back and painstakingly delete them later.</p>
|
||||
</section>
|
||||
<section id="interactive-mode">
|
||||
<h2>Interactive mode<a class="headerlink" href="#interactive-mode" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Interactive mode works very similar to the [batch-command processor counterpart](Batch-Command-
|
||||
Processor). It allows you more step-wise control over how the batch file is executed. This is useful
|
||||
for debugging or for picking and choosing only particular blocks to run. Use <code class="docutils literal notranslate"><span class="pre">@batchcode</span></code> with the
|
||||
<code class="docutils literal notranslate"><span class="pre">/interactive</span></code> flag to enter interactive mode.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > @batchcode/interactive tutorial_examples.batch_code
|
||||
<p>Interactive mode works very similar to the [batch-command processor counterpart](Batch-Command- Processor). It allows you more step-wise control over how the batch file is executed. This is useful for debugging or for picking and choosing only particular blocks to run. Use <code class="docutils literal notranslate"><span class="pre">batchcode</span></code> with the <code class="docutils literal notranslate"><span class="pre">/interactive</span></code> flag to enter interactive mode.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > batchcode/interactive tutorial_examples.batch_code
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You should see the following:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>01/02: red_button = create_object(red_button.RedButton, [...] (hh for help)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This shows that you are on the first <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block, the first of only two commands in this batch
|
||||
file. Observe that the block has <em>not</em> actually been executed at this point!</p>
|
||||
<p>To take a look at the full code snippet you are about to run, use <code class="docutils literal notranslate"><span class="pre">ll</span></code> (a batch-processor version of
|
||||
<code class="docutils literal notranslate"><span class="pre">look</span></code>).</p>
|
||||
<p>This shows that you are on the first <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block, the first of only two commands in this batch file. Observe that the block has <em>not</em> actually been executed at this point!</p>
|
||||
<p>To take a look at the full code snippet you are about to run, use <code class="docutils literal notranslate"><span class="pre">ll</span></code> (a batch-processor version of <code class="docutils literal notranslate"><span class="pre">look</span></code>).</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span><span class="p">,</span> <span class="n">search</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.contrib.tutorial_examples</span> <span class="kn">import</span> <span class="n">red_button</span>
|
||||
<span class="kn">from</span> <span class="nn">typeclasses.objects</span> <span class="kn">import</span> <span class="n">Object</span>
|
||||
|
|
@ -258,21 +216,14 @@ file. Observe that the block has <em>not</em> actually been executed at this poi
|
|||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"A red button was created."</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Compare with the example code given earlier. Notice how the content of <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> has been pasted at
|
||||
the top of the <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block. Use <code class="docutils literal notranslate"><span class="pre">pp</span></code> to actually execute this block (this will create the button
|
||||
<p>Compare with the example code given earlier. Notice how the content of <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> has been pasted at the top of the <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block. Use <code class="docutils literal notranslate"><span class="pre">pp</span></code> to actually execute this block (this will create the button
|
||||
and give you a message). Use <code class="docutils literal notranslate"><span class="pre">nn</span></code> (next) to go to the next command. Use <code class="docutils literal notranslate"><span class="pre">hh</span></code> for a list of commands.</p>
|
||||
<p>If there are tracebacks, fix them in the batch file, then use <code class="docutils literal notranslate"><span class="pre">rr</span></code> to reload the file. You will
|
||||
still be at the same code block and can rerun it easily with <code class="docutils literal notranslate"><span class="pre">pp</span></code> as needed. This makes for a simple
|
||||
debug cycle. It also allows you to rerun individual troublesome blocks - as mentioned, in a large
|
||||
batch file this can be very useful (don’t forget the <code class="docutils literal notranslate"><span class="pre">/debug</span></code> mode either).</p>
|
||||
<p>Use <code class="docutils literal notranslate"><span class="pre">nn</span></code> and <code class="docutils literal notranslate"><span class="pre">bb</span></code> (next and back) to step through the file; e.g. <code class="docutils literal notranslate"><span class="pre">nn</span> <span class="pre">12</span></code> will jump 12 steps forward
|
||||
(without processing any blocks in between). All normal commands of Evennia should work too while
|
||||
working in interactive mode.</p>
|
||||
<p>If there are tracebacks, fix them in the batch file, then use <code class="docutils literal notranslate"><span class="pre">rr</span></code> to reload the file. You will still be at the same code block and can rerun it easily with <code class="docutils literal notranslate"><span class="pre">pp</span></code> as needed. This makes for a simple debug cycle. It also allows you to rerun individual troublesome blocks - as mentioned, in a large batch file this can be very useful (don’t forget the <code class="docutils literal notranslate"><span class="pre">/debug</span></code> mode either).</p>
|
||||
<p>Use <code class="docutils literal notranslate"><span class="pre">nn</span></code> and <code class="docutils literal notranslate"><span class="pre">bb</span></code> (next and back) to step through the file; e.g. <code class="docutils literal notranslate"><span class="pre">nn</span> <span class="pre">12</span></code> will jump 12 steps forward (without processing any blocks in between). All normal commands of Evennia should work too while working in interactive mode.</p>
|
||||
</section>
|
||||
<section id="limitations-and-caveats">
|
||||
<h2>Limitations and Caveats<a class="headerlink" href="#limitations-and-caveats" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The batch-code processor is by far the most flexible way to build a world in Evennia. There are
|
||||
however some caveats you need to keep in mind.</p>
|
||||
<p>The batch-code processor is by far the most flexible way to build a world in Evennia. There are however some caveats you need to keep in mind.</p>
|
||||
<section id="safety">
|
||||
<h3>Safety<a class="headerlink" href="#safety" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Or rather the lack of it. There is a reason only <em>superusers</em> are allowed to run the batch-code
|
||||
|
|
@ -286,24 +237,11 @@ really do anything outside what the game commands allow them to.</p>
|
|||
</section>
|
||||
<section id="no-communication-between-code-blocks">
|
||||
<h3>No communication between code blocks<a class="headerlink" href="#no-communication-between-code-blocks" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Global variables won’t work in code batch files, each block is executed as stand-alone environments.
|
||||
<code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> blocks are literally pasted on top of each <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block so updating some header-variable
|
||||
in your block will not make that change available in another block. Whereas a python execution
|
||||
limitation, allowing this would also lead to very hard-to-debug code when using the interactive mode</p>
|
||||
<ul class="simple">
|
||||
<li><p>this would be a classical example of “spaghetti code”.</p></li>
|
||||
</ul>
|
||||
<p>The main practical issue with this is when building e.g. a room in one code block and later want to
|
||||
connect that room with a room you built in the current block. There are two ways to do this:</p>
|
||||
<p>Global variables won’t work in code batch files, each block is executed as stand-alone environments. <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> blocks are literally pasted on top of each <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block so updating some header-variable in your block will not make that change available in another block. Whereas a python execution limitation, allowing this would also lead to very hard-to-debug code when using the interactive mode - this would be a classical example of “spaghetti code”.</p>
|
||||
<p>The main practical issue with this is when building e.g. a room in one code block and later want to connect that room with a room you built in the current block. There are two ways to do this:</p>
|
||||
<ul>
|
||||
<li><p>Perform a database search for the name of the room you created (since you cannot know in advance
|
||||
which dbref it got assigned). The problem is that a name may not be unique (you may have a lot of “A
|
||||
dark forest” rooms). There is an easy way to handle this though - use <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> or <em>Aliases</em>. You
|
||||
can assign any number of tags and/or aliases to any object. Make sure that one of those tags or
|
||||
aliases is unique to the room (like “room56”) and you will henceforth be able to always uniquely
|
||||
search and find it later.</p></li>
|
||||
<li><p>Use the <code class="docutils literal notranslate"><span class="pre">caller</span></code> global property as an inter-block storage. For example, you could have a
|
||||
dictionary of room references in an <code class="docutils literal notranslate"><span class="pre">ndb</span></code>:</p>
|
||||
<li><p>Perform a database search for the name of the room you created (since you cannot know in advance which dbref it got assigned). The problem is that a name may not be unique (you may have a lot of “A dark forest” rooms). There is an easy way to handle this though - use <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> or <em>Aliases</em>. You can assign any number of tags and/or aliases to any object. Make sure that one of those tags or aliases is unique to the room (like “room56”) and you will henceforth be able to always uniquely search and find it later.</p></li>
|
||||
<li><p>Use the <code class="docutils literal notranslate"><span class="pre">caller</span></code> global property as an inter-block storage. For example, you could have a dictionary of room references in an <code class="docutils literal notranslate"><span class="pre">ndb</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1">#HEADER </span>
|
||||
<span class="k">if</span> <span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">all_rooms</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">all_rooms</span> <span class="o">=</span> <span class="p">{}</span>
|
||||
|
|
@ -320,23 +258,16 @@ dictionary of room references in an <code class="docutils literal notranslate"><
|
|||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<p>Note how we check in <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> if <code class="docutils literal notranslate"><span class="pre">caller.ndb.all_rooms</span></code> doesn’t already exist before creating the
|
||||
dict. Remember that <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> is copied in front of every <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block. Without that <code class="docutils literal notranslate"><span class="pre">if</span></code> statement
|
||||
<p>Note how we check in <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> if <code class="docutils literal notranslate"><span class="pre">caller.ndb.all_rooms</span></code> doesn’t already exist before creating the dict. Remember that <code class="docutils literal notranslate"><span class="pre">#HEADER</span></code> is copied in front of every <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block. Without that <code class="docutils literal notranslate"><span class="pre">if</span></code> statement
|
||||
we’d be wiping the dict every block!</p>
|
||||
</section>
|
||||
<section id="dont-treat-a-batchcode-file-like-any-python-file">
|
||||
<h3>Don’t treat a batchcode file like any Python file<a class="headerlink" href="#dont-treat-a-batchcode-file-like-any-python-file" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Despite being a valid Python file, a batchcode file should <em>only</em> be run by the batchcode processor.
|
||||
You should not do things like define Typeclasses or Commands in them, or import them into other
|
||||
code. Importing a module in Python will execute base level of the module, which in the case of your
|
||||
average batchcode file could mean creating a lot of new objects every time.</p>
|
||||
<p>Despite being a valid Python file, a batchcode file should <em>only</em> be run by the batchcode processor. You should not do things like define Typeclasses or Commands in them, or import them into other code. Importing a module in Python will execute base level of the module, which in the case of your average batchcode file could mean creating a lot of new objects every time.</p>
|
||||
</section>
|
||||
<section id="dont-let-code-rely-on-the-batch-files-real-file-path">
|
||||
<h3>Don’t let code rely on the batch-file’s real file path<a class="headerlink" href="#dont-let-code-rely-on-the-batch-files-real-file-path" title="Permalink to this headline">¶</a></h3>
|
||||
<p>When you import things into your batchcode file, don’t use relative imports but always import with
|
||||
paths starting from the root of your game directory or evennia library. Code that relies on the
|
||||
batch file’s “actual” location <em>will fail</em>. Batch code files are read as text and the strings
|
||||
executed. When the code runs it has no knowledge of what file those strings where once a part of.</p>
|
||||
<p>When you import things into your batchcode file, don’t use relative imports but always import with paths starting from the root of your game directory or evennia library. Code that relies on the batch file’s “actual” location <em>will fail</em>. Batch code files are read as text and the strings executed. When the code runs it has no knowledge of what file those strings where once a part of.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -357,13 +288,14 @@ executed. When the code runs it has no knowledge of what file those strings wher
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
<a href="Inputfuncs.html" title="Inputfuncs"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="Batch-Processors.html" >Batch Processors</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Batch Code Processor</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Inputfuncs" href="Inputfuncs.html" />
|
||||
<link rel="prev" title="Batch Code Processor" href="Batch-Code-Processor.html" />
|
||||
<link rel="next" title="Batch Code Processor" href="Batch-Code-Processor.html" />
|
||||
<link rel="prev" title="Batch Processors" href="Batch-Processors.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,13 +30,14 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Inputfuncs.html" title="Inputfuncs"
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="Batch-Processors.html" accesskey="U">Batch Processors</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Batch Command Processor</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
|
|
@ -63,21 +64,20 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Batch Command Processor</a><ul>
|
||||
<li><a class="reference internal" href="#basic-usage">Basic Usage</a></li>
|
||||
<li><a class="reference internal" href="#the-batch-file">The batch file</a></li>
|
||||
<li><a class="reference internal" href="#interactive-mode">Interactive mode</a></li>
|
||||
<li><a class="reference internal" href="#limitations-and-caveats">Limitations and Caveats</a></li>
|
||||
<li><a class="reference internal" href="#assorted-notes">Assorted notes</a></li>
|
||||
<li><a class="reference internal" href="#editor-highlighting-for-ev-files">Editor highlighting for .ev files</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Batch-Code-Processor.html"
|
||||
title="previous chapter">Batch Code Processor</a></p>
|
||||
<p class="topless"><a href="Batch-Processors.html"
|
||||
title="previous chapter">Batch Processors</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Inputfuncs.html"
|
||||
title="next chapter">Inputfuncs</a></p>
|
||||
<p class="topless"><a href="Batch-Code-Processor.html"
|
||||
title="next chapter">Batch Code Processor</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -113,10 +113,8 @@
|
|||
<p>For an introduction and motivation to using batch processors, see <a class="reference internal" href="Batch-Processors.html"><span class="doc std std-doc">here</span></a>. This
|
||||
page describes the Batch-<em>command</em> processor. The Batch-<em>code</em> one is covered [here](Batch-Code-
|
||||
Processor).</p>
|
||||
<section id="basic-usage">
|
||||
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The batch-command processor is a superuser-only function, invoked by</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > @batchcommand path.to.batchcmdfile
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > batchcommand path.to.batchcmdfile
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Where <code class="docutils literal notranslate"><span class="pre">path.to.batchcmdfile</span></code> is the path to a <em>batch-command file</em> with the “<code class="docutils literal notranslate"><span class="pre">.ev</span></code>” file ending.
|
||||
|
|
@ -124,7 +122,7 @@ This path is given like a python path relative to a folder you define to hold yo
|
|||
with <code class="docutils literal notranslate"><span class="pre">BATCH_IMPORT_PATH</span></code> in your settings. Default folder is (assuming your game is in the <code class="docutils literal notranslate"><span class="pre">mygame</span></code>
|
||||
folder) <code class="docutils literal notranslate"><span class="pre">mygame/world</span></code>. So if you want to run the example batch file in
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame/world/batch_cmds.ev</span></code>, you could use</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > @batchcommand batch_cmds
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > batchcommand batch_cmds
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A batch-command file contains a list of Evennia in-game commands separated by comments. The
|
||||
|
|
@ -132,30 +130,18 @@ processor will run the batch file from beginning to end. Note that <em>it will n
|
|||
it fail</em> (there is no universal way for the processor to know what a failure looks like for all
|
||||
different commands). So keep a close watch on the output, or use <em>Interactive mode</em> (see below) to
|
||||
run the file in a more controlled, gradual manner.</p>
|
||||
</section>
|
||||
<section id="the-batch-file">
|
||||
<h2>The batch file<a class="headerlink" href="#the-batch-file" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The batch file is a simple plain-text file containing Evennia commands. Just like you would write
|
||||
them in-game, except you have more freedom with line breaks.</p>
|
||||
<p>Here are the rules of syntax of an <code class="docutils literal notranslate"><span class="pre">*.ev</span></code> file. You’ll find it’s really, really simple:</p>
|
||||
<ul class="simple">
|
||||
<li><p>All lines having the <code class="docutils literal notranslate"><span class="pre">#</span></code> (hash)-symbol <em>as the first one on the line</em> are considered <em>comments</em>.
|
||||
All non-comment lines are treated as a command and/or their arguments.</p></li>
|
||||
<li><p>Comment lines have an actual function – they mark the <em>end of the previous command definition</em>.
|
||||
So never put two commands directly after one another in the file - separate them with a comment, or
|
||||
the second of the two will be considered an argument to the first one. Besides, using plenty of
|
||||
comments is good practice anyway.</p></li>
|
||||
<li><p>A line that starts with the word <code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> is a comment line but also signifies a special
|
||||
instruction. The syntax is <code class="docutils literal notranslate"><span class="pre">#INSERT</span> <span class="pre"><path.batchfile></span></code> and tries to import a given batch-cmd file
|
||||
into this one. The inserted batch file (file ending <code class="docutils literal notranslate"><span class="pre">.ev</span></code>) will run normally from the point of the
|
||||
<code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> instruction.</p></li>
|
||||
<li><p>Extra whitespace in a command definition is <em>ignored</em>. - A completely empty line translates in to
|
||||
a line break in texts. Two empty lines thus means a new paragraph (this is obviously only relevant
|
||||
for commands accepting such formatting, such as the <code class="docutils literal notranslate"><span class="pre">@desc</span></code> command).</p></li>
|
||||
<li><p>All lines having the <code class="docutils literal notranslate"><span class="pre">#</span></code> (hash)-symbol <em>as the first one on the line</em> are considered <em>comments</em>. All non-comment lines are treated as a command and/or their arguments.</p></li>
|
||||
<li><p>Comment lines have an actual function – they mark the <em>end of the previous command definition</em>. So never put two commands directly after one another in the file - separate them with a comment, or the second of the two will be considered an argument to the first one. Besides, using plenty of comments is good practice anyway.</p></li>
|
||||
<li><p>A line that starts with the word <code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> is a comment line but also signifies a special instruction. The syntax is <code class="docutils literal notranslate"><span class="pre">#INSERT</span> <span class="pre"><path.batchfile></span></code> and tries to import a given batch-cmd file into this one. The inserted batch file (file ending <code class="docutils literal notranslate"><span class="pre">.ev</span></code>) will run normally from the point of the <code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> instruction.</p></li>
|
||||
<li><p>Extra whitespace in a command definition is <em>ignored</em>. - A completely empty line translates in to a line break in texts. Two empty lines thus means a new paragraph (this is obviously only relevant for commands accepting such formatting, such as the <code class="docutils literal notranslate"><span class="pre">@desc</span></code> command).</p></li>
|
||||
<li><p>The very last command in the file is not required to end with a comment.</p></li>
|
||||
<li><p>You <em>cannot</em> nest another <code class="docutils literal notranslate"><span class="pre">@batchcommand</span></code> statement into your batch file. If you want to link many
|
||||
batch-files together, use the <code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> batch instruction instead. You also cannot launch the
|
||||
<code class="docutils literal notranslate"><span class="pre">@batchcode</span></code> command from your batch file, the two batch processors are not compatible.</p></li>
|
||||
<li><p>You <em>cannot</em> nest another <code class="docutils literal notranslate"><span class="pre">batchcommand</span></code> statement into your batch file. If you want to link many batch-files together, use the <code class="docutils literal notranslate"><span class="pre">#INSERT</span></code> batch instruction instead. You also cannot launch the <code class="docutils literal notranslate"><span class="pre">batchcode</span></code> command from your batch file, the two batch processors are not compatible.</p></li>
|
||||
</ul>
|
||||
<p>Below is a version of the example file found in <code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples/batch_cmds.ev</span></code>.</p>
|
||||
<div class="highlight-bash notranslate"><div class="highlight"><pre><span></span> <span class="c1">#</span>
|
||||
|
|
@ -201,23 +187,17 @@ batch-files together, use the <code class="docutils literal notranslate"><span c
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>To test this, run <code class="docutils literal notranslate"><span class="pre">@batchcommand</span></code> on the file:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> @batchcommand contrib.tutorial_examples.batch_cmds
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> batchcommand contrib.tutorial_examples.batch_cmds
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>A button will be created, described and dropped in Limbo. All commands will be executed by the user
|
||||
calling the command.</p>
|
||||
<p>A button will be created, described and dropped in Limbo. All commands will be executed by the user calling the command.</p>
|
||||
<blockquote>
|
||||
<div><p>Note that if you interact with the button, you might find that its description changes, loosing
|
||||
your custom-set description above. This is just the way this particular object works.</p>
|
||||
<div><p>Note that if you interact with the button, you might find that its description changes, loosing your custom-set description above. This is just the way this particular object works.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="interactive-mode">
|
||||
<h2>Interactive mode<a class="headerlink" href="#interactive-mode" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Interactive mode allows you to more step-wise control over how the batch file is executed. This is
|
||||
useful for debugging and also if you have a large batch file and is only updating a small part of it
|
||||
– running the entire file again would be a waste of time (and in the case of <code class="docutils literal notranslate"><span class="pre">@create</span></code>-ing objects
|
||||
you would to end up with multiple copies of same-named objects, for example). Use <code class="docutils literal notranslate"><span class="pre">@batchcommand</span></code>
|
||||
with the <code class="docutils literal notranslate"><span class="pre">/interactive</span></code> flag to enter interactive mode.</p>
|
||||
<p>Interactive mode allows you to more step-wise control over how the batch file is executed. This is useful for debugging and also if you have a large batch file and is only updating a small part of it – running the entire file again would be a waste of time (and in the case of <code class="docutils literal notranslate"><span class="pre">create</span></code>-ing objects you would to end up with multiple copies of same-named objects, for example). Use <code class="docutils literal notranslate"><span class="pre">batchcommand</span></code> with the <code class="docutils literal notranslate"><span class="pre">/interactive</span></code> flag to enter interactive mode.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > @batchcommand/interactive tutorial_examples.batch_cmds
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -225,62 +205,30 @@ with the <code class="docutils literal notranslate"><span class="pre">/interacti
|
|||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>01/04: @create button:tutorial_examples.red_button.RedButton (hh for help)
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This shows that you are on the <code class="docutils literal notranslate"><span class="pre">@create</span></code> command, the first out of only four commands in this batch
|
||||
file. Observe that the command <code class="docutils literal notranslate"><span class="pre">@create</span></code> has <em>not</em> been actually processed at this point!</p>
|
||||
<p>This shows that you are on the <code class="docutils literal notranslate"><span class="pre">@create</span></code> command, the first out of only four commands in this batch file. Observe that the command <code class="docutils literal notranslate"><span class="pre">@create</span></code> has <em>not</em> been actually processed at this point!</p>
|
||||
<p>To take a look at the full command you are about to run, use <code class="docutils literal notranslate"><span class="pre">ll</span></code> (a batch-processor version of
|
||||
<code class="docutils literal notranslate"><span class="pre">look</span></code>). Use <code class="docutils literal notranslate"><span class="pre">pp</span></code> to actually process the current command (this will actually <code class="docutils literal notranslate"><span class="pre">@create</span></code> the button)
|
||||
– and make sure it worked as planned. Use <code class="docutils literal notranslate"><span class="pre">nn</span></code> (next) to go to the next command. Use <code class="docutils literal notranslate"><span class="pre">hh</span></code> for a
|
||||
list of commands.</p>
|
||||
<p>If there are errors, fix them in the batch file, then use <code class="docutils literal notranslate"><span class="pre">rr</span></code> to reload the file. You will still be
|
||||
at the same command and can rerun it easily with <code class="docutils literal notranslate"><span class="pre">pp</span></code> as needed. This makes for a simple debug
|
||||
cycle. It also allows you to rerun individual troublesome commands - as mentioned, in a large batch
|
||||
file this can be very useful. Do note that in many cases, commands depend on the previous ones (e.g.
|
||||
if <code class="docutils literal notranslate"><span class="pre">@create</span></code> in the example above had failed, the following commands would have had nothing to
|
||||
operate on).</p>
|
||||
<p>Use <code class="docutils literal notranslate"><span class="pre">nn</span></code> and <code class="docutils literal notranslate"><span class="pre">bb</span></code> (next and back) to step through the file; e.g. <code class="docutils literal notranslate"><span class="pre">nn</span> <span class="pre">12</span></code> will jump 12 steps forward
|
||||
(without processing any command in between). All normal commands of Evennia should work too while
|
||||
working in interactive mode.</p>
|
||||
<code class="docutils literal notranslate"><span class="pre">look</span></code>). Use <code class="docutils literal notranslate"><span class="pre">pp</span></code> to actually process the current command (this will actually <code class="docutils literal notranslate"><span class="pre">@create</span></code> the button) – and make sure it worked as planned. Use <code class="docutils literal notranslate"><span class="pre">nn</span></code> (next) to go to the next command. Use <code class="docutils literal notranslate"><span class="pre">hh</span></code> for a list of commands.</p>
|
||||
<p>If there are errors, fix them in the batch file, then use <code class="docutils literal notranslate"><span class="pre">rr</span></code> to reload the file. You will still be at the same command and can rerun it easily with <code class="docutils literal notranslate"><span class="pre">pp</span></code> as needed. This makes for a simple debug cycle. It also allows you to rerun individual troublesome commands - as mentioned, in a large batch file this can be very useful. Do note that in many cases, commands depend on the previous ones (e.g. if <code class="docutils literal notranslate"><span class="pre">create</span></code> in the example above had failed, the following commands would have had nothing to operate on).</p>
|
||||
<p>Use <code class="docutils literal notranslate"><span class="pre">nn</span></code> and <code class="docutils literal notranslate"><span class="pre">bb</span></code> (next and back) to step through the file; e.g. <code class="docutils literal notranslate"><span class="pre">nn</span> <span class="pre">12</span></code> will jump 12 steps forward (without processing any command in between). All normal commands of Evennia should work too while working in interactive mode.</p>
|
||||
</section>
|
||||
<section id="limitations-and-caveats">
|
||||
<h2>Limitations and Caveats<a class="headerlink" href="#limitations-and-caveats" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The batch-command processor is great for automating smaller builds or for testing new commands and
|
||||
objects repeatedly without having to write so much. There are several caveats you have to be aware
|
||||
of when using the batch-command processor for building larger, complex worlds though.</p>
|
||||
<p>The batch-command processor is great for automating smaller builds or for testing new commands and objects repeatedly without having to write so much. There are several caveats you have to be aware of when using the batch-command processor for building larger, complex worlds though.</p>
|
||||
<p>The main issue is that when you run a batch-command script you (<em>you</em>, as in your superuser
|
||||
character) are actually moving around in the game creating and building rooms in sequence, just as
|
||||
if you had been entering those commands manually, one by one. You have to take this into account
|
||||
when creating the file, so that you can ‘walk’ (or teleport) to the right places in order.</p>
|
||||
<p>This also means there are several pitfalls when designing and adding certain types of objects. Here
|
||||
are some examples:</p>
|
||||
character) are actually moving around in the game creating and building rooms in sequence, just as if you had been entering those commands manually, one by one. You have to take this into account when creating the file, so that you can ‘walk’ (or teleport) to the right places in order.</p>
|
||||
<p>This also means there are several pitfalls when designing and adding certain types of objects. Here are some examples:</p>
|
||||
<ul class="simple">
|
||||
<li><p><em>Rooms that change your <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Command Set</span></a></em>: Imagine that you build a ‘dark’ room, which
|
||||
severely limits the cmdsets of those entering it (maybe you have to find the light switch to
|
||||
proceed). In your batch script you would create this room, then teleport to it - and promptly be
|
||||
shifted into the dark state where none of your normal build commands work …</p></li>
|
||||
<li><p><em>Auto-teleportation</em>: Rooms that automatically teleport those that enter them to another place
|
||||
(like a trap room, for example). You would be teleported away too.</p></li>
|
||||
<li><p><em>Mobiles</em>: If you add aggressive mobs, they might attack you, drawing you into combat. If they
|
||||
have AI they might even follow you around when building - or they might move away from you before
|
||||
you’ve had time to finish describing and equipping them!</p></li>
|
||||
<li><p><em>Rooms that change your <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Command Set</span></a></em>: Imagine that you build a ‘dark’ room, which severely limits the cmdsets of those entering it (maybe you have to find the light switch to proceed). In your batch script you would create this room, then teleport to it - and promptly be shifted into the dark state where none of your normal build commands work …</p></li>
|
||||
<li><p><em>Auto-teleportation</em>: Rooms that automatically teleport those that enter them to another place (like a trap room, for example). You would be teleported away too.</p></li>
|
||||
<li><p><em>Mobiles</em>: If you add aggressive mobs, they might attack you, drawing you into combat. If they have AI they might even follow you around when building - or they might move away from you before you’ve had time to finish describing and equipping them!</p></li>
|
||||
</ul>
|
||||
<p>The solution to all these is to plan ahead. Make sure that superusers are never affected by whatever
|
||||
effects are in play. Add an on/off switch to objects and make sure it’s always set to <em>off</em> upon
|
||||
creation. It’s all doable, one just needs to keep it in mind.</p>
|
||||
<p>The solution to all these is to plan ahead. Make sure that superusers are never affected by whatever effects are in play. Add an on/off switch to objects and make sure it’s always set to <em>off</em> upon creation. It’s all doable, one just needs to keep it in mind.</p>
|
||||
</section>
|
||||
<section id="assorted-notes">
|
||||
<h2>Assorted notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The fact that you build as ‘yourself’ can also be considered an advantage however, should you ever
|
||||
decide to change the default command to allow others than superusers to call the processor. Since
|
||||
normal access-checks are still performed, a malevolent builder with access to the processor should
|
||||
not be able to do all that much damage (this is the main drawback of the <a class="reference internal" href="Batch-Code-Processor.html"><span class="doc std std-doc">Batch Code
|
||||
Processor</span></a>)</p>
|
||||
<section id="editor-highlighting-for-ev-files">
|
||||
<h2>Editor highlighting for .ev files<a class="headerlink" href="#editor-highlighting-for-ev-files" title="Permalink to this headline">¶</a></h2>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference external" href="https://www.gnu.org/software/emacs/">GNU Emacs</a> users might find it interesting to use emacs’
|
||||
<em>evennia mode</em>. This is an Emacs major mode found in <code class="docutils literal notranslate"><span class="pre">evennia/utils/evennia-mode.el</span></code>. It offers
|
||||
correct syntax highlighting and indentation with <code class="docutils literal notranslate"><span class="pre"><tab></span></code> when editing <code class="docutils literal notranslate"><span class="pre">.ev</span></code> files in Emacs. See the
|
||||
header of that file for installation instructions.</p></li>
|
||||
<li><p><a class="reference external" href="https://www.vim.org/">VIM</a> users can use amfl’s <a class="reference external" href="https://github.com/amfl/vim-evennia">vim-evennia</a>
|
||||
mode instead, see its readme for install instructions.</p></li>
|
||||
<li><p><a class="reference external" href="https://www.gnu.org/software/emacs/">GNU Emacs</a> users might find it interesting to use emacs’ <em>evennia mode</em>. This is an Emacs major mode found in <code class="docutils literal notranslate"><span class="pre">evennia/utils/evennia-mode.el</span></code>. It offers correct syntax highlighting and indentation with <code class="docutils literal notranslate"><span class="pre"><tab></span></code> when editing <code class="docutils literal notranslate"><span class="pre">.ev</span></code> files in Emacs. See the header of that file for installation instructions.</p></li>
|
||||
<li><p><a class="reference external" href="https://www.vim.org/">VIM</a> users can use amfl’s <a class="reference external" href="https://github.com/amfl/vim-evennia">vim-evennia</a> mode instead, see its readme for install instructions.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -301,13 +249,14 @@ mode instead, see its readme for install instructions.</p></li>
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Inputfuncs.html" title="Inputfuncs"
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-2"><a href="Batch-Processors.html" >Batch Processors</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Batch Command Processor</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Batch Code Processor" href="Batch-Code-Processor.html" />
|
||||
<link rel="prev" title="Connection Screen" href="Connection-Screen.html" />
|
||||
<link rel="next" title="Batch Command Processor" href="Batch-Command-Processor.html" />
|
||||
<link rel="prev" title="Default Commands" href="Default-Commands.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,10 +30,10 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Connection-Screen.html" title="Connection Screen"
|
||||
<a href="Default-Commands.html" title="Default Commands"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -69,11 +69,11 @@
|
|||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Connection-Screen.html"
|
||||
title="previous chapter">Connection Screen</a></p>
|
||||
<p class="topless"><a href="Default-Commands.html"
|
||||
title="previous chapter">Default Commands</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Batch-Code-Processor.html"
|
||||
title="next chapter">Batch Code Processor</a></p>
|
||||
<p class="topless"><a href="Batch-Command-Processor.html"
|
||||
title="next chapter">Batch Command Processor</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -106,74 +106,51 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="batch-processors">
|
||||
<h1>Batch Processors<a class="headerlink" href="#batch-processors" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Building a game world is a lot of work, especially when starting out. Rooms should be created,
|
||||
descriptions have to be written, objects must be detailed and placed in their proper places. In many
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Batch-Command-Processor.html">Batch Command Processor</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#the-batch-file">The batch file</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#interactive-mode">Interactive mode</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#limitations-and-caveats">Limitations and Caveats</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#editor-highlighting-for-ev-files">Editor highlighting for .ev files</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Batch-Code-Processor.html">Batch Code Processor</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#the-batch-file">The batch file</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#debug-mode">Debug mode</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#interactive-mode">Interactive mode</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#limitations-and-caveats">Limitations and Caveats</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<p>Building a game world is a lot of work, especially when starting out. Rooms should be created, descriptions have to be written, objects must be detailed and placed in their proper places. In many
|
||||
traditional MUD setups you had to do all this online, line by line, over a telnet session.</p>
|
||||
<p>Evennia already moves away from much of this by shifting the main coding work to external Python
|
||||
modules. But also building would be helped if one could do some or all of it externally. Enter
|
||||
Evennia’s <em>batch processors</em> (there are two of them). The processors allows you, as a game admin, to
|
||||
build your game completely offline in normal text files (<em>batch files</em>) that the processors
|
||||
understands. Then, when you are ready, you use the processors to read it all into Evennia (and into
|
||||
the database) in one go.</p>
|
||||
<p>You can of course still build completely online should you want to - this is certainly the easiest
|
||||
way to go when learning and for small build projects. But for major building work, the advantages of
|
||||
using the batch-processors are many:</p>
|
||||
<p>Evennia already moves away from much of this by shifting the main coding work to external Python modules. But also building would be helped if one could do some or all of it externally. Enter Evennia’s <em>batch processors</em> (there are two of them). The processors allows you, as a game admin, to build your game completely offline in normal text files (<em>batch files</em>) that the processors understands. Then, when you are ready, you use the processors to read it all into Evennia (and into the database) in one go.</p>
|
||||
<p>You can of course still build completely online should you want to - this is certainly the easiest way to go when learning and for small build projects. But for major building work, the advantages of using the batch-processors are many:</p>
|
||||
<ul class="simple">
|
||||
<li><p>It’s hard to compete with the comfort of a modern desktop text editor; Compared to a traditional
|
||||
MUD line input, you can get much better overview and many more features. Also, accidentally pressing
|
||||
Return won’t immediately commit things to the database.</p></li>
|
||||
<li><p>You might run external spell checkers on your batch files. In the case of one of the batch-
|
||||
processors (the one that deals with Python code), you could also run external debuggers and code
|
||||
analyzers on your file to catch problems before feeding it to Evennia.</p></li>
|
||||
<li><p>The batch files (as long as you keep them) are records of your work. They make a natural starting
|
||||
point for quickly re-building your world should you ever decide to start over.</p></li>
|
||||
<li><p>If you are an Evennia developer, using a batch file is a fast way to setup a test-game after
|
||||
having reset the database.</p></li>
|
||||
<li><p>The batch files might come in useful should you ever decide to distribute all or part of your
|
||||
world to others.</p></li>
|
||||
<li><p>It’s hard to compete with the comfort of a modern desktop text editor; Compared to a traditional MUD line input, you can get much better overview and many more features. Also, accidentally pressing Return won’t immediately commit things to the database.</p></li>
|
||||
<li><p>You might run external spell checkers on your batch files. In the case of one of the batch- processors (the one that deals with Python code), you could also run external debuggers and code analyzers on your file to catch problems before feeding it to Evennia.</p></li>
|
||||
<li><p>The batch files (as long as you keep them) are records of your work. They make a natural starting point for quickly re-building your world should you ever decide to start over.</p></li>
|
||||
<li><p>If you are an Evennia developer, using a batch file is a fast way to setup a test-game after having reset the database.</p></li>
|
||||
<li><p>The batch files might come in useful should you ever decide to distribute all or part of your world to others.</p></li>
|
||||
</ul>
|
||||
<p>There are two batch processors, the Batch-<em>command</em> processor and the Batch-<em>code</em> processor. The
|
||||
first one is the simpler of the two. It doesn’t require any programming knowledge - you basically
|
||||
just list in-game commands in a text file. The code-processor on the other hand is much more
|
||||
powerful but also more complex - it lets you use Evennia’s API to code your world in full-fledged
|
||||
Python code.</p>
|
||||
<ul class="simple">
|
||||
<li><p>The <a class="reference internal" href="Batch-Command-Processor.html"><span class="doc std std-doc">Batch Command Processor</span></a></p></li>
|
||||
<li><p>The <a class="reference internal" href="Batch-Code-Processor.html"><span class="doc std std-doc">Batch Code Processor</span></a></p></li>
|
||||
</ul>
|
||||
<p>If you plan to use international characters in your batchfiles you are wise to read about <em>file
|
||||
encodings</em> below.</p>
|
||||
<section id="a-note-on-file-encodings">
|
||||
<h2>A note on File Encodings<a class="headerlink" href="#a-note-on-file-encodings" title="Permalink to this headline">¶</a></h2>
|
||||
<p>As mentioned, both the processors take text files as input and then proceed to process them. As long
|
||||
as you stick to the standard <a class="reference external" href="https://en.wikipedia.org/wiki/Ascii">ASCII</a> character set (which means
|
||||
the normal English characters, basically) you should not have to worry much about this section.</p>
|
||||
<p>Many languages however use characters outside the simple <code class="docutils literal notranslate"><span class="pre">ASCII</span></code> table. Common examples are various
|
||||
apostrophes and umlauts but also completely different symbols like those of the greek or cyrillic
|
||||
alphabets.</p>
|
||||
<p>First, we should make it clear that Evennia itself handles international characters just fine. It
|
||||
(and Django) uses <a class="reference external" href="https://en.wikipedia.org/wiki/Unicode">unicode</a> strings internally.</p>
|
||||
<p>The problem is that when reading a text file like the batchfile, we need to know how to decode the
|
||||
byte-data stored therein to universal unicode. That means we need an <em>encoding</em> (a mapping) for how
|
||||
the file stores its data. There are many, many byte-encodings used around the world, with opaque
|
||||
names such as <code class="docutils literal notranslate"><span class="pre">Latin-1</span></code>, <code class="docutils literal notranslate"><span class="pre">ISO-8859-3</span></code> or <code class="docutils literal notranslate"><span class="pre">ARMSCII-8</span></code> to pick just a few examples. Problem is that
|
||||
it’s practially impossible to determine which encoding was used to save a file just by looking at it
|
||||
(it’s just a bunch of bytes!). You have to <em>know</em>.</p>
|
||||
<p>With this little introduction it should be clear that Evennia can’t guess but has to <em>assume</em> an
|
||||
encoding when trying to load a batchfile. The text editor and Evennia must speak the same “language”
|
||||
so to speak. Evennia will by default first try the international <code class="docutils literal notranslate"><span class="pre">UTF-8</span></code> encoding, but you can have
|
||||
Evennia try any sequence of different encodings by customizing the <code class="docutils literal notranslate"><span class="pre">ENCODINGS</span></code> list in your settings
|
||||
file. Evennia will use the first encoding in the list that do not raise any errors. Only if none
|
||||
work will the server give up and return an error message.</p>
|
||||
<p>You can often change the text editor encoding (this depends on your editor though), otherwise you
|
||||
need to add the editor’s encoding to Evennia’s <code class="docutils literal notranslate"><span class="pre">ENCODINGS</span></code> list. If you are unsure, write a test
|
||||
file with lots of non-ASCII letters in the editor of your choice, then import to make sure it works
|
||||
as it should.</p>
|
||||
<p>More help with encodings can be found in the entry <a class="reference internal" href="../Concepts/Text-Encodings.html"><span class="doc std std-doc">Text Encodings</span></a> and also in the
|
||||
Wikipedia article <a class="reference external" href="https://en.wikipedia.org/wiki/Text_encodings">here</a>.</p>
|
||||
<p>As mentioned, both the processors take text files as input and then proceed to process them. As long as you stick to the standard <a class="reference external" href="https://en.wikipedia.org/wiki/Ascii">ASCII</a> character set (which means the normal English characters, basically) you should not have to worry much about this section.</p>
|
||||
<p>Many languages however use characters outside the simple <code class="docutils literal notranslate"><span class="pre">ASCII</span></code> table. Common examples are various apostrophes and umlauts but also completely different symbols like those of the greek or cyrillic alphabets.</p>
|
||||
<p>First, we should make it clear that Evennia itself handles international characters just fine. It (and Django) uses <a class="reference external" href="https://en.wikipedia.org/wiki/Unicode">unicode</a> strings internally.</p>
|
||||
<p>The problem is that when reading a text file like the batchfile, we need to know how to decode the byte-data stored therein to universal unicode. That means we need an <em>encoding</em> (a mapping) for how the file stores its data. There are many, many byte-encodings used around the world, with opaque names such as <code class="docutils literal notranslate"><span class="pre">Latin-1</span></code>, <code class="docutils literal notranslate"><span class="pre">ISO-8859-3</span></code> or <code class="docutils literal notranslate"><span class="pre">ARMSCII-8</span></code> to pick just a few examples. Problem is that it’s practially impossible to determine which encoding was used to save a file just by looking at it (it’s just a bunch of bytes!). You have to <em>know</em>.</p>
|
||||
<p>With this little introduction it should be clear that Evennia can’t guess but has to <em>assume</em> an encoding when trying to load a batchfile. The text editor and Evennia must speak the same “language” so to speak. Evennia will by default first try the international <code class="docutils literal notranslate"><span class="pre">UTF-8</span></code> encoding, but you can have Evennia try any sequence of different encodings by customizing the <code class="docutils literal notranslate"><span class="pre">ENCODINGS</span></code> list in your settings file. Evennia will use the first encoding in the list that do not raise any errors. Only if none work will the server give up and return an error message.</p>
|
||||
<p>You can often change the text editor encoding (this depends on your editor though), otherwise you need to add the editor’s encoding to Evennia’s <code class="docutils literal notranslate"><span class="pre">ENCODINGS</span></code> list. If you are unsure, write a test file with lots of non-ASCII letters in the editor of your choice, then import to make sure it works as it should.</p>
|
||||
<p>More help with encodings can be found in the entry <a class="reference internal" href="../Concepts/Text-Encodings.html"><span class="doc std std-doc">Text Encodings</span></a> and also in the Wikipedia article <a class="reference external" href="https://en.wikipedia.org/wiki/Text_encodings">here</a>.</p>
|
||||
<p><strong>A footnote for the batch-code processor</strong>: Just because <em>Evennia</em> can parse your file and your
|
||||
fancy special characters, doesn’t mean that <em>Python</em> allows their use. Python syntax only allows
|
||||
international characters inside <em>strings</em>. In all other source code only <code class="docutils literal notranslate"><span class="pre">ASCII</span></code> set characters are
|
||||
fancy special characters, doesn’t mean that <em>Python</em> allows their use. Python syntax only allows international characters inside <em>strings</em>. In all other source code only <code class="docutils literal notranslate"><span class="pre">ASCII</span></code> set characters are
|
||||
allowed.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -194,10 +171,10 @@ allowed.</p>
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Connection-Screen.html" title="Connection Screen"
|
||||
<a href="Default-Commands.html" title="Default Commands"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -63,19 +63,20 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Channels</a><ul>
|
||||
<li><a class="reference internal" href="#using-channels-in-game">Using channels in-game</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-channels">Working with channels</a><ul>
|
||||
<li><a class="reference internal" href="#viewing-and-joining-channels">Viewing and joining channels</a></li>
|
||||
<li><a class="reference internal" href="#chat-on-channels">Chat on channels</a></li>
|
||||
<li><a class="reference internal" href="#talk-on-channels">Talk on channels</a></li>
|
||||
<li><a class="reference internal" href="#channel-administration">Channel administration</a><ul>
|
||||
<li><a class="reference internal" href="#restricting-channel-administration">Restricting channel administration</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#using-channels-in-code">Using channels in code</a><ul>
|
||||
<li><a class="reference internal" href="#allowing-characters-to-use-channels">Allowing Characters to use Channels</a></li>
|
||||
<li><a class="reference internal" href="#customizing-channel-output-and-behavior">Customizing channel output and behavior</a></li>
|
||||
<li><a class="reference internal" href="#channels-in-code">Channels in code</a></li>
|
||||
<li><a class="reference internal" href="#channel-logging">Channel logging</a><ul>
|
||||
<li><a class="reference internal" href="#channel-class">Channel class</a></li>
|
||||
<li><a class="reference internal" href="#channel-logging">Channel logging</a></li>
|
||||
<li><a class="reference internal" href="#properties-on-channels">Properties on Channels</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -143,15 +144,12 @@ it to every other subscriber.</p>
|
|||
<p><span class="versionmodified changed">Changed in version 1.0: </span>Channel system changed to use a central ‘channel’ command and nicks instead of
|
||||
auto-generated channel-commands and -cmdset. ChannelHandler was removed.</p>
|
||||
</div>
|
||||
<section id="using-channels-in-game">
|
||||
<h2>Using channels in-game<a class="headerlink" href="#using-channels-in-game" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In the default command set, channels are all handled via the mighty
|
||||
<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">channel
|
||||
command</span></a>, <code class="docutils literal notranslate"><span class="pre">channel</span></code> (or
|
||||
<code class="docutils literal notranslate"><span class="pre">chan</span></code>). By default, this command will assume all entities dealing with
|
||||
channels are <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>.</p>
|
||||
<section id="working-with-channels">
|
||||
<h2>Working with channels<a class="headerlink" href="#working-with-channels" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="viewing-and-joining-channels">
|
||||
<h3>Viewing and joining channels<a class="headerlink" href="#viewing-and-joining-channels" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In the default command set, channels are all handled via the mighty <a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">channel command</span></a>, <code class="docutils literal notranslate"><span class="pre">channel</span></code> (or <code class="docutils literal notranslate"><span class="pre">chan</span></code>). By default, this command will assume all entities dealing with channels are <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>.</p>
|
||||
<p>Viewing channels</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel - shows your subscriptions
|
||||
channel/all - shows all subs available to you
|
||||
channel/who - shows who subscribes to this channel
|
||||
|
|
@ -169,8 +167,8 @@ channel/unmute channelname
|
|||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="chat-on-channels">
|
||||
<h3>Chat on channels<a class="headerlink" href="#chat-on-channels" title="Permalink to this headline">¶</a></h3>
|
||||
<section id="talk-on-channels">
|
||||
<h3>Talk on channels<a class="headerlink" href="#talk-on-channels" title="Permalink to this headline">¶</a></h3>
|
||||
<p>To speak on a channel, do</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel public Hello world!
|
||||
</pre></div>
|
||||
|
|
@ -255,8 +253,7 @@ channel/unban mychannel = annoyinguser123
|
|||
<p>Banning adds the user to the channels blacklist. This means they will not be
|
||||
able to <em>rejoin</em> if you boot them. You will need to run <code class="docutils literal notranslate"><span class="pre">channel/boot</span></code> to
|
||||
actually kick them out.</p>
|
||||
<p>See the <a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">Channel command</span></a> api
|
||||
docs (and in-game help) for more details.</p>
|
||||
<p>See the <a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">Channel command</span></a> api docs (and in-game help) for more details.</p>
|
||||
<p>Admin-level users can also modify channel’s <a class="reference internal" href="Locks.html"><span class="doc std std-doc">locks</span></a>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/lock buildchannel = listen:all();send:perm(Builders)
|
||||
</pre></div>
|
||||
|
|
@ -271,11 +268,7 @@ control over the channel you can edit it, boot users and do other management tas
|
|||
</ul>
|
||||
<section id="restricting-channel-administration">
|
||||
<h4>Restricting channel administration<a class="headerlink" href="#restricting-channel-administration" title="Permalink to this headline">¶</a></h4>
|
||||
<p>By default everyone can use the channel command (<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdChannel</span></a>)
|
||||
to create channels and will then control the channels they created (to boot/ban
|
||||
people etc). If you as a developer does not want regular players to do this
|
||||
(perhaps you want only staff to be able to spawn new channels), you can
|
||||
override the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command and change its <code class="docutils literal notranslate"><span class="pre">locks</span></code> property.</p>
|
||||
<p>By default everyone can use the channel command (<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdChannel</span></a>) to create channels and will then control the channels they created (to boot/ban people etc). If you as a developer does not want regular players to do this (perhaps you want only staff to be able to spawn new channels), you can override the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command and change its <code class="docutils literal notranslate"><span class="pre">locks</span></code> property.</p>
|
||||
<p>The default <code class="docutils literal notranslate"><span class="pre">help</span></code> command has the following <code class="docutils literal notranslate"><span class="pre">locks</span></code> property:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">locks</span> <span class="o">=</span> <span class="s2">"cmd:not perm(channel_banned); admin:all(); manage:all(); changelocks: perm(Admin)"</span>
|
||||
</pre></div>
|
||||
|
|
@ -313,19 +306,18 @@ access-denied error when trying to use use these switches.</p>
|
|||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="using-channels-in-code">
|
||||
<h2>Using channels in code<a class="headerlink" href="#using-channels-in-code" title="Permalink to this headline">¶</a></h2>
|
||||
<p>For most common changes, the default channel, the recipient hooks and possibly
|
||||
overriding the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command will get you very far. But you can also tweak
|
||||
channels themselves.</p>
|
||||
<section id="allowing-characters-to-use-channels">
|
||||
<h2>Allowing Characters to use Channels<a class="headerlink" href="#allowing-characters-to-use-channels" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The default <code class="docutils literal notranslate"><span class="pre">channel</span></code> command (<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdChannel</span></a>)
|
||||
sits in the <code class="docutils literal notranslate"><span class="pre">Account</span></code> <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">command set</span></a>. It is set up such that it will
|
||||
always operate on <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>, even if you were to add it to the
|
||||
<code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>.</p>
|
||||
<p>It’s a one-line change to make this command accept non-account callers. But for
|
||||
convenience we provide a version for Characters/Objects. Just import
|
||||
<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdObjectChannel" title="evennia.commands.default.comms.CmdObjectChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdObjectChannel</span></a>
|
||||
and inherit from that instead.</p>
|
||||
<h3>Allowing Characters to use Channels<a class="headerlink" href="#allowing-characters-to-use-channels" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The default <code class="docutils literal notranslate"><span class="pre">channel</span></code> command (<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdChannel</span></a>) sits in the <code class="docutils literal notranslate"><span class="pre">Account</span></code> <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">command set</span></a>. It is set up such that it will always operate on <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>, even if you were to add it to the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>.</p>
|
||||
<p>It’s a one-line change to make this command accept non-account callers. But for convenience we provide a version for Characters/Objects. Just import <a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdObjectChannel" title="evennia.commands.default.comms.CmdObjectChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdObjectChannel</span></a> and inherit from that instead.</p>
|
||||
</section>
|
||||
<section id="customizing-channel-output-and-behavior">
|
||||
<h2>Customizing channel output and behavior<a class="headerlink" href="#customizing-channel-output-and-behavior" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Customizing channel output and behavior<a class="headerlink" href="#customizing-channel-output-and-behavior" title="Permalink to this headline">¶</a></h3>
|
||||
<p>When distributing a message, the channel will call a series of hooks on itself
|
||||
and (more importantly) on each recipient. So you can customize things a lot by
|
||||
just modifying hooks on your normal Object/Account typeclasses.</p>
|
||||
|
|
@ -354,19 +346,10 @@ recipient is skipped.</p></li>
|
|||
So make sure you modify the set actually used by your subcribers (or both).
|
||||
Default channels all use <code class="docutils literal notranslate"><span class="pre">Account</span></code> subscribers.</p>
|
||||
</section>
|
||||
<section id="channels-in-code">
|
||||
<h2>Channels in code<a class="headerlink" href="#channels-in-code" title="Permalink to this headline">¶</a></h2>
|
||||
<p>For most common changes, the default channel, the recipient hooks and possibly
|
||||
overriding the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command will get you very far. But you can also tweak
|
||||
channels themselves.</p>
|
||||
<p>Channels are <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities. This means they are
|
||||
persistent in the database, can have <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">attributes</span></a> and <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a>
|
||||
and can be easily extended.</p>
|
||||
<p>To change which channel typeclass Evennia uses for default commands, change
|
||||
<code class="docutils literal notranslate"><span class="pre">settings.BASE_CHANNEL_TYPECLASS</span></code>. The base command class is
|
||||
<a class="reference internal" href="../api/evennia.comms.comms.html#evennia.comms.comms.DefaultChannel" title="evennia.comms.comms.DefaultChannel"><span class="xref myst py py-class"><code class="docutils literal notranslate"><span class="pre">evennia.comms.comms.DefaultChannel</span></code></span></a>.
|
||||
There is an empty child class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/channels.py</span></code>, same
|
||||
as for other typelass-bases.</p>
|
||||
<section id="channel-class">
|
||||
<h3>Channel class<a class="headerlink" href="#channel-class" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Channels are <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities. This means they are persistent in the database, can have <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">attributes</span></a> and <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> and can be easily extended.</p>
|
||||
<p>To change which channel typeclass Evennia uses for default commands, change <code class="docutils literal notranslate"><span class="pre">settings.BASE_CHANNEL_TYPECLASS</span></code>. The base command class is <a class="reference internal" href="../api/evennia.comms.comms.html#evennia.comms.comms.DefaultChannel" title="evennia.comms.comms.DefaultChannel"><span class="xref myst py py-class"><code class="docutils literal notranslate"><span class="pre">evennia.comms.comms.DefaultChannel</span></code></span></a>. There is an empty child class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/channels.py</span></code>, same as for other typelass-bases.</p>
|
||||
<p>In code you create a new channel with <code class="docutils literal notranslate"><span class="pre">evennia.create_channel</span></code> or
|
||||
<code class="docutils literal notranslate"><span class="pre">Channel.create</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_channel</span><span class="p">,</span> <span class="n">search_object</span>
|
||||
|
|
@ -399,28 +382,24 @@ as for other typelass-bases.</p>
|
|||
</div>
|
||||
<p>The Channel’s <code class="docutils literal notranslate"><span class="pre">.connect</span></code> method will accept both <code class="docutils literal notranslate"><span class="pre">Account</span></code> and <code class="docutils literal notranslate"><span class="pre">Object</span></code> subscribers
|
||||
and will handle them transparently.</p>
|
||||
<p>The channel has many more hooks, both hooks shared with all typeclasses as well
|
||||
as special ones related to muting/banning etc. See the channel class for
|
||||
<p>The channel has many more hooks, both hooks shared with all typeclasses as well as special ones related to muting/banning etc. See the channel class for
|
||||
details.</p>
|
||||
</section>
|
||||
<section id="channel-logging">
|
||||
<h2>Channel logging<a class="headerlink" href="#channel-logging" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Channel logging<a class="headerlink" href="#channel-logging" title="Permalink to this headline">¶</a></h3>
|
||||
<div class="versionchanged">
|
||||
<p><span class="versionmodified changed">Changed in version 0.7: </span>Channels changed from using Msg to TmpMsg and optional log files.</p>
|
||||
</div>
|
||||
<div class="versionchanged">
|
||||
<p><span class="versionmodified changed">Changed in version 1.0: </span>Channels stopped supporting Msg and TmpMsg, using only log files.</p>
|
||||
</div>
|
||||
<p>The channel messages are not stored in the database. A channel is instead
|
||||
always logged to a regular text log-file
|
||||
<code class="docutils literal notranslate"><span class="pre">mygame/server/logs/channel_<channelname>.log</span></code>. This is where <code class="docutils literal notranslate"><span class="pre">channels/history</span> <span class="pre">channelname</span></code>
|
||||
gets its data from. A channel’s log will rotate when it grows too big, which
|
||||
thus also automatically limits the max amount of history a user can view with
|
||||
<p>The channel messages are not stored in the database. A channel is instead always logged to a regular text log-file <code class="docutils literal notranslate"><span class="pre">mygame/server/logs/channel_<channelname>.log</span></code>. This is where <code class="docutils literal notranslate"><span class="pre">channels/history</span> <span class="pre">channelname</span></code> gets its data from. A channel’s log will rotate when it grows too big, which thus also automatically limits the max amount of history a user can view with
|
||||
<code class="docutils literal notranslate"><span class="pre">/history</span></code>.</p>
|
||||
<p>The log file name is set on the channel class as the <code class="docutils literal notranslate"><span class="pre">log_file</span></code> property. This
|
||||
is a string that takes the formatting token <code class="docutils literal notranslate"><span class="pre">{channelname}</span></code> to be replaced with
|
||||
the (lower-case) name of the channel. By default the log is written to in the
|
||||
channel’s <code class="docutils literal notranslate"><span class="pre">at_post_channel_msg</span></code> method.</p>
|
||||
</section>
|
||||
<section id="properties-on-channels">
|
||||
<h3>Properties on Channels<a class="headerlink" href="#properties-on-channels" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Channels have all the standard properties of a Typeclassed entity (<code class="docutils literal notranslate"><span class="pre">key</span></code>,
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
<li><a class="reference internal" href="#utils-delay">utils.delay()</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#object-classes">Object Classes</a><ul>
|
||||
<li><a class="reference internal" href="#finding-classes">Finding Classes</a><ul>
|
||||
<li><a class="reference internal" href="#utils-inherits-from">utils.inherits_from()</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -81,12 +81,6 @@
|
|||
<li><a class="reference internal" href="#utils-crop">utils.crop()</a></li>
|
||||
<li><a class="reference internal" href="#utils-dedent">utils.dedent()</a></li>
|
||||
<li><a class="reference internal" href="#to-str-and-to-bytes">to_str() and to_bytes()</a></li>
|
||||
<li><a class="reference internal" href="#ansi-coloring-tools">Ansi Coloring Tools</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#display-utilities">Display utilities</a><ul>
|
||||
<li><a class="reference internal" href="#making-ascii-tables">Making ascii tables</a></li>
|
||||
<li><a class="reference internal" href="#menus">Menus</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -133,6 +127,9 @@
|
|||
<h1>Coding Utils<a class="headerlink" href="#coding-utils" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Evennia comes with many utilities to help with common coding tasks. Most are accessible directly
|
||||
from the flat API, otherwise you can find them in the <code class="docutils literal notranslate"><span class="pre">evennia/utils/</span></code> folder.</p>
|
||||
<blockquote>
|
||||
<div><p>This is just a small selection of the tools in <code class="docutils literal notranslate"><span class="pre">evennia/utils</span></code>. It’s worth to browse <a class="reference internal" href="../api/evennia.utils.html#evennia-utils"><span class="std std-ref">the directory</span></a> and in particular the content of <a class="reference internal" href="../api/evennia.utils.utils.html#evennia-utils-utils"><span class="std std-ref">evennia/utils/utils.py</span></a> directly to find more useful stuff.</p>
|
||||
</div></blockquote>
|
||||
<section id="searching">
|
||||
<h2>Searching<a class="headerlink" href="#searching" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A common thing to do is to search for objects. There it’s easiest to use the <code class="docutils literal notranslate"><span class="pre">search</span></code> method defined
|
||||
|
|
@ -140,11 +137,8 @@ on all objects. This will search for objects in the same location and inside the
|
|||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">objname</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The most common time one needs to do this is inside a command body. <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">=</span> <span class="pre">self.caller.search(objname)</span></code> will search inside the caller’s (typically, the character that typed
|
||||
the command) <code class="docutils literal notranslate"><span class="pre">.contents</span></code> (their “inventory”) and <code class="docutils literal notranslate"><span class="pre">.location</span></code> (their “room”).</p>
|
||||
<p>Give the keyword <code class="docutils literal notranslate"><span class="pre">global_search=True</span></code> to extend search to encompass entire database. Aliases will
|
||||
also be matched by this search. You will find multiple examples of this functionality in the default
|
||||
command set.</p>
|
||||
<p>The most common time one needs to do this is inside a command body. <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">=</span> <span class="pre">self.caller.search(objname)</span></code> will search inside the caller’s (typically, the character that typed the command) <code class="docutils literal notranslate"><span class="pre">.contents</span></code> (their “inventory”) and <code class="docutils literal notranslate"><span class="pre">.location</span></code> (their “room”).</p>
|
||||
<p>Give the keyword <code class="docutils literal notranslate"><span class="pre">global_search=True</span></code> to extend search to encompass entire database. Aliases will also be matched by this search. You will find multiple examples of this functionality in the default command set.</p>
|
||||
<p>If you need to search for objects in a code module you can use the functions in
|
||||
<code class="docutils literal notranslate"><span class="pre">evennia.utils.search</span></code>. You can access these as shortcuts <code class="docutils literal notranslate"><span class="pre">evennia.search_*</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">search_object</span>
|
||||
|
|
@ -152,42 +146,38 @@ command set.</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../api/evennia.accounts.manager.html#evennia.accounts.manager.AccountDBManager.search_account" title="evennia.accounts.manager.AccountDBManager.search_account"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_account</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.objects.manager.html#evennia.objects.manager.ObjectDBManager.search_object" title="evennia.objects.manager.ObjectDBManager.search_object"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_object</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.search.html#evennia.utils.search.search_tag" title="evennia.utils.search.search_tag"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.search(object)_by_tag</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.scripts.manager.html#evennia.scripts.manager.ScriptDBManager.search_script" title="evennia.scripts.manager.ScriptDBManager.search_script"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_script</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.comms.managers.html#evennia.comms.managers.ChannelDBManager.search_channel" title="evennia.comms.managers.ChannelDBManager.search_channel"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_channel</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.comms.managers.html#evennia.comms.managers.MsgManager.search_message" title="evennia.comms.managers.MsgManager.search_message"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_message</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.help.manager.html#evennia.help.manager.HelpEntryManager.search_help" title="evennia.help.manager.HelpEntryManager.search_help"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_help</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.accounts.manager.html#evennia.accounts.manager.AccountDBManager.search_account" title="evennia.accounts.manager.AccountDBManager.search_account"><span class="xref myst py py-meth">evennia.search_account</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.objects.manager.html#evennia.objects.manager.ObjectDBManager.search_object" title="evennia.objects.manager.ObjectDBManager.search_object"><span class="xref myst py py-meth">evennia.search_object</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.search.html#evennia.utils.search.search_tag" title="evennia.utils.search.search_tag"><span class="xref myst py py-func">evennia.search(object)_by_tag</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.scripts.manager.html#evennia.scripts.manager.ScriptDBManager.search_script" title="evennia.scripts.manager.ScriptDBManager.search_script"><span class="xref myst py py-meth">evennia.search_script</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.comms.managers.html#evennia.comms.managers.ChannelDBManager.search_channel" title="evennia.comms.managers.ChannelDBManager.search_channel"><span class="xref myst py py-meth">evennia.search_channel</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.comms.managers.html#evennia.comms.managers.MsgManager.search_message" title="evennia.comms.managers.MsgManager.search_message"><span class="xref myst py py-meth">evennia.search_message</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.help.manager.html#evennia.help.manager.HelpEntryManager.search_help" title="evennia.help.manager.HelpEntryManager.search_help"><span class="xref myst py py-meth">evennia.search_help</span></a></p></li>
|
||||
</ul>
|
||||
<p>Note that these latter methods will always return a <code class="docutils literal notranslate"><span class="pre">list</span></code> of results, even if the list has one or
|
||||
zero entries.</p>
|
||||
<p>Note that these latter methods will always return a <code class="docutils literal notranslate"><span class="pre">list</span></code> of results, even if the list has one or zero entries.</p>
|
||||
</section>
|
||||
<section id="create">
|
||||
<h2>Create<a class="headerlink" href="#create" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Apart from the in-game build commands (<code class="docutils literal notranslate"><span class="pre">@create</span></code> etc), you can also build all of Evennia’s game
|
||||
entities directly in code (for example when defining new create commands).</p>
|
||||
<p>Apart from the in-game build commands (<code class="docutils literal notranslate"><span class="pre">@create</span></code> etc), you can also build all of Evennia’s game entities directly in code (for example when defining new create commands).</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">import</span> <span class="nn">evennia</span>
|
||||
|
||||
<span class="n">myobj</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">create_objects</span><span class="p">(</span><span class="s2">"game.gamesrc.objects.myobj.MyObj"</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"MyObj"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_account" title="evennia.utils.create.create_account"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_account</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_object" title="evennia.utils.create.create_object"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_object</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_script</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_channel" title="evennia.utils.create.create_channel"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_channel</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_help_entry" title="evennia.utils.create.create_help_entry"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_help_entry</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_message" title="evennia.utils.create.create_message"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_message</span></code></span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_account" title="evennia.utils.create.create_account"><span class="xref myst py py-func">evennia.create_account</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_object" title="evennia.utils.create.create_object"><span class="xref myst py py-func">evennia.create_object</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">evennia.create_script</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_channel" title="evennia.utils.create.create_channel"><span class="xref myst py py-func">evennia.create_channel</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_help_entry" title="evennia.utils.create.create_help_entry"><span class="xref myst py py-func">evennia.create_help_entry</span></a></p></li>
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_message" title="evennia.utils.create.create_message"><span class="xref myst py py-func">evennia.create_message</span></a></p></li>
|
||||
</ul>
|
||||
<p>Each of these create-functions have a host of arguments to further customize the created entity. See
|
||||
<code class="docutils literal notranslate"><span class="pre">evennia/utils/create.py</span></code> for more information.</p>
|
||||
<p>Each of these create-functions have a host of arguments to further customize the created entity. See <code class="docutils literal notranslate"><span class="pre">evennia/utils/create.py</span></code> for more information.</p>
|
||||
</section>
|
||||
<section id="logging">
|
||||
<h2>Logging<a class="headerlink" href="#logging" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Normally you can use Python <code class="docutils literal notranslate"><span class="pre">print</span></code> statements to see output to the terminal/log. The <code class="docutils literal notranslate"><span class="pre">print</span></code>
|
||||
statement should only be used for debugging though. For producion output, use the <code class="docutils literal notranslate"><span class="pre">logger</span></code> which
|
||||
will create proper logs either to terminal or to file.</p>
|
||||
statement should only be used for debugging though. For producion output, use the <code class="docutils literal notranslate"><span class="pre">logger</span></code> which will create proper logs either to terminal or to file.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">logger</span>
|
||||
<span class="c1">#</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">log_err</span><span class="p">(</span><span class="s2">"This is an Error!"</span><span class="p">)</span>
|
||||
|
|
@ -196,8 +186,7 @@ will create proper logs either to terminal or to file.</p>
|
|||
<span class="n">logger</span><span class="o">.</span><span class="n">log_dep</span><span class="p">(</span><span class="s2">"This feature is deprecated"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>There is a special log-message type, <code class="docutils literal notranslate"><span class="pre">log_trace()</span></code> that is intended to be called from inside a
|
||||
traceback - this can be very useful for relaying the traceback message back to log without having it
|
||||
<p>There is a special log-message type, <code class="docutils literal notranslate"><span class="pre">log_trace()</span></code> that is intended to be called from inside a traceback - this can be very useful for relaying the traceback message back to log without having it
|
||||
kill the server.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">try</span><span class="p">:</span>
|
||||
<span class="c1"># [some code that may fail...]</span>
|
||||
|
|
@ -205,24 +194,18 @@ kill the server.</p>
|
|||
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">(</span><span class="s2">"This text will show beneath the traceback itself."</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">log_file</span></code> logger, finally, is a very useful logger for outputting arbitrary log messages. This
|
||||
is a heavily optimized asynchronous log mechanism using
|
||||
<a class="reference external" href="https://en.wikipedia.org/wiki/Thread_%28computing%29">threads</a> to avoid overhead. You should be
|
||||
able to use it for very heavy custom logging without fearing disk-write delays.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">log_file</span></code> logger, finally, is a very useful logger for outputting arbitrary log messages. This is a heavily optimized asynchronous log mechanism using <a class="reference external" href="https://en.wikipedia.org/wiki/Thread_%28computing%29">threads</a> to avoid overhead. You should be able to use it for very heavy custom logging without fearing disk-write delays.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">logger</span><span class="o">.</span><span class="n">log_file</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">filename</span><span class="o">=</span><span class="s2">"mylog.log"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If not an absolute path is given, the log file will appear in the <code class="docutils literal notranslate"><span class="pre">mygame/server/logs/</span></code> directory.
|
||||
If the file already exists, it will be appended to. Timestamps on the same format as the normal
|
||||
Evennia logs will be automatically added to each entry. If a filename is not specified, output will
|
||||
be written to a file <code class="docutils literal notranslate"><span class="pre">game/logs/game.log</span></code>.</p>
|
||||
<p>If not an absolute path is given, the log file will appear in the <code class="docutils literal notranslate"><span class="pre">mygame/server/logs/</span></code> directory. If the file already exists, it will be appended to. Timestamps on the same format as the normal Evennia logs will be automatically added to each entry. If a filename is not specified, output will be written to a file <code class="docutils literal notranslate"><span class="pre">game/logs/game.log</span></code>.</p>
|
||||
<p>See also the <a class="reference internal" href="../Coding/Debugging.html"><span class="doc std std-doc">Debugging</span></a> documentation for help with finding elusive bugs.</p>
|
||||
</section>
|
||||
<section id="time-utilities">
|
||||
<h2>Time Utilities<a class="headerlink" href="#time-utilities" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="game-time">
|
||||
<h3>Game time<a class="headerlink" href="#game-time" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Evennia tracks the current server time. You can access this time via the <code class="docutils literal notranslate"><span class="pre">evennia.gametime</span></code>
|
||||
shortcut:</p>
|
||||
<p>Evennia tracks the current server time. You can access this time via the <code class="docutils literal notranslate"><span class="pre">evennia.gametime</span></code> shortcut:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">gametime</span>
|
||||
|
||||
<span class="c1"># all the functions below return times in seconds).</span>
|
||||
|
|
@ -247,12 +230,8 @@ shortcut:</p>
|
|||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The setting <code class="docutils literal notranslate"><span class="pre">TIME_FACTOR</span></code> determines how fast/slow in-game time runs compared to the real world. The
|
||||
setting <code class="docutils literal notranslate"><span class="pre">TIME_GAME_EPOCH</span></code> sets the starting game epoch (in seconds). The functions from the
|
||||
<code class="docutils literal notranslate"><span class="pre">gametime</span></code> module all return their times in seconds. You can convert this to whatever units of time
|
||||
you desire for your game. You can use the <code class="docutils literal notranslate"><span class="pre">@time</span></code> command to view the server time info.</p>
|
||||
<p>You can also <em>schedule</em> things to happen at specific in-game times using the
|
||||
<a class="reference internal" href="../api/evennia.utils.gametime.html#evennia.utils.gametime.schedule" title="evennia.utils.gametime.schedule"><span class="xref myst py py-func">gametime.schedule</span></a> function:</p>
|
||||
<p>The setting <code class="docutils literal notranslate"><span class="pre">TIME_FACTOR</span></code> determines how fast/slow in-game time runs compared to the real world. The setting <code class="docutils literal notranslate"><span class="pre">TIME_GAME_EPOCH</span></code> sets the starting game epoch (in seconds). The functions from the <code class="docutils literal notranslate"><span class="pre">gametime</span></code> module all return their times in seconds. You can convert this to whatever units of time you desire for your game. You can use the <code class="docutils literal notranslate"><span class="pre">@time</span></code> command to view the server time info.
|
||||
You can also <em>schedule</em> things to happen at specific in-game times using the <a class="reference internal" href="../api/evennia.utils.gametime.html#evennia.utils.gametime.schedule" title="evennia.utils.gametime.schedule"><span class="xref myst py py-func">gametime.schedule</span></a> function:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">evennia</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">church_clock</span><span class="p">:</span>
|
||||
|
|
@ -265,9 +244,7 @@ you desire for your game. You can use the <code class="docutils literal notransl
|
|||
</section>
|
||||
<section id="utils-time-format">
|
||||
<h3>utils.time_format()<a class="headerlink" href="#utils-time-format" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This function takes a number of seconds as input (e.g. from the <code class="docutils literal notranslate"><span class="pre">gametime</span></code> module above) and
|
||||
converts it to a nice text output in days, hours etc. It’s useful when you want to show how old
|
||||
something is. It converts to four different styles of output using the <em>style</em> keyword:</p>
|
||||
<p>This function takes a number of seconds as input (e.g. from the <code class="docutils literal notranslate"><span class="pre">gametime</span></code> module above) and converts it to a nice text output in days, hours etc. It’s useful when you want to show how old something is. It converts to four different styles of output using the <em>style</em> keyword:</p>
|
||||
<ul class="simple">
|
||||
<li><p>style 0 - <code class="docutils literal notranslate"><span class="pre">5d:45m:12s</span></code> (standard colon output)</p></li>
|
||||
<li><p>style 1 - <code class="docutils literal notranslate"><span class="pre">5d</span></code> (shows only the longest time unit)</p></li>
|
||||
|
|
@ -277,50 +254,30 @@ something is. It converts to four different styles of output using the <em>style
|
|||
</section>
|
||||
<section id="utils-delay">
|
||||
<h3>utils.delay()<a class="headerlink" href="#utils-delay" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This allows for making a delayed call.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">utils</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_callback</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">text</span><span class="p">):</span>
|
||||
<span class="n">obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># wait 10 seconds before sending "Echo!" to obj (which we assume is defined)</span>
|
||||
<span class="n">deferred</span> <span class="o">=</span> <span class="n">utils</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">_callback</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="s2">"Echo!"</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
<span class="n">utils</span><span class="o">.</span><span class="n">delay</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">_callback</span><span class="p">,</span> <span class="n">obj</span><span class="p">,</span> <span class="s2">"Echo!"</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># code here will run immediately, not waiting for the delay to fire!</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This creates an asynchronous delayed call. It will fire the given callback function after the given
|
||||
number of seconds. This is a very light wrapper over a Twisted
|
||||
<a class="reference external" href="https://twistedmatrix.com/documents/current/core/howto/defer.html">Deferred</a>. Normally this is run
|
||||
non-persistently, which means that if the server is <code class="docutils literal notranslate"><span class="pre">@reload</span></code>ed before the delay is over, the
|
||||
callback will never run (the server forgets it). If setting <code class="docutils literal notranslate"><span class="pre">persistent</span></code> to True, the delay will be
|
||||
stored in the database and survive a <code class="docutils literal notranslate"><span class="pre">@reload</span></code> - but for this to work it is susceptible to the same
|
||||
limitations incurred when saving to an <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attribute</span></a>.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">deferred</span></code> return object can usually be ignored, but calling its <code class="docutils literal notranslate"><span class="pre">.cancel()</span></code> method will abort
|
||||
the delay prematurely.</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> is the lightest form of delayed call in Evennia. For other way to create time-bound
|
||||
tasks, see the <a class="reference internal" href="TickerHandler.html"><span class="doc std std-doc">TickerHandler</span></a> and <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>.</p>
|
||||
<blockquote>
|
||||
<div><p>Note that many delayed effects can be achieved without any need for an active timer. For example
|
||||
if you have a trait that should recover a point every 5 seconds you might just need its value when
|
||||
it’s needed, but checking the current time and calculating on the fly what value it should have.</p>
|
||||
</div></blockquote>
|
||||
<p>See <span class="xref myst">The Asynchronous process</span> for more information.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="object-classes">
|
||||
<h2>Object Classes<a class="headerlink" href="#object-classes" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="finding-classes">
|
||||
<h2>Finding Classes<a class="headerlink" href="#finding-classes" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="utils-inherits-from">
|
||||
<h3>utils.inherits_from()<a class="headerlink" href="#utils-inherits-from" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This useful function takes two arguments - an object to check and a parent. It returns <code class="docutils literal notranslate"><span class="pre">True</span></code> if
|
||||
object inherits from parent <em>at any distance</em> (as opposed to Python’s in-built <code class="docutils literal notranslate"><span class="pre">is_instance()</span></code> that
|
||||
<p>This useful function takes two arguments - an object to check and a parent. It returns <code class="docutils literal notranslate"><span class="pre">True</span></code> if object inherits from parent <em>at any distance</em> (as opposed to Python’s in-built <code class="docutils literal notranslate"><span class="pre">is_instance()</span></code> that
|
||||
will only catch immediate dependence). This function also accepts as input any combination of
|
||||
classes, instances or python-paths-to-classes.</p>
|
||||
<p>Note that Python code should usually work with <a class="reference external" href="https://en.wikipedia.org/wiki/Duck_typing">duck
|
||||
typing</a>. But in Evennia’s case it can sometimes be useful
|
||||
to check if an object inherits from a given <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a> as a way of identification. Say
|
||||
for example that we have a typeclass <em>Animal</em>. This has a subclass <em>Felines</em> which in turn has a
|
||||
subclass <em>HouseCat</em>. Maybe there are a bunch of other animal types too, like horses and dogs. Using
|
||||
<code class="docutils literal notranslate"><span class="pre">inherits_from</span></code> will allow you to check for all animals in one go:</p>
|
||||
<p>Note that Python code should usually work with <a class="reference external" href="https://en.wikipedia.org/wiki/Duck_typing">duck typing</a>. But in Evennia’s case it can sometimes be useful to check if an object inherits from a given <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a> as a way of identification. Say for example that we have a typeclass <em>Animal</em>. This has a subclass <em>Felines</em> which in turn has a subclass <em>HouseCat</em>. Maybe there are a bunch of other animal types too, like horses and dogs. Using <code class="docutils literal notranslate"><span class="pre">inherits_from</span></code> will allow you to check for all animals in one go:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">utils</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="n">utils</span><span class="o">.</span><span class="n">inherits_from</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">"typeclasses.objects.animals.Animal"</span><span class="p">):</span>
|
||||
<span class="n">obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"The bouncer stops you in the door. He says: 'No talking animals allowed.'"</span><span class="p">)</span>
|
||||
|
|
@ -335,8 +292,7 @@ complete</em> selection of text utilities found in <code class="docutils literal
|
|||
If nothing else it can be good to look here before starting to develop a solution of your own.</p>
|
||||
<section id="utils-fill">
|
||||
<h3>utils.fill()<a class="headerlink" href="#utils-fill" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also
|
||||
indents as needed.</p>
|
||||
<p>This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also indents as needed.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">outtxt</span> <span class="o">=</span> <span class="n">fill</span><span class="p">(</span><span class="n">intxt</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mi">78</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
|
|
@ -353,13 +309,7 @@ can be useful in listings when showing multiple lines would mess up things.</p>
|
|||
</section>
|
||||
<section id="utils-dedent">
|
||||
<h3>utils.dedent()<a class="headerlink" href="#utils-dedent" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This solves what may at first glance appear to be a trivial problem with text - removing
|
||||
indentations. It is used to shift entire paragraphs to the left, without disturbing any further
|
||||
formatting they may have. A common case for this is when using Python triple-quoted strings in code</p>
|
||||
<ul class="simple">
|
||||
<li><p>they will retain whichever indentation they have in the code, and to make easily-readable source
|
||||
code one usually don’t want to shift the string to the left edge.</p></li>
|
||||
</ul>
|
||||
<p>This solves what may at first glance appear to be a trivial problem with text - removing indentations. It is used to shift entire paragraphs to the left, without disturbing any further formatting they may have. A common case for this is when using Python triple-quoted strings in code - they will retain whichever indentation they have in the code, and to make easily-readable source code one usually don’t want to shift the string to the left edge.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1">#python code is entered at a given indentation</span>
|
||||
<span class="n">intxt</span> <span class="o">=</span> <span class="s2">"""</span>
|
||||
<span class="s2"> This is an example text that will end</span>
|
||||
|
|
@ -376,40 +326,8 @@ help entries).</p>
|
|||
</section>
|
||||
<section id="to-str-and-to-bytes">
|
||||
<h3>to_str() and to_bytes()<a class="headerlink" href="#to-str-and-to-bytes" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Evennia supplies two utility functions for converting text to the correct
|
||||
encodings. <code class="docutils literal notranslate"><span class="pre">to_str()</span></code> and <code class="docutils literal notranslate"><span class="pre">to_bytes()</span></code>. Unless you are adding a custom protocol and
|
||||
need to send byte-data over the wire, <code class="docutils literal notranslate"><span class="pre">to_str</span></code> is the only one you’ll need.</p>
|
||||
<p>The difference from Python’s in-built <code class="docutils literal notranslate"><span class="pre">str()</span></code> and <code class="docutils literal notranslate"><span class="pre">bytes()</span></code> operators are that
|
||||
the Evennia ones makes use of the <code class="docutils literal notranslate"><span class="pre">ENCODINGS</span></code> setting and will try very hard to
|
||||
never raise a traceback but instead echo errors through logging. See
|
||||
<a class="reference internal" href="../Concepts/Text-Encodings.html"><span class="doc std std-doc">here</span></a> for more info.</p>
|
||||
</section>
|
||||
<section id="ansi-coloring-tools">
|
||||
<h3>Ansi Coloring Tools<a class="headerlink" href="#ansi-coloring-tools" title="Permalink to this headline">¶</a></h3>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.ansi.html#evennia-utils-ansi"><span class="std std-ref">evennia.utils.ansi</span></a></p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
<section id="display-utilities">
|
||||
<h2>Display utilities<a class="headerlink" href="#display-utilities" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="making-ascii-tables">
|
||||
<h3>Making ascii tables<a class="headerlink" href="#making-ascii-tables" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The <a class="reference internal" href="../api/evennia.utils.evtable.html#evennia.utils.evtable.EvTable" title="evennia.utils.evtable.EvTable"><span class="xref myst py py-class">EvTable</span></a> class (<code class="docutils literal notranslate"><span class="pre">evennia/utils/evtable.py</span></code>) can be used
|
||||
to create correctly formatted text tables. There is also
|
||||
<a class="reference internal" href="../api/evennia.utils.evform.html#evennia.utils.evform.EvForm" title="evennia.utils.evform.EvForm"><span class="xref myst py py-class">EvForm</span></a> (<code class="docutils literal notranslate"><span class="pre">evennia/utils/evform.py</span></code>). This reads a fixed-format
|
||||
text template from a file in order to create any level of sophisticated ascii layout. Both evtable
|
||||
and evform have lots of options and inputs so see the header of each module for help.</p>
|
||||
<p>The third-party <a class="reference external" href="https://code.google.com/p/prettytable/">PrettyTable</a> module is also included in
|
||||
Evennia. PrettyTable is considered deprecated in favor of EvTable since PrettyTable cannot handle
|
||||
ANSI colour. PrettyTable can be found in <code class="docutils literal notranslate"><span class="pre">evennia/utils/prettytable/</span></code>. See its homepage above for
|
||||
instructions.</p>
|
||||
</section>
|
||||
<section id="menus">
|
||||
<h3>Menus<a class="headerlink" href="#menus" title="Permalink to this headline">¶</a></h3>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference internal" href="../api/evennia.utils.evmenu.html#evennia.utils.evmenu.EvMenu" title="evennia.utils.evmenu.EvMenu"><span class="xref myst py py-class">evennia.EvMenu</span></a></p></li>
|
||||
</ul>
|
||||
<p>Evennia supplies two utility functions for converting text to the correct encodings. <code class="docutils literal notranslate"><span class="pre">to_str()</span></code> and <code class="docutils literal notranslate"><span class="pre">to_bytes()</span></code>. Unless you are adding a custom protocol and need to send byte-data over the wire, <code class="docutils literal notranslate"><span class="pre">to_str</span></code> is the only one you’ll need.</p>
|
||||
<p>The difference from Python’s in-built <code class="docutils literal notranslate"><span class="pre">str()</span></code> and <code class="docutils literal notranslate"><span class="pre">bytes()</span></code> operators are that the Evennia ones makes use of the <code class="docutils literal notranslate"><span class="pre">ENCODINGS</span></code> setting and will try very hard to never raise a traceback but instead echo errors through logging. See <a class="reference internal" href="../Concepts/Text-Encodings.html"><span class="doc std std-doc">here</span></a> for more info.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Command Sets" href="Command-Sets.html" />
|
||||
<link rel="prev" title="Portal And Server" href="Portal-And-Server.html" />
|
||||
<link rel="prev" title="Locks" href="Locks.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<a href="Command-Sets.html" title="Command Sets"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
<a href="Locks.html" title="Locks"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -91,8 +91,8 @@
|
|||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Portal-And-Server.html"
|
||||
title="previous chapter">Portal And Server</a></p>
|
||||
<p class="topless"><a href="Locks.html"
|
||||
title="previous chapter">Locks</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Command-Sets.html"
|
||||
title="next chapter">Command Sets</a></p>
|
||||
|
|
@ -137,8 +137,7 @@ be familiar with how the command system works. The two pages were split for easy
|
|||
<li><p>A <em>Command</em> is a python class containing all the functioning code for what a command does - for example, a <em>get</em> command would contain code for picking up objects.</p></li>
|
||||
<li><p>A <em>Command Set</em> (often referred to as a CmdSet or cmdset) is like a container for one or more Commands. A given Command can go into any number of different command sets. Only by putting the command set on a character object you will make all the commands therein available to use by that character. You can also store command sets on normal objects if you want users to be able to use the object in various ways. Consider a “Tree” object with a cmdset defining the commands <em>climb</em> and <em>chop down</em>. Or a “Clock” with a cmdset containing the single command <em>check time</em>.</p></li>
|
||||
</ol>
|
||||
<p>This page goes into full detail about how to use Commands. To fully use them you must also read the page detailing <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Command Sets</span></a>. There is also a step-by-step <a class="reference internal" href="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">Adding Command Tutorial</span></a> that will get you started quickly without the
|
||||
extra explanations.</p>
|
||||
<p>This page goes into full detail about how to use Commands. To fully use them you must also read the page detailing <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Command Sets</span></a>. There is also a step-by-step <a class="reference internal" href="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">Adding Command Tutorial</span></a> that will get you started quickly without the extra explanations.</p>
|
||||
<section id="defining-commands">
|
||||
<h2>Defining Commands<a class="headerlink" href="#defining-commands" title="Permalink to this headline">¶</a></h2>
|
||||
<p>All commands are implemented as normal Python classes inheriting from the base class <code class="docutils literal notranslate"><span class="pre">Command</span></code>
|
||||
|
|
@ -230,7 +229,7 @@ NPC).</p>
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdstring</span></code> - the matched key for the command. This would be <em>look</em> in our example.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">args</span></code> - this is the rest of the string, except the command name. So if the string entered was <em>look at sword</em>, <code class="docutils literal notranslate"><span class="pre">args</span></code> would be ” <em>at sword</em>”. Note the space kept - Evennia would correctly interpret <code class="docutils literal notranslate"><span class="pre">lookat</span> <span class="pre">sword</span></code> too. This is useful for things like <code class="docutils literal notranslate"><span class="pre">/switches</span></code> that should not use space. In the <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> class used for default commands, this space is stripped. Also see the <code class="docutils literal notranslate"><span class="pre">arg_regex</span></code> property if you want to enforce a space to make <code class="docutils literal notranslate"><span class="pre">lookat</span> <span class="pre">sword</span></code> give a command-not-found error.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code> - the game <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> on which this command is defined. This need not be the caller, but since <code class="docutils literal notranslate"><span class="pre">look</span></code> is a common (default) command, this is probably defined directly on <em>BigGuy</em> - so <code class="docutils literal notranslate"><span class="pre">obj</span></code> will point to BigGuy. Otherwise <code class="docutils literal notranslate"><span class="pre">obj</span></code> could be an Account or any interactive object with commands defined on it, like in the example of the “check time” command defined on a “Clock” object. - <code class="docutils literal notranslate"><span class="pre">cmdset</span></code> - this is a reference to the merged CmdSet (see below) from which this command was
|
||||
matched. This variable is rarely used, it’s main use is for the <a class="reference internal" href="Help-System.html#command-auto-help-system"><span class="std std-doc">auto-help system</span></a> (<em>Advanced note: the merged cmdset need NOT be the same as <code class="docutils literal notranslate"><span class="pre">BigGuy.cmdset</span></code>. The merged set can be a combination of the cmdsets from other objects in the room, for example</em>).</p></li>
|
||||
matched. This variable is rarely used, it’s main use is for the <span class="xref myst">auto-help system</span> (<em>Advanced note: the merged cmdset need NOT be the same as <code class="docutils literal notranslate"><span class="pre">BigGuy.cmdset</span></code>. The merged set can be a combination of the cmdsets from other objects in the room, for example</em>).</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">raw_string</span></code> - this is the raw input coming from the user, without stripping any surrounding
|
||||
whitespace. The only thing that is stripped is the ending newline marker.</p></li>
|
||||
</ul>
|
||||
|
|
@ -254,7 +253,7 @@ truthfully report this value - that case the <code class="docutils literal notra
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">help_category</span></code> (optional string) - setting this helps to structure the auto-help into categories. If none is set, this will be set to <em>General</em>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">save_for_next</span></code> (optional boolean). This defaults to <code class="docutils literal notranslate"><span class="pre">False</span></code>. If <code class="docutils literal notranslate"><span class="pre">True</span></code>, a copy of this command object (along with any changes you have done to it) will be stored by the system and can be accessed by the next command by retrieving <code class="docutils literal notranslate"><span class="pre">self.caller.ndb.last_cmd</span></code>. The next run command will either clear or replace the storage.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">arg_regex</span></code> (optional raw string): Used to force the parser to limit itself and tell it when the command-name ends and arguments begin (such as requiring this to be a space or a /switch). This is done with a regular expression. <a class="reference internal" href="#arg-regex"><span class="std std-doc">See the arg_regex section</span></a> for the details.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">auto_help</span></code> (optional boolean). Defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code>. This allows for turning off the <a class="reference internal" href="Help-System.html#command-auto-help-system"><span class="std std-doc">auto-help system</span></a> on a per-command basis. This could be useful if you either want to write your help entries manually or hide the existence of a command from <code class="docutils literal notranslate"><span class="pre">help</span></code>’s generated list.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">auto_help</span></code> (optional boolean). Defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code>. This allows for turning off the <span class="xref myst">auto-help system</span> on a per-command basis. This could be useful if you either want to write your help entries manually or hide the existence of a command from <code class="docutils literal notranslate"><span class="pre">help</span></code>’s generated list.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">is_exit</span></code> (bool) - this marks the command as being used for an in-game exit. This is, by default, set by all Exit objects and you should not need to set it manually unless you make your own Exit system. It is used for optimization and allows the cmdhandler to easily disregard this command when the cmdset has its <code class="docutils literal notranslate"><span class="pre">no_exits</span></code> flag set.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">is_channel</span></code> (bool)- this marks the command as being used for an in-game channel. This is, by default, set by all Channel objects and you should not need to set it manually unless you make your own Channel system. is used for optimization and allows the cmdhandler to easily disregard this command when its cmdset has its <code class="docutils literal notranslate"><span class="pre">no_channels</span></code> flag set.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">msg_all_sessions</span></code> (bool): This affects the behavior of the <code class="docutils literal notranslate"><span class="pre">Command.msg</span></code> method. If unset (default), calling <code class="docutils literal notranslate"><span class="pre">self.msg(text)</span></code> from the Command will always only send text to the Session that actually triggered this Command. If set however, <code class="docutils literal notranslate"><span class="pre">self.msg(text)</span></code> will send to all Sessions relevant to the object this Command sits on. Just which Sessions receives the text depends on the object and the server’s <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code>.</p></li>
|
||||
|
|
@ -599,7 +598,7 @@ thus do so asynchronously, using callbacks.</p>
|
|||
<a href="Command-Sets.html" title="Command Sets"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
<a href="Locks.html" title="Locks"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Typeclasses" href="Typeclasses.html" />
|
||||
<link rel="next" title="Portal And Server" href="Portal-And-Server.html" />
|
||||
<link rel="prev" title="Tutorial for basic MUSH like game" href="../Howtos/Tutorial-for-basic-MUSH-like-game.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Howtos/Tutorial-for-basic-MUSH-like-game.html" title="Tutorial for basic MUSH like game"
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Core Components</a><ul>
|
||||
<li><a class="reference internal" href="#basic-entites">Basic entites</a></li>
|
||||
<li><a class="reference internal" href="#base-components">Base components</a></li>
|
||||
<li><a class="reference internal" href="#commands">Commands</a></li>
|
||||
<li><a class="reference internal" href="#utils-and-tools">Utils and tools</a></li>
|
||||
<li><a class="reference internal" href="#web-components">Web components</a></li>
|
||||
|
|
@ -74,8 +74,8 @@
|
|||
<p class="topless"><a href="../Howtos/Tutorial-for-basic-MUSH-like-game.html"
|
||||
title="previous chapter">Tutorial for basic MUSH like game</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Typeclasses.html"
|
||||
title="next chapter">Typeclasses</a></p>
|
||||
<p class="topless"><a href="Portal-And-Server.html"
|
||||
title="next chapter">Portal And Server</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -109,75 +109,54 @@
|
|||
<section class="tex2jax_ignore mathjax_ignore" id="core-components">
|
||||
<h1>Core Components<a class="headerlink" href="#core-components" title="Permalink to this headline">¶</a></h1>
|
||||
<p>These are the ‘building blocks’ out of which Evennia is built. This documentation is complementary to, and often goes deeper than, the doc-strings of each component in the <a class="reference internal" href="../Evennia-API.html"><span class="doc std std-doc">API</span></a>.</p>
|
||||
<section id="basic-entites">
|
||||
<h2>Basic entites<a class="headerlink" href="#basic-entites" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="base-components">
|
||||
<h2>Base components<a class="headerlink" href="#base-components" title="Permalink to this headline">¶</a></h2>
|
||||
<p>These are base pieces used to make an Evennia game. Most are long-lived and are persisted in the database.</p>
|
||||
<div class="toctree-wrapper compound">
|
||||
<ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Portal-And-Server.html">Portal And Server</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Sessions.html">Sessions</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#working-with-sessions">Working with Sessions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#portal-and-server-sessions">Portal and Server Sessions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Typeclasses.html">Typeclasses</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#difference-between-typeclasses-and-classes">Difference between typeclasses and classes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#creating-a-new-typeclass">Creating a new typeclass</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#about-typeclass-properties">About typeclass properties</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#overloading-hooks">Overloading hooks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#querying-for-typeclasses">Querying for typeclasses</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#updating-existing-typeclass-instances">Updating existing typeclass instances</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#swap-typeclass">Swap typeclass</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#working-with-typeclasses">Working with typeclasses</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#how-typeclasses-actually-work">How typeclasses actually work</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#caveats">Caveats</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#will-i-run-out-of-dbrefs">Will I run out of dbrefs?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Sessions.html">Sessions</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#properties-on-sessions">Properties on Sessions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#multisession-mode">Multisession mode</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#returning-data-to-the-session">Returning data to the session</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#customizing-the-session-object">Customizing the Session object</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#portal-and-server-sessions">Portal and Server Sessions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#sessionhandlers">Sessionhandlers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Accounts.html">Accounts</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Accounts.html#how-to-customize-your-own-account-types">How to customize your own Account types</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Accounts.html#properties-on-accounts">Properties on Accounts</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Accounts.html#working-with-accounts">Working with Accounts</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Objects.html">Objects</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#how-to-create-your-own-object-types">How to create your own object types</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#working-with-objects">Working with Objects</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#characters">Characters</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#rooms">Rooms</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#exits">Exits</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#adding-common-functionality">Adding common functionality</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#properties-and-functions-on-objects">Properties and functions on Objects</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Objects.html#subclasses-of-object">Subclasses of <code class="docutils literal notranslate"><span class="pre">Object</span></code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Scripts.html">Scripts</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#in-game-command-examples">In-game command examples</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#code-examples">Code examples</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#defining-new-scripts">Defining new Scripts</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#timed-scripts">Timed Scripts</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#script-attached-to-another-object">Script attached to another object</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#other-script-methods">Other Script methods</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#the-global-scripts-container">The GLOBAL_SCRIPTS container</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#hints-dealing-with-script-errors">Hints: Dealing with Script Errors</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#working-with-scripts">Working with Scripts</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#using-global-scripts">Using GLOBAL_SCRIPTS</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Channels.html">Channels</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Channels.html#using-channels-in-game">Using channels in-game</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Channels.html#allowing-characters-to-use-channels">Allowing Characters to use Channels</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Channels.html#customizing-channel-output-and-behavior">Customizing channel output and behavior</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Channels.html#channels-in-code">Channels in code</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Channels.html#channel-logging">Channel logging</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Channels.html#working-with-channels">Working with channels</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Channels.html#using-channels-in-code">Using channels in code</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Msg.html">Msg</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Msg.html#msg-in-code">Msg in code</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Msg.html#working-with-msg">Working with Msg</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Msg.html#tempmsg">TempMsg</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Attributes.html">Attributes</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#managing-attributes-in-code">Managing Attributes in Code</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#managing-attributes-in-game">Managing Attributes in-game</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#locking-and-checking-attributes">Locking and checking Attributes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#working-with-attributes">Working with Attributes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#what-types-of-data-can-i-save-in-an-attribute">What types of data can I save in an Attribute?</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#properties-of-attributes">Properties of Attributes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#in-memory-attributes-nattributes">In-memory Attributes (NAttributes)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -187,40 +166,35 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Tags.html">Tags</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Tags.html#properties-of-tags-and-aliases-and-permissions">Properties of Tags (and Aliases and Permissions)</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Tags.html#adding-removing-tags">Adding/Removing Tags</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Tags.html#searching-for-objects-with-a-given-tag">Searching for objects with a given tag</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Tags.html#using-aliases-and-permissions">Using Aliases and Permissions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Tags.html#assorted-notes">Assorted notes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Tags.html#working-with-tags">Working with Tags</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Tags.html#aliases-and-permissions">Aliases and Permissions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Prototypes.html">Spawner and Prototypes</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#using-the-olc">Using the OLC</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#the-prototype">The prototype</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#storing-prototypes">Storing prototypes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#using-spawn">Using @spawn</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#using-evennia-prototypes-spawner">Using evennia.prototypes.spawner()</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#working-with-prototypes">Working with Prototypes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#database-prototypes">Database prototypes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#module-based-prototypes">Module-based prototypes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#spawning">Spawning</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Help-System.html">Help System</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#using-the-help-system-from-in-game">Using the help system from in-game</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#sources-of-help-entries">Sources of help entries</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#entry-priority">Entry priority</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#locking-help-entries">Locking help entries</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#customizing-the-look-of-the-help-system">Customizing the look of the help system</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#working-with-three-types-of-help-entries">Working with three types of help entries</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#subtopics">Subtopics</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#technical-notes">Technical notes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Permissions.html">Permissions</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#the-super-user">The super user</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#managing-permissions">Managing Permissions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#the-permission-hierarchy">The permission hierarchy</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#checking-permissions">Checking permissions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#superusers">Superusers</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#working-with-permissions">Working with Permissions</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#quelling">Quelling</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Portal-And-Server.html">Portal And Server</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Locks.html">Locks</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#working-with-locks">Working with locks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#more-lock-definition-examples">More Lock definition examples</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#on-djangos-permission-system">On Django’s permission system</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
|
@ -249,34 +223,15 @@
|
|||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Default-Commands.html">Default Commands</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Connection-Screen.html">Connection Screen</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Connection-Screen.html#commands-available-at-the-connection-screen">Commands available at the Connection Screen</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Batch-Processors.html">Batch Processors</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html">Batch Command Processor</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html">Batch Code Processor</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Processors.html#a-note-on-file-encodings">A note on File Encodings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Batch-Code-Processor.html">Batch Code Processor</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#basic-usage">Basic Usage</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#the-batch-file">The batch file</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#debug-mode">Debug mode</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#interactive-mode">Interactive mode</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#limitations-and-caveats">Limitations and Caveats</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Batch-Command-Processor.html">Batch Command Processor</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#basic-usage">Basic Usage</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#the-batch-file">The batch file</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#interactive-mode">Interactive mode</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#limitations-and-caveats">Limitations and Caveats</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#assorted-notes">Assorted notes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Inputfuncs.html">Inputfuncs</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Inputfuncs.html#adding-your-own-inputfuncs">Adding your own inputfuncs</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Inputfuncs.html#default-inputfuncs">Default inputfuncs</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Inputfuncs.html#unmonitor">unmonitor</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -292,43 +247,31 @@
|
|||
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#create">Create</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#logging">Logging</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#time-utilities">Time Utilities</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#object-classes">Object Classes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#finding-classes">Finding Classes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#text-utilities">Text utilities</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#display-utilities">Display utilities</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="EvEditor.html">EvEditor</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#launching-the-editor">Launching the editor</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#example-of-usage">Example of usage</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#persistent-editor">Persistent editor</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#line-editor-usage">Line editor usage</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#the-eveditor-to-edit-code">The EvEditor to edit code</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#working-with-eveditor">Working with EvEditor</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="EvForm.html">EvForm</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="EvMenu.html">EvMenu</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#introduction">Introduction</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#launching-the-menu">Launching the menu</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#the-menu-nodes">The Menu nodes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#temporary-storage">Temporary storage</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#customizing-menu-formatting">Customizing Menu formatting</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#evmenu-templating-language">EvMenu templating language</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#id1">Examples:</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#ask-for-simple-input">Ask for simple input</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#asking-for-one-line-input">Asking for one-line input</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#the-list-node-decorator">The <code class="docutils literal notranslate"><span class="pre">@list_node</span></code> decorator</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#assorted-notes">Assorted notes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="EvMore.html">EvMore</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMore.html#using-evmore">Using EvMore</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#example-menus">Example Menus</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="EvMore.html">EvMore</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="EvTable.html">EvTable</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="FuncParser.html">The Inline Function Parser</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#uses-in-default-evennia">Uses in default Evennia</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#using-the-funcparser">Using the FuncParser</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="FuncParser.html">FuncParser inline text parsing</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#working-with-funcparser">Working with FuncParser</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#defining-custom-callables">Defining custom callables</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#default-callables">Default callables</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#default-funcparser-callables">Default funcparser callables</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="MonitorHandler.html">MonitorHandler</a><ul>
|
||||
|
|
@ -339,19 +282,8 @@
|
|||
<li class="toctree-l2"><a class="reference internal" href="TickerHandler.html#about-tickers">About Tickers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Locks.html">Locks</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#setting-and-checking-a-lock">Setting and checking a lock</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#defining-locks">Defining locks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#checking-simple-strings">Checking simple strings</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#default-locks">Default locks</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#more-lock-definition-examples">More Lock definition examples</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#a-complete-example-of-setting-locks-on-an-object">A complete example of setting locks on an object</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Locks.html#on-djangos-permission-system">On Django’s permission system</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Signals.html">Signals</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Signals.html#attaching-a-handler-to-a-signal">Attaching a handler to a signal</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Signals.html#available-signals">Available signals</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Signals.html#working-with-signals">Working with Signals</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -419,7 +351,7 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="../Howtos/Tutorial-for-basic-MUSH-like-game.html" title="Tutorial for basic MUSH like game"
|
||||
|
|
|
|||
|
|
@ -1,175 +0,0 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>Connection Screen — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||||
<script src="../_static/jquery.js"></script>
|
||||
<script src="../_static/underscore.js"></script>
|
||||
<script src="../_static/doctools.js"></script>
|
||||
<script src="../_static/language_data.js"></script>
|
||||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Batch Processors" href="Batch-Processors.html" />
|
||||
<link rel="prev" title="Default Commands" href="Default-Commands.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Default-Commands.html" title="Default Commands"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Connection Screen</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
||||
<div class="document">
|
||||
|
||||
<div class="documentwrapper">
|
||||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
<p class="logo"><a href="../index.html">
|
||||
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
|
||||
</a></p>
|
||||
<div id="searchbox" style="display: none" role="search">
|
||||
<h3 id="searchlabel">Quick search</h3>
|
||||
<div class="searchformwrapper">
|
||||
<form class="search" action="../search.html" method="get">
|
||||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||||
<input type="submit" value="Go" />
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Connection Screen</a><ul>
|
||||
<li><a class="reference internal" href="#commands-available-at-the-connection-screen">Commands available at the Connection Screen</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Default-Commands.html"
|
||||
title="previous chapter">Default Commands</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Batch-Processors.html"
|
||||
title="next chapter">Batch Processors</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="../_sources/Components/Connection-Screen.md.txt"
|
||||
rel="nofollow">Show Page Source</a></li>
|
||||
</ul>
|
||||
</div><h3>Links</h3>
|
||||
<ul>
|
||||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||||
<li>
|
||||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>Versions</h3>
|
||||
<ul>
|
||||
<li><a href="Connection-Screen.html">1.0-dev (develop branch)</a></li>
|
||||
<ul>
|
||||
<li><a href="../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||||
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="connection-screen">
|
||||
<h1>Connection Screen<a class="headerlink" href="#connection-screen" title="Permalink to this headline">¶</a></h1>
|
||||
<p>When you first connect to your game you are greeted by Evennia’s default connection screen.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>==============================================================
|
||||
Welcome to Evennia, version Beta-ra4d24e8a3cab+!
|
||||
|
||||
If you have an existing account, connect to it by typing:
|
||||
connect <username> <password>
|
||||
If you need to create an account, type (without the <>'s):
|
||||
create <username> <password>
|
||||
|
||||
If you have spaces in your username, enclose it in quotes.
|
||||
Enter help for more info. look will re-show this screen.
|
||||
==============================================================
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Effective, but not very exciting. You will most likely want to change this to be more unique for
|
||||
your game. This is simple:</p>
|
||||
<ol class="simple">
|
||||
<li><p>Edit <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/connection_screens.py</span></code>.</p></li>
|
||||
<li><p><a class="reference internal" href="../Setup/Running-Evennia.html"><span class="doc std std-doc">Reload</span></a> Evennia.</p></li>
|
||||
</ol>
|
||||
<p>Evennia will look into this module and locate all <em>globally defined strings</em> in it. These strings
|
||||
are used as the text in your connection screen and are shown to the user at startup. If more than
|
||||
one such string/screen is defined in the module, a <em>random</em> screen will be picked from among those
|
||||
available.</p>
|
||||
<section id="commands-available-at-the-connection-screen">
|
||||
<h2>Commands available at the Connection Screen<a class="headerlink" href="#commands-available-at-the-connection-screen" title="Permalink to this headline">¶</a></h2>
|
||||
<p>You can also customize the <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> available to use while the connection screen is
|
||||
shown (<code class="docutils literal notranslate"><span class="pre">connect</span></code>, <code class="docutils literal notranslate"><span class="pre">create</span></code> etc). These commands are a bit special since when the screen is running
|
||||
the account is not yet logged in. A command is made available at the login screen by adding them to
|
||||
<code class="docutils literal notranslate"><span class="pre">UnloggedinCmdSet</span></code> in <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdset.py</span></code>. See <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> and the
|
||||
tutorial section on how to add new commands to a default command set.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
<ul>
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="../genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Default-Commands.html" title="Default Commands"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Connection Screen</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
<div class="footer" role="contentinfo">
|
||||
© Copyright 2022, The Evennia developer community.
|
||||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Connection Screen" href="Connection-Screen.html" />
|
||||
<link rel="next" title="Batch Processors" href="Batch-Processors.html" />
|
||||
<link rel="prev" title="Command Sets" href="Command-Sets.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Connection-Screen.html" title="Connection Screen"
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Command-Sets.html" title="Command Sets"
|
||||
|
|
@ -64,8 +64,8 @@
|
|||
<p class="topless"><a href="Command-Sets.html"
|
||||
title="previous chapter">Command Sets</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Connection-Screen.html"
|
||||
title="next chapter">Connection Screen</a></p>
|
||||
<p class="topless"><a href="Batch-Processors.html"
|
||||
title="next chapter">Batch Processors</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -211,7 +211,7 @@ with <a class="reference internal" href="EvEditor.html"><span class="doc std std
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Connection-Screen.html" title="Connection Screen"
|
||||
<a href="Batch-Processors.html" title="Batch Processors"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Command-Sets.html" title="Command Sets"
|
||||
|
|
|
|||
|
|
@ -64,12 +64,14 @@
|
|||
<ul>
|
||||
<li><a class="reference internal" href="#">EvEditor</a><ul>
|
||||
<li><a class="reference internal" href="#launching-the-editor">Launching the editor</a></li>
|
||||
<li><a class="reference internal" href="#example-of-usage">Example of usage</a></li>
|
||||
<li><a class="reference internal" href="#working-with-eveditor">Working with EvEditor</a><ul>
|
||||
<li><a class="reference internal" href="#persistent-editor">Persistent editor</a></li>
|
||||
<li><a class="reference internal" href="#line-editor-usage">Line editor usage</a></li>
|
||||
<li><a class="reference internal" href="#the-eveditor-to-edit-code">The EvEditor to edit code</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
|
|
@ -137,8 +139,8 @@ It has no other mechanical function.</p></li>
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code> (default <code class="docutils literal notranslate"><span class="pre">False</span></code>): if set to <code class="docutils literal notranslate"><span class="pre">True</span></code>, the editor will survive a reboot.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="example-of-usage">
|
||||
<h2>Example of usage<a class="headerlink" href="#example-of-usage" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-eveditor">
|
||||
<h2>Working with EvEditor<a class="headerlink" href="#working-with-eveditor" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This is an example command for setting a specific Attribute using the editor.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">eveditor</span>
|
||||
|
|
@ -171,9 +173,8 @@ It has no other mechanical function.</p></li>
|
|||
<span class="n">key</span><span class="o">=</span><span class="n">key</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="persistent-editor">
|
||||
<h2>Persistent editor<a class="headerlink" href="#persistent-editor" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Persistent editor<a class="headerlink" href="#persistent-editor" title="Permalink to this headline">¶</a></h3>
|
||||
<p>If you set the <code class="docutils literal notranslate"><span class="pre">persistent</span></code> keyword to <code class="docutils literal notranslate"><span class="pre">True</span></code> when creating the editor, it will remain open even
|
||||
when reloading the game. In order to be persistent, an editor needs to have its callback functions
|
||||
(<code class="docutils literal notranslate"><span class="pre">loadfunc</span></code>, <code class="docutils literal notranslate"><span class="pre">savefunc</span></code> and <code class="docutils literal notranslate"><span class="pre">quitfunc</span></code>) as top-level functions defined in the module. Since these
|
||||
|
|
@ -214,7 +215,7 @@ functions will be stored, Python will need to find them.</p>
|
|||
</div>
|
||||
</section>
|
||||
<section id="line-editor-usage">
|
||||
<h2>Line editor usage<a class="headerlink" href="#line-editor-usage" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Line editor usage<a class="headerlink" href="#line-editor-usage" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The editor mimics the <code class="docutils literal notranslate"><span class="pre">VIM</span></code> editor as best as possible. The below is an excerpt of the return from
|
||||
the in-editor help command (<code class="docutils literal notranslate"><span class="pre">:h</span></code>).</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <txt> - any non-command is appended to the end of the buffer.
|
||||
|
|
@ -260,29 +261,21 @@ the in-editor help command (<code class="docutils literal notranslate"><span cla
|
|||
</div>
|
||||
</section>
|
||||
<section id="the-eveditor-to-edit-code">
|
||||
<h2>The EvEditor to edit code<a class="headerlink" href="#the-eveditor-to-edit-code" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code> is also used to edit some Python code in Evennia. The <code class="docutils literal notranslate"><span class="pre">@py</span></code> command supports an
|
||||
<code class="docutils literal notranslate"><span class="pre">/edit</span></code> switch that will open the EvEditor in code mode. This mode isn’t significantly different
|
||||
from the standard one, except it handles automatic indentation of blocks and a few options to
|
||||
control this behavior.</p>
|
||||
<h3>The EvEditor to edit code<a class="headerlink" href="#the-eveditor-to-edit-code" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code> is also used to edit some Python code in Evennia. The <code class="docutils literal notranslate"><span class="pre">py</span></code> command supports an <code class="docutils literal notranslate"><span class="pre">/edit</span></code> switch that will open the EvEditor in code mode. This mode isn’t significantly different from the standard one, except it handles automatic indentation of blocks and a few options to control this behavior.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">:<</span></code> to remove a level of indentation for the future lines.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">:+</span></code> to add a level of indentation for the future lines.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">:=</span></code> to disable automatic indentation altogether.</p></li>
|
||||
</ul>
|
||||
<p>Automatic indentation is there to make code editing more simple. Python needs correct indentation,
|
||||
not as an aesthetic addition, but as a requirement to determine beginning and ending of blocks. The
|
||||
EvEditor will try to guess the next level of indentation. If you type a block “if”, for instance,
|
||||
the EvEditor will propose you an additional level of indentation at the next line. This feature
|
||||
cannot be perfect, however, and sometimes, you will have to use the above options to handle
|
||||
indentation.</p>
|
||||
<p>Automatic indentation is there to make code editing more simple. Python needs correct indentation, not as an aesthetic addition, but as a requirement to determine beginning and ending of blocks. The EvEditor will try to guess the next level of indentation. If you type a block “if”, for instance, the EvEditor will propose you an additional level of indentation at the next line. This feature cannot be perfect, however, and sometimes, you will have to use the above options to handle indentation.</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">:=</span></code> can be used to turn automatic indentation off completely. This can be very useful when trying
|
||||
to paste several lines of code that are already correctly indented, for instance.</p>
|
||||
<p>To see the EvEditor in code mode, you can use the <code class="docutils literal notranslate"><span class="pre">@py/edit</span></code> command. Type in your code (on one or
|
||||
several lines). You can then use the <code class="docutils literal notranslate"><span class="pre">:w</span></code> option (save without quitting) and the code you have
|
||||
<p>To see the EvEditor in code mode, you can use the <code class="docutils literal notranslate"><span class="pre">@py/edit</span></code> command. Type in your code (on one or several lines). You can then use the <code class="docutils literal notranslate"><span class="pre">:w</span></code> option (save without quitting) and the code you have
|
||||
typed will be executed. The <code class="docutils literal notranslate"><span class="pre">:!</span></code> will do the same thing. Executing code while not closing the
|
||||
editor can be useful if you want to test the code you have typed but add new lines after your test.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -63,10 +63,6 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">EvMenu</a><ul>
|
||||
<li><a class="reference internal" href="#introduction">Introduction</a><ul>
|
||||
<li><a class="reference internal" href="#examples">Examples</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#launching-the-menu">Launching the menu</a></li>
|
||||
<li><a class="reference internal" href="#the-menu-nodes">The Menu nodes</a><ul>
|
||||
<li><a class="reference internal" href="#input-arguments-to-the-node">Input arguments to the node</a></li>
|
||||
|
|
@ -80,16 +76,25 @@
|
|||
<li><a class="reference internal" href="#option-key-goto">option-key ‘goto’</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#temporary-storage">Temporary storage</a></li>
|
||||
<li><a class="reference internal" href="#customizing-menu-formatting">Customizing Menu formatting</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#evmenu-templating-language">EvMenu templating language</a><ul>
|
||||
<li><a class="reference internal" href="#template-options">Template Options</a></li>
|
||||
<li><a class="reference internal" href="#templating-example">Templating example</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#id1">Examples:</a><ul>
|
||||
<li><a class="reference internal" href="#asking-for-one-line-input">Asking for one-line input</a><ul>
|
||||
<li><a class="reference internal" href="#the-yield-way">The <code class="docutils literal notranslate"><span class="pre">yield</span></code> way</a></li>
|
||||
<li><a class="reference internal" href="#the-get-input-way">The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> way</a><ul>
|
||||
<li><a class="reference internal" href="#example-yes-no-prompt">Example: Yes/No prompt</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#the-list-node-decorator">The <code class="docutils literal notranslate"><span class="pre">@list_node</span></code> decorator</a></li>
|
||||
<li><a class="reference internal" href="#example-menus">Example Menus</a><ul>
|
||||
<li><a class="reference internal" href="#example-simple-branching-menu">Example: Simple branching menu</a></li>
|
||||
<li><a class="reference internal" href="#example-dynamic-goto">Example: Dynamic goto</a></li>
|
||||
<li><a class="reference internal" href="#example-set-caller-properties">Example: Set caller properties</a></li>
|
||||
|
|
@ -99,16 +104,6 @@
|
|||
<li><a class="reference internal" href="#defining-nodes-in-a-dictionary">Defining nodes in a dictionary</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#ask-for-simple-input">Ask for simple input</a><ul>
|
||||
<li><a class="reference internal" href="#the-yield-way">The <code class="docutils literal notranslate"><span class="pre">yield</span></code> way</a></li>
|
||||
<li><a class="reference internal" href="#the-get-input-way">The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> way</a><ul>
|
||||
<li><a class="reference internal" href="#example-yes-no-prompt">Example: Yes/No prompt</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#the-list-node-decorator">The <code class="docutils literal notranslate"><span class="pre">@list_node</span></code> decorator</a></li>
|
||||
<li><a class="reference internal" href="#assorted-notes">Assorted notes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -151,37 +146,25 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="evmenu">
|
||||
<h1>EvMenu<a class="headerlink" href="#evmenu" title="Permalink to this headline">¶</a></h1>
|
||||
<p>EvMenu is used for generate branching multi-choice menus. Each menu ‘node’ can
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>Is your answer yes or no?
|
||||
_________________________________________
|
||||
<span class="o">[</span>Y<span class="o">]</span>es! - Answer yes.
|
||||
<span class="o">[</span>N<span class="o">]</span>o! - Answer no.
|
||||
<span class="o">[</span>A<span class="o">]</span>bort - Answer neither, and abort.
|
||||
|
||||
> Y
|
||||
You chose yes!
|
||||
|
||||
Thanks <span class="k">for</span> your answer. Goodbye!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><em>EvMenu</em> is used for generate branching multi-choice menus. Each menu ‘node’ can
|
||||
accepts specific options as input or free-form input. Depending what the player
|
||||
chooses, they are forwarded to different nodes in the menu.</p>
|
||||
<section id="introduction">
|
||||
<h2>Introduction<a class="headerlink" href="#introduction" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> utility class is located in <a class="reference internal" href="../api/evennia.utils.evmenu.html#evennia-utils-evmenu"><span class="std std-ref">evennia/utils/evmenu.py</span></a>.
|
||||
It allows for easily adding interactive menus to the game; for example to implement Character
|
||||
creation, building commands or similar. Below is an example of offering NPC conversation choices:</p>
|
||||
<section id="examples">
|
||||
<h3>Examples<a class="headerlink" href="#examples" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This section gives some examples of how menus work in-game. A menu is a state
|
||||
(it’s actually a custom cmdset) where menu-specific commands are made available
|
||||
to you. An EvMenu is usually started from inside a command, but could also
|
||||
just be put in a file and run with <code class="docutils literal notranslate"><span class="pre">py</span></code>.</p>
|
||||
<p>This is how the example menu will look in-game:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Is your answer yes or no?
|
||||
_________________________________________
|
||||
[Y]es! - Answer yes.
|
||||
[N]o! - Answer no.
|
||||
[A]bort - Answer neither, and abort.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If you pick (for example) Y(es), you will see</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>You chose yes!
|
||||
|
||||
Thanks for your answer. Goodbye!
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>After which the menu will end (in this example at least - it could also continue
|
||||
on to other questions and choices or even repeat the same node over and over!)</p>
|
||||
<p>Here’s the full EvMenu code for this example:</p>
|
||||
<p>This is how the example menu at the top of this page will look in code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">evmenu</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_handle_answer</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_input</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
|
|
@ -317,8 +300,6 @@ uses the template-string and a mapping of callables (we must add
|
|||
means depends on your game) to decide if your approach succeeded. It may then
|
||||
choose to point you to nodes that continue the conversation or maybe dump you
|
||||
into combat!</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="launching-the-menu">
|
||||
<h2>Launching the menu<a class="headerlink" href="#launching-the-menu" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Initializing the menu is done using a call to the <code class="docutils literal notranslate"><span class="pre">evennia.utils.evmenu.EvMenu</span></code> class. This is the
|
||||
|
|
@ -354,39 +335,14 @@ most common way to do so - from inside a <a class="reference internal" href="Com
|
|||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> (Object or Account): is a reference to the object using the menu. This object will get a
|
||||
new <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">CmdSet</span></a> assigned to it, for handling the menu.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">menu_data</span></code> (str, module or dict): is a module or python path to a module where the global-level
|
||||
functions will each be considered to be a menu node. Their names in the module will be the names
|
||||
by which they are referred to in the module. Importantly, function names starting with an
|
||||
underscore
|
||||
<code class="docutils literal notranslate"><span class="pre">_</span></code> will be ignored by the loader. Alternatively, this can be a direct mapping
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> (Object or Account): is a reference to the object using the menu. This object will get a new <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">CmdSet</span></a> assigned to it, for handling the menu.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">menu_data</span></code> (str, module or dict): is a module or python path to a module where the global-level functions will each be considered to be a menu node. Their names in the module will be the names by which they are referred to in the module. Importantly, function names starting with an underscore <code class="docutils literal notranslate"><span class="pre">_</span></code> will be ignored by the loader. Alternatively, this can be a direct mapping
|
||||
<code class="docutils literal notranslate"><span class="pre">{"nodename":function,</span> <span class="pre">...}</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">startnode</span></code> (str): is the name of the menu-node to start the menu at. Changing this means that
|
||||
you can jump into a menu tree at different positions depending on circumstance and thus possibly
|
||||
re-use menu entries.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset_mergetype</span></code> (str): This is usually one of “Replace” or “Union” (see [CmdSets](Command-
|
||||
Sets).
|
||||
The first means that the menu is exclusive - the user has no access to any other commands while
|
||||
in the menu. The Union mergetype means the menu co-exists with previous commands (and may
|
||||
overload
|
||||
them, so be careful as to what to name your menu entries in this case).</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset_priority</span></code> (int): The priority with which to merge in the menu cmdset. This allows for
|
||||
advanced usage.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">auto_quit</span></code>, <code class="docutils literal notranslate"><span class="pre">auto_look</span></code>, <code class="docutils literal notranslate"><span class="pre">auto_help</span></code> (bool): If either of these are <code class="docutils literal notranslate"><span class="pre">True</span></code>, the menu
|
||||
automatically makes a <code class="docutils literal notranslate"><span class="pre">quit</span></code>, <code class="docutils literal notranslate"><span class="pre">look</span></code> or <code class="docutils literal notranslate"><span class="pre">help</span></code> command available to the user. The main reason why
|
||||
you’d want to turn this off is if you want to use the aliases “q”, “l” or “h” for something in
|
||||
your
|
||||
menu. Nevertheless, at least <code class="docutils literal notranslate"><span class="pre">quit</span></code> is highly recommend - if <code class="docutils literal notranslate"><span class="pre">False</span></code>, the menu <em>must</em> itself
|
||||
supply
|
||||
an “exit node” (a node without any options), or the user will be stuck in the menu until the
|
||||
server
|
||||
reloads (or eternally if the menu is <code class="docutils literal notranslate"><span class="pre">persistent</span></code>)!</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cmd_on_exit</span></code> (str): This command string will be executed right <em>after</em> the menu has closed down.
|
||||
From experience, it’s useful to trigger a “look” command to make sure the user is aware of the
|
||||
change of state; but any command can be used. If set to <code class="docutils literal notranslate"><span class="pre">None</span></code>, no command will be triggered
|
||||
after
|
||||
exiting the menu.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">startnode</span></code> (str): is the name of the menu-node to start the menu at. Changing this means that you can jump into a menu tree at different positions depending on circumstance and thus possibly re-use menu entries.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset_mergetype</span></code> (str): This is usually one of “Replace” or “Union” (see [CmdSets](Command- Sets). The first means that the menu is exclusive - the user has no access to any other commands while in the menu. The Union mergetype means the menu co-exists with previous commands (and may overload them, so be careful as to what to name your menu entries in this case).</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset_priority</span></code> (int): The priority with which to merge in the menu cmdset. This allows for advanced usage.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">auto_quit</span></code>, <code class="docutils literal notranslate"><span class="pre">auto_look</span></code>, <code class="docutils literal notranslate"><span class="pre">auto_help</span></code> (bool): If either of these are <code class="docutils literal notranslate"><span class="pre">True</span></code>, the menu automatically makes a <code class="docutils literal notranslate"><span class="pre">quit</span></code>, <code class="docutils literal notranslate"><span class="pre">look</span></code> or <code class="docutils literal notranslate"><span class="pre">help</span></code> command available to the user. The main reason why you’d want to turn this off is if you want to use the aliases “q”, “l” or “h” for something in your menu. Nevertheless, at least <code class="docutils literal notranslate"><span class="pre">quit</span></code> is highly recommend - if <code class="docutils literal notranslate"><span class="pre">False</span></code>, the menu <em>must</em> itself supply an “exit node” (a node without any options), or the user will be stuck in the menu until the server reloads (or eternally if the menu is <code class="docutils literal notranslate"><span class="pre">persistent</span></code>)!</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cmd_on_exit</span></code> (str): This command string will be executed right <em>after</em> the menu has closed down. From experience, it’s useful to trigger a “look” command to make sure the user is aware of the change of state; but any command can be used. If set to <code class="docutils literal notranslate"><span class="pre">None</span></code>, no command will be triggered after exiting the menu.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code> (bool) - if <code class="docutils literal notranslate"><span class="pre">True</span></code>, the menu will survive a reload (so the user will not be kicked
|
||||
out by the reload - make sure they can exit on their own!)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">startnode_input</span></code> (str or (str, dict) tuple): Pass an input text or a input text + kwargs to the
|
||||
|
|
@ -397,9 +353,7 @@ start a menu differently depending on the Command’s arguments in which it was
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">debug</span></code> (bool): If set, the <code class="docutils literal notranslate"><span class="pre">menudebug</span></code> command will be made available in the menu. Use it to
|
||||
list the current state of the menu and use <code class="docutils literal notranslate"><span class="pre">menudebug</span> <span class="pre"><variable></span></code> to inspect a specific state
|
||||
variable from the list.</p></li>
|
||||
<li><p>All other keyword arguments will be available as initial data for the nodes. They will be
|
||||
available in all nodes as properties on <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> (see below). These will also
|
||||
survive a <code class="docutils literal notranslate"><span class="pre">@reload</span></code> if the menu is <code class="docutils literal notranslate"><span class="pre">persistent</span></code>.</p></li>
|
||||
<li><p>All other keyword arguments will be available as initial data for the nodes. They will be available in all nodes as properties on <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> (see below). These will also survive a <code class="docutils literal notranslate"><span class="pre">reload</span></code> if the menu is <code class="docutils literal notranslate"><span class="pre">persistent</span></code>.</p></li>
|
||||
</ul>
|
||||
<p>You don’t need to store the EvMenu instance anywhere - the very act of initializing it will store it
|
||||
as <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> on the <code class="docutils literal notranslate"><span class="pre">caller</span></code>. This object will be deleted automatically when the menu
|
||||
|
|
@ -601,9 +555,8 @@ goto-callable. This functionality comes from a time before goto could be a calla
|
|||
</div></blockquote>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="temporary-storage">
|
||||
<h2>Temporary storage<a class="headerlink" href="#temporary-storage" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Temporary storage<a class="headerlink" href="#temporary-storage" title="Permalink to this headline">¶</a></h3>
|
||||
<p>When the menu starts, the EvMenu instance is stored on the caller as <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code>. Through
|
||||
this object you can in principle reach the menu’s internal state if you know what you are doing.
|
||||
This is also a good place to store temporary, more global variables that may be cumbersome to keep
|
||||
|
|
@ -614,7 +567,7 @@ that this will remain after the menu closes though, so you need to handle any ne
|
|||
yourself.</p>
|
||||
</section>
|
||||
<section id="customizing-menu-formatting">
|
||||
<h2>Customizing Menu formatting<a class="headerlink" href="#customizing-menu-formatting" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Customizing Menu formatting<a class="headerlink" href="#customizing-menu-formatting" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> display of nodes, options etc are controlled by a series of formatting methods on the
|
||||
<code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> class. To customize these, simply create a new child class of <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> and override as
|
||||
needed. Here is an example:</p>
|
||||
|
|
@ -678,6 +631,7 @@ needed. Here is an example:</p>
|
|||
</div>
|
||||
<p>See <code class="docutils literal notranslate"><span class="pre">evennia/utils/evmenu.py</span></code> for the details of their default implementations.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="evmenu-templating-language">
|
||||
<h2>EvMenu templating language<a class="headerlink" href="#evmenu-templating-language" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In <a class="reference external" href="http://evmenu.py">evmenu.py</a> are two helper functions <code class="docutils literal notranslate"><span class="pre">parse_menu_template</span></code> and <code class="docutils literal notranslate"><span class="pre">template2menu</span></code>
|
||||
|
|
@ -827,8 +781,171 @@ myfunc(foo) # error!
|
|||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="id1">
|
||||
<h2>Examples:<a class="headerlink" href="#id1" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="asking-for-one-line-input">
|
||||
<h2>Asking for one-line input<a class="headerlink" href="#asking-for-one-line-input" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This describes two ways for asking for simple questions from the user. Using Python’s <code class="docutils literal notranslate"><span class="pre">input</span></code>
|
||||
will <em>not</em> work in Evennia. <code class="docutils literal notranslate"><span class="pre">input</span></code> will <em>block</em> the entire server for <em>everyone</em> until that one
|
||||
player has entered their text, which is not what you want.</p>
|
||||
<section id="the-yield-way">
|
||||
<h3>The <code class="docutils literal notranslate"><span class="pre">yield</span></code> way<a class="headerlink" href="#the-yield-way" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In the <code class="docutils literal notranslate"><span class="pre">func</span></code> method of your Commands (only) you can use Python’s built-in <code class="docutils literal notranslate"><span class="pre">yield</span></code> command to
|
||||
request input in a similar way to <code class="docutils literal notranslate"><span class="pre">input</span></code>. It looks like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">result</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Please enter your answer:"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will send “Please enter your answer” to the Command’s <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> and then pause at that
|
||||
point. All other players at the server will be unaffected. Once caller enteres a reply, the code
|
||||
execution will continue and you can do stuff with the <code class="docutils literal notranslate"><span class="pre">result</span></code>. Here is an example:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
<span class="k">class</span> <span class="nc">CmdTestInput</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"test"</span>
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Please enter something:"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You entered </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||||
<span class="n">result2</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Now enter something else:"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You now entered </span><span class="si">{</span><span class="n">result2</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">yield</span></code> is simple and intuitive, but it will only access input from <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> and you
|
||||
cannot abort or time out the pause until the player has responded. Under the hood, it is actually
|
||||
just a wrapper calling <code class="docutils literal notranslate"><span class="pre">get_input</span></code> described in the following section.</p>
|
||||
<blockquote>
|
||||
<div><p>Important Note: In Python you <em>cannot mix <code class="docutils literal notranslate"><span class="pre">yield</span></code> and <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre"><value></span></code> in the same method</em>. It has
|
||||
to do with <code class="docutils literal notranslate"><span class="pre">yield</span></code> turning the method into a
|
||||
<a class="reference external" href="https://www.learnpython.org/en/Generators">generator</a>. A <code class="docutils literal notranslate"><span class="pre">return</span></code> without an argument works, you
|
||||
can just not do <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre"><value></span></code>. This is usually not something you need to do in <code class="docutils literal notranslate"><span class="pre">func()</span></code> anyway,
|
||||
but worth keeping in mind.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="the-get-input-way">
|
||||
<h3>The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> way<a class="headerlink" href="#the-get-input-way" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The evmenu module offers a helper function named <code class="docutils literal notranslate"><span class="pre">get_input</span></code>. This is wrapped by the <code class="docutils literal notranslate"><span class="pre">yield</span></code>
|
||||
statement which is often easier and more intuitive to use. But <code class="docutils literal notranslate"><span class="pre">get_input</span></code> offers more flexibility
|
||||
and power if you need it. While in the same module as <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>, <code class="docutils literal notranslate"><span class="pre">get_input</span></code> is technically unrelated
|
||||
to it. The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> allows you to ask and receive simple one-line input from the user without
|
||||
launching the full power of a menu to do so. To use, call <code class="docutils literal notranslate"><span class="pre">get_input</span></code> like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the entity that should receive the prompt for input given as <code class="docutils literal notranslate"><span class="pre">prompt</span></code>. The
|
||||
<code class="docutils literal notranslate"><span class="pre">callback</span></code> is a callable <code class="docutils literal notranslate"><span class="pre">function(caller,</span> <span class="pre">prompt,</span> <span class="pre">user_input)</span></code> that you define to handle the answer
|
||||
from the user. When run, the caller will see <code class="docutils literal notranslate"><span class="pre">prompt</span></code> appear on their screens and <em>any</em> text they
|
||||
enter will be sent into the callback for whatever processing you want.</p>
|
||||
<p>Below is a fully explained callback and example call:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils.evmenu</span> <span class="kn">import</span> <span class="n">get_input</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">callback</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> This is a callback you define yourself.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> caller (Account or Object): The one being asked</span>
|
||||
<span class="sd"> for input</span>
|
||||
<span class="sd"> prompt (str): A copy of the current prompt</span>
|
||||
<span class="sd"> user_input (str): The input from the account.</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> repeat (bool): If not set or False, exit the</span>
|
||||
<span class="sd"> input prompt and clean up. If returning anything</span>
|
||||
<span class="sd"> True, stay in the prompt, which means this callback</span>
|
||||
<span class="sd"> will be called again with the next user input.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"When asked '</span><span class="si">{</span><span class="n">prompt</span><span class="si">}</span><span class="s2">', you answered '</span><span class="si">{</span><span class="n">user_input</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
|
||||
|
||||
<span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">"Write something! "</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will show as</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Write something!
|
||||
> Hello
|
||||
When asked 'Write something!', you answered 'Hello'.
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Normally, the <code class="docutils literal notranslate"><span class="pre">get_input</span></code> function quits after any input, but as seen in the example docs, you could
|
||||
return True from the callback to repeat the prompt until you pass whatever check you want.</p>
|
||||
<blockquote>
|
||||
<div><p>Note: You <em>cannot</em> link consecutive questions by putting a new <code class="docutils literal notranslate"><span class="pre">get_input</span></code> call inside the
|
||||
callback If you want that you should use an EvMenu instead (see the <a class="reference internal" href="#example-repeating-the-same-node"><span class="std std-doc">Repeating the same
|
||||
node</span></a> example above). Otherwise you can either peek at the
|
||||
implementation of <code class="docutils literal notranslate"><span class="pre">get_input</span></code> and implement your own mechanism (it’s just using cmdset nesting) or
|
||||
you can look at <a class="reference external" href="https://groups.google.com/forum/#%21category-topic/evennia/evennia-questions/16pi0SfMO5U">this extension suggested on the mailing
|
||||
list</a>.</p>
|
||||
</div></blockquote>
|
||||
<section id="example-yes-no-prompt">
|
||||
<h4>Example: Yes/No prompt<a class="headerlink" href="#example-yes-no-prompt" title="Permalink to this headline">¶</a></h4>
|
||||
<p>Below is an example of a Yes/No prompt using the <code class="docutils literal notranslate"><span class="pre">get_input</span></code> function:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">yesno</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">result</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="s2">"yes"</span><span class="p">,</span> <span class="s2">"n"</span><span class="p">,</span> <span class="s2">"no"</span><span class="p">):</span>
|
||||
<span class="c1"># do stuff to handle the yes/no answer</span>
|
||||
<span class="c1"># ...</span>
|
||||
<span class="c1"># if we return None/False the prompt state</span>
|
||||
<span class="c1"># will quit after this</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># the answer is not on the right yes/no form</span>
|
||||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Please answer Yes or No. </span><span class="se">\n</span><span class="si">{prompt}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="o">@</span> <span class="c1"># returning True will make sure the prompt state is not exited</span>
|
||||
<span class="k">return</span> <span class="kc">True</span>
|
||||
|
||||
<span class="c1"># ask the question</span>
|
||||
<span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">"Is Evennia great (Yes/No)?"</span><span class="p">,</span> <span class="n">yesno</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="the-list-node-decorator">
|
||||
<h2>The <code class="docutils literal notranslate"><span class="pre">@list_node</span></code> decorator<a class="headerlink" href="#the-list-node-decorator" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">evennia.utils.evmenu.list_node</span></code> is an advanced decorator for use with <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> node functions.
|
||||
It is used to quickly create menus for manipulating large numbers of items.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">text</span> <span class="n">here</span>
|
||||
<span class="n">______________________________________________</span>
|
||||
|
||||
<span class="mf">1.</span> <span class="n">option1</span> <span class="mf">7.</span> <span class="n">option7</span> <span class="mf">13.</span> <span class="n">option13</span>
|
||||
<span class="mf">2.</span> <span class="n">option2</span> <span class="mf">8.</span> <span class="n">option8</span> <span class="mf">14.</span> <span class="n">option14</span>
|
||||
<span class="mf">3.</span> <span class="n">option3</span> <span class="mf">9.</span> <span class="n">option9</span> <span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="n">revius</span> <span class="n">page</span>
|
||||
<span class="mf">4.</span> <span class="n">option4</span> <span class="mf">10.</span> <span class="n">option10</span> <span class="n">page</span> <span class="mi">2</span>
|
||||
<span class="mf">5.</span> <span class="n">option5</span> <span class="mf">11.</span> <span class="n">option11</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="n">ext</span> <span class="n">page</span>
|
||||
<span class="mf">6.</span> <span class="n">option6</span> <span class="mf">12.</span> <span class="n">option12</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The menu will automatically create an multi-page option listing that one can flip through. One can
|
||||
inpect each entry and then select them with prev/next. This is how it is used:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.evmenu</span> <span class="kn">import</span> <span class="n">list_node</span>
|
||||
|
||||
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="n">_options</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="s1">'option1'</span><span class="p">,</span> <span class="s1">'option2'</span><span class="p">,</span> <span class="o">...</span> <span class="s1">'option100'</span><span class="p">]</span>
|
||||
|
||||
<span class="n">_select</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menuchoice</span><span class="p">,</span> <span class="n">available_choices</span><span class="p">):</span>
|
||||
<span class="c1"># analyze choice</span>
|
||||
<span class="k">return</span> <span class="s2">"next_node"</span>
|
||||
|
||||
<span class="nd">@list_node</span><span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="n">select</span><span class="o">=</span><span class="n">_select</span><span class="p">,</span> <span class="n">pagesize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
|
||||
<span class="k">def</span> <span class="nf">node_mylist</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">options</span></code> argument to <code class="docutils literal notranslate"><span class="pre">list_node</span></code> is either a list, a generator or a callable returning a list
|
||||
of strings for each option that should be displayed in the node.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">select</span></code> is a callable in the example above but could also be the name of a menu node. If a
|
||||
callable, the <code class="docutils literal notranslate"><span class="pre">menuchoice</span></code> argument holds the selection done and <code class="docutils literal notranslate"><span class="pre">available_choices</span></code> holds all the
|
||||
options available. The callable should return the menu to go to depending on the selection (or
|
||||
<code class="docutils literal notranslate"><span class="pre">None</span></code> to rerun the same node). If the name of a menu node, the selection will be passed as
|
||||
<code class="docutils literal notranslate"><span class="pre">selection</span></code> kwarg to that node.</p>
|
||||
<p>The decorated node itself should return <code class="docutils literal notranslate"><span class="pre">text</span></code> to display in the node. It must return at least an
|
||||
empty dictionary for its options. It returning options, those will supplement the options
|
||||
auto-created by the <code class="docutils literal notranslate"><span class="pre">list_node</span></code> decorator.</p>
|
||||
</section>
|
||||
<section id="example-menus">
|
||||
<h2>Example Menus<a class="headerlink" href="#example-menus" title="Permalink to this headline">¶</a></h2>
|
||||
<ul class="simple">
|
||||
<li><p><strong><a class="reference internal" href="#example-simple-branching-menu"><span class="std std-doc">Simple branching menu</span></a></strong> - choose from options</p></li>
|
||||
<li><p><strong><a class="reference internal" href="#example-dynamic-goto"><span class="std std-doc">Dynamic goto</span></a></strong> - jumping to different nodes based on response</p></li>
|
||||
|
|
@ -844,8 +961,7 @@ helper function accessed as <code class="docutils literal notranslate"><span cla
|
|||
</ul>
|
||||
<section id="example-simple-branching-menu">
|
||||
<h3>Example: Simple branching menu<a class="headerlink" href="#example-simple-branching-menu" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Below is an example of a simple branching menu node leading to different other nodes depending on
|
||||
choice:</p>
|
||||
<p>Below is an example of a simple branching menu node leading to different other nodes depending on choice:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/world/mychargen.py</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">define_character</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||||
|
|
@ -1064,9 +1180,7 @@ when the user exits the menu.</p>
|
|||
</section>
|
||||
<section id="example-repeating-the-same-node">
|
||||
<h3>Example: Repeating the same node<a class="headerlink" href="#example-repeating-the-same-node" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Sometimes you want to make a chain of menu nodes one after another, but you don’t want the user to
|
||||
be able to continue to the next node until you have verified that what they input in the previous
|
||||
node is ok. A common example is a login menu:</p>
|
||||
<p>Sometimes you want to make a chain of menu nodes one after another, but you don’t want the user to be able to continue to the next node until you have verified that what they input in the previous node is ok. A common example is a login menu:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="k">def</span> <span class="nf">_check_username</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># we assume lookup_username() exists</span>
|
||||
|
|
@ -1177,178 +1291,6 @@ probably more work than it’s worth: You can create dynamic menus by instead ma
|
|||
function more clever. See the <a class="reference internal" href="../Howtos/Tutorial-NPC-Merchants.html"><span class="doc std std-doc">NPC shop tutorial</span></a> for an example of this.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="ask-for-simple-input">
|
||||
<h2>Ask for simple input<a class="headerlink" href="#ask-for-simple-input" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This describes two ways for asking for simple questions from the user. Using Python’s <code class="docutils literal notranslate"><span class="pre">input</span></code>
|
||||
will <em>not</em> work in Evennia. <code class="docutils literal notranslate"><span class="pre">input</span></code> will <em>block</em> the entire server for <em>everyone</em> until that one
|
||||
player has entered their text, which is not what you want.</p>
|
||||
<section id="the-yield-way">
|
||||
<h3>The <code class="docutils literal notranslate"><span class="pre">yield</span></code> way<a class="headerlink" href="#the-yield-way" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In the <code class="docutils literal notranslate"><span class="pre">func</span></code> method of your Commands (only) you can use Python’s built-in <code class="docutils literal notranslate"><span class="pre">yield</span></code> command to
|
||||
request input in a similar way to <code class="docutils literal notranslate"><span class="pre">input</span></code>. It looks like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">result</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Please enter your answer:"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will send “Please enter your answer” to the Command’s <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> and then pause at that
|
||||
point. All other players at the server will be unaffected. Once caller enteres a reply, the code
|
||||
execution will continue and you can do stuff with the <code class="docutils literal notranslate"><span class="pre">result</span></code>. Here is an example:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
<span class="k">class</span> <span class="nc">CmdTestInput</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"test"</span>
|
||||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
<span class="n">result</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Please enter something:"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You entered </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||||
<span class="n">result2</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Now enter something else:"</span><span class="p">)</span>
|
||||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"You now entered </span><span class="si">{</span><span class="n">result2</span><span class="si">}</span><span class="s2">."</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">yield</span></code> is simple and intuitive, but it will only access input from <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> and you
|
||||
cannot abort or time out the pause until the player has responded. Under the hood, it is actually
|
||||
just a wrapper calling <code class="docutils literal notranslate"><span class="pre">get_input</span></code> described in the following section.</p>
|
||||
<blockquote>
|
||||
<div><p>Important Note: In Python you <em>cannot mix <code class="docutils literal notranslate"><span class="pre">yield</span></code> and <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre"><value></span></code> in the same method</em>. It has
|
||||
to do with <code class="docutils literal notranslate"><span class="pre">yield</span></code> turning the method into a
|
||||
<a class="reference external" href="https://www.learnpython.org/en/Generators">generator</a>. A <code class="docutils literal notranslate"><span class="pre">return</span></code> without an argument works, you
|
||||
can just not do <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre"><value></span></code>. This is usually not something you need to do in <code class="docutils literal notranslate"><span class="pre">func()</span></code> anyway,
|
||||
but worth keeping in mind.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="the-get-input-way">
|
||||
<h3>The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> way<a class="headerlink" href="#the-get-input-way" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The evmenu module offers a helper function named <code class="docutils literal notranslate"><span class="pre">get_input</span></code>. This is wrapped by the <code class="docutils literal notranslate"><span class="pre">yield</span></code>
|
||||
statement which is often easier and more intuitive to use. But <code class="docutils literal notranslate"><span class="pre">get_input</span></code> offers more flexibility
|
||||
and power if you need it. While in the same module as <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code>, <code class="docutils literal notranslate"><span class="pre">get_input</span></code> is technically unrelated
|
||||
to it. The <code class="docutils literal notranslate"><span class="pre">get_input</span></code> allows you to ask and receive simple one-line input from the user without
|
||||
launching the full power of a menu to do so. To use, call <code class="docutils literal notranslate"><span class="pre">get_input</span></code> like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the entity that should receive the prompt for input given as <code class="docutils literal notranslate"><span class="pre">prompt</span></code>. The
|
||||
<code class="docutils literal notranslate"><span class="pre">callback</span></code> is a callable <code class="docutils literal notranslate"><span class="pre">function(caller,</span> <span class="pre">prompt,</span> <span class="pre">user_input)</span></code> that you define to handle the answer
|
||||
from the user. When run, the caller will see <code class="docutils literal notranslate"><span class="pre">prompt</span></code> appear on their screens and <em>any</em> text they
|
||||
enter will be sent into the callback for whatever processing you want.</p>
|
||||
<p>Below is a fully explained callback and example call:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils.evmenu</span> <span class="kn">import</span> <span class="n">get_input</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">callback</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">user_input</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> This is a callback you define yourself.</span>
|
||||
|
||||
<span class="sd"> Args:</span>
|
||||
<span class="sd"> caller (Account or Object): The one being asked</span>
|
||||
<span class="sd"> for input</span>
|
||||
<span class="sd"> prompt (str): A copy of the current prompt</span>
|
||||
<span class="sd"> user_input (str): The input from the account.</span>
|
||||
|
||||
<span class="sd"> Returns:</span>
|
||||
<span class="sd"> repeat (bool): If not set or False, exit the</span>
|
||||
<span class="sd"> input prompt and clean up. If returning anything</span>
|
||||
<span class="sd"> True, stay in the prompt, which means this callback</span>
|
||||
<span class="sd"> will be called again with the next user input.</span>
|
||||
<span class="sd"> """</span>
|
||||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="sa">f</span><span class="s2">"When asked '</span><span class="si">{</span><span class="n">prompt</span><span class="si">}</span><span class="s2">', you answered '</span><span class="si">{</span><span class="n">user_input</span><span class="si">}</span><span class="s2">'."</span><span class="p">)</span>
|
||||
|
||||
<span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">"Write something! "</span><span class="p">,</span> <span class="n">callback</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This will show as</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Write something!
|
||||
> Hello
|
||||
When asked 'Write something!', you answered 'Hello'.
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Normally, the <code class="docutils literal notranslate"><span class="pre">get_input</span></code> function quits after any input, but as seen in the example docs, you could
|
||||
return True from the callback to repeat the prompt until you pass whatever check you want.</p>
|
||||
<blockquote>
|
||||
<div><p>Note: You <em>cannot</em> link consecutive questions by putting a new <code class="docutils literal notranslate"><span class="pre">get_input</span></code> call inside the
|
||||
callback If you want that you should use an EvMenu instead (see the <a class="reference internal" href="#example-repeating-the-same-node"><span class="std std-doc">Repeating the same
|
||||
node</span></a> example above). Otherwise you can either peek at the
|
||||
implementation of <code class="docutils literal notranslate"><span class="pre">get_input</span></code> and implement your own mechanism (it’s just using cmdset nesting) or
|
||||
you can look at <a class="reference external" href="https://groups.google.com/forum/#%21category-topic/evennia/evennia-questions/16pi0SfMO5U">this extension suggested on the mailing
|
||||
list</a>.</p>
|
||||
</div></blockquote>
|
||||
<section id="example-yes-no-prompt">
|
||||
<h4>Example: Yes/No prompt<a class="headerlink" href="#example-yes-no-prompt" title="Permalink to this headline">¶</a></h4>
|
||||
<p>Below is an example of a Yes/No prompt using the <code class="docutils literal notranslate"><span class="pre">get_input</span></code> function:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">yesno</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">prompt</span><span class="p">,</span> <span class="n">result</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">result</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"y"</span><span class="p">,</span> <span class="s2">"yes"</span><span class="p">,</span> <span class="s2">"n"</span><span class="p">,</span> <span class="s2">"no"</span><span class="p">):</span>
|
||||
<span class="c1"># do stuff to handle the yes/no answer</span>
|
||||
<span class="c1"># ...</span>
|
||||
<span class="c1"># if we return None/False the prompt state</span>
|
||||
<span class="c1"># will quit after this</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="c1"># the answer is not on the right yes/no form</span>
|
||||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Please answer Yes or No. </span><span class="se">\n</span><span class="si">{prompt}</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="o">@</span> <span class="c1"># returning True will make sure the prompt state is not exited</span>
|
||||
<span class="k">return</span> <span class="kc">True</span>
|
||||
|
||||
<span class="c1"># ask the question</span>
|
||||
<span class="n">get_input</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">"Is Evennia great (Yes/No)?"</span><span class="p">,</span> <span class="n">yesno</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="the-list-node-decorator">
|
||||
<h2>The <code class="docutils literal notranslate"><span class="pre">@list_node</span></code> decorator<a class="headerlink" href="#the-list-node-decorator" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">evennia.utils.evmenu.list_node</span></code> is an advanced decorator for use with <code class="docutils literal notranslate"><span class="pre">EvMenu</span></code> node functions.
|
||||
It is used to quickly create menus for manipulating large numbers of items.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">text</span> <span class="n">here</span>
|
||||
<span class="n">______________________________________________</span>
|
||||
|
||||
<span class="mf">1.</span> <span class="n">option1</span> <span class="mf">7.</span> <span class="n">option7</span> <span class="mf">13.</span> <span class="n">option13</span>
|
||||
<span class="mf">2.</span> <span class="n">option2</span> <span class="mf">8.</span> <span class="n">option8</span> <span class="mf">14.</span> <span class="n">option14</span>
|
||||
<span class="mf">3.</span> <span class="n">option3</span> <span class="mf">9.</span> <span class="n">option9</span> <span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="n">revius</span> <span class="n">page</span>
|
||||
<span class="mf">4.</span> <span class="n">option4</span> <span class="mf">10.</span> <span class="n">option10</span> <span class="n">page</span> <span class="mi">2</span>
|
||||
<span class="mf">5.</span> <span class="n">option5</span> <span class="mf">11.</span> <span class="n">option11</span> <span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="n">ext</span> <span class="n">page</span>
|
||||
<span class="mf">6.</span> <span class="n">option6</span> <span class="mf">12.</span> <span class="n">option12</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The menu will automatically create an multi-page option listing that one can flip through. One can
|
||||
inpect each entry and then select them with prev/next. This is how it is used:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.evmenu</span> <span class="kn">import</span> <span class="n">list_node</span>
|
||||
|
||||
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="n">_options</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||||
<span class="k">return</span> <span class="p">[</span><span class="s1">'option1'</span><span class="p">,</span> <span class="s1">'option2'</span><span class="p">,</span> <span class="o">...</span> <span class="s1">'option100'</span><span class="p">]</span>
|
||||
|
||||
<span class="n">_select</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">menuchoice</span><span class="p">,</span> <span class="n">available_choices</span><span class="p">):</span>
|
||||
<span class="c1"># analyze choice</span>
|
||||
<span class="k">return</span> <span class="s2">"next_node"</span>
|
||||
|
||||
<span class="nd">@list_node</span><span class="p">(</span><span class="n">options</span><span class="p">,</span> <span class="n">select</span><span class="o">=</span><span class="n">_select</span><span class="p">,</span> <span class="n">pagesize</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
|
||||
<span class="k">def</span> <span class="nf">node_mylist</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="n">raw_string</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="o">...</span>
|
||||
|
||||
<span class="k">return</span> <span class="n">text</span><span class="p">,</span> <span class="n">options</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">options</span></code> argument to <code class="docutils literal notranslate"><span class="pre">list_node</span></code> is either a list, a generator or a callable returning a list
|
||||
of strings for each option that should be displayed in the node.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">select</span></code> is a callable in the example above but could also be the name of a menu node. If a
|
||||
callable, the <code class="docutils literal notranslate"><span class="pre">menuchoice</span></code> argument holds the selection done and <code class="docutils literal notranslate"><span class="pre">available_choices</span></code> holds all the
|
||||
options available. The callable should return the menu to go to depending on the selection (or
|
||||
<code class="docutils literal notranslate"><span class="pre">None</span></code> to rerun the same node). If the name of a menu node, the selection will be passed as
|
||||
<code class="docutils literal notranslate"><span class="pre">selection</span></code> kwarg to that node.</p>
|
||||
<p>The decorated node itself should return <code class="docutils literal notranslate"><span class="pre">text</span></code> to display in the node. It must return at least an
|
||||
empty dictionary for its options. It returning options, those will supplement the options
|
||||
auto-created by the <code class="docutils literal notranslate"><span class="pre">list_node</span></code> decorator.</p>
|
||||
</section>
|
||||
<section id="assorted-notes">
|
||||
<h2>Assorted notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The EvMenu is implemented using <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a>. When you start a new EvMenu, the user of the
|
||||
menu will be assigned a <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">CmdSet</span></a> with the commands they need to navigate the menu.
|
||||
This means that if you were to, from inside the menu, assign a new command set to the caller, <em>you
|
||||
may override the Menu Cmdset and kill the menu</em>. If you want to assign cmdsets to the caller as part
|
||||
of the menu, you should store the cmdset on <code class="docutils literal notranslate"><span class="pre">caller.ndb._evmenu</span></code> and wait to actually assign it
|
||||
until the exit node.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -60,14 +60,6 @@
|
|||
</div>
|
||||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">EvMore</a><ul>
|
||||
<li><a class="reference internal" href="#using-evmore">Using EvMore</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="EvMenu.html"
|
||||
title="previous chapter">EvMenu</a></p>
|
||||
|
|
@ -110,8 +102,6 @@
|
|||
window. The <code class="docutils literal notranslate"><span class="pre">evennia.utils.evmore.EvMore</span></code> class gives the user the in-game ability to only view one
|
||||
page of text at a time. It is usually used via its access function, <code class="docutils literal notranslate"><span class="pre">evmore.msg</span></code>.</p>
|
||||
<p>The name comes from the famous unix pager utility <em>more</em> which performs just this function.</p>
|
||||
<section id="using-evmore">
|
||||
<h2>Using EvMore<a class="headerlink" href="#using-evmore" title="Permalink to this headline">¶</a></h2>
|
||||
<p>To use the pager, just pass the long text through it:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">evmore</span>
|
||||
|
||||
|
|
@ -136,7 +126,6 @@ commands to jump to previous pages, to the top or bottom of the document as well
|
|||
paging.</p>
|
||||
<p>The pager takes several more keyword arguments for controlling the message output. See the
|
||||
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.utils.evmore">evmore-API</a> for more info.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="The Inline Function Parser" href="FuncParser.html" />
|
||||
<link rel="next" title="FuncParser inline text parsing" href="FuncParser.html" />
|
||||
<link rel="prev" title="EvMore" href="EvMore.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="FuncParser.html" title="The Inline Function Parser"
|
||||
<a href="FuncParser.html" title="FuncParser inline text parsing"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="EvMore.html" title="EvMore"
|
||||
|
|
@ -65,7 +65,7 @@
|
|||
title="previous chapter">EvMore</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="FuncParser.html"
|
||||
title="next chapter">The Inline Function Parser</a></p>
|
||||
title="next chapter">FuncParser inline text parsing</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -117,7 +117,7 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="FuncParser.html" title="The Inline Function Parser"
|
||||
<a href="FuncParser.html" title="FuncParser inline text parsing"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="EvMore.html" title="EvMore"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
|
||||
|
||||
<title>The Inline Function Parser — Evennia 1.0-dev documentation</title>
|
||||
<title>FuncParser inline text parsing — Evennia 1.0-dev documentation</title>
|
||||
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
|
||||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||||
|
|
@ -37,7 +37,7 @@
|
|||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">The Inline Function Parser</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">FuncParser inline text parsing</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
|
@ -62,15 +62,14 @@
|
|||
<script>$('#searchbox').show(0);</script>
|
||||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">The Inline Function Parser</a><ul>
|
||||
<li><a class="reference internal" href="#uses-in-default-evennia">Uses in default Evennia</a></li>
|
||||
<li><a class="reference internal" href="#using-the-funcparser">Using the FuncParser</a></li>
|
||||
<li><a class="reference internal" href="#">FuncParser inline text parsing</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-funcparser">Working with FuncParser</a></li>
|
||||
<li><a class="reference internal" href="#defining-custom-callables">Defining custom callables</a><ul>
|
||||
<li><a class="reference internal" href="#escaping-special-character">Escaping special character</a></li>
|
||||
<li><a class="reference internal" href="#safe-convertion-of-inputs">Safe convertion of inputs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#default-callables">Default callables</a><ul>
|
||||
<li><a class="reference internal" href="#default-funcparser-callables">Default funcparser callables</a><ul>
|
||||
<li><a class="reference internal" href="#evennia-utils-funcparser-funcparser-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.FUNCPARSER_CALLABLES</span></code></a></li>
|
||||
<li><a class="reference internal" href="#evennia-utils-funcparser-searching-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.SEARCHING_CALLABLES</span></code></a></li>
|
||||
<li><a class="reference internal" href="#evennia-utils-funcparser-actor-stance-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ACTOR_STANCE_CALLABLES</span></code></a></li>
|
||||
|
|
@ -117,8 +116,8 @@
|
|||
<div class="bodywrapper">
|
||||
<div class="body" role="main">
|
||||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="the-inline-function-parser">
|
||||
<h1>The Inline Function Parser<a class="headerlink" href="#the-inline-function-parser" title="Permalink to this headline">¶</a></h1>
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="funcparser-inline-text-parsing">
|
||||
<h1>FuncParser inline text parsing<a class="headerlink" href="#funcparser-inline-text-parsing" title="Permalink to this headline">¶</a></h1>
|
||||
<p>The <a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.FuncParser" title="evennia.utils.funcparser.FuncParser"><span class="xref myst py py-class">FuncParser</span></a> extracts and executes ‘inline functions’ embedded in a string on the form <code class="docutils literal notranslate"><span class="pre">$funcname(args,</span> <span class="pre">kwargs)</span></code>. Under the hood, this will lead to a call to a Python function you control. The inline function call will be replaced by the return from the function.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.funcparser</span> <span class="kn">import</span> <span class="n">FuncParser</span>
|
||||
|
||||
|
|
@ -147,32 +146,20 @@
|
|||
<span class="s2">"This is an escaped $pow(4) and so is this $pow(3)"</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="uses-in-default-evennia">
|
||||
<h2>Uses in default Evennia<a class="headerlink" href="#uses-in-default-evennia" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-funcparser">
|
||||
<h2>Working with FuncParser<a class="headerlink" href="#working-with-funcparser" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The FuncParser can be applied to any string. Out of the box it’s applied in a few situations:</p>
|
||||
<ul class="simple">
|
||||
<li><p><em>Outgoing messages</em>. All messages sent from the server is processed through FuncParser and every
|
||||
callable is provided the <a class="reference internal" href="Sessions.html"><span class="doc std std-doc">Session</span></a> of the object receiving the message. This potentially
|
||||
allows a message to be modified on the fly to look different for different recipients.</p></li>
|
||||
<li><p><em>Prototype values</em>. A <a class="reference internal" href="Prototypes.html"><span class="doc std std-doc">Prototype</span></a> dict’s values are run through the parser such that every
|
||||
callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders
|
||||
to safely call functions to set non-string values to prototype values, get random values, reference
|
||||
<li><p><em>Outgoing messages</em>. All messages sent from the server is processed through FuncParser and every callable is provided the <a class="reference internal" href="Sessions.html"><span class="doc std std-doc">Session</span></a> of the object receiving the message. This potentially allows a message to be modified on the fly to look different for different recipients.</p></li>
|
||||
<li><p><em>Prototype values</em>. A <a class="reference internal" href="Prototypes.html"><span class="doc std std-doc">Prototype</span></a> dict’s values are run through the parser such that every callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders to safely call functions to set non-string values to prototype values, get random values, reference
|
||||
other fields of the prototype, and more.</p></li>
|
||||
<li><p><em>Actor-stance in messages to others</em>. In the
|
||||
<a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">Object.msg_contents</span></a> method,
|
||||
the outgoing string is parsed for special <code class="docutils literal notranslate"><span class="pre">$You()</span></code> and <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> callables to decide if a given recipient
|
||||
<li><p><em>Actor-stance in messages to others</em>. In the <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">Object.msg_contents</span></a> method, the outgoing string is parsed for special <code class="docutils literal notranslate"><span class="pre">$You()</span></code> and <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> callables to decide if a given recipient
|
||||
should see “You” or the character’s name.</p></li>
|
||||
</ul>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p>The inline-function parser is not intended as a ‘softcode’ programming language. It does not
|
||||
have things like loops and conditionals, for example. While you could in principle extend it to
|
||||
do very advanced things and allow builders a lot of power, all-out coding is something
|
||||
Evennia expects you to do in a proper text editor, outside of the game, not from inside it.</p>
|
||||
<p>The inline-function parser is not intended as a ‘softcode’ programming language. It does not have things like loops and conditionals, for example. While you could in principle extend it to do very advanced things and allow builders a lot of power, all-out coding is something Evennia expects you to do in a proper text editor, outside of the game, not from inside it.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="using-the-funcparser">
|
||||
<h2>Using the FuncParser<a class="headerlink" href="#using-the-funcparser" title="Permalink to this headline">¶</a></h2>
|
||||
<p>You can apply inline function parsing to any string. The
|
||||
<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.FuncParser" title="evennia.utils.funcparser.FuncParser"><span class="xref myst py py-class">FuncParser</span></a> is imported as <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">funcparser</span>
|
||||
|
|
@ -237,8 +224,7 @@ is the <code class="docutils literal notranslate"><span class="pre">raise_errors
|
|||
<span class="n">funcparser</span><span class="o">=<</span><span class="n">FuncParser</span><span class="o">></span><span class="p">,</span> <span class="n">raise_errors</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">mydefault=2</span></code> kwarg could be overwritten if we made the call as <code class="docutils literal notranslate"><span class="pre">$test(mydefault=...)</span></code>
|
||||
but <code class="docutils literal notranslate"><span class="pre">myreserved=[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> will <em>always</em> be sent as-is and will override a call <code class="docutils literal notranslate"><span class="pre">$test(myreserved=...)</span></code>.
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">mydefault=2</span></code> kwarg could be overwritten if we made the call as <code class="docutils literal notranslate"><span class="pre">$test(mydefault=...)</span></code> but <code class="docutils literal notranslate"><span class="pre">myreserved=[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> will <em>always</em> be sent as-is and will override a call <code class="docutils literal notranslate"><span class="pre">$test(myreserved=...)</span></code>.
|
||||
The <code class="docutils literal notranslate"><span class="pre">funcparser</span></code>/<code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> kwargs are also always included as reserved kwargs.</p>
|
||||
</section>
|
||||
<section id="defining-custom-callables">
|
||||
|
|
@ -250,20 +236,15 @@ The <code class="docutils literal notranslate"><span class="pre">funcparser</spa
|
|||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> must always be included. If you are unsure how <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> work in Python,
|
||||
<a class="reference external" href="https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3">read about them here</a>.</p>
|
||||
<div><p>The <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> must always be included. If you are unsure how <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> work in Python, <a class="reference external" href="https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3">read about them here</a>.</p>
|
||||
</div></blockquote>
|
||||
<p>The input from the innermost <code class="docutils literal notranslate"><span class="pre">$funcname(...)</span></code> call in your callable will always be a <code class="docutils literal notranslate"><span class="pre">str</span></code>. Here’s
|
||||
an example of an <code class="docutils literal notranslate"><span class="pre">$toint</span></code> function; it converts numbers to integers.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>"There's a $toint(22.0)% chance of survival."
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>What will enter the <code class="docutils literal notranslate"><span class="pre">$toint</span></code> callable (as <code class="docutils literal notranslate"><span class="pre">args[0]</span></code>) is the <em>string</em> <code class="docutils literal notranslate"><span class="pre">"22.0"</span></code>. The function is responsible
|
||||
for converting this to a number so that we can convert it to an integer. We must also properly handle invalid
|
||||
inputs (like non-numbers).</p>
|
||||
<p>If you want to mark an error, raise <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ParsingError</span></code>. This stops the entire parsing
|
||||
of the string and may or may not raise the exception depending on what you set <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> to when you
|
||||
created the parser.</p>
|
||||
<p>What will enter the <code class="docutils literal notranslate"><span class="pre">$toint</span></code> callable (as <code class="docutils literal notranslate"><span class="pre">args[0]</span></code>) is the <em>string</em> <code class="docutils literal notranslate"><span class="pre">"22.0"</span></code>. The function is responsible for converting this to a number so that we can convert it to an integer. We must also properly handle invalid inputs (like non-numbers).</p>
|
||||
<p>If you want to mark an error, raise <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ParsingError</span></code>. This stops the entire parsing of the string and may or may not raise the exception depending on what you set <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> to when you created the parser.</p>
|
||||
<p>However, if you <em>nest</em> functions, the return of the innermost function may be something other than
|
||||
a string. Let’s introduce the <code class="docutils literal notranslate"><span class="pre">$eval</span></code> function, which evaluates simple expressions using
|
||||
Python’s <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> and/or <code class="docutils literal notranslate"><span class="pre">simple_eval</span></code>. It returns whatever data type it
|
||||
|
|
@ -275,18 +256,14 @@ evaluates to.</p>
|
|||
It evaluates this and returns the <code class="docutils literal notranslate"><span class="pre">float</span></code> <code class="docutils literal notranslate"><span class="pre">22.0</span></code>. This time the outermost <code class="docutils literal notranslate"><span class="pre">$toint</span></code> will be called with
|
||||
this <code class="docutils literal notranslate"><span class="pre">float</span></code> instead of with a string.</p>
|
||||
<blockquote>
|
||||
<div><p>It’s important to safely validate your inputs since users may end up nesting your callables in any order.
|
||||
See the next section for useful tools to help with this.</p>
|
||||
<div><p>It’s important to safely validate your inputs since users may end up nesting your callables in any order. See the next section for useful tools to help with this.</p>
|
||||
</div></blockquote>
|
||||
<p>In these examples, the result will be embedded in the larger string, so the result of the entire parsing
|
||||
will be a string:</p>
|
||||
<p>In these examples, the result will be embedded in the larger string, so the result of the entire parsing will be a string:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">above_string</span><span class="p">)</span>
|
||||
<span class="s2">"There's a 22</span><span class="si">% c</span><span class="s2">hance of survival."</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>However, if you use the <code class="docutils literal notranslate"><span class="pre">parse_to_any</span></code> (or <code class="docutils literal notranslate"><span class="pre">parse(...,</span> <span class="pre">return_str=False)</span></code>) and
|
||||
<em>don’t add any extra string around the outermost function call</em>,
|
||||
you’ll get the return type of the outermost callable back:</p>
|
||||
<p>However, if you use the <code class="docutils literal notranslate"><span class="pre">parse_to_any</span></code> (or <code class="docutils literal notranslate"><span class="pre">parse(...,</span> <span class="pre">return_str=False)</span></code>) and <em>don’t add any extra string around the outermost function call</em>, you’ll get the return type of the outermost callable back:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">"$toint($eval(10 * 2.2)"</span><span class="p">)</span>
|
||||
<span class="mi">22</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">"the number $toint($eval(10 * 2.2)."</span><span class="p">)</span>
|
||||
|
|
@ -342,9 +319,7 @@ can support. This is because FunctionParser strings can be used by
|
|||
non-developer players/builders and some things (such as complex
|
||||
classes/callables etc) are just not safe/possible to convert from string
|
||||
representation.</p>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">evennia.utils.utils</span></code> is a helper called
|
||||
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.safe_convert_to_types" title="evennia.utils.utils.safe_convert_to_types"><span class="xref myst py py-func">safe_convert_to_types</span></a>. This function
|
||||
automates the conversion of simple data types in a safe way:</p>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">evennia.utils.utils</span></code> is a helper called <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.safe_convert_to_types" title="evennia.utils.utils.safe_convert_to_types"><span class="xref myst py py-func">safe_convert_to_types</span></a>. This function automates the conversion of simple data types in a safe way:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">safe_convert_to_types</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">_process_callable</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
|
|
@ -360,43 +335,24 @@ automates the conversion of simple data types in a safe way:</p>
|
|||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In other words, in the callable <code class="docutils literal notranslate"><span class="pre">$process(expression,</span> <span class="pre">local,</span> <span class="pre">extra1=..,</span> <span class="pre">extra2=...)</span></code>, the first argument will be handled by the ‘py’ converter
|
||||
(described below), the second will passed through regular Python <code class="docutils literal notranslate"><span class="pre">str</span></code>,
|
||||
kwargs will be handled by <code class="docutils literal notranslate"><span class="pre">int</span></code> and <code class="docutils literal notranslate"><span class="pre">str</span></code> respectively. You can supply
|
||||
your own converter function as long as it takes one argument and returns
|
||||
the converted result.</p>
|
||||
<p>In other words,</p>
|
||||
<p>In other words, in the callable <code class="docutils literal notranslate"><span class="pre">$process(expression,</span> <span class="pre">local,</span> <span class="pre">extra1=..,</span> <span class="pre">extra2=...)</span></code>, the first argument will be handled by the ‘py’ converter (described below), the second will passed through regular Python <code class="docutils literal notranslate"><span class="pre">str</span></code>, kwargs will be handled by <code class="docutils literal notranslate"><span class="pre">int</span></code> and <code class="docutils literal notranslate"><span class="pre">str</span></code> respectively. You can supply your own converter function as long as it takes one argument and returns the converted result.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">safe_convert_to_type</span><span class="p">(</span>
|
||||
<span class="p">(</span><span class="n">tuple_of_arg_converters</span><span class="p">,</span> <span class="n">dict_of_kwarg_converters</span><span class="p">),</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The special converter <code class="docutils literal notranslate"><span class="pre">"py"</span></code> will try to convert a string argument to a Python structure with the help of the
|
||||
following tools (which you may also find useful to experiment with on your own):</p>
|
||||
<p>The special converter <code class="docutils literal notranslate"><span class="pre">"py"</span></code> will try to convert a string argument to a Python structure with the help of the following tools (which you may also find useful to experiment with on your own):</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference external" href="https://docs.python.org/3.8/library/ast.html#ast.literal_eval">ast.literal_eval</a> is an in-built Python
|
||||
function. It
|
||||
<em>only</em> supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and <code class="docutils literal notranslate"><span class="pre">None</span></code>. That’s
|
||||
it - no arithmetic or modifications of data is allowed. This is good for converting individual values and
|
||||
lists/dicts from the input line to real Python objects.</p></li>
|
||||
<li><p><a class="reference external" href="https://pypi.org/project/simpleeval/">simpleeval</a> is a third-party tool included with Evennia. This
|
||||
allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings
|
||||
with <code class="docutils literal notranslate"><span class="pre">+-/*</span></code> as well as do simple comparisons like <code class="docutils literal notranslate"><span class="pre">4</span> <span class="pre">></span> <span class="pre">3</span></code> and more. It does <em>not</em> accept more complex
|
||||
containers like lists/dicts etc, so this and <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> are complementary to each other.</p></li>
|
||||
<li><p><a class="reference external" href="https://docs.python.org/3.8/library/ast.html#ast.literal_eval">ast.literal_eval</a> is an in-built Python function. It <em>only</em> supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and <code class="docutils literal notranslate"><span class="pre">None</span></code>. That’s it - no arithmetic or modifications of data is allowed. This is good for converting individual values and lists/dicts from the input line to real Python objects.</p></li>
|
||||
<li><p><a class="reference external" href="https://pypi.org/project/simpleeval/">simpleeval</a> is a third-party tool included with Evennia. This allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings with <code class="docutils literal notranslate"><span class="pre">+-/*</span></code> as well as do simple comparisons like <code class="docutils literal notranslate"><span class="pre">4</span> <span class="pre">></span> <span class="pre">3</span></code> and more. It does <em>not</em> accept more complex containers like lists/dicts etc, so this and <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> are complementary to each other.</p></li>
|
||||
</ul>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>It may be tempting to run use Python’s in-built <code class="docutils literal notranslate"><span class="pre">eval()</span></code> or <code class="docutils literal notranslate"><span class="pre">exec()</span></code> functions as converters since
|
||||
these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
|
||||
know that ONLY developers will ever modify the string going into the callable. The parser is intended
|
||||
for untrusted users (if you were trusted you’d have access to Python already). Letting untrusted users
|
||||
pass strings to <code class="docutils literal notranslate"><span class="pre">eval</span></code>/<code class="docutils literal notranslate"><span class="pre">exec</span></code> is a MAJOR security risk. It allows the caller to run arbitrary
|
||||
Python code on your server. This is the path to maliciously deleted hard drives. Just don’t do it and
|
||||
sleep better at night.</p>
|
||||
<p>It may be tempting to run use Python’s in-built <code class="docutils literal notranslate"><span class="pre">eval()</span></code> or <code class="docutils literal notranslate"><span class="pre">exec()</span></code> functions as converters since these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really know that ONLY developers will ever modify the string going into the callable. The parser is intended for untrusted users (if you were trusted you’d have access to Python already). Letting untrusted users pass strings to <code class="docutils literal notranslate"><span class="pre">eval</span></code>/<code class="docutils literal notranslate"><span class="pre">exec</span></code> is a MAJOR security risk. It allows the caller to run arbitrary Python code on your server. This is the path to maliciously deleted hard drives. Just don’t do it and sleep better at night.</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="default-callables">
|
||||
<h2>Default callables<a class="headerlink" href="#default-callables" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="default-funcparser-callables">
|
||||
<h2>Default funcparser callables<a class="headerlink" href="#default-funcparser-callables" title="Permalink to this headline">¶</a></h2>
|
||||
<p>These are some example callables you can import and add your parser. They are divided into
|
||||
global-level dicts in <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser</span></code>. Just import the dict(s) and merge/add one or
|
||||
more to them when you create your <code class="docutils literal notranslate"><span class="pre">FuncParser</span></code> instance to have those callables be available.</p>
|
||||
|
|
@ -404,47 +360,28 @@ more to them when you create your <code class="docutils literal notranslate"><sp
|
|||
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.FUNCPARSER_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-funcparser-callables" title="Permalink to this headline">¶</a></h3>
|
||||
<p>These are the ‘base’ callables.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$eval(expression)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_eval" title="evennia.utils.funcparser.funcparser_callable_eval"><span class="xref myst py py-func">code</span></a>) -
|
||||
this uses <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> and <code class="docutils literal notranslate"><span class="pre">simple_eval</span></code> (see previous section) attemt to convert a string expression
|
||||
to a python object. This handles e.g. lists of literals <code class="docutils literal notranslate"><span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> and simple expressions like <code class="docutils literal notranslate"><span class="pre">"1</span> <span class="pre">+</span> <span class="pre">2"</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$toint(number)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_toint" title="evennia.utils.funcparser.funcparser_callable_toint"><span class="xref myst py py-func">code</span></a>) -
|
||||
always converts an output to an integer, if possible.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$eval(expression)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_eval" title="evennia.utils.funcparser.funcparser_callable_eval"><span class="xref myst py py-func">code</span></a>) - this uses <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> and <code class="docutils literal notranslate"><span class="pre">simple_eval</span></code> (see previous section) attemt to convert a string expression to a python object. This handles e.g. lists of literals <code class="docutils literal notranslate"><span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> and simple expressions like <code class="docutils literal notranslate"><span class="pre">"1</span> <span class="pre">+</span> <span class="pre">2"</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$toint(number)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_toint" title="evennia.utils.funcparser.funcparser_callable_toint"><span class="xref myst py py-func">code</span></a>) - always converts an output to an integer, if possible.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$add/sub/mult/div(obj1,</span> <span class="pre">obj2)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_add" title="evennia.utils.funcparser.funcparser_callable_add"><span class="xref myst py py-func">code</span></a>) -
|
||||
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with
|
||||
<code class="docutils literal notranslate"><span class="pre">$eval</span></code>, this could for example be used also to add two lists together, which is not possible with <code class="docutils literal notranslate"><span class="pre">eval</span></code>;
|
||||
for example <code class="docutils literal notranslate"><span class="pre">$add($eval([1,2,3]),</span> <span class="pre">$eval([4,5,6]))</span> <span class="pre">-></span> <span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3,</span> <span class="pre">4,</span> <span class="pre">5,</span> <span class="pre">6]</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$round(float,</span> <span class="pre">significant)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_round" title="evennia.utils.funcparser.funcparser_callable_round"><span class="xref myst py py-func">code</span></a>) -
|
||||
rounds an input float into the number of provided significant digits. For example <code class="docutils literal notranslate"><span class="pre">$round(3.54343,</span> <span class="pre">3)</span> <span class="pre">-></span> <span class="pre">3.543</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$random([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_random" title="evennia.utils.funcparser.funcparser_callable_random"><span class="xref myst py py-func">code</span></a>) -
|
||||
this works like the Python <code class="docutils literal notranslate"><span class="pre">random()</span></code> function, but will randomize to an integer value if both start/end are
|
||||
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with <code class="docutils literal notranslate"><span class="pre">$eval</span></code>, this could for example be used also to add two lists together, which is not possible with <code class="docutils literal notranslate"><span class="pre">eval</span></code>; for example <code class="docutils literal notranslate"><span class="pre">$add($eval([1,2,3]),</span> <span class="pre">$eval([4,5,6]))</span> <span class="pre">-></span> <span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3,</span> <span class="pre">4,</span> <span class="pre">5,</span> <span class="pre">6]</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$round(float,</span> <span class="pre">significant)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_round" title="evennia.utils.funcparser.funcparser_callable_round"><span class="xref myst py py-func">code</span></a>) - rounds an input float into the number of provided significant digits. For example <code class="docutils literal notranslate"><span class="pre">$round(3.54343,</span> <span class="pre">3)</span> <span class="pre">-></span> <span class="pre">3.543</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$random([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_random" title="evennia.utils.funcparser.funcparser_callable_random"><span class="xref myst py py-func">code</span></a>) - this works like the Python <code class="docutils literal notranslate"><span class="pre">random()</span></code> function, but will randomize to an integer value if both start/end are
|
||||
integers. Without argument, will return a float between 0 and 1.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$randint([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_randint" title="evennia.utils.funcparser.funcparser_callable_randint"><span class="xref myst py py-func">code</span></a>) -
|
||||
works like the <code class="docutils literal notranslate"><span class="pre">randint()</span></code> python function and always returns an integer.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$choice(list)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_choice" title="evennia.utils.funcparser.funcparser_callable_choice"><span class="xref myst py py-func">code</span></a>) -
|
||||
the input will automatically be parsed the same way as <code class="docutils literal notranslate"><span class="pre">$eval</span></code> and is expected to be an iterable. A random
|
||||
element of this list will be returned.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$pad(text[,</span> <span class="pre">width,</span> <span class="pre">align,</span> <span class="pre">fillchar])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_pad" title="evennia.utils.funcparser.funcparser_callable_pad"><span class="xref myst py py-func">code</span></a>) -
|
||||
this will pad content. <code class="docutils literal notranslate"><span class="pre">$pad("Hello",</span> <span class="pre">30,</span> <span class="pre">c,</span> <span class="pre">-)</span></code> will lead to a text centered in a 30-wide block surrounded by <code class="docutils literal notranslate"><span class="pre">-</span></code>
|
||||
characters.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$crop(text,</span> <span class="pre">width=78,</span> <span class="pre">suffix='[...]')</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_crop" title="evennia.utils.funcparser.funcparser_callable_crop"><span class="xref myst py py-func">code</span></a>) -
|
||||
this will crop a text longer than the width, by default ending it with a <code class="docutils literal notranslate"><span class="pre">[...]</span></code>-suffix that also fits within
|
||||
the width. If no width is given, the client width or <code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_CLIENT_WIDTH</span></code> will be used.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$space(num)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_space" title="evennia.utils.funcparser.funcparser_callable_space"><span class="xref myst py py-func">code</span></a>) -
|
||||
this will insert <code class="docutils literal notranslate"><span class="pre">num</span></code> spaces.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$just(string,</span> <span class="pre">width=40,</span> <span class="pre">align=c,</span> <span class="pre">indent=2)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_justify" title="evennia.utils.funcparser.funcparser_callable_justify"><span class="xref myst py py-func">code</span></a>) -
|
||||
justifies the text to a given width, aligning it left/right/center or ‘f’ for full (spread text across width).</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$randint([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_randint" title="evennia.utils.funcparser.funcparser_callable_randint"><span class="xref myst py py-func">code</span></a>) - works like the <code class="docutils literal notranslate"><span class="pre">randint()</span></code> python function and always returns an integer.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$choice(list)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_choice" title="evennia.utils.funcparser.funcparser_callable_choice"><span class="xref myst py py-func">code</span></a>) - the input will automatically be parsed the same way as <code class="docutils literal notranslate"><span class="pre">$eval</span></code> and is expected to be an iterable. A random element of this list will be returned.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$pad(text[,</span> <span class="pre">width,</span> <span class="pre">align,</span> <span class="pre">fillchar])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_pad" title="evennia.utils.funcparser.funcparser_callable_pad"><span class="xref myst py py-func">code</span></a>) - this will pad content. <code class="docutils literal notranslate"><span class="pre">$pad("Hello",</span> <span class="pre">30,</span> <span class="pre">c,</span> <span class="pre">-)</span></code> will lead to a text centered in a 30-wide block surrounded by <code class="docutils literal notranslate"><span class="pre">-</span></code> characters.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$crop(text,</span> <span class="pre">width=78,</span> <span class="pre">suffix='[...]')</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_crop" title="evennia.utils.funcparser.funcparser_callable_crop"><span class="xref myst py py-func">code</span></a>) - this will crop a text longer than the width, by default ending it with a <code class="docutils literal notranslate"><span class="pre">[...]</span></code>-suffix that also fits within the width. If no width is given, the client width or <code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_CLIENT_WIDTH</span></code> will be used.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$space(num)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_space" title="evennia.utils.funcparser.funcparser_callable_space"><span class="xref myst py py-func">code</span></a>) - this will insert <code class="docutils literal notranslate"><span class="pre">num</span></code> spaces.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$just(string,</span> <span class="pre">width=40,</span> <span class="pre">align=c,</span> <span class="pre">indent=2)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_justify" title="evennia.utils.funcparser.funcparser_callable_justify"><span class="xref myst py py-func">code</span></a>) - justifies the text to a given width, aligning it left/right/center or ‘f’ for full (spread text across width).</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$ljust</span></code> - shortcut to justify-left. Takes all other kwarg of <code class="docutils literal notranslate"><span class="pre">$just</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$rjust</span></code> - shortcut to right justify.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$cjust</span></code> - shortcut to center justify.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$clr(startcolor,</span> <span class="pre">text[,</span> <span class="pre">endcolor])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_clr" title="evennia.utils.funcparser.funcparser_callable_clr"><span class="xref myst py py-func">code</span></a>) -
|
||||
color text. The color is given with one or two characters without the preceeding <code class="docutils literal notranslate"><span class="pre">|</span></code>. If no endcolor is
|
||||
given, the string will go back to neutral, so <code class="docutils literal notranslate"><span class="pre">$clr(r,</span> <span class="pre">Hello)</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">|rHello|n</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$clr(startcolor,</span> <span class="pre">text[,</span> <span class="pre">endcolor])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_clr" title="evennia.utils.funcparser.funcparser_callable_clr"><span class="xref myst py py-func">code</span></a>) - color text. The color is given with one or two characters without the preceeding <code class="docutils literal notranslate"><span class="pre">|</span></code>. If no endcolor is given, the string will go back to neutral, so <code class="docutils literal notranslate"><span class="pre">$clr(r,</span> <span class="pre">Hello)</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">|rHello|n</span></code>.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="evennia-utils-funcparser-searching-callables">
|
||||
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.SEARCHING_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-searching-callables" title="Permalink to this headline">¶</a></h3>
|
||||
<p>These are callables that requires access-checks in order to search for objects. So they require some
|
||||
extra reserved kwargs to be passed when running the parser:</p>
|
||||
<p>These are callables that requires access-checks in order to search for objects. So they require some extra reserved kwargs to be passed when running the parser:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">caller</span><span class="o">=<</span><span class="nb">object</span> <span class="ow">or</span> <span class="n">account</span><span class="o">></span><span class="p">,</span> <span class="n">access</span><span class="o">=</span><span class="s2">"control"</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
|
||||
|
||||
|
|
@ -453,27 +390,20 @@ extra reserved kwargs to be passed when running the parser:</p>
|
|||
<p>The <code class="docutils literal notranslate"><span class="pre">caller</span></code> is required, it’s the the object to do the access-check for. The <code class="docutils literal notranslate"><span class="pre">access</span></code> kwarg is the
|
||||
<a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock type</span></a> to check, default being <code class="docutils literal notranslate"><span class="pre">"control"</span></code>.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$search(query,type=account|script,return_list=False)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_search" title="evennia.utils.funcparser.funcparser_callable_search"><span class="xref myst py py-func">code</span></a>) -
|
||||
this will look up and try to match an object by key or alias. Use the <code class="docutils literal notranslate"><span class="pre">type</span></code> kwarg to
|
||||
search for <code class="docutils literal notranslate"><span class="pre">account</span></code> or <code class="docutils literal notranslate"><span class="pre">script</span></code> instead. By default this will return nothing if there are more than one
|
||||
match; if <code class="docutils literal notranslate"><span class="pre">return_list</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code> a list of 0, 1 or more matches will be returned instead.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$search(query,type=account|script,return_list=False)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_search" title="evennia.utils.funcparser.funcparser_callable_search"><span class="xref myst py py-func">code</span></a>) - this will look up and try to match an object by key or alias. Use the <code class="docutils literal notranslate"><span class="pre">type</span></code> kwarg to search for <code class="docutils literal notranslate"><span class="pre">account</span></code> or <code class="docutils literal notranslate"><span class="pre">script</span></code> instead. By default this will return nothing if there are more than one match; if <code class="docutils literal notranslate"><span class="pre">return_list</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code> a list of 0, 1 or more matches will be returned instead.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$obj(query)</span></code>, <code class="docutils literal notranslate"><span class="pre">$dbref(query)</span></code> - legacy aliases for <code class="docutils literal notranslate"><span class="pre">$search</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$objlist(query)</span></code> - legacy alias for <code class="docutils literal notranslate"><span class="pre">$search</span></code>, always returning a list.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="evennia-utils-funcparser-actor-stance-callables">
|
||||
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ACTOR_STANCE_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-actor-stance-callables" title="Permalink to this headline">¶</a></h3>
|
||||
<p>These are used to implement actor-stance emoting. They are used by the
|
||||
<a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">DefaultObject.msg_contents</span></a> method
|
||||
by default. You can read a lot more about this on the page
|
||||
<p>These are used to implement actor-stance emoting. They are used by the <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">DefaultObject.msg_contents</span></a> method by default. You can read a lot more about this on the page
|
||||
<a class="reference internal" href="../Concepts/Change-Message-Per-Receiver.html"><span class="doc std std-doc">Change messages per receiver</span></a>.</p>
|
||||
<p>On the parser side, all these inline functions require extra kwargs be passed into the parser
|
||||
(done by <code class="docutils literal notranslate"><span class="pre">msg_contents</span></code> by default):</p>
|
||||
<p>On the parser side, all these inline functions require extra kwargs be passed into the parser (done by <code class="docutils literal notranslate"><span class="pre">msg_contents</span></code> by default):</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">caller</span><span class="o">=<</span><span class="n">obj</span><span class="o">></span><span class="p">,</span> <span class="n">receiver</span><span class="o">=<</span><span class="n">obj</span><span class="o">></span><span class="p">,</span> <span class="n">mapping</span><span class="o">=</span><span class="p">{</span><span class="s1">'key'</span><span class="p">:</span> <span class="o"><</span><span class="n">obj</span><span class="o">></span><span class="p">,</span> <span class="o">...</span><span class="p">})</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Here the <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the one sending the message and <code class="docutils literal notranslate"><span class="pre">receiver</span></code> the one to see it. The <code class="docutils literal notranslate"><span class="pre">mapping</span></code> contains
|
||||
references to other objects accessible via these callables.</p>
|
||||
<p>Here the <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the one sending the message and <code class="docutils literal notranslate"><span class="pre">receiver</span></code> the one to see it. The <code class="docutils literal notranslate"><span class="pre">mapping</span></code> contains references to other objects accessible via these callables.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">$you([key])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_you" title="evennia.utils.funcparser.funcparser_callable_you"><span class="xref myst py py-func">code</span></a>) -
|
||||
if no <code class="docutils literal notranslate"><span class="pre">key</span></code> is given, this represents the <code class="docutils literal notranslate"><span class="pre">caller</span></code>, otherwise an object from <code class="docutils literal notranslate"><span class="pre">mapping</span></code>
|
||||
|
|
@ -555,7 +485,7 @@ all the defaults (like <code class="docutils literal notranslate"><span class="p
|
|||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">The Inline Function Parser</a></li>
|
||||
<li class="nav-item nav-item-this"><a href="">FuncParser inline text parsing</a></li>
|
||||
</ul>
|
||||
<div class="develop">develop branch</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -63,21 +63,22 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Help System</a><ul>
|
||||
<li><a class="reference internal" href="#using-the-help-system-from-in-game">Using the help system from in-game</a></li>
|
||||
<li><a class="reference internal" href="#sources-of-help-entries">Sources of help entries</a><ul>
|
||||
<li><a class="reference internal" href="#the-help-entry">The Help Entry</a><ul>
|
||||
<li><a class="reference internal" href="#subtopics">Subtopics</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#command-auto-help-system">Command Auto-help system</a></li>
|
||||
<li><a class="reference internal" href="#database-help-entries">Database-help entries</a></li>
|
||||
<li><a class="reference internal" href="#file-help-entries">File-help entries</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#entry-priority">Entry priority</a></li>
|
||||
<li><a class="reference internal" href="#working-with-three-types-of-help-entries">Working with three types of help entries</a><ul>
|
||||
<li><a class="reference internal" href="#database-stored-help-entries">Database-stored help entries</a></li>
|
||||
<li><a class="reference internal" href="#file-stored-help-entries">File-stored help entries</a></li>
|
||||
<li><a class="reference internal" href="#command-help-entries">Command-help entries</a></li>
|
||||
<li><a class="reference internal" href="#locking-help-entries">Locking help entries</a></li>
|
||||
<li><a class="reference internal" href="#customizing-the-look-of-the-help-system">Customizing the look of the help system</a></li>
|
||||
<li><a class="reference internal" href="#technical-notes">Technical notes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#subtopics">Subtopics</a></li>
|
||||
<li><a class="reference internal" href="#technical-notes">Technical notes</a><ul>
|
||||
<li><a class="reference internal" href="#help-entry-clashes">Help-entry clashes</a></li>
|
||||
<li><a class="reference internal" href="#the-help-entry-container">The Help Entry container</a></li>
|
||||
<li><a class="reference internal" href="#help-pagination">Help pagination</a></li>
|
||||
<li><a class="reference internal" href="#search-engine">Search engine</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -120,47 +121,52 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="help-system">
|
||||
<h1>Help System<a class="headerlink" href="#help-system" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Evennia has an extensive help system covering both command-help and regular
|
||||
free-form help documentation. It supports subtopics and if failing to find a
|
||||
match it will provide suggestsions, first from alternative topics and then by
|
||||
finding mentions of the search term in help entries.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> help theatre
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>> <span class="nb">help</span> theatre
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">------------------------------------------------------------------------------</span>
|
||||
<span class="n">Help</span> <span class="k">for</span> <span class="n">The</span> <span class="n">theatre</span> <span class="p">(</span><span class="n">aliases</span><span class="p">:</span> <span class="n">the</span> <span class="n">hub</span><span class="p">,</span> <span class="n">curtains</span><span class="p">)</span>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>------------------------------------------------------------------------------
|
||||
Help <span class="k">for</span> The theatre <span class="o">(</span>aliases: the hub, curtains<span class="o">)</span>
|
||||
|
||||
<span class="n">The</span> <span class="n">theatre</span> <span class="ow">is</span> <span class="n">at</span> <span class="n">the</span> <span class="n">centre</span> <span class="n">of</span> <span class="n">the</span> <span class="n">city</span><span class="p">,</span> <span class="n">both</span> <span class="n">literally</span> <span class="ow">and</span> <span class="n">figuratively</span> <span class="o">...</span>
|
||||
<span class="p">(</span><span class="n">A</span> <span class="n">lot</span> <span class="n">more</span> <span class="n">text</span> <span class="n">about</span> <span class="n">it</span> <span class="n">follows</span> <span class="o">...</span><span class="p">)</span>
|
||||
The theatre is at the centre of the city, both literally and figuratively ...
|
||||
<span class="o">(</span>A lot more text about it follows ...<span class="o">)</span>
|
||||
|
||||
<span class="n">Subtopics</span><span class="p">:</span>
|
||||
<span class="n">theatre</span><span class="o">/</span><span class="n">lore</span>
|
||||
<span class="n">theatre</span><span class="o">/</span><span class="n">layout</span>
|
||||
<span class="n">theatre</span><span class="o">/</span><span class="n">dramatis</span> <span class="n">personae</span>
|
||||
<span class="o">------------------------------------------------------------------------------</span>
|
||||
Subtopics:
|
||||
theatre/lore
|
||||
theatre/layout
|
||||
theatre/dramatis personae
|
||||
------------------------------------------------------------------------------
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> help evennia
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>> <span class="nb">help</span> evennia
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">------------------------------------------------------------------------------</span>
|
||||
<span class="n">No</span> <span class="n">help</span> <span class="n">found</span>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>------------------------------------------------------------------------------
|
||||
No <span class="nb">help</span> found
|
||||
|
||||
<span class="n">There</span> <span class="ow">is</span> <span class="n">no</span> <span class="n">help</span> <span class="n">topic</span> <span class="n">matching</span> <span class="s1">'evennia'</span><span class="o">.</span>
|
||||
<span class="o">...</span> <span class="n">But</span> <span class="n">matches</span> <span class="n">where</span> <span class="n">found</span> <span class="n">within</span> <span class="n">the</span> <span class="n">help</span> <span class="n">texts</span> <span class="n">of</span> <span class="n">the</span> <span class="n">suggestions</span> <span class="n">below</span><span class="o">.</span>
|
||||
There is no <span class="nb">help</span> topic matching <span class="s1">'evennia'</span>.
|
||||
... But matches where found within the <span class="nb">help</span> texts of the suggestions below.
|
||||
|
||||
<span class="n">Suggestions</span><span class="p">:</span>
|
||||
<span class="n">grapevine2chan</span><span class="p">,</span> <span class="n">about</span><span class="p">,</span> <span class="n">irc2chan</span>
|
||||
<span class="o">-----------------------------------------------------------------------------</span>
|
||||
Suggestions:
|
||||
grapevine2chan, about, irc2chan
|
||||
-----------------------------------------------------------------------------
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="using-the-help-system-from-in-game">
|
||||
<h2>Using the help system from in-game<a class="headerlink" href="#using-the-help-system-from-in-game" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Evennia has an extensive help system covering both command-help and regular free-form help documentation. It supports subtopics and if failing to find a match it will provide suggestsions, first from alternative topics and then by finding mentions of the search term in help entries.</p>
|
||||
<p>The help system is accessed in-game by use of the <code class="docutils literal notranslate"><span class="pre">help</span></code> command:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>help <topic>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Sub-topics are accessed as <code class="docutils literal notranslate"><span class="pre">help</span> <span class="pre"><topic>/<subtopic>/...</span></code>.</p>
|
||||
<section id="working-with-three-types-of-help-entries">
|
||||
<h2>Working with three types of help entries<a class="headerlink" href="#working-with-three-types-of-help-entries" title="Permalink to this headline">¶</a></h2>
|
||||
<p>There are three ways to generate help entries:</p>
|
||||
<ul class="simple">
|
||||
<li><p>In the database</p></li>
|
||||
<li><p>As Python modules</p></li>
|
||||
<li><p>From Command doc strings</p></li>
|
||||
</ul>
|
||||
<section id="database-stored-help-entries">
|
||||
<h3>Database-stored help entries<a class="headerlink" href="#database-stored-help-entries" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Creating a new help entry from in-game is done with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>sethelp <topic>[;aliases] [,category] [,lockstring] = <text>
|
||||
</pre></div>
|
||||
|
|
@ -169,194 +175,22 @@ finding mentions of the search term in help entries.</p>
|
|||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>sethelp The Gods;pantheon, Lore = In the beginning all was dark ...
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Use the <code class="docutils literal notranslate"><span class="pre">/edit</span></code> switch to open the EvEditor for more convenient in-game writing
|
||||
(but note that devs can also create help entries outside the game using their
|
||||
regular code editor, see below).</p>
|
||||
<blockquote>
|
||||
<div><p>You can also create help entries as Python modules, outside of the game. See
|
||||
<em>FileHelp</em> entries below.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="sources-of-help-entries">
|
||||
<h2>Sources of help entries<a class="headerlink" href="#sources-of-help-entries" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Evennia collects help entries from three sources:</p>
|
||||
<ul class="simple">
|
||||
<li><p><em>Auto-generated command help</em> - this is literally the doc-strings of
|
||||
the <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Command classes</span></a>. The idea is that the command docs are
|
||||
easier to maintain and keep up-to-date if the developer can change them at the
|
||||
same time as they do the code.</p></li>
|
||||
<li><p><em>Database-stored help entries</em> - These are created in-game (using the
|
||||
default <code class="docutils literal notranslate"><span class="pre">sethelp</span></code> command as exemplified in the previous section).</p></li>
|
||||
<li><p><em>File-stored help entries</em> - These are created outside the game, as dicts in
|
||||
normal Python modules. They allows developers to write and maintain their help
|
||||
files using a proper text editor.</p></li>
|
||||
</ul>
|
||||
<section id="the-help-entry">
|
||||
<h3>The Help Entry<a class="headerlink" href="#the-help-entry" title="Permalink to this headline">¶</a></h3>
|
||||
<p>All help entries (no matter the source) have the following properties:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - This is the main topic-name. For Commands, this is literally the
|
||||
command’s <code class="docutils literal notranslate"><span class="pre">key</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">aliases</span></code> - Alternate names for the help entry. This can be useful if the main
|
||||
name is hard to remember.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">help_category</span></code> - The general grouping of the entry. This is optional. If not
|
||||
given it will use the default category given by
|
||||
<code class="docutils literal notranslate"><span class="pre">settings.COMMAND_DEFAULT_HELP_CATEGORY</span></code> for Commands and
|
||||
<code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_HELP_CATEGORY</span></code> for file+db help entries.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> - Lock string (for commands) or LockHandler (all help entries).
|
||||
This defines who may read this entry. See the next section.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">tags</span></code> - This is not used by default, but could be used to further organize
|
||||
help entries.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">text</span></code> - The actual help entry text. This will be dedented and stripped of
|
||||
extra space at beginning and end.</p></li>
|
||||
</ul>
|
||||
<p>A <code class="docutils literal notranslate"><span class="pre">text</span></code> that scrolls off the screen will automatically be paginated by
|
||||
the <a class="reference internal" href="EvMore.html"><span class="doc std std-doc">EvMore</span></a> pager (you can control this with
|
||||
<code class="docutils literal notranslate"><span class="pre">settings.HELP_MORE_ENABLED=False</span></code>). If you use EvMore and want to control
|
||||
exactly where the pager should break the page, mark the break with the control
|
||||
character <code class="docutils literal notranslate"><span class="pre">\f</span></code>.</p>
|
||||
<section id="subtopics">
|
||||
<h4>Subtopics<a class="headerlink" href="#subtopics" title="Permalink to this headline">¶</a></h4>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">New in version 1.0.</span></p>
|
||||
</div>
|
||||
<p>Rather than making a very long help entry, the <code class="docutils literal notranslate"><span class="pre">text</span></code> may also be broken up
|
||||
into <em>subtopics</em>. A list of the next level of subtopics are shown below the
|
||||
main help text and allows the user to read more about some particular detail
|
||||
that wouldn’t fit in the main text.</p>
|
||||
<p>Subtopics use a markup slightly similar to markdown headings. The top level
|
||||
heading must be named <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">subtopics</span></code> (non case-sensitive) and the following
|
||||
headers must be sub-headings to this (so <code class="docutils literal notranslate"><span class="pre">##</span> <span class="pre">subtopic</span> <span class="pre">name</span></code> etc). All headings
|
||||
are non-case sensitive (the help command will format them). The topics can be
|
||||
nested at most to a depth of 5 (which is probably too many levels already). The
|
||||
parser uses fuzzy matching to find the subtopic, so one does not have to type
|
||||
it all out exactly.</p>
|
||||
<p>Below is an example of a <code class="docutils literal notranslate"><span class="pre">text</span></code> with sub topics.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>The theatre is the heart of the city, here you can find ...
|
||||
(This is the main help text, what you get with `help theatre`)
|
||||
|
||||
# subtopics
|
||||
|
||||
## lore
|
||||
|
||||
The theatre holds many mysterious things...
|
||||
(`help theatre/lore`)
|
||||
|
||||
### the grand opening
|
||||
|
||||
The grand opening is the name for a mysterious event where ghosts appeared ...
|
||||
(`this is a subsub-topic to lore, accessible as `help theatre/lore/grand` or
|
||||
any other partial match).
|
||||
|
||||
### the Phantom
|
||||
|
||||
Deep under the theatre, rumors has it a monster hides ...
|
||||
(another subsubtopic, accessible as `help theatre/lore/phantom`)
|
||||
|
||||
## layout
|
||||
|
||||
The theatre is a two-story building situated at ...
|
||||
(`help theatre/layout`)
|
||||
|
||||
## dramatis personae
|
||||
|
||||
There are many interesting people prowling the halls of the theatre ...
|
||||
(`help theatre/dramatis` or `help theathre/drama` or `help theatre/personae` would work)
|
||||
|
||||
### Primadonna Ada
|
||||
|
||||
Everyone knows the primadonna! She is ...
|
||||
(A subtopic under dramatis personae, accessible as `help theatre/drama/ada` etc)
|
||||
|
||||
### The gatekeeper
|
||||
|
||||
He always keeps an eye on the door and ...
|
||||
(`help theatre/drama/gate`)
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="command-auto-help-system">
|
||||
<h3>Command Auto-help system<a class="headerlink" href="#command-auto-help-system" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The auto-help system uses the <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> strings of your command classes and
|
||||
formats this to a nice- looking help entry. This makes for a very easy way to
|
||||
keep the help updated - just document your commands well and updating the help
|
||||
file is just a <code class="docutils literal notranslate"><span class="pre">reload</span></code> away.</p>
|
||||
<p>Example (from a module with command definitions):</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">class</span> <span class="nc">CmdMyCmd</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
<span class="sd"> mycmd - my very own command</span>
|
||||
|
||||
<span class="sd"> Usage:</span>
|
||||
<span class="sd"> mycmd[/switches] <args></span>
|
||||
|
||||
<span class="sd"> Switches:</span>
|
||||
<span class="sd"> test - test the command</span>
|
||||
<span class="sd"> run - do something else</span>
|
||||
|
||||
<span class="sd"> This is my own command that does this and that.</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
<span class="c1"># [...]</span>
|
||||
|
||||
<span class="n">locks</span> <span class="o">=</span> <span class="s2">"cmd:all();read:all()"</span> <span class="c1"># default</span>
|
||||
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">"General"</span> <span class="c1"># default</span>
|
||||
<span class="n">auto_help</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># default</span>
|
||||
|
||||
<span class="c1"># [...]</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The text at the very top of the command class definition is the class’
|
||||
<code class="docutils literal notranslate"><span class="pre">__doc__</span></code>-string and will be shown to users looking for help. Try to use a
|
||||
consistent format - all default commands are using the structure shown above.</p>
|
||||
<p>You can limit access to the help entry by the <code class="docutils literal notranslate"><span class="pre">view</span></code> and/or <code class="docutils literal notranslate"><span class="pre">read</span></code> locks on the
|
||||
Command. See <a class="reference internal" href="#locking-help-entries"><span class="std std-doc">the section below</span></a> for details.</p>
|
||||
<p>You should also supply the <code class="docutils literal notranslate"><span class="pre">help_category</span></code> class property if you can; this helps
|
||||
to group help entries together for people to more easily find them. See the
|
||||
<code class="docutils literal notranslate"><span class="pre">help</span></code> command in-game to see the default categories. If you don’t specify the
|
||||
category, <code class="docutils literal notranslate"><span class="pre">settings.COMMAND_DEFAULT_HELP_CATEGORY</span></code> (default is “General”) is
|
||||
used.</p>
|
||||
<p>If you don’t want your command to be picked up by the auto-help system at all
|
||||
(like if you want to write its docs manually using the info in the next section
|
||||
or you use a <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">cmdset</span></a> that has its own help functionality) you
|
||||
can explicitly set <code class="docutils literal notranslate"><span class="pre">auto_help</span></code> class property to <code class="docutils literal notranslate"><span class="pre">False</span></code> in your command
|
||||
definition.</p>
|
||||
<p>Alternatively, you can keep the advantages of <em>auto-help</em> in commands, but
|
||||
control the display of command helps. You can do so by overriding the command’s
|
||||
<code class="docutils literal notranslate"><span class="pre">get_help(caller,</span> <span class="pre">cmdset)</span></code> method. By default, this method will return the
|
||||
class docstring. You could modify it to add custom behavior: the text returned
|
||||
by this method will be displayed to the character asking for help in this
|
||||
command.</p>
|
||||
</section>
|
||||
<section id="database-help-entries">
|
||||
<h3>Database-help entries<a class="headerlink" href="#database-help-entries" title="Permalink to this headline">¶</a></h3>
|
||||
<p>These are most commonly created in-game using the <code class="docutils literal notranslate"><span class="pre">sethelp</span></code> command. If you need to create one
|
||||
manually, you can do so with <code class="docutils literal notranslate"><span class="pre">evennia.create_help_entry()</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_help_entry</span>
|
||||
<p>This will create a new help entry in the database. Use the <code class="docutils literal notranslate"><span class="pre">/edit</span></code> switch to open the EvEditor for more convenient in-game writing (but note that devs can also create help entries outside the game using their regular code editor, see below).</p>
|
||||
<p>The <a class="reference internal" href="../api/evennia.help.models.html#evennia.help.models.HelpEntry" title="evennia.help.models.HelpEntry"><span class="xref myst py py-class">HelpEntry</span></a> stores database help. It is <em>not</em> a Typeclassed entity and can’t be extended using the typeclass mechanism.</p>
|
||||
<p>Here’s how to create a database-help entry in code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_help_entry</span>
|
||||
<span class="n">entry</span> <span class="o">=</span> <span class="n">create_help_entry</span><span class="p">(</span><span class="s2">"emote"</span><span class="p">,</span>
|
||||
<span class="s2">"Emoting is important because ..."</span><span class="p">,</span>
|
||||
<span class="n">category</span><span class="o">=</span><span class="s2">"Roleplaying"</span><span class="p">,</span> <span class="n">locks</span><span class="o">=</span><span class="s2">"view:all()"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The entity being created is a <a class="reference internal" href="../api/evennia.help.models.html#evennia.help.models.HelpEntry" title="evennia.help.models.HelpEntry"><span class="xref myst py py-class">evennia.help.models.HelpEntry</span></a>
|
||||
object. This is <em>not</em> a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entity and is not meant to
|
||||
be modified to any great degree. It holds the properties listed earlier. The
|
||||
text is stored in a field <code class="docutils literal notranslate"><span class="pre">entrytext</span></code>. It does not provide a <code class="docutils literal notranslate"><span class="pre">get_help</span></code> method
|
||||
like commands, stores and returns the <code class="docutils literal notranslate"><span class="pre">entrytext</span></code> directly.</p>
|
||||
<p>You can search for (db-)-<code class="docutils literal notranslate"><span class="pre">HelpEntry</span></code> objects using <code class="docutils literal notranslate"><span class="pre">evennia.search_help</span></code> but note that
|
||||
this will not return the two other types of help entries.</p>
|
||||
</section>
|
||||
<section id="file-help-entries">
|
||||
<h3>File-help entries<a class="headerlink" href="#file-help-entries" title="Permalink to this headline">¶</a></h3>
|
||||
<section id="file-stored-help-entries">
|
||||
<h3>File-stored help entries<a class="headerlink" href="#file-stored-help-entries" title="Permalink to this headline">¶</a></h3>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">New in version 1.0.</span></p>
|
||||
</div>
|
||||
<p>File-help entries are created by the game development team outside of the game. The
|
||||
help entries are defined in normal Python modules (<code class="docutils literal notranslate"><span class="pre">.py</span></code> file ending) containing
|
||||
a <code class="docutils literal notranslate"><span class="pre">dict</span></code> to represent each entry. They require a server <code class="docutils literal notranslate"><span class="pre">reload</span></code> before any changes
|
||||
apply.</p>
|
||||
<p>File-help entries are created by the game development team outside of the game. The help entries are defined in normal Python modules (<code class="docutils literal notranslate"><span class="pre">.py</span></code> file ending) containing a <code class="docutils literal notranslate"><span class="pre">dict</span></code> to represent each entry. They require a server <code class="docutils literal notranslate"><span class="pre">reload</span></code> before any changes apply.</p>
|
||||
<ul class="simple">
|
||||
<li><p>Evennia will look through all modules given by
|
||||
<code class="docutils literal notranslate"><span class="pre">settings.FILE_HELP_ENTRY_MODULES</span></code>. This should be a list of python-paths for
|
||||
|
|
@ -411,26 +245,36 @@ Here’s an example of a help module:</p>
|
|||
to keep your strings a reasonable width (it will look better). Just reload the
|
||||
server and the file-based help entries will be available to view.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="entry-priority">
|
||||
<h2>Entry priority<a class="headerlink" href="#entry-priority" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Should you have clashing help-entries between the three types of available
|
||||
entries, the priority is</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Command-auto-help > Db-help > File-help
|
||||
<section id="command-help-entries">
|
||||
<h3>Command-help entries<a class="headerlink" href="#command-help-entries" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">__docstring__</span></code> of <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Command classes</span></a> are automatically extracted into a help entry. You set <code class="docutils literal notranslate"><span class="pre">help_category</span></code> directly on the class.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">MyCommand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||||
<span class="sd">""" </span>
|
||||
<span class="sd"> This command is great! </span>
|
||||
|
||||
<span class="sd"> Usage: </span>
|
||||
<span class="sd"> mycommand [argument]</span>
|
||||
|
||||
<span class="sd"> When this command is called, great things happen. If you </span>
|
||||
<span class="sd"> pass an argument, even GREATER things HAPPEN!</span>
|
||||
|
||||
<span class="sd"> """</span>
|
||||
|
||||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"mycommand"</span>
|
||||
|
||||
<span class="n">locks</span><span class="p">:</span> <span class="s2">"cmd:all();read:all()"</span> <span class="c1"># default </span>
|
||||
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">"General"</span> <span class="c1"># default</span>
|
||||
<span class="n">auto_help</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># default </span>
|
||||
|
||||
<span class="c1"># ...</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>So if you create a db-help entry ‘foo’, it will replace any file-based help
|
||||
entry ‘foo’. But if there is a Command ‘foo’, that’s the help you’ll get when
|
||||
you enter <code class="docutils literal notranslate"><span class="pre">help</span> <span class="pre">foo</span></code>.</p>
|
||||
<p>The reasoning for this is that commands must always be understood in order to
|
||||
play the game. Meanwhile db-based help can be kept up-to-date from in-game
|
||||
builders and may be less ‘static’ than the file-based ones.</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">sethelp</span></code> command (which only deals with creating db-based help entries)
|
||||
will warn you if a new help entry might shadow/be shadowed by a
|
||||
same/similar-named command or file-based help entry.</p>
|
||||
<p>When you update your code, the command’s help will follow. The idea is that the command docs are easier to maintain and keep up-to-date if the developer can change them at the same time as they do the code.</p>
|
||||
</section>
|
||||
<section id="locking-help-entries">
|
||||
<h2>Locking help entries<a class="headerlink" href="#locking-help-entries" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Locking help entries<a class="headerlink" href="#locking-help-entries" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The default <code class="docutils literal notranslate"><span class="pre">help</span></code> command gather all available commands and help entries
|
||||
together so they can be searched or listed. By setting locks on the command/help
|
||||
entry one can limit who can read help about it.</p>
|
||||
|
|
@ -473,32 +317,100 @@ the new ‘read’ lock-type to control access to the entry itself.</p>
|
|||
</div>
|
||||
</section>
|
||||
<section id="customizing-the-look-of-the-help-system">
|
||||
<h2>Customizing the look of the help system<a class="headerlink" href="#customizing-the-look-of-the-help-system" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This is done almost exclusively by overriding the <code class="docutils literal notranslate"><span class="pre">help</span></code> command
|
||||
<a class="reference internal" href="../api/evennia.commands.default.help.html#evennia.commands.default.help.CmdHelp" title="evennia.commands.default.help.CmdHelp"><span class="xref myst py py-class">evennia.commands.default.help.CmdHelp</span></a>.</p>
|
||||
<p>Since the available commands may vary from moment to moment, <code class="docutils literal notranslate"><span class="pre">help</span></code> is
|
||||
responsible for collating the three sources of help-entries (commands/db/file)
|
||||
together and search through them on the fly. It also does all the formatting of
|
||||
the output.</p>
|
||||
<p>To make it easier to tweak the look, the parts of the code that changes the
|
||||
visual presentation and entity searching has been broken out into separate
|
||||
methods on the command class. Override these in your version of <code class="docutils literal notranslate"><span class="pre">help</span></code> to change
|
||||
the display or tweak as you please. See the api link above for details.</p>
|
||||
<h3>Customizing the look of the help system<a class="headerlink" href="#customizing-the-look-of-the-help-system" title="Permalink to this headline">¶</a></h3>
|
||||
<p>This is done almost exclusively by overriding the <code class="docutils literal notranslate"><span class="pre">help</span></code> command <a class="reference internal" href="../api/evennia.commands.default.help.html#evennia.commands.default.help.CmdHelp" title="evennia.commands.default.help.CmdHelp"><span class="xref myst py py-class">evennia.commands.default.help.CmdHelp</span></a>.</p>
|
||||
<p>Since the available commands may vary from moment to moment, <code class="docutils literal notranslate"><span class="pre">help</span></code> is responsible for collating the three sources of help-entries (commands/db/file) together and search through them on the fly. It also does all the formatting of the output.</p>
|
||||
<p>To make it easier to tweak the look, the parts of the code that changes the visual presentation and entity searching has been broken out into separate methods on the command class. Override these in your version of <code class="docutils literal notranslate"><span class="pre">help</span></code> to change the display or tweak as you please. See the api link above for details.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="subtopics">
|
||||
<h2>Subtopics<a class="headerlink" href="#subtopics" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="versionadded">
|
||||
<p><span class="versionmodified added">New in version 1.0.</span></p>
|
||||
</div>
|
||||
<p>Rather than making a very long help entry, the <code class="docutils literal notranslate"><span class="pre">text</span></code> may also be broken up into <em>subtopics</em>. A list of the next level of subtopics are shown below the main help text and allows the user to read more about some particular detail that wouldn’t fit in the main text.</p>
|
||||
<p>Subtopics use a markup slightly similar to markdown headings. The top level heading must be named <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">subtopics</span></code> (non case-sensitive) and the following headers must be sub-headings to this (so <code class="docutils literal notranslate"><span class="pre">##</span> <span class="pre">subtopic</span> <span class="pre">name</span></code> etc). All headings are non-case sensitive (the help command will format them). The topics can be nested at most to a depth of 5 (which is probably too many levels already). The parser uses fuzzy matching to find the subtopic, so one does not have to type it all out exactly.</p>
|
||||
<p>Below is an example of a <code class="docutils literal notranslate"><span class="pre">text</span></code> with sub topics.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>The theatre is the heart of the city, here you can find ...
|
||||
(This is the main help text, what you get with `help theatre`)
|
||||
|
||||
# subtopics
|
||||
|
||||
## lore
|
||||
|
||||
The theatre holds many mysterious things...
|
||||
(`help theatre/lore`)
|
||||
|
||||
### the grand opening
|
||||
|
||||
The grand opening is the name for a mysterious event where ghosts appeared ...
|
||||
(`this is a subsub-topic to lore, accessible as `help theatre/lore/grand` or
|
||||
any other partial match).
|
||||
|
||||
### the Phantom
|
||||
|
||||
Deep under the theatre, rumors has it a monster hides ...
|
||||
(another subsubtopic, accessible as `help theatre/lore/phantom`)
|
||||
|
||||
## layout
|
||||
|
||||
The theatre is a two-story building situated at ...
|
||||
(`help theatre/layout`)
|
||||
|
||||
## dramatis personae
|
||||
|
||||
There are many interesting people prowling the halls of the theatre ...
|
||||
(`help theatre/dramatis` or `help theathre/drama` or `help theatre/personae` would work)
|
||||
|
||||
### Primadonna Ada
|
||||
|
||||
Everyone knows the primadonna! She is ...
|
||||
(A subtopic under dramatis personae, accessible as `help theatre/drama/ada` etc)
|
||||
|
||||
### The gatekeeper
|
||||
|
||||
He always keeps an eye on the door and ...
|
||||
(`help theatre/drama/gate`)
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="technical-notes">
|
||||
<h2>Technical notes<a class="headerlink" href="#technical-notes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Since it needs to search so different types of data, the help system has to
|
||||
collect all possibilities in memory before searching through the entire set. It
|
||||
uses the <a class="reference external" href="https://github.com/yeraydiazdiaz/lunr.py">Lunr</a> search engine to
|
||||
search through the main bulk of help entries. Lunr is a mature engine used for
|
||||
web-pages and produces much more sensible results than previous solutions.</p>
|
||||
<p>Once the main entry has been found, subtopics are then searched with
|
||||
simple <code class="docutils literal notranslate"><span class="pre">==</span></code>, <code class="docutils literal notranslate"><span class="pre">startswith</span></code> and <code class="docutils literal notranslate"><span class="pre">in</span></code> matching (there are so relatively few of them
|
||||
at that point).</p>
|
||||
<section id="help-entry-clashes">
|
||||
<h3>Help-entry clashes<a class="headerlink" href="#help-entry-clashes" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Should you have clashing help-entries (of the same name) between the three types of available entries, the priority is</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Command-auto-help > Db-help > File-help
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">sethelp</span></code> command (which only deals with creating db-based help entries) will warn you if a new help entry might shadow/be shadowed by a same/similar-named command or file-based help entry.</p>
|
||||
</section>
|
||||
<section id="the-help-entry-container">
|
||||
<h3>The Help Entry container<a class="headerlink" href="#the-help-entry-container" title="Permalink to this headline">¶</a></h3>
|
||||
<p>All help entries (no matter the source) are parsed into an object with the following properties:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - This is the main topic-name. For Commands, this is literally the command’s <code class="docutils literal notranslate"><span class="pre">key</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">aliases</span></code> - Alternate names for the help entry. This can be useful if the main name is hard to remember.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">help_category</span></code> - The general grouping of the entry. This is optional. If not given it will use the default category given by <code class="docutils literal notranslate"><span class="pre">settings.COMMAND_DEFAULT_HELP_CATEGORY</span></code> for Commands and
|
||||
<code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_HELP_CATEGORY</span></code> for file+db help entries.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> - Lock string (for commands) or LockHandler (all help entries). This defines who may read this entry. See the next section.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">tags</span></code> - This is not used by default, but could be used to further organize help entries.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">text</span></code> - The actual help entry text. This will be dedented and stripped of extra space at beginning and end.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="help-pagination">
|
||||
<h3>Help pagination<a class="headerlink" href="#help-pagination" title="Permalink to this headline">¶</a></h3>
|
||||
<p>A <code class="docutils literal notranslate"><span class="pre">text</span></code> that scrolls off the screen will automatically be paginated by the <a class="reference internal" href="EvMore.html"><span class="doc std std-doc">EvMore</span></a> pager (you can control this with <code class="docutils literal notranslate"><span class="pre">settings.HELP_MORE_ENABLED=False</span></code>). If you use EvMore and want to control exactly where the pager should break the page, mark the break with the control character <code class="docutils literal notranslate"><span class="pre">\f</span></code>.</p>
|
||||
</section>
|
||||
<section id="search-engine">
|
||||
<h3>Search engine<a class="headerlink" href="#search-engine" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Since it needs to search so different types of data, the help system has to collect all possibilities in memory before searching through the entire set. It uses the <a class="reference external" href="https://github.com/yeraydiazdiaz/lunr.py">Lunr</a> search engine to search through the main bulk of help entries. Lunr is a mature engine used for web-pages and produces much more sensible results than previous solutions.</p>
|
||||
<p>Once the main entry has been found, subtopics are then searched with simple <code class="docutils literal notranslate"><span class="pre">==</span></code>, <code class="docutils literal notranslate"><span class="pre">startswith</span></code> and <code class="docutils literal notranslate"><span class="pre">in</span></code> matching (there are so relatively few of them at that point).</p>
|
||||
<div class="versionchanged">
|
||||
<p><span class="versionmodified changed">Changed in version 1.0: </span>Replaced the old bag-of-words algorithm with lunr package.</p>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Coding Utils" href="Coding-Utils.html" />
|
||||
<link rel="prev" title="Batch Command Processor" href="Batch-Command-Processor.html" />
|
||||
<link rel="prev" title="Batch Code Processor" href="Batch-Code-Processor.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<a href="Coding-Utils.html" title="Coding Utils"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -76,16 +76,16 @@
|
|||
<li><a class="reference internal" href="#repeat">repeat</a></li>
|
||||
<li><a class="reference internal" href="#unrepeat">unrepeat</a></li>
|
||||
<li><a class="reference internal" href="#monitor">monitor</a></li>
|
||||
<li><a class="reference internal" href="#unmonitor">unmonitor</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#unmonitor">unmonitor</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Batch-Command-Processor.html"
|
||||
title="previous chapter">Batch Command Processor</a></p>
|
||||
<p class="topless"><a href="Batch-Code-Processor.html"
|
||||
title="previous chapter">Batch Code Processor</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Coding-Utils.html"
|
||||
title="next chapter">Coding Utils</a></p>
|
||||
|
|
@ -121,29 +121,45 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="inputfuncs">
|
||||
<h1>Inputfuncs<a class="headerlink" href="#inputfuncs" title="Permalink to this headline">¶</a></h1>
|
||||
<p>An <em>inputfunc</em> is an Evennia function that handles a particular input (an <a class="reference internal" href="../Concepts/OOB.html"><span class="doc std std-doc">inputcommand</span></a>) from
|
||||
the client. The inputfunc is the last destination for the inputcommand along the <span class="xref myst">ingoing message
|
||||
path</span>. The inputcommand always has the form <code class="docutils literal notranslate"><span class="pre">(commandname,</span> <span class="pre">(args),</span> <span class="pre">{kwargs})</span></code> and Evennia will use this to try to find and call an inputfunc on the form</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">commandname</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># ...</span>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> Internet│
|
||||
┌─────┐ │ ┌────────┐
|
||||
┌──────┐ │Text │ │ ┌────────────┐ ┌─────────┐ │Command │
|
||||
│Client├────┤JSON ├─┼──►commandtuple├────►Inputfunc├────►DB query│
|
||||
└──────┘ │etc │ │ └────────────┘ └─────────┘ │etc │
|
||||
└─────┘ │ └────────┘
|
||||
│Evennia
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The Inputfunc is the last fixed step on the <a class="reference internal" href="../Concepts/Messagepath.html#ingoing-message-path"><span class="std std-doc">Ingoing message path</span></a>. The available Inputfuncs are looked up and called using <code class="docutils literal notranslate"><span class="pre">commandtuple</span></code> structures sent from the client. The job of the Inputfunc is to perform whatever action is requested, by firing a Command, performing a database query or whatever is needed.</p>
|
||||
<p>Given a <code class="docutils literal notranslate"><span class="pre">commandtuple</span></code> on the form</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>(commandname, (args), {kwargs})
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Evennia will try to find and call an Inputfunc on the form</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">commandname</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># ...</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or, if no match was found, it will call an inputfunc named “default” on this form</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">cmdname</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># cmdname is the name of the mismatched inputcommand</span>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">cmdname</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># cmdname is the name of the mismatched inputcommand</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The default inputfuncs are found in <a class="reference internal" href="../api/evennia.server.inputfuncs.html#evennia-server-inputfuncs"><span class="std std-ref">evennia/server/inputfuncs.py</span></a>.</p>
|
||||
<section id="adding-your-own-inputfuncs">
|
||||
<h2>Adding your own inputfuncs<a class="headerlink" href="#adding-your-own-inputfuncs" title="Permalink to this headline">¶</a></h2>
|
||||
<p>This is simple. Add a function on the above form to <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/inputfuncs.py</span></code>. Your
|
||||
function must be in the global, outermost scope of that module and not start with an underscore
|
||||
(<code class="docutils literal notranslate"><span class="pre">_</span></code>) to be recognized as an inputfunc. Reload the server. That’s it. To overload a default
|
||||
inputfunc (see below), just add a function with the same name.</p>
|
||||
<p>The modules Evennia looks into for inputfuncs are defined in the list <code class="docutils literal notranslate"><span class="pre">settings.INPUT_FUNC_MODULES</span></code>.
|
||||
This list will be imported from left to right and later imported functions will replace earlier
|
||||
ones.</p>
|
||||
<ol class="simple">
|
||||
<li><p>Add a function on the above form to <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/inputfuncs.py</span></code>. Your function must be in the global, outermost scope of that module and not start with an underscore (<code class="docutils literal notranslate"><span class="pre">_</span></code>) to be recognized as an inputfunc. i</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">reload</span></code> the server.</p></li>
|
||||
</ol>
|
||||
<p>To overload a default inputfunc (see below), just add a function with the same name. You can also extend the settings-list <code class="docutils literal notranslate"><span class="pre">INPUT_FUNC_MODULES</span></code>.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>INPUT_FUNC_MODULES += ["path.to.my.inputfunc.module"]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>All global-level functions with a name not starting with <code class="docutils literal notranslate"><span class="pre">_</span></code> in these module(s) will be used by Evennia as an inputfunc. The list is imported from left to right, so latter imported functions will replace earlier ones.</p>
|
||||
</section>
|
||||
<section id="default-inputfuncs">
|
||||
<h2>Default inputfuncs<a class="headerlink" href="#default-inputfuncs" title="Permalink to this headline">¶</a></h2>
|
||||
|
|
@ -155,10 +171,8 @@ ones.</p>
|
|||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("text",</span> <span class="pre">(textstring,),</span> <span class="pre">{})</span></code></p></li>
|
||||
<li><p>Output: Depends on Command triggered</p></li>
|
||||
</ul>
|
||||
<p>This is the most common of inputcommands, and the only one supported by every traditional mud. The
|
||||
argument is usually what the user sent from their command line. Since all text input from the user
|
||||
like this is considered a <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Command</span></a>, this inputfunc will do things like nick-replacement
|
||||
and then pass on the input to the central Commandhandler.</p>
|
||||
<p>This is the most common of inputs, and the only one supported by every traditional mud. The argument is usually what the user sent from their command line. Since all text input from the user
|
||||
like this is considered a <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Command</span></a>, this inputfunc will do things like nick-replacement and then pass on the input to the central Commandhandler.</p>
|
||||
</section>
|
||||
<section id="echo">
|
||||
<h3>echo<a class="headerlink" href="#echo" title="Permalink to this headline">¶</a></h3>
|
||||
|
|
@ -166,13 +180,11 @@ and then pass on the input to the central Commandhandler.</p>
|
|||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("echo",</span> <span class="pre">(args),</span> <span class="pre">{})</span></code></p></li>
|
||||
<li><p>Output: <code class="docutils literal notranslate"><span class="pre">("text",</span> <span class="pre">("Echo</span> <span class="pre">returns:</span> <span class="pre">%s"</span> <span class="pre">%</span> <span class="pre">args),</span> <span class="pre">{})</span></code></p></li>
|
||||
</ul>
|
||||
<p>This is a test input, which just echoes the argument back to the session as text. Can be used for
|
||||
testing custom client input.</p>
|
||||
<p>This is a test input, which just echoes the argument back to the session as text. Can be used for testing custom client input.</p>
|
||||
</section>
|
||||
<section id="default">
|
||||
<h3>default<a class="headerlink" href="#default" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The default function, as mentioned above, absorbs all non-recognized inputcommands. The default one
|
||||
will just log an error.</p>
|
||||
<p>The default function, as mentioned above, absorbs all non-recognized inputcommands. The default one will just log an error.</p>
|
||||
</section>
|
||||
<section id="client-options">
|
||||
<h3>client_options<a class="headerlink" href="#client-options" title="Permalink to this headline">¶</a></h3>
|
||||
|
|
@ -203,8 +215,7 @@ as an outputcommand <code class="docutils literal notranslate"><span class="pre"
|
|||
<li><p>raw (bool): Leave text tags unparsed</p></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<div><p>Note that there are two GMCP aliases to this inputfunc - <code class="docutils literal notranslate"><span class="pre">hello</span></code> and <code class="docutils literal notranslate"><span class="pre">supports_set</span></code>, which means
|
||||
it will be accessed via the GMCP <code class="docutils literal notranslate"><span class="pre">Hello</span></code> and <code class="docutils literal notranslate"><span class="pre">Supports.Set</span></code> instructions assumed by some clients.</p>
|
||||
<div><p>Note that there are two GMCP aliases to this inputfunc - <code class="docutils literal notranslate"><span class="pre">hello</span></code> and <code class="docutils literal notranslate"><span class="pre">supports_set</span></code>, which means it will be accessed via the GMCP <code class="docutils literal notranslate"><span class="pre">Hello</span></code> and <code class="docutils literal notranslate"><span class="pre">Supports.Set</span></code> instructions assumed by some clients.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="get-client-options">
|
||||
|
|
@ -213,8 +224,7 @@ it will be accessed via the GMCP <code class="docutils literal notranslate"><spa
|
|||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("get_client_options,</span> <span class="pre">(),</span> <span class="pre">{key:value,</span> <span class="pre">...})</span></code></p></li>
|
||||
<li><p>Output: <code class="docutils literal notranslate"><span class="pre">("client_options,</span> <span class="pre">(),</span> <span class="pre">{key:value,</span> <span class="pre">...})</span></code></p></li>
|
||||
</ul>
|
||||
<p>This is a convenience wrapper that retrieves the current options by sending “get” to
|
||||
<code class="docutils literal notranslate"><span class="pre">client_options</span></code> above.</p>
|
||||
<p>This is a convenience wrapper that retrieves the current options by sending “get” to <code class="docutils literal notranslate"><span class="pre">client_options</span></code> above.</p>
|
||||
</section>
|
||||
<section id="get-inputfuncs">
|
||||
<h3>get_inputfuncs<a class="headerlink" href="#get-inputfuncs" title="Permalink to this headline">¶</a></h3>
|
||||
|
|
@ -222,8 +232,7 @@ it will be accessed via the GMCP <code class="docutils literal notranslate"><spa
|
|||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("get_inputfuncs",</span> <span class="pre">(),</span> <span class="pre">{})</span></code></p></li>
|
||||
<li><p>Output: <code class="docutils literal notranslate"><span class="pre">("get_inputfuncs",</span> <span class="pre">(),</span> <span class="pre">{funcname:docstring,</span> <span class="pre">...})</span></code></p></li>
|
||||
</ul>
|
||||
<p>Returns an outputcommand on the form <code class="docutils literal notranslate"><span class="pre">("get_inputfuncs",</span> <span class="pre">(),</span> <span class="pre">{funcname:docstring,</span> <span class="pre">...})</span></code> - a list of
|
||||
all the available inputfunctions along with their docstrings.</p>
|
||||
<p>Returns an outputcommand on the form <code class="docutils literal notranslate"><span class="pre">("get_inputfuncs",</span> <span class="pre">(),</span> <span class="pre">{funcname:docstring,</span> <span class="pre">...})</span></code> - a list of all the available inputfunctions along with their docstrings.</p>
|
||||
</section>
|
||||
<section id="login">
|
||||
<h3>login<a class="headerlink" href="#login" title="Permalink to this headline">¶</a></h3>
|
||||
|
|
@ -234,15 +243,13 @@ all the available inputfunctions along with their docstrings.</p>
|
|||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("login",</span> <span class="pre">(username,</span> <span class="pre">password),</span> <span class="pre">{})</span></code></p></li>
|
||||
<li><p>Output: Depends on login hooks</p></li>
|
||||
</ul>
|
||||
<p>This performs the inputfunc version of a login operation on the current Session.</p>
|
||||
<p>This performs the inputfunc version of a login operation on the current Session. It’s meant to be used by custom client setups.</p>
|
||||
</section>
|
||||
<section id="get-value">
|
||||
<h3>get_value<a class="headerlink" href="#get-value" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Input: <code class="docutils literal notranslate"><span class="pre">("get_value",</span> <span class="pre">(name,</span> <span class="pre">),</span> <span class="pre">{})</span></code>
|
||||
Output: <code class="docutils literal notranslate"><span class="pre">("get_value",</span> <span class="pre">(value,</span> <span class="pre">),</span> <span class="pre">{})</span></code></p>
|
||||
<p>Retrieves a value from the Character or Account currently controlled by this Session. Takes one
|
||||
argument, This will only accept particular white-listed names, you’ll need to overload the function
|
||||
to expand. By default the following values can be retrieved:</p>
|
||||
<p>Retrieves a value from the Character or Account currently controlled by this Session. Takes one argument, This will only accept particular white-listed names, you’ll need to overload the function to expand. By default the following values can be retrieved:</p>
|
||||
<ul class="simple">
|
||||
<li><p>“name” or “key”: The key of the Account or puppeted Character.</p></li>
|
||||
<li><p>“location”: Name of the current location, or “None”.</p></li>
|
||||
|
|
@ -252,16 +259,11 @@ to expand. By default the following values can be retrieved:</p>
|
|||
<section id="repeat">
|
||||
<h3>repeat<a class="headerlink" href="#repeat" title="Permalink to this headline">¶</a></h3>
|
||||
<ul class="simple">
|
||||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("repeat",</span> <span class="pre">(),</span> <span class="pre">{"callback":funcname,</span>                      <span class="pre">"interval":</span> <span class="pre">secs,</span> <span class="pre">"stop":</span> <span class="pre">False})</span></code></p></li>
|
||||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("repeat",</span> <span class="pre">(),</span> <span class="pre">{"callback":funcname,</span>  <span class="pre">"interval":</span> <span class="pre">secs,</span> <span class="pre">"stop":</span> <span class="pre">False})</span></code></p></li>
|
||||
<li><p>Output: Depends on the repeated function. Will return <code class="docutils literal notranslate"><span class="pre">("text",</span> <span class="pre">(repeatlist),{}</span></code> with a list of
|
||||
accepted names if given an unfamiliar callback name.</p></li>
|
||||
</ul>
|
||||
<p>This will tell evennia to repeatedly call a named function at a given interval. Behind the scenes
|
||||
this will set up a <a class="reference internal" href="TickerHandler.html"><span class="doc std std-doc">Ticker</span></a>. Only previously acceptable functions are possible to
|
||||
repeat-call in this way, you’ll need to overload this inputfunc to add the ones you want to offer.
|
||||
By default only two example functions are allowed, “test1” and “test2”, which will just echo a text
|
||||
back at the given interval. Stop the repeat by sending <code class="docutils literal notranslate"><span class="pre">"stop":</span> <span class="pre">True</span></code> (note that you must include
|
||||
both the callback name and interval for Evennia to know what to stop).</p>
|
||||
<p>This will tell evennia to repeatedly call a named function at a given interval. Behind the scenes this will set up a <a class="reference internal" href="TickerHandler.html"><span class="doc std std-doc">Ticker</span></a>. Only previously acceptable functions are possible to repeat-call in this way, you’ll need to overload this inputfunc to add the ones you want to offer. By default only two example functions are allowed, “test1” and “test2”, which will just echo a text back at the given interval. Stop the repeat by sending <code class="docutils literal notranslate"><span class="pre">"stop":</span> <span class="pre">True</span></code> (note that you must include both the callback name and interval for Evennia to know what to stop).</p>
|
||||
</section>
|
||||
<section id="unrepeat">
|
||||
<h3>unrepeat<a class="headerlink" href="#unrepeat" title="Permalink to this headline">¶</a></h3>
|
||||
|
|
@ -277,28 +279,23 @@ both the callback name and interval for Evennia to know what to stop).</p>
|
|||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("monitor",</span> <span class="pre">(),</span> <span class="pre">("name":field_or_argname,</span> <span class="pre">stop=False)</span></code></p></li>
|
||||
<li><p>Output (on change): <code class="docutils literal notranslate"><span class="pre">("monitor",</span> <span class="pre">(),</span> <span class="pre">{"name":name,</span> <span class="pre">"value":value})</span></code></p></li>
|
||||
</ul>
|
||||
<p>This sets up on-object monitoring of Attributes or database fields. Whenever the field or Attribute
|
||||
changes in any way, the outputcommand will be sent. This is using the
|
||||
<a class="reference internal" href="MonitorHandler.html"><span class="doc std std-doc">MonitorHandler</span></a> behind the scenes. Pass the “stop” key to stop monitoring. Note
|
||||
that you must supply the name also when stopping to let the system know which monitor should be
|
||||
cancelled.</p>
|
||||
<p>Only fields/attributes in a whitelist are allowed to be used, you have to overload this function to
|
||||
add more. By default the following fields/attributes can be monitored:</p>
|
||||
<p>This sets up on-object monitoring of Attributes or database fields. Whenever the field or Attribute changes in any way, the outputcommand will be sent. This is using the <a class="reference internal" href="MonitorHandler.html"><span class="doc std std-doc">MonitorHandler</span></a> behind the scenes. Pass the “stop” key to stop monitoring. Note that you must supply the name also when stopping to let the system know which monitor should be cancelled.</p>
|
||||
<p>Only fields/attributes in a whitelist are allowed to be used, you have to overload this function to add more. By default the following fields/attributes can be monitored:</p>
|
||||
<ul class="simple">
|
||||
<li><p>“name”: The current character name</p></li>
|
||||
<li><p>“location”: The current location</p></li>
|
||||
<li><p>“desc”: The description Argument</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
<section id="unmonitor">
|
||||
<h2>unmonitor<a class="headerlink" href="#unmonitor" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>unmonitor<a class="headerlink" href="#unmonitor" title="Permalink to this headline">¶</a></h3>
|
||||
<ul class="simple">
|
||||
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">("unmonitor",</span> <span class="pre">(),</span> <span class="pre">{"name":name})</span></code></p></li>
|
||||
<li><p>Output: None</p></li>
|
||||
</ul>
|
||||
<p>A convenience wrapper that sends “stop” to the <code class="docutils literal notranslate"><span class="pre">monitor</span></code> function.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -320,7 +317,7 @@ add more. By default the following fields/attributes can be monitored:</p>
|
|||
<a href="Coding-Utils.html" title="Coding Utils"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
|
||||
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Signals" href="Signals.html" />
|
||||
<link rel="prev" title="TickerHandler" href="TickerHandler.html" />
|
||||
<link rel="next" title="Commands" href="Commands.html" />
|
||||
<link rel="prev" title="Permissions" href="Permissions.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,10 +30,10 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Signals.html" title="Signals"
|
||||
<a href="Commands.html" title="Commands"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="TickerHandler.html" title="TickerHandler"
|
||||
<a href="Permissions.html" title="Permissions"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -63,28 +63,30 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Locks</a><ul>
|
||||
<li><a class="reference internal" href="#setting-and-checking-a-lock">Setting and checking a lock</a></li>
|
||||
<li><a class="reference internal" href="#defining-locks">Defining locks</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-locks">Working with locks</a><ul>
|
||||
<li><a class="reference internal" href="#defining-locks">Defining locks</a></li>
|
||||
<li><a class="reference internal" href="#valid-access-types">Valid access_types</a></li>
|
||||
<li><a class="reference internal" href="#custom-access-types">Custom access_types</a></li>
|
||||
<li><a class="reference internal" href="#lock-functions">Lock functions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#checking-simple-strings">Checking simple strings</a></li>
|
||||
<li><a class="reference internal" href="#default-locks">Default locks</a></li>
|
||||
<li><a class="reference internal" href="#more-lock-definition-examples">More Lock definition examples</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#more-lock-definition-examples">More Lock definition examples</a><ul>
|
||||
<li><a class="reference internal" href="#a-complete-example-of-setting-locks-on-an-object">A complete example of setting locks on an object</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#on-djangos-permission-system">On Django’s permission system</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="TickerHandler.html"
|
||||
title="previous chapter">TickerHandler</a></p>
|
||||
<p class="topless"><a href="Permissions.html"
|
||||
title="previous chapter">Permissions</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Signals.html"
|
||||
title="next chapter">Signals</a></p>
|
||||
<p class="topless"><a href="Commands.html"
|
||||
title="next chapter">Commands</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -118,21 +120,18 @@
|
|||
<section class="tex2jax_ignore mathjax_ignore" id="locks">
|
||||
<h1>Locks<a class="headerlink" href="#locks" title="Permalink to this headline">¶</a></h1>
|
||||
<p>For most games it is a good idea to restrict what people can do. In Evennia such restrictions are
|
||||
applied and checked by something called <em>locks</em>. All Evennia entities (<a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a>,
|
||||
<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Help-System.html"><span class="doc std std-doc">Help System</span></a>,
|
||||
<a class="reference internal" href="Msg.html"><span class="doc std std-doc">messages</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">channels</span></a>) are accessed through locks.</p>
|
||||
applied and checked by something called <em>locks</em>. All Evennia entities (<a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Help-System.html"><span class="doc std std-doc">Help System</span></a>, <a class="reference internal" href="Msg.html"><span class="doc std std-doc">messages</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">channels</span></a>) are accessed through locks.</p>
|
||||
<p>A lock can be thought of as an “access rule” restricting a particular use of an Evennia entity.
|
||||
Whenever another entity wants that kind of access the lock will analyze that entity in different
|
||||
ways to determine if access should be granted or not. Evennia implements a “lockdown” philosophy -
|
||||
all entities are inaccessible unless you explicitly define a lock that allows some or full access.</p>
|
||||
ways to determine if access should be granted or not. Evennia implements a “lockdown” philosophy - all entities are inaccessible unless you explicitly define a lock that allows some or full access.</p>
|
||||
<p>Let’s take an example: An object has a lock on itself that restricts how people may “delete” that
|
||||
object. Apart from knowing that it restricts deletion, the lock also knows that only players with
|
||||
the specific ID of, say, <code class="docutils literal notranslate"><span class="pre">34</span></code> are allowed to delete it. So whenever a player tries to run <code class="docutils literal notranslate"><span class="pre">delete</span></code>
|
||||
on the object, the <code class="docutils literal notranslate"><span class="pre">delete</span></code> command makes sure to check if this player is really allowed to do so.
|
||||
It calls the lock, which in turn checks if the player’s id is <code class="docutils literal notranslate"><span class="pre">34</span></code>. Only then will it allow <code class="docutils literal notranslate"><span class="pre">delete</span></code>
|
||||
to go on with its job.</p>
|
||||
<section id="setting-and-checking-a-lock">
|
||||
<h2>Setting and checking a lock<a class="headerlink" href="#setting-and-checking-a-lock" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-locks">
|
||||
<h2>Working with locks<a class="headerlink" href="#working-with-locks" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The in-game command for setting locks on objects is <code class="docutils literal notranslate"><span class="pre">lock</span></code>:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > lock obj = <lockstring>
|
||||
</pre></div>
|
||||
|
|
@ -154,9 +153,8 @@ command:</p>
|
|||
<span class="k">return</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="defining-locks">
|
||||
<h2>Defining locks<a class="headerlink" href="#defining-locks" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Defining locks<a class="headerlink" href="#defining-locks" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Defining a lock (i.e. an access restriction) in Evennia is done by adding simple strings of lock
|
||||
definitions to the object’s <code class="docutils literal notranslate"><span class="pre">locks</span></code> property using <code class="docutils literal notranslate"><span class="pre">obj.locks.add()</span></code>.</p>
|
||||
<p>Here are some examples of lock strings (not including the quotes):</p>
|
||||
|
|
@ -181,6 +179,7 @@ the lockstring. The string below yields the same result as the previous example:
|
|||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>delete:id(34);edit:all();get: not attr(very_weak) or perm(Admin)
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="valid-access-types">
|
||||
<h3>Valid access_types<a class="headerlink" href="#valid-access-types" title="Permalink to this headline">¶</a></h3>
|
||||
<p>An <code class="docutils literal notranslate"><span class="pre">access_type</span></code>, the first part of a lockstring, defines what kind of capability a lock controls,
|
||||
|
|
@ -198,13 +197,8 @@ the default command set) actually checks for, as in the example of <code class="
|
|||
</li>
|
||||
<li><p><a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>:</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">control</span></code> - who is the “owner” of the object. Can set locks, delete it etc. Defaults to the
|
||||
creator of the object.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">call</span></code> - who may call Object-commands stored on this Object except for the Object itself. By
|
||||
default, Objects share their Commands with anyone in the same location (e.g. so you can ‘press’ a
|
||||
<code class="docutils literal notranslate"><span class="pre">Button</span></code> object in the room). For Characters and Mobs (who likely only use those Commands for
|
||||
themselves and don’t want to share them) this should usually be turned off completely, using
|
||||
something like <code class="docutils literal notranslate"><span class="pre">call:false()</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">control</span></code> - who is the “owner” of the object. Can set locks, delete it etc. Defaults to the creator of the object.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">call</span></code> - who may call Object-commands stored on this Object except for the Object itself. By default, Objects share their Commands with anyone in the same location (e.g. so you can ‘press’ a <code class="docutils literal notranslate"><span class="pre">Button</span></code> object in the room). For Characters and Mobs (who likely only use those Commands for themselves and don’t want to share them) this should usually be turned off completely, using something like <code class="docutils literal notranslate"><span class="pre">call:false()</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">examine</span></code> - who may examine this object’s properties.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">delete</span></code> - who may delete the object.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">edit</span></code> - who may edit properties and attributes of the object.</p></li>
|
||||
|
|
@ -264,14 +258,11 @@ boot listeners etc.</p></li>
|
|||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>So to take an example, whenever an exit is to be traversed, a lock of the type <em>traverse</em> will be
|
||||
checked. Defining a suitable lock type for an exit object would thus involve a lockstring <code class="docutils literal notranslate"><span class="pre">traverse:</span> <span class="pre"><lock</span> <span class="pre">functions></span></code>.</p>
|
||||
<p>So to take an example, whenever an exit is to be traversed, a lock of the type <em>traverse</em> will be checked. Defining a suitable lock type for an exit object would thus involve a lockstring <code class="docutils literal notranslate"><span class="pre">traverse:</span> <span class="pre"><lock</span> <span class="pre">functions></span></code>.</p>
|
||||
</section>
|
||||
<section id="custom-access-types">
|
||||
<h3>Custom access_types<a class="headerlink" href="#custom-access-types" title="Permalink to this headline">¶</a></h3>
|
||||
<p>As stated above, the <code class="docutils literal notranslate"><span class="pre">access_type</span></code> part of the lock is simply the ‘name’ or ‘type’ of the lock. The
|
||||
text is an arbitrary string that must be unique for an object. If adding a lock with the same
|
||||
<code class="docutils literal notranslate"><span class="pre">access_type</span></code> as one that already exists on the object, the new one override the old one.</p>
|
||||
<p>As stated above, the <code class="docutils literal notranslate"><span class="pre">access_type</span></code> part of the lock is simply the ‘name’ or ‘type’ of the lock. The text is an arbitrary string that must be unique for an object. If adding a lock with the same <code class="docutils literal notranslate"><span class="pre">access_type</span></code> as one that already exists on the object, the new one override the old one.</p>
|
||||
<p>For example, if you wanted to create a bulletin board system and wanted to restrict who can either
|
||||
read a board or post to a board. You could then define locks such as:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">obj</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">"read:perm(Player);post:perm(Admin)"</span><span class="p">)</span>
|
||||
|
|
@ -290,7 +281,7 @@ trying to read the board):</p>
|
|||
</section>
|
||||
<section id="lock-functions">
|
||||
<h3>Lock functions<a class="headerlink" href="#lock-functions" title="Permalink to this headline">¶</a></h3>
|
||||
<p>A lock function is a normal Python function put in a place Evennia looks for such functions. The
|
||||
<p>A <em>lock function</em> is a normal Python function put in a place Evennia looks for such functions. The
|
||||
modules Evennia looks at is the list <code class="docutils literal notranslate"><span class="pre">settings.LOCK_FUNC_MODULES</span></code>. <em>All functions</em> in any of those
|
||||
modules will automatically be considered a valid lock function. The default ones are found in
|
||||
<code class="docutils literal notranslate"><span class="pre">evennia/locks/lockfuncs.py</span></code> and you can start adding your own in <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/lockfuncs.py</span></code>.
|
||||
|
|
@ -352,9 +343,8 @@ permissions and dbrefs of <em>Accounts</em>, not on Characters.</p></li>
|
|||
setting set to a given value.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
<section id="checking-simple-strings">
|
||||
<h2>Checking simple strings<a class="headerlink" href="#checking-simple-strings" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Checking simple strings<a class="headerlink" href="#checking-simple-strings" title="Permalink to this headline">¶</a></h3>
|
||||
<p>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 <code class="docutils literal notranslate"><span class="pre">check_lockstring(accessing_obj,</span> <span class="pre">lockstring,</span> <span class="pre">bypass_superuser=False)</span></code> that allows this.</p>
|
||||
|
|
@ -364,11 +354,10 @@ has a method <code class="docutils literal notranslate"><span class="pre">check_
|
|||
<span class="k">return</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note here that the <code class="docutils literal notranslate"><span class="pre">access_type</span></code> can be left to a dummy value since this method does not actually do
|
||||
a Lock lookup.</p>
|
||||
<p>Note here that the <code class="docutils literal notranslate"><span class="pre">access_type</span></code> can be left to a dummy value since this method does not actually do a Lock lookup.</p>
|
||||
</section>
|
||||
<section id="default-locks">
|
||||
<h2>Default locks<a class="headerlink" href="#default-locks" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Default locks<a class="headerlink" href="#default-locks" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Evennia sets up a few basic locks on all new objects and accounts (if we didn’t, noone would have
|
||||
any access to anything from the start). This is all defined in the root <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclasses</span></a>
|
||||
of the respective entity, in the hook method <code class="docutils literal notranslate"><span class="pre">basetype_setup()</span></code> (which you usually don’t want to
|
||||
|
|
@ -378,6 +367,7 @@ child object to change the default. Also creation commands like <code class="doc
|
|||
objects you create - for example it sets the <code class="docutils literal notranslate"><span class="pre">control</span></code> lock_type so as to allow you, its creator, to
|
||||
control and delete the object.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="more-lock-definition-examples">
|
||||
<h2>More Lock definition examples<a class="headerlink" href="#more-lock-definition-examples" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>examine: attr(eyesight, excellent) or perm(Builders)
|
||||
|
|
@ -414,9 +404,8 @@ would be be added as a lock string to the <code class="docutils literal notransl
|
|||
<p>This is how the <code class="docutils literal notranslate"><span class="pre">create</span></code> command sets up new objects. In sequence, this permission string sets the
|
||||
owner of this object be the creator (the one running <code class="docutils literal notranslate"><span class="pre">create</span></code>). Builders may examine the object
|
||||
whereas only Admins and the creator may delete it. Everyone can pick it up.</p>
|
||||
</section>
|
||||
<section id="a-complete-example-of-setting-locks-on-an-object">
|
||||
<h2>A complete example of setting locks on an object<a class="headerlink" href="#a-complete-example-of-setting-locks-on-an-object" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>A complete example of setting locks on an object<a class="headerlink" href="#a-complete-example-of-setting-locks-on-an-object" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Assume we have two objects - one is ourselves (not superuser) and the other is an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a>
|
||||
called <code class="docutils literal notranslate"><span class="pre">box</span></code>.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > create/drop box
|
||||
|
|
@ -475,20 +464,11 @@ strength above 50 however and you’ll pick it up no problem. Done! A very heavy
|
|||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="on-djangos-permission-system">
|
||||
<h2>On Django’s permission system<a class="headerlink" href="#on-djangos-permission-system" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Django also implements a comprehensive permission/security system of its own. The reason we don’t
|
||||
use that is because it is app-centric (app in the Django sense). Its permission strings are of the
|
||||
form <code class="docutils literal notranslate"><span class="pre">appname.permstring</span></code> and it automatically adds three of them for each database model in the app</p>
|
||||
<ul class="simple">
|
||||
<li><p>for the app evennia/object this would be for example ‘object.create’, ‘object.admin’ and
|
||||
‘object.edit’. This makes a lot of sense for a web application, not so much for a MUD, especially
|
||||
when we try to hide away as much of the underlying architecture as possible.</p></li>
|
||||
</ul>
|
||||
<p>The django permissions are not completely gone however. We use it for validating passwords during
|
||||
login. It is also used exclusively for managing Evennia’s web-based admin site, which is a graphical
|
||||
front-end for the database of Evennia. You edit and assign such permissions directly from the web
|
||||
interface. It’s stand-alone from the permissions described above.</p>
|
||||
<p>Django also implements a comprehensive permission/security system of its own. The reason we don’t use that is because it is app-centric (app in the Django sense). Its permission strings are of the form <code class="docutils literal notranslate"><span class="pre">appname.permstring</span></code> and it automatically adds three of them for each database model in the app - for the app evennia/object this would be for example ‘object.create’, ‘object.admin’ and ‘object.edit’. This makes a lot of sense for a web application, not so much for a MUD, especially when we try to hide away as much of the underlying architecture as possible.</p>
|
||||
<p>The django permissions are not completely gone however. We use it for validating passwords during login. It is also used exclusively for managing Evennia’s web-based admin site, which is a graphical front-end for the database of Evennia. You edit and assign such permissions directly from the web interface. It’s stand-alone from the permissions described above.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -508,10 +488,10 @@ interface. It’s stand-alone from the permissions described above.</p>
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Signals.html" title="Signals"
|
||||
<a href="Commands.html" title="Commands"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="TickerHandler.html" title="TickerHandler"
|
||||
<a href="Permissions.html" title="Permissions"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="TickerHandler" href="TickerHandler.html" />
|
||||
<link rel="prev" title="The Inline Function Parser" href="FuncParser.html" />
|
||||
<link rel="prev" title="FuncParser inline text parsing" href="FuncParser.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<a href="TickerHandler.html" title="TickerHandler"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="FuncParser.html" title="The Inline Function Parser"
|
||||
<a href="FuncParser.html" title="FuncParser inline text parsing"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="FuncParser.html"
|
||||
title="previous chapter">The Inline Function Parser</a></p>
|
||||
title="previous chapter">FuncParser inline text parsing</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="TickerHandler.html"
|
||||
title="next chapter">TickerHandler</a></p>
|
||||
|
|
@ -194,7 +194,7 @@ the monitor to remove:</p>
|
|||
<a href="TickerHandler.html" title="TickerHandler"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="FuncParser.html" title="The Inline Function Parser"
|
||||
<a href="FuncParser.html" title="FuncParser inline text parsing"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Msg</a><ul>
|
||||
<li><a class="reference internal" href="#msg-in-code">Msg in code</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-msg">Working with Msg</a><ul>
|
||||
<li><a class="reference internal" href="#properties-on-msg">Properties on Msg</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -110,13 +110,8 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="msg">
|
||||
<h1>Msg<a class="headerlink" href="#msg" title="Permalink to this headline">¶</a></h1>
|
||||
<p>The <a class="reference internal" href="../api/evennia.comms.models.html#evennia.comms.models.Msg" title="evennia.comms.models.Msg"><span class="xref myst py py-class">Msg</span></a> object represents a database-saved
|
||||
piece of communication. Think of it as a discrete piece of email - it contains
|
||||
a message, some metadata and will always have a sender and one or more
|
||||
recipients.</p>
|
||||
<p>Once created, a Msg is normally not changed. It is persitently saved in the
|
||||
database. This allows for comprehensive logging of communications. Here are some
|
||||
good uses for <code class="docutils literal notranslate"><span class="pre">Msg</span></code> objects:</p>
|
||||
<p>The <a class="reference internal" href="../api/evennia.comms.models.html#evennia.comms.models.Msg" title="evennia.comms.models.Msg"><span class="xref myst py py-class">Msg</span></a> object represents a database-saved piece of communication. Think of it as a discrete piece of email - it contains a message, some metadata and will always have a sender and one or more recipients.</p>
|
||||
<p>Once created, a Msg is normally not changed. It is persitently saved in the database. This allows for comprehensive logging of communications. Here are some good uses for <code class="docutils literal notranslate"><span class="pre">Msg</span></code> objects:</p>
|
||||
<ul class="simple">
|
||||
<li><p>page/tells (the <code class="docutils literal notranslate"><span class="pre">page</span></code> command is how Evennia uses them out of the box)</p></li>
|
||||
<li><p>messages in a bulletin board</p></li>
|
||||
|
|
@ -133,13 +128,10 @@ actual in-game letter-object based on the Msg)</p>
|
|||
<div class="versionchanged">
|
||||
<p><span class="versionmodified changed">Changed in version 1.0: </span>Channels dropped Msg-support. Now only used in <code class="docutils literal notranslate"><span class="pre">page</span></code> command by default.</p>
|
||||
</div>
|
||||
<section id="msg-in-code">
|
||||
<h2>Msg in code<a class="headerlink" href="#msg-in-code" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The Msg is intended to be used exclusively in code, to build other game systems. It is <em>not</em>
|
||||
a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entity, which means it cannot (easily) be overridden. It
|
||||
doesn’t support Attributes (but it <em>does</em> support <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a>). It tries to be lean
|
||||
and small since a new one is created for every message.</p>
|
||||
<p>You create a new message with <code class="docutils literal notranslate"><span class="pre">evennia.create_message</span></code>:</p>
|
||||
<section id="working-with-msg">
|
||||
<h2>Working with Msg<a class="headerlink" href="#working-with-msg" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The Msg is intended to be used exclusively in code, to build other game systems. It is <em>not</em> a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entity, which means it cannot (easily) be overridden. It doesn’t support Attributes (but it <em>does</em> support <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a>). It tries to be lean and small since a new one is created for every message.
|
||||
You create a new message with <code class="docutils literal notranslate"><span class="pre">evennia.create_message</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_message</span>
|
||||
<span class="n">message</span> <span class="o">=</span> <span class="n">create_message</span><span class="p">(</span><span class="n">senders</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">receivers</span><span class="p">,</span>
|
||||
<span class="n">locks</span><span class="o">=...</span><span class="p">,</span> <span class="n">tags</span><span class="o">=...</span><span class="p">,</span> <span class="n">header</span><span class="o">=...</span><span class="p">)</span>
|
||||
|
|
@ -188,11 +180,7 @@ target.</p></li>
|
|||
</section>
|
||||
<section id="tempmsg">
|
||||
<h2>TempMsg<a class="headerlink" href="#tempmsg" title="Permalink to this headline">¶</a></h2>
|
||||
<p><a class="reference internal" href="../api/evennia.comms.models.html#evennia.comms.models.TempMsg" title="evennia.comms.models.TempMsg"><span class="xref myst py py-class">evennia.comms.models.TempMsg</span></a> is an object
|
||||
that implements the same API as the regular <code class="docutils literal notranslate"><span class="pre">Msg</span></code>, but which has no database
|
||||
component (and thus cannot be searched). It’s meant to plugged into systems
|
||||
expecting a <code class="docutils literal notranslate"><span class="pre">Msg</span></code> but where you just want to process the message without saving
|
||||
it.</p>
|
||||
<p><a class="reference internal" href="../api/evennia.comms.models.html#evennia.comms.models.TempMsg" title="evennia.comms.models.TempMsg"><span class="xref myst py py-class">evennia.comms.models.TempMsg</span></a> is an object that implements the same API as the regular <code class="docutils literal notranslate"><span class="pre">Msg</span></code>, but which has no database component (and thus cannot be searched). It’s meant to plugged into systems expecting a <code class="docutils literal notranslate"><span class="pre">Msg</span></code> but where you just want to process the message without saving it.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -63,15 +63,17 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Objects</a><ul>
|
||||
<li><a class="reference internal" href="#how-to-create-your-own-object-types">How to create your own object types</a></li>
|
||||
<li><a class="reference internal" href="#adding-common-functionality">Adding common functionality</a></li>
|
||||
<li><a class="reference internal" href="#working-with-objects">Working with Objects</a><ul>
|
||||
<li><a class="reference internal" href="#properties-and-functions-on-objects">Properties and functions on Objects</a></li>
|
||||
<li><a class="reference internal" href="#subclasses-of-object">Subclasses of <code class="docutils literal notranslate"><span class="pre">Object</span></code></a><ul>
|
||||
<li><a class="reference internal" href="#characters">Characters</a></li>
|
||||
<li><a class="reference internal" href="#rooms">Rooms</a></li>
|
||||
<li><a class="reference internal" href="#exits">Exits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#characters">Characters</a></li>
|
||||
<li><a class="reference internal" href="#rooms">Rooms</a></li>
|
||||
<li><a class="reference internal" href="#exits">Exits</a><ul>
|
||||
<li><a class="reference internal" href="#exit-details">Exit details</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#adding-common-functionality">Adding common functionality</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -159,8 +161,8 @@ spend most time working with. Objects are <a class="reference internal" href="Ty
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.rooms.Room</span></code> (inherits from <code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code>)</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.exits.Exit</span></code> (inherits from <code class="docutils literal notranslate"><span class="pre">DefaultExit</span></code>)</p></li>
|
||||
</ul>
|
||||
<section id="how-to-create-your-own-object-types">
|
||||
<h2>How to create your own object types<a class="headerlink" href="#how-to-create-your-own-object-types" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-objects">
|
||||
<h2>Working with Objects<a class="headerlink" href="#working-with-objects" title="Permalink to this headline">¶</a></h2>
|
||||
<p>You can easily add your own in-game behavior by either modifying one of the typeclasses in your game dir or by inheriting from them.</p>
|
||||
<p>You can put your new typeclass directly in the relevant module, or you could organize your code in some other way. Here we assume we make a new module <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/flowers.py</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># mygame/typeclasses/flowers.py</span>
|
||||
|
|
@ -178,13 +180,11 @@ spend most time working with. Objects are <a class="reference internal" href="Ty
|
|||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">"This is a pretty rose with thorns."</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now you just need to point to the class <em>Rose</em> with the <code class="docutils literal notranslate"><span class="pre">create</span></code> command
|
||||
to make a new rose:</p>
|
||||
<p>Now you just need to point to the class <em>Rose</em> with the <code class="docutils literal notranslate"><span class="pre">create</span></code> command to make a new rose:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> create/drop MyRose:flowers.Rose
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>What the <code class="docutils literal notranslate"><span class="pre">create</span></code> command actually <em>does</em> is to use the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_object" title="evennia.utils.create.create_object"><span class="xref myst py py-func">evennia.create_object</span></a>
|
||||
function. You can do the same thing yourself in code:</p>
|
||||
<p>What the <code class="docutils literal notranslate"><span class="pre">create</span></code> command actually <em>does</em> is to use the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_object" title="evennia.utils.create.create_object"><span class="xref myst py py-func">evennia.create_object</span></a> function. You can do the same thing yourself in code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_object</span>
|
||||
<span class="n">new_rose</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="s2">"typeclasses.flowers.Rose"</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"MyRose"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
|
|
@ -195,29 +195,9 @@ powerful and should be used for all coded object creating (so this is what you u
|
|||
your own building commands).</p>
|
||||
<p>This particular Rose class doesn’t really do much, all it does it make sure the attribute
|
||||
<code class="docutils literal notranslate"><span class="pre">desc</span></code>(which is what the <code class="docutils literal notranslate"><span class="pre">look</span></code> command looks for) is pre-set, which is pretty pointless since you
|
||||
will usually want to change this at build time (using the <code class="docutils literal notranslate"><span class="pre">desc</span></code> command or using the
|
||||
<a class="reference internal" href="Prototypes.html"><span class="doc std std-doc">Spawner</span></a>).</p>
|
||||
</section>
|
||||
<section id="adding-common-functionality">
|
||||
<h2>Adding common functionality<a class="headerlink" href="#adding-common-functionality" title="Permalink to this headline">¶</a></h2>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">Object</span></code>, <code class="docutils literal notranslate"><span class="pre">Character</span></code>, <code class="docutils literal notranslate"><span class="pre">Room</span></code> and <code class="docutils literal notranslate"><span class="pre">Exit</span></code> also inherit from <code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.objects.ObjectParent</span></code>.
|
||||
This is an empty ‘mixin’ class. Optionally, you can modify this class if you want to easily add some <em>common</em> functionality to all your Objects, Characters, Rooms and Exits at once. You can still customize each subclass separately (see the Python docs on <a class="reference external" href="https://docs.python.org/3/tutorial/classes.html#multiple-inheritance">multiple inheritance</a> for details).</p>
|
||||
<p>Here is an example:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/objects.py</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">evennia.objects.objects</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">ObjectParent</span><span class="p">:</span>
|
||||
<span class="k">def</span> <span class="nf">at_pre_get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">getter</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># make all entities by default un-pickable</span>
|
||||
<span class="k">return</span> <span class="kc">False</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now all of <code class="docutils literal notranslate"><span class="pre">Object</span></code>, <code class="docutils literal notranslate"><span class="pre">Exit</span></code>. <code class="docutils literal notranslate"><span class="pre">Room</span></code> and <code class="docutils literal notranslate"><span class="pre">Character</span></code> default to not being able to be picked up using the <code class="docutils literal notranslate"><span class="pre">get</span></code> command.</p>
|
||||
</section>
|
||||
will usually want to change this at build time (using the <code class="docutils literal notranslate"><span class="pre">desc</span></code> command or using the <a class="reference internal" href="Prototypes.html"><span class="doc std std-doc">Spawner</span></a>).</p>
|
||||
<section id="properties-and-functions-on-objects">
|
||||
<h2>Properties and functions on Objects<a class="headerlink" href="#properties-and-functions-on-objects" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Properties and functions on Objects<a class="headerlink" href="#properties-and-functions-on-objects" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Beyond the properties assigned to all <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">typeclassed</span></a> objects (see that page for a list
|
||||
of those), the Object also has the following custom properties:</p>
|
||||
<ul class="simple">
|
||||
|
|
@ -250,21 +230,39 @@ of those), the Object also has the following custom properties:</p>
|
|||
</ul>
|
||||
<p>The Object Typeclass defines many more <em>hook methods</em> beyond <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>. Evennia calls these hooks at various points. When implementing your custom objects, you will inherit from the base parent and overload these hooks with your own custom code. See <code class="docutils literal notranslate"><span class="pre">evennia.objects.objects</span></code> for an updated list of all the available hooks or the <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject" title="evennia.objects.objects.DefaultObject"><span class="xref myst py py-class">API for DefaultObject here</span></a>.</p>
|
||||
</section>
|
||||
<section id="subclasses-of-object">
|
||||
<h2>Subclasses of <code class="docutils literal notranslate"><span class="pre">Object</span></code><a class="headerlink" href="#subclasses-of-object" title="Permalink to this headline">¶</a></h2>
|
||||
<p>There are three special subclasses of <em>Object</em> in default Evennia - <em>Characters</em>, <em>Rooms</em> and <em>Exits</em>. The reason they are separated is because these particular object types are fundamental, something you will always need and in some cases requires some extra attention in order to be recognized by the game engine (there is nothing stopping you from redefining them though). In practice they are all pretty similar to the base Object.</p>
|
||||
</section>
|
||||
<section id="characters">
|
||||
<h3>Characters<a class="headerlink" href="#characters" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Characters are objects controlled by <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>. When a new Account logs in to Evennia for the first time, a new <code class="docutils literal notranslate"><span class="pre">Character</span></code> object is created and the Account object is assigned to the <code class="docutils literal notranslate"><span class="pre">account</span></code> attribute. A <code class="docutils literal notranslate"><span class="pre">Character</span></code> object must have a <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Default Commandset</span></a> set on itself at creation, or the account will not be able to issue any commands! If you just inherit your own class from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultCharacter</span></code> and make sure to use <code class="docutils literal notranslate"><span class="pre">super()</span></code> to call the parent methods you should be fine. In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> is an empty <code class="docutils literal notranslate"><span class="pre">Character</span></code> class ready for you to modify.</p>
|
||||
<h2>Characters<a class="headerlink" href="#characters" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultCharacter" title="evennia.objects.objects.DefaultCharacter"><span class="xref myst py py-class">DefaultCharacters</span></a> is the root class for player in-game entities. They are usually <em>puppeted</em> by <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>.</p>
|
||||
<p>When a new Account logs in to Evennia for the first time, a new <code class="docutils literal notranslate"><span class="pre">Character</span></code> object is created and the Account object is assigned to the <code class="docutils literal notranslate"><span class="pre">account</span></code> attribute (but Evennia supports <a class="reference internal" href="../Concepts/Connection-Styles.html"><span class="doc std std-doc">alternative connection-styles</span></a> if so desired).</p>
|
||||
<p>A <code class="docutils literal notranslate"><span class="pre">Character</span></code> object must have a <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Default Commandset</span></a> set on itself at creation, or the account will not be able to issue any commands!</p>
|
||||
<p>If you want to change the default character created by the default commands, you can change it in settings:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>BASE_CHARACTER_TYPECLASS = "typeclasses.characters.Character"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This deafult points at the empty class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> , ready for you to modify as you please.</p>
|
||||
</section>
|
||||
<section id="rooms">
|
||||
<h3>Rooms<a class="headerlink" href="#rooms" title="Permalink to this headline">¶</a></h3>
|
||||
<p><em>Rooms</em> are the root containers of all other objects. The only thing really separating a room from any other object is that they have no <code class="docutils literal notranslate"><span class="pre">location</span></code> of their own and that default commands like <code class="docutils literal notranslate"><span class="pre">@dig</span></code> creates objects of this class - so if you want to expand your rooms with more functionality, just inherit from <code class="docutils literal notranslate"><span class="pre">ev.DefaultRoom</span></code>. In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/rooms.py</span></code> is an empty <code class="docutils literal notranslate"><span class="pre">Room</span></code> class ready for you to modify.</p>
|
||||
<h2>Rooms<a class="headerlink" href="#rooms" title="Permalink to this headline">¶</a></h2>
|
||||
<p><a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom" title="evennia.objects.objects.DefaultRoom"><span class="xref myst py py-class">Rooms</span></a> are the root containers of all other objects.</p>
|
||||
<p>The only thing really separating a room from any other object is that they have no <code class="docutils literal notranslate"><span class="pre">location</span></code> of their own and that default commands like <code class="docutils literal notranslate"><span class="pre">dig</span></code> creates objects of this class - so if you want to expand your rooms with more functionality, just inherit from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultRoom</span></code>.</p>
|
||||
<p>To change the default room created by <code class="docutils literal notranslate"><span class="pre">dig</span></code>, <code class="docutils literal notranslate"><span class="pre">tunnel</span></code> and other commands, change it in settings:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>BASE_ROOM_TYPECLASS = "typeclases.rooms.Room"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The empty class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/rooms.py</span></code> is a good place to start!</p>
|
||||
</section>
|
||||
<section id="exits">
|
||||
<h3>Exits<a class="headerlink" href="#exits" title="Permalink to this headline">¶</a></h3>
|
||||
<h2>Exits<a class="headerlink" href="#exits" title="Permalink to this headline">¶</a></h2>
|
||||
<p><em>Exits</em> are objects connecting other objects (usually <em>Rooms</em>) together. An object named <em>North</em> or <em>in</em> might be an exit, as well as <em>door</em>, <em>portal</em> or <em>jump out the window</em>. An exit has two things that separate them from other objects. Firstly, their <em>destination</em> property is set and points to a valid object. This fact makes it easy and fast to locate exits in the database. Secondly, exits define a special <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Transit Command</span></a> on themselves when they are created. This command is named the same as the exit object and will, when called, handle the practicalities of moving the character to the Exits’s <em>destination</em> - this allows you to just enter the name of the exit on its own to move around, just as you would expect.</p>
|
||||
<p>The exit functionality is all defined on the Exit typeclass, so you could in principle completely change how exits work in your game (it’s not recommended though, unless you really know what you are doing). Exits are <a class="reference internal" href="Locks.html"><span class="doc std std-doc">locked</span></a> using an access_type called <em>traverse</em> and also make use of a few hook methods for giving feedback if the traversal fails. See <code class="docutils literal notranslate"><span class="pre">evennia.DefaultExit</span></code> for more info. In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/exits.py</span></code> there is an empty <code class="docutils literal notranslate"><span class="pre">Exit</span></code> class for you to modify.</p>
|
||||
<p>The exit functionality is all defined on the Exit typeclass, so you could in principle completely change how exits work in your game (it’s not recommended though, unless you really know what you are doing). Exits are <a class="reference internal" href="Locks.html"><span class="doc std std-doc">locked</span></a> using an access_type called <em>traverse</em> and also make use of a few hook methods for giving feedback if the traversal fails. See <code class="docutils literal notranslate"><span class="pre">evennia.DefaultExit</span></code> for more info.</p>
|
||||
<p>Exits are normally overridden on a case-by-case basis, but if you want to change the default exit createad by rooms like <code class="docutils literal notranslate"><span class="pre">dig</span></code> , <code class="docutils literal notranslate"><span class="pre">tunnel</span></code> or <code class="docutils literal notranslate"><span class="pre">open</span></code> you can change it in settings:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>BASE_EXIT_TYPECLASS = "typeclasses.exits.Exit"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/exits.py</span></code> there is an empty <code class="docutils literal notranslate"><span class="pre">Exit</span></code> class for you to modify.</p>
|
||||
<section id="exit-details">
|
||||
<h3>Exit details<a class="headerlink" href="#exit-details" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The process of traversing an exit is as follows:</p>
|
||||
<ol class="simple">
|
||||
<li><p>The traversing <code class="docutils literal notranslate"><span class="pre">obj</span></code> sends a command that matches the Exit-command name on the Exit object. The <a class="reference internal" href="Commands.html"><span class="doc std std-doc">cmdhandler</span></a> detects this and triggers the command defined on the Exit. Traversal always involves the “source” (the current location) and the <code class="docutils literal notranslate"><span class="pre">destination</span></code> (this is stored on the Exit object).</p></li>
|
||||
|
|
@ -286,6 +284,24 @@ of those), the Object also has the following custom properties:</p>
|
|||
<p>If the move fails for whatever reason, the Exit will look for an Attribute <code class="docutils literal notranslate"><span class="pre">err_traverse</span></code> on itself and display this as an error message. If this is not found, the Exit will instead call <code class="docutils literal notranslate"><span class="pre">at_failed_traverse(obj)</span></code> on itself.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="adding-common-functionality">
|
||||
<h2>Adding common functionality<a class="headerlink" href="#adding-common-functionality" title="Permalink to this headline">¶</a></h2>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">Object</span></code>, <code class="docutils literal notranslate"><span class="pre">Character</span></code>, <code class="docutils literal notranslate"><span class="pre">Room</span></code> and <code class="docutils literal notranslate"><span class="pre">Exit</span></code> also inherit from <code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.objects.ObjectParent</span></code>.
|
||||
This is an empty ‘mixin’ class. Optionally, you can modify this class if you want to easily add some <em>common</em> functionality to all your Objects, Characters, Rooms and Exits at once. You can still customize each subclass separately (see the Python docs on <a class="reference external" href="https://docs.python.org/3/tutorial/classes.html#multiple-inheritance">multiple inheritance</a> for details).</p>
|
||||
<p>Here is an example:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/objects.py</span>
|
||||
<span class="c1"># ... </span>
|
||||
|
||||
<span class="kn">from</span> <span class="nn">evennia.objects.objects</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">ObjectParent</span><span class="p">:</span>
|
||||
<span class="k">def</span> <span class="nf">at_pre_get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">getter</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="c1"># make all entities by default un-pickable</span>
|
||||
<span class="k">return</span> <span class="kc">False</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Now all of <code class="docutils literal notranslate"><span class="pre">Object</span></code>, <code class="docutils literal notranslate"><span class="pre">Exit</span></code>. <code class="docutils literal notranslate"><span class="pre">Room</span></code> and <code class="docutils literal notranslate"><span class="pre">Character</span></code> default to not being able to be picked up using the <code class="docutils literal notranslate"><span class="pre">get</span></code> command.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Portal And Server" href="Portal-And-Server.html" />
|
||||
<link rel="next" title="Locks" href="Locks.html" />
|
||||
<link rel="prev" title="Help System" href="Help-System.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
<a href="Locks.html" title="Locks"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Help-System.html" title="Help System"
|
||||
|
|
@ -64,15 +64,14 @@
|
|||
<ul>
|
||||
<li><a class="reference internal" href="#">Permissions</a><ul>
|
||||
<li><a class="reference internal" href="#the-super-user">The super user</a></li>
|
||||
<li><a class="reference internal" href="#managing-permissions">Managing Permissions</a></li>
|
||||
<li><a class="reference internal" href="#working-with-permissions">Working with Permissions</a><ul>
|
||||
<li><a class="reference internal" href="#the-permission-hierarchy">The permission hierarchy</a></li>
|
||||
<li><a class="reference internal" href="#checking-permissions">Checking permissions</a><ul>
|
||||
<li><a class="reference internal" href="#checking-permissions">Checking permissions</a></li>
|
||||
<li><a class="reference internal" href="#checking-with-obj-permissions-check">Checking with obj.permissions.check()</a></li>
|
||||
<li><a class="reference internal" href="#lock-funcs">Lock funcs</a></li>
|
||||
<li><a class="reference internal" href="#some-examples">Some examples</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#superusers">Superusers</a></li>
|
||||
<li><a class="reference internal" href="#quelling">Quelling</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -82,8 +81,8 @@
|
|||
<p class="topless"><a href="Help-System.html"
|
||||
title="previous chapter">Help System</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Portal-And-Server.html"
|
||||
title="next chapter">Portal And Server</a></p>
|
||||
<p class="topless"><a href="Locks.html"
|
||||
title="next chapter">Locks</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -129,8 +128,8 @@ entirely.</p>
|
|||
test the game’s locks and restrictions with (see <code class="docutils literal notranslate"><span class="pre">quell</span></code> below). Usually there is no need to have
|
||||
but one superuser.</p>
|
||||
</section>
|
||||
<section id="managing-permissions">
|
||||
<h2>Managing Permissions<a class="headerlink" href="#managing-permissions" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-permissions">
|
||||
<h2>Working with Permissions<a class="headerlink" href="#working-with-permissions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>In-game, you use the <code class="docutils literal notranslate"><span class="pre">perm</span></code> command to add and remove permissions</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> > perm/account Tommy = Builders
|
||||
> perm/account/del Tommy = Builders
|
||||
|
|
@ -156,9 +155,8 @@ typeclassed entities as the property <code class="docutils literal notranslate">
|
|||
<span class="n">obj</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">"Blacksmith"</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="the-permission-hierarchy">
|
||||
<h2>The permission hierarchy<a class="headerlink" href="#the-permission-hierarchy" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>The permission hierarchy<a class="headerlink" href="#the-permission-hierarchy" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Selected permission strings can be organized in a <em>permission hierarchy</em> by editing the tuple
|
||||
<code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_HIERARCHY</span></code>. Evennia’s default permission hierarchy is as follows
|
||||
(in increasing order of power):</p>
|
||||
|
|
@ -176,8 +174,9 @@ typeclassed entities as the property <code class="docutils literal notranslate">
|
|||
<p>When checking a hierarchical permission (using one of the methods to follow), you will pass checks for your level and all <em>below</em> you. That is, even if the check explicitly checks for “Builder” level access, you will actually pass if you have one of “Builder”, “Admin” or “Developer”. By contrast, if you check for a non-hierarchical permission, like “Blacksmith” you <em>must</em> have exactly that permission to pass.</p>
|
||||
</section>
|
||||
<section id="checking-permissions">
|
||||
<h2>Checking permissions<a class="headerlink" href="#checking-permissions" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Checking permissions<a class="headerlink" href="#checking-permissions" title="Permalink to this headline">¶</a></h3>
|
||||
<p>It’s important to note that you check for the permission of a <em>puppeted</em> <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> (like a Character), the check will always first use the permissions of any <code class="docutils literal notranslate"><span class="pre">Account</span></code> connected to that Object before checking for permissions on the Object. In the case of hierarchical permissions (Admins, Builders etc), the Account permission will always be used (this stops an Account from escalating their permission by puppeting a high-level Character). If the permission looked for is not in the hierarchy, an exact match is required, first on the Account and if not found there (or if no Account is connected), then on the Object itself.</p>
|
||||
</section>
|
||||
<section id="checking-with-obj-permissions-check">
|
||||
<h3>Checking with obj.permissions.check()<a class="headerlink" href="#checking-with-obj-permissions-check" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The simplest way to check if an entity has a permission is to check its <em>PermissionHandler</em>, stored as <code class="docutils literal notranslate"><span class="pre">.permissions</span></code> on all typeclassed entities.</p>
|
||||
|
|
@ -268,17 +267,6 @@ objects (regardless of hierarchical perm or not).</p></li>
|
|||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="superusers">
|
||||
<h2>Superusers<a class="headerlink" href="#superusers" title="Permalink to this headline">¶</a></h2>
|
||||
<p>There is normally only one <em>superuser</em> account and that is the one first created
|
||||
when starting Evennia (User #1). This is sometimes known as the “Owner” or “God”
|
||||
user. A superuser has more than full access - it completely <em>bypasses</em> all
|
||||
locks and will always pass the <code class="docutils literal notranslate"><span class="pre">PermissionHandler.check()</span></code> check. This allows
|
||||
for the superuser to always have access to everything in an emergency. But it
|
||||
could also hide any eventual errors you might have made in your lock definitions. So
|
||||
when trying out game systems you should either use quelling (see below) or make
|
||||
a second Developer-level character that does not bypass such checks.</p>
|
||||
</section>
|
||||
<section id="quelling">
|
||||
<h2>Quelling<a class="headerlink" href="#quelling" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">quell</span></code> command can be used to enforce the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lockfunc to ignore
|
||||
|
|
@ -308,7 +296,7 @@ affectable by locks.</p>
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
<a href="Locks.html" title="Locks"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Help-System.html" title="Help System"
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Commands" href="Commands.html" />
|
||||
<link rel="prev" title="Permissions" href="Permissions.html" />
|
||||
<link rel="next" title="Sessions" href="Sessions.html" />
|
||||
<link rel="prev" title="Core Components" href="Components-Overview.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,10 +30,10 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Commands.html" title="Commands"
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Permissions.html" title="Permissions"
|
||||
<a href="Components-Overview.html" title="Core Components"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -61,11 +61,11 @@
|
|||
</div>
|
||||
<script>$('#searchbox').show(0);</script>
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Permissions.html"
|
||||
title="previous chapter">Permissions</a></p>
|
||||
<p class="topless"><a href="Components-Overview.html"
|
||||
title="previous chapter">Core Components</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Commands.html"
|
||||
title="next chapter">Commands</a></p>
|
||||
<p class="topless"><a href="Sessions.html"
|
||||
title="next chapter">Sessions</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -98,11 +98,6 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="portal-and-server">
|
||||
<h1>Portal And Server<a class="headerlink" href="#portal-and-server" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Evennia consists of two processes, known as <em>Portal</em> and <em>Server</em>. They can be controlled from
|
||||
inside the game or from the command line as described <a class="reference internal" href="../Setup/Running-Evennia.html"><span class="doc std std-doc">in the Running-Evennia doc</span></a>.</p>
|
||||
<p>In short, the Portal knows everything about internet protocols (telnet, websockets etc), but knows very little about the game.</p>
|
||||
<p>In contrast, the Server knows everything about the game. It knows that a player has connected but now <em>how</em> they connected.</p>
|
||||
<p>The effect of this is that you can fully <code class="docutils literal notranslate"><span class="pre">reload</span></code> the Server and have players still connected to the game. One the server comes back up, it will re-connect to the Portal and re-sync all players as if nothing happened.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>Internet│ ┌──────────┐ ┌─┐ ┌─┐ ┌─────────┐
|
||||
│ │Portal │ │S│ ┌───┐ │S│ │Server │
|
||||
P │ │ │ │e│ │AMP│ │e│ │ │
|
||||
|
|
@ -116,7 +111,14 @@ inside the game or from the command line as described <a class="reference intern
|
|||
│Evennia
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The Server and Portal are glued together via an AMP (Asynchronous Messaging Protocol) connection. This allows the two programs to communicate seamlessly on the same machine.</p>
|
||||
<p>The <em>Portal</em> and <em>Server</em> consitutes the two main halves of Evennia.</p>
|
||||
<p>These are two separate <code class="docutils literal notranslate"><span class="pre">twistd</span></code> processes and can be controlled from inside the game or from the command line as described <a class="reference internal" href="../Setup/Running-Evennia.html"><span class="doc std std-doc">in the Running-Evennia doc</span></a>.</p>
|
||||
<ul class="simple">
|
||||
<li><p>The Portal knows everything about internet protocols (telnet, websockets etc), but knows very little about the game.</p></li>
|
||||
<li><p>The Server knows everything about the game. It knows that a player has connected but now <em>how</em> they connected.</p></li>
|
||||
</ul>
|
||||
<p>The effect of this is that you can fully <code class="docutils literal notranslate"><span class="pre">reload</span></code> the Server and have players still connected to the game. One the server comes back up, it will re-connect to the Portal and re-sync all players as if nothing happened.</p>
|
||||
<p>The Portal and Server are intended to always run on the same machine. They are glued together via an AMP (Asynchronous Messaging Protocol) connection. This allows the two programs to communicate seamlessly.</p>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -135,10 +137,10 @@ inside the game or from the command line as described <a class="reference intern
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Commands.html" title="Commands"
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Permissions.html" title="Permissions"
|
||||
<a href="Components-Overview.html" title="Core Components"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -63,8 +63,9 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Spawner and Prototypes</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-prototypes">Working with Prototypes</a><ul>
|
||||
<li><a class="reference internal" href="#using-the-olc">Using the OLC</a></li>
|
||||
<li><a class="reference internal" href="#the-prototype">The prototype</a><ul>
|
||||
<li><a class="reference internal" href="#the-prototype">The prototype</a></li>
|
||||
<li><a class="reference internal" href="#prototype-keys">Prototype keys</a><ul>
|
||||
<li><a class="reference internal" href="#more-on-prototype-inheritance">More on prototype inheritance</a></li>
|
||||
</ul>
|
||||
|
|
@ -75,13 +76,12 @@
|
|||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#storing-prototypes">Storing prototypes</a><ul>
|
||||
<li><a class="reference internal" href="#database-prototypes">Database prototypes</a></li>
|
||||
<li><a class="reference internal" href="#module-based-prototypes">Module-based prototypes</a></li>
|
||||
<li><a class="reference internal" href="#spawning">Spawning</a><ul>
|
||||
<li><a class="reference internal" href="#using-evennia-prototypes-spawner">Using evennia.prototypes.spawner()</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#using-spawn">Using @spawn</a></li>
|
||||
<li><a class="reference internal" href="#using-evennia-prototypes-spawner">Using evennia.prototypes.spawner()</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -124,47 +124,30 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="spawner-and-prototypes">
|
||||
<h1>Spawner and Prototypes<a class="headerlink" href="#spawner-and-prototypes" title="Permalink to this headline">¶</a></h1>
|
||||
<p>The <em>spawner</em> is a system for defining and creating individual objects from a base template called a
|
||||
<em>prototype</em>. It is only designed for use with in-game <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, not any other type of
|
||||
entity.</p>
|
||||
<p>The normal way to create a custom object in Evennia is to make a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a>. If you
|
||||
haven’t read up on Typeclasses yet, think of them as normal Python classes that save to the database
|
||||
behind the scenes. Say you wanted to create a “Goblin” enemy. A common way to do this would be to
|
||||
first create a <code class="docutils literal notranslate"><span class="pre">Mobile</span></code> typeclass that holds everything common to mobiles in the game, like generic
|
||||
AI, combat code and various movement methods. A <code class="docutils literal notranslate"><span class="pre">Goblin</span></code> subclass is then made to inherit from
|
||||
<code class="docutils literal notranslate"><span class="pre">Mobile</span></code>. The <code class="docutils literal notranslate"><span class="pre">Goblin</span></code> class adds stuff unique to goblins, like group-based AI (because goblins are
|
||||
smarter in a group), the ability to panic, dig for gold etc.</p>
|
||||
<p>But now it’s time to actually start to create some goblins and put them in the world. What if we
|
||||
wanted those goblins to not all look the same? Maybe we want grey-skinned and green-skinned goblins
|
||||
or some goblins that can cast spells or which wield different weapons? We <em>could</em> make subclasses of
|
||||
<code class="docutils literal notranslate"><span class="pre">Goblin</span></code>, like <code class="docutils literal notranslate"><span class="pre">GreySkinnedGoblin</span></code> and <code class="docutils literal notranslate"><span class="pre">GoblinWieldingClub</span></code>. But that seems a bit excessive (and a
|
||||
lot of Python code for every little thing). Using classes can also become impractical when wanting
|
||||
to combine them - what if we want a grey-skinned goblin shaman wielding a spear - setting up a web
|
||||
of classes inheriting each other with multiple inheritance can be tricky.</p>
|
||||
<p>This is what the <em>prototype</em> is for. It is a Python dictionary that describes these per-instance
|
||||
changes to an object. The prototype also has the advantage of allowing an in-game builder to
|
||||
customize an object without access to the Python backend. Evennia also allows for saving and
|
||||
searching prototypes so other builders can find and use (and tweak) them later. Having a library of
|
||||
interesting prototypes is a good reasource for builders. The OLC system allows for creating, saving,
|
||||
loading and manipulating prototypes using a menu system.</p>
|
||||
<div class="highlight-shell notranslate"><div class="highlight"><pre><span></span>> spawn goblin
|
||||
|
||||
Spawned Goblin Grunt<span class="o">(</span><span class="c1">#45)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The <em>spawner</em> is a system for defining and creating individual objects from a base template called a <em>prototype</em>. It is only designed for use with in-game <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, not any other type of entity.</p>
|
||||
<p>The normal way to create a custom object in Evennia is to make a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a>. If you haven’t read up on Typeclasses yet, think of them as normal Python classes that save to the database behind the scenes. Say you wanted to create a “Goblin” enemy. A common way to do this would be to first create a <code class="docutils literal notranslate"><span class="pre">Mobile</span></code> typeclass that holds everything common to mobiles in the game, like generic AI, combat code and various movement methods. A <code class="docutils literal notranslate"><span class="pre">Goblin</span></code> subclass is then made to inherit from <code class="docutils literal notranslate"><span class="pre">Mobile</span></code>. The <code class="docutils literal notranslate"><span class="pre">Goblin</span></code> class adds stuff unique to goblins, like group-based AI (because goblins are smarter in a group), the ability to panic, dig for gold etc.</p>
|
||||
<p>But now it’s time to actually start to create some goblins and put them in the world. What if we wanted those goblins to not all look the same? Maybe we want grey-skinned and green-skinned goblins or some goblins that can cast spells or which wield different weapons? We <em>could</em> make subclasses of <code class="docutils literal notranslate"><span class="pre">Goblin</span></code>, like <code class="docutils literal notranslate"><span class="pre">GreySkinnedGoblin</span></code> and <code class="docutils literal notranslate"><span class="pre">GoblinWieldingClub</span></code>. But that seems a bit excessive (and a lot of Python code for every little thing). Using classes can also become impractical when wanting to combine them - what if we want a grey-skinned goblin shaman wielding a spear - setting up a web of classes inheriting each other with multiple inheritance can be tricky.</p>
|
||||
<p>This is what the <em>prototype</em> is for. It is a Python dictionary that describes these per-instance changes to an object. The prototype also has the advantage of allowing an in-game builder to customize an object without access to the Python backend. Evennia also allows for saving and searching prototypes so other builders can find and use (and tweak) them later. Having a library of interesting prototypes is a good reasource for builders. The OLC system allows for creating, saving, loading and manipulating prototypes using a menu system.</p>
|
||||
<p>The <em>spawner</em> takes a prototype and uses it to create (spawn) new, custom objects.</p>
|
||||
<section id="working-with-prototypes">
|
||||
<h2>Working with Prototypes<a class="headerlink" href="#working-with-prototypes" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="using-the-olc">
|
||||
<h2>Using the OLC<a class="headerlink" href="#using-the-olc" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Enter the <code class="docutils literal notranslate"><span class="pre">olc</span></code> command or <code class="docutils literal notranslate"><span class="pre">@spawn/olc</span></code> to enter the prototype wizard. This is a menu system for
|
||||
<h3>Using the OLC<a class="headerlink" href="#using-the-olc" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Enter the <code class="docutils literal notranslate"><span class="pre">olc</span></code> command or <code class="docutils literal notranslate"><span class="pre">spawn/olc</span></code> to enter the prototype wizard. This is a menu system for
|
||||
creating, loading, saving and manipulating prototypes. It’s intended to be used by in-game builders
|
||||
and will give a better understanding of prototypes in general. Use <code class="docutils literal notranslate"><span class="pre">help</span></code> on each node of the menu
|
||||
for more information. Below are further details about how prototypes work and how they are used.</p>
|
||||
</section>
|
||||
<section id="the-prototype">
|
||||
<h2>The prototype<a class="headerlink" href="#the-prototype" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The prototype dictionary can either be created for you by the OLC (see above), be written manually
|
||||
in a Python module (and then referenced by the <code class="docutils literal notranslate"><span class="pre">@spawn</span></code> command/OLC), or created on-the-fly and
|
||||
manually loaded into the spawner function or <code class="docutils literal notranslate"><span class="pre">@spawn</span></code> command.</p>
|
||||
<p>The dictionary defines all possible database-properties of an Object. It has a fixed set of allowed
|
||||
keys. When preparing to store the prototype in the database (or when using the OLC), some
|
||||
of these keys are mandatory. When just passing a one-time prototype-dict to the spawner the system
|
||||
is
|
||||
more lenient and will use defaults for keys not explicitly provided.</p>
|
||||
<h3>The prototype<a class="headerlink" href="#the-prototype" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The prototype dictionary can either be created for you by the OLC (see above), be written manually in a Python module (and then referenced by the <code class="docutils literal notranslate"><span class="pre">spawn</span></code> command/OLC), or created on-the-fly and
|
||||
manually loaded into the spawner function or <code class="docutils literal notranslate"><span class="pre">spawn</span></code> command.</p>
|
||||
<p>The dictionary defines all possible database-properties of an Object. It has a fixed set of allowed keys. When preparing to store the prototype in the database (or when using the OLC), some of these keys are mandatory. When just passing a one-time prototype-dict to the spawner the system is more lenient and will use defaults for keys not explicitly provided.</p>
|
||||
<p>In dictionary form, a prototype can look something like this:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="p">{</span>
|
||||
<span class="s2">"prototype_key"</span><span class="p">:</span> <span class="s2">"house"</span>
|
||||
|
|
@ -174,18 +157,13 @@ more lenient and will use defaults for keys not explicitly provided.</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<p>If you wanted to load it into the spawner in-game you could just put all on one line:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@spawn {"prototype_key="house", "key": "Large house", ...}
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>spawn {"prototype_key="house", "key": "Large house", ...}
|
||||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Note that the prototype dict as given on the command line must be a valid Python structure -
|
||||
so you need to put quotes around strings etc. For security reasons, a dict inserted from-in game
|
||||
cannot have any
|
||||
other advanced Python functionality, such as executable code, <code class="docutils literal notranslate"><span class="pre">lambda</span></code> etc. If builders are supposed
|
||||
to be able to use such features, you need to offer them through [$protfuncs](Spawner-and-
|
||||
Prototypes#protfuncs), embedded runnable functions that you have full control to check and vet
|
||||
before running.</p>
|
||||
<div><p>Note that the prototype dict as given on the command line must be a valid Python structure - so you need to put quotes around strings etc. For security reasons, a dict inserted from-in game cannot have any other advanced Python functionality, such as executable code, <code class="docutils literal notranslate"><span class="pre">lambda</span></code> etc. If builders are supposed to be able to use such features, you need to offer them through [$protfuncs](Spawner-and- Prototypes#protfuncs), embedded runnable functions that you have full control to check and vet before running.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="prototype-keys">
|
||||
<h3>Prototype keys<a class="headerlink" href="#prototype-keys" title="Permalink to this headline">¶</a></h3>
|
||||
<p>All keys starting with <code class="docutils literal notranslate"><span class="pre">prototype_</span></code> are for book keeping.</p>
|
||||
|
|
@ -200,53 +178,31 @@ left-right inheritance. If this is not given, a <code class="docutils literal no
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">prototype_desc</span></code> - this is optional and used when listing the prototype in in-game listings.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">protototype_tags</span></code> - this is optional and allows for tagging the prototype in order to find it
|
||||
easier later.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">prototype_locks</span></code> - two lock types are supported: <code class="docutils literal notranslate"><span class="pre">edit</span></code> and <code class="docutils literal notranslate"><span class="pre">spawn</span></code>. The first lock restricts
|
||||
the copying and editing of the prototype when loaded through the OLC. The second determines who
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">prototype_locks</span></code> - two lock types are supported: <code class="docutils literal notranslate"><span class="pre">edit</span></code> and <code class="docutils literal notranslate"><span class="pre">spawn</span></code>. The first lock restricts the copying and editing of the prototype when loaded through the OLC. The second determines who
|
||||
may use the prototype to create new objects.</p></li>
|
||||
</ul>
|
||||
<p>The remaining keys determine actual aspects of the objects to spawn from this prototype:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - the main object identifier. Defaults to “Spawned Object <em>X</em>”, where <em>X</em> is a random
|
||||
integer.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">typeclass</span></code> - A full python-path (from your gamedir) to the typeclass you want to use. If not
|
||||
set, the <code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> should be
|
||||
defined, with <code class="docutils literal notranslate"><span class="pre">typeclass</span></code> defined somewhere in the parent chain. When creating a one-time
|
||||
prototype
|
||||
dict just for spawning, one could omit this - <code class="docutils literal notranslate"><span class="pre">settings.BASE_OBJECT_TYPECLASS</span></code> will be used
|
||||
instead.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - the main object identifier. Defaults to “Spawned Object <em>X</em>”, where <em>X</em> is a random integer.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">typeclass</span></code> - A full python-path (from your gamedir) to the typeclass you want to use. If not set, the <code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> should be defined, with <code class="docutils literal notranslate"><span class="pre">typeclass</span></code> defined somewhere in the parent chain. When creating a one-time prototype dict just for spawning, one could omit this - <code class="docutils literal notranslate"><span class="pre">settings.BASE_OBJECT_TYPECLASS</span></code> will be used instead.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">location</span></code> - this should be a <code class="docutils literal notranslate"><span class="pre">#dbref</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">home</span></code> - a valid <code class="docutils literal notranslate"><span class="pre">#dbref</span></code>. Defaults to <code class="docutils literal notranslate"><span class="pre">location</span></code> or <code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_HOME</span></code> if location does not
|
||||
exist.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">home</span></code> - a valid <code class="docutils literal notranslate"><span class="pre">#dbref</span></code>. Defaults to <code class="docutils literal notranslate"><span class="pre">location</span></code> or <code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_HOME</span></code> if location does not exist.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">destination</span></code> - a valid <code class="docutils literal notranslate"><span class="pre">#dbref</span></code>. Only used by exits.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">permissions</span></code> - list of permission strings, like <code class="docutils literal notranslate"><span class="pre">["Accounts",</span> <span class="pre">"may_use_red_door"]</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> - a <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock-string</span></a> like <code class="docutils literal notranslate"><span class="pre">"edit:all();control:perm(Builder)"</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">aliases</span></code> - list of strings for use as aliases</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">tags</span></code> - list <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a>. These are given as tuples <code class="docutils literal notranslate"><span class="pre">(tag,</span> <span class="pre">category,</span> <span class="pre">data)</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">attrs</span></code> - list of <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>. These are given as tuples <code class="docutils literal notranslate"><span class="pre">(attrname,</span> <span class="pre">value,</span> <span class="pre">category,</span> <span class="pre">lockstring)</span></code></p></li>
|
||||
<li><p>Any other keywords are interpreted as non-category <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and their values.
|
||||
This is convenient for simple Attributes - use <code class="docutils literal notranslate"><span class="pre">attrs</span></code> for full control of Attributes.</p></li>
|
||||
<li><p>Any other keywords are interpreted as non-category <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and their values. This is convenient for simple Attributes - use <code class="docutils literal notranslate"><span class="pre">attrs</span></code> for full control of Attributes.</p></li>
|
||||
</ul>
|
||||
<section id="more-on-prototype-inheritance">
|
||||
<h4>More on prototype inheritance<a class="headerlink" href="#more-on-prototype-inheritance" title="Permalink to this headline">¶</a></h4>
|
||||
<ul class="simple">
|
||||
<li><p>A prototype can inherit by defining a <code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> pointing to the name
|
||||
(<code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> of another prototype). If a list of <code class="docutils literal notranslate"><span class="pre">prototype_keys</span></code>, this
|
||||
will be stepped through from left to right, giving priority to the first in
|
||||
the list over those appearing later. That is, if your inheritance is
|
||||
<code class="docutils literal notranslate"><span class="pre">prototype_parent</span> <span class="pre">=</span> <span class="pre">('A',</span> <span class="pre">'B,'</span> <span class="pre">'C')</span></code>, and all parents contain colliding keys,
|
||||
then the one from <code class="docutils literal notranslate"><span class="pre">A</span></code> will apply.</p></li>
|
||||
<li><p>The prototype keys that start with <code class="docutils literal notranslate"><span class="pre">prototype_*</span></code> are all unique to each
|
||||
prototype. They are <em>never</em> inherited from parent to child.</p></li>
|
||||
<li><p>The prototype fields <code class="docutils literal notranslate"><span class="pre">'attr':</span> <span class="pre">[(key,</span> <span class="pre">value,</span> <span class="pre">category,</span> <span class="pre">lockstring),...]</span></code>
|
||||
and <code class="docutils literal notranslate"><span class="pre">'tags':</span> <span class="pre">[(key,</span> <span class="pre">category,</span> <span class="pre">data),</span> <span class="pre">...]</span></code> are inherited in a <em>complementary</em>
|
||||
fashion. That means that only colliding key+category matches will be replaced, not the entire list.
|
||||
Remember that the category <code class="docutils literal notranslate"><span class="pre">None</span></code> is also considered a valid category!</p></li>
|
||||
<li><p>Adding an Attribute as a simple <code class="docutils literal notranslate"><span class="pre">key:value</span></code> will under the hood be translated
|
||||
into an Attribute tuple <code class="docutils literal notranslate"><span class="pre">(key,</span> <span class="pre">value,</span> <span class="pre">None,</span> <span class="pre">'')</span></code> and may replace an Attribute
|
||||
in the parent if it the same key and a <code class="docutils literal notranslate"><span class="pre">None</span></code> category.</p></li>
|
||||
<li><p>All other keys (<code class="docutils literal notranslate"><span class="pre">permissions</span></code>, <code class="docutils literal notranslate"><span class="pre">destination</span></code>, <code class="docutils literal notranslate"><span class="pre">aliases</span></code> etc) are completely
|
||||
<em>replaced</em> by the child’s value if given. For the parent’s value to be
|
||||
retained, the child must not define these keys at all.</p></li>
|
||||
<li><p>A prototype can inherit by defining a <code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> pointing to the name (<code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> of another prototype). If a list of <code class="docutils literal notranslate"><span class="pre">prototype_keys</span></code>, this will be stepped through from left to right, giving priority to the first in the list over those appearing later. That is, if your inheritance is <code class="docutils literal notranslate"><span class="pre">prototype_parent</span> <span class="pre">=</span> <span class="pre">('A',</span> <span class="pre">'B,'</span> <span class="pre">'C')</span></code>, and all parents contain colliding keys, then the one from <code class="docutils literal notranslate"><span class="pre">A</span></code> will apply.</p></li>
|
||||
<li><p>The prototype keys that start with <code class="docutils literal notranslate"><span class="pre">prototype_*</span></code> are all unique to each prototype. They are <em>never</em> inherited from parent to child.</p></li>
|
||||
<li><p>The prototype fields <code class="docutils literal notranslate"><span class="pre">'attr':</span> <span class="pre">[(key,</span> <span class="pre">value,</span> <span class="pre">category,</span> <span class="pre">lockstring),...]</span></code> and <code class="docutils literal notranslate"><span class="pre">'tags':</span> <span class="pre">[(key,</span> <span class="pre">category,</span> <span class="pre">data),</span> <span class="pre">...]</span></code> are inherited in a <em>complementary</em> fashion. That means that only colliding key+category matches will be replaced, not the entire list. Remember that the category <code class="docutils literal notranslate"><span class="pre">None</span></code> is also considered a valid category!</p></li>
|
||||
<li><p>Adding an Attribute as a simple <code class="docutils literal notranslate"><span class="pre">key:value</span></code> will under the hood be translated into an Attribute tuple <code class="docutils literal notranslate"><span class="pre">(key,</span> <span class="pre">value,</span> <span class="pre">None,</span> <span class="pre">'')</span></code> and may replace an Attribute in the parent if it the same key and a <code class="docutils literal notranslate"><span class="pre">None</span></code> category.</p></li>
|
||||
<li><p>All other keys (<code class="docutils literal notranslate"><span class="pre">permissions</span></code>, <code class="docutils literal notranslate"><span class="pre">destination</span></code>, <code class="docutils literal notranslate"><span class="pre">aliases</span></code> etc) are completely <em>replaced</em> by the child’s value if given. For the parent’s value to be retained, the child must not define these keys at all.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
|
|
@ -258,32 +214,26 @@ retained, the child must not define these keys at all.</p></li>
|
|||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>It can also be a <em>callable</em>. This callable is called without arguments whenever the prototype is
|
||||
used to
|
||||
spawn a new object:</p>
|
||||
<p>It can also be a <em>callable</em>. This callable is called without arguments whenever the prototype is used to spawn a new object:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="n">_get_a_random_goblin_name</span><span class="p">,</span> <span class="o">...</span><span class="p">}</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>By use of Python <code class="docutils literal notranslate"><span class="pre">lambda</span></code> one can wrap the callable so as to make immediate settings in the
|
||||
prototype:</p>
|
||||
<p>By use of Python <code class="docutils literal notranslate"><span class="pre">lambda</span></code> one can wrap the callable so as to make immediate settings in the prototype:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="k">lambda</span><span class="p">:</span> <span class="n">random</span><span class="o">.</span><span class="n">choice</span><span class="p">((</span><span class="s2">"Urfgar"</span><span class="p">,</span> <span class="s2">"Rick the smelly"</span><span class="p">,</span> <span class="s2">"Blargh the foul"</span><span class="p">,</span> <span class="o">...</span><span class="p">)),</span> <span class="o">...</span><span class="p">}</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<section id="protfuncs">
|
||||
<h4>Protfuncs<a class="headerlink" href="#protfuncs" title="Permalink to this headline">¶</a></h4>
|
||||
<p>Finally, the value can be a <em>prototype function</em> (<em>Protfunc</em>). These look like simple function calls
|
||||
that you embed in strings and that has a <code class="docutils literal notranslate"><span class="pre">$</span></code> in front, like</p>
|
||||
<p>Finally, the value can be a <em>prototype function</em> (<em>Protfunc</em>). These look like simple function calls that you embed in strings and that has a <code class="docutils literal notranslate"><span class="pre">$</span></code> in front, like</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="p">{</span><span class="s2">"key"</span><span class="p">:</span> <span class="s2">"$choice(Urfgar, Rick the smelly, Blargh the foul)"</span><span class="p">,</span>
|
||||
<span class="s2">"attrs"</span><span class="p">:</span> <span class="p">{</span><span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"This is a large $red(and very red) demon. "</span>
|
||||
<span class="s2">"He has $randint(2,5) skulls in a chain around his neck."</span><span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>At execution time, the place of the protfunc will be replaced with the result of that protfunc being
|
||||
called (this is always a string). A protfunc is a <a class="reference internal" href="FuncParser.html"><span class="doc std std-doc">FuncParser function</span></a> run
|
||||
every time the prototype is used to spawn a new object.</p>
|
||||
<p>Here is how a protfunc is defined (same as an inlinefunc).</p>
|
||||
<p>At execution time, the place of the protfunc will be replaced with the result of that protfunc being called (this is always a string). A protfunc is a <a class="reference internal" href="FuncParser.html"><span class="doc std std-doc">FuncParser function</span></a> run every time the prototype is used to spawn a new object.</p>
|
||||
<p>Here is how a protfunc is defined (same as other funcparser functions).</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># this is a silly example, you can just color the text red with |r directly!</span>
|
||||
<span class="k">def</span> <span class="nf">red</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
<span class="sd">"""</span>
|
||||
|
|
@ -296,23 +246,17 @@ every time the prototype is used to spawn a new object.</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Note that we must make sure to validate input and raise <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if that fails. Also, it is
|
||||
<em>not</em> possible to use keywords in the call to the protfunc (so something like <code class="docutils literal notranslate"><span class="pre">$echo(text,</span> <span class="pre">align=left)</span></code> is invalid). The <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> requred is for internal evennia use and not used at all for
|
||||
protfuncs (only by inlinefuncs).</p>
|
||||
<div><p>Note that we must make sure to validate input and raise <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if that fails. Also, it is <em>not</em> possible to use keywords in the call to the protfunc (so something like <code class="docutils literal notranslate"><span class="pre">$echo(text,</span> <span class="pre">align=left)</span></code> is invalid). The <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> requred is for internal evennia use and not used at all for protfuncs (only by inlinefuncs).</p>
|
||||
</div></blockquote>
|
||||
<p>To make this protfunc available to builders in-game, add it to a new module and add the path to that
|
||||
module to <code class="docutils literal notranslate"><span class="pre">settings.PROT_FUNC_MODULES</span></code>:</p>
|
||||
<p>To make this protfunc available to builders in-game, add it to a new module and add the path to that module to <code class="docutils literal notranslate"><span class="pre">settings.PROT_FUNC_MODULES</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/server/conf/settings.py</span>
|
||||
|
||||
<span class="n">PROT_FUNC_MODULES</span> <span class="o">+=</span> <span class="p">[</span><span class="s2">"world.myprotfuncs"</span><span class="p">]</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>All <em>global callables</em> in your added module will be considered a new protfunc. To avoid this (e.g.
|
||||
to have helper functions that are not protfuncs on their own), name your function something starting
|
||||
with <code class="docutils literal notranslate"><span class="pre">_</span></code>.</p>
|
||||
<p>The default protfuncs available out of the box are defined in <code class="docutils literal notranslate"><span class="pre">evennia/prototypes/profuncs.py</span></code>. To
|
||||
override the ones available, just add the same-named function in your own protfunc module.</p>
|
||||
<p>All <em>global callables</em> in your added module will be considered a new protfunc. To avoid this (e.g. to have helper functions that are not protfuncs on their own), name your function something starting with <code class="docutils literal notranslate"><span class="pre">_</span></code>.</p>
|
||||
<p>The default protfuncs available out of the box are defined in <code class="docutils literal notranslate"><span class="pre">evennia/prototypes/profuncs.py</span></code>. To override the ones available, just add the same-named function in your own protfunc module.</p>
|
||||
<table class="colwidths-auto docutils align-default">
|
||||
<thead>
|
||||
<tr class="row-odd"><th class="head"><p>Protfunc</p></th>
|
||||
|
|
@ -370,31 +314,17 @@ override the ones available, just add the same-named function in your own protfu
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing
|
||||
real Python functions is a lot more powerful and flexible. Their main use is to allow in-game
|
||||
builders to
|
||||
do limited coding/scripting for their prototypes without giving them direct access to raw Python.</p>
|
||||
<p>For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing real Python functions is a lot more powerful and flexible. Their main use is to allow in-game builders to do limited coding/scripting for their prototypes without giving them direct access to raw Python.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
<section id="storing-prototypes">
|
||||
<h2>Storing prototypes<a class="headerlink" href="#storing-prototypes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A prototype can be defined and stored in two ways, either in the database or as a dict in a module.</p>
|
||||
<section id="database-prototypes">
|
||||
<h3>Database prototypes<a class="headerlink" href="#database-prototypes" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Stored as <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> in the database. These are sometimes referred to as <em>database-
|
||||
prototypes</em> This is the only way for in-game builders to modify and add prototypes. They have the
|
||||
advantage of being easily modifiable and sharable between builders but you need to work with them
|
||||
using in-game tools.</p>
|
||||
<h2>Database prototypes<a class="headerlink" href="#database-prototypes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Stored as <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> in the database. These are sometimes referred to as <em>database- prototypes</em> This is the only way for in-game builders to modify and add prototypes. They have the advantage of being easily modifiable and sharable between builders but you need to work with them using in-game tools.</p>
|
||||
</section>
|
||||
<section id="module-based-prototypes">
|
||||
<h3>Module-based prototypes<a class="headerlink" href="#module-based-prototypes" title="Permalink to this headline">¶</a></h3>
|
||||
<p>These prototypes are defined as dictionaries assigned to global variables in one of the modules
|
||||
defined in <code class="docutils literal notranslate"><span class="pre">settings.PROTOTYPE_MODULES</span></code>. They can only be modified from outside the game so they are
|
||||
are necessarily “read-only” from in-game and cannot be modified (but copies of them could be made
|
||||
into database-prototypes). These were the only prototypes available before Evennia 0.8. Module based
|
||||
prototypes can be useful in order for developers to provide read-only “starting” or “base”
|
||||
prototypes to build from or if they just prefer to work offline in an external code editor.</p>
|
||||
<h2>Module-based prototypes<a class="headerlink" href="#module-based-prototypes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>These prototypes are defined as dictionaries assigned to global variables in one of the modules defined in <code class="docutils literal notranslate"><span class="pre">settings.PROTOTYPE_MODULES</span></code>. They can only be modified from outside the game so they are are necessarily “read-only” from in-game and cannot be modified (but copies of them could be made into database-prototypes). These were the only prototypes available before Evennia 0.8. Module based prototypes can be useful in order for developers to provide read-only “starting” or “base” prototypes to build from or if they just prefer to work offline in an external code editor.</p>
|
||||
<p>By default <code class="docutils literal notranslate"><span class="pre">mygame/world/prototypes.py</span></code> is set up for you to add your own prototypes. <em>All global
|
||||
dicts</em> in this module will be considered by Evennia to be a prototype. You could also tell Evennia
|
||||
to look for prototypes in more modules if you want:</p>
|
||||
|
|
@ -423,17 +353,14 @@ was given explicitly, that would take precedence. This is a legacy behavior and
|
|||
that you always add <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> to be consistent.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
</section>
|
||||
<section id="using-spawn">
|
||||
<h2>Using @spawn<a class="headerlink" href="#using-spawn" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The spawner can be used from inside the game through the Builder-only <code class="docutils literal notranslate"><span class="pre">@spawn</span></code> command. Assuming the
|
||||
“goblin” typeclass is available to the system (either as a database-prototype or read from module),
|
||||
you can spawn a new goblin with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@spawn goblin
|
||||
<section id="spawning">
|
||||
<h2>Spawning<a class="headerlink" href="#spawning" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The spawner can be used from inside the game through the Builder-only <code class="docutils literal notranslate"><span class="pre">@spawn</span></code> command. Assuming the “goblin” typeclass is available to the system (either as a database-prototype or read from module), you can spawn a new goblin with</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>spawn goblin
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can also specify the prototype directly as a valid Python dictionary:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@spawn {"prototype_key": "shaman", \
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>spawn {"prototype_key": "shaman", \
|
||||
"key":"Orc shaman", \
|
||||
"prototype_parent": "goblin", \
|
||||
"weapon": "wooden staff", \
|
||||
|
|
@ -441,14 +368,10 @@ you can spawn a new goblin with</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Note: The <code class="docutils literal notranslate"><span class="pre">@spawn</span></code> command is more lenient about the prototype dictionary than shown here. So you
|
||||
can for example skip the <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> if you are just testing a throw-away prototype. A random
|
||||
hash will be used to please the validation. You could also skip <code class="docutils literal notranslate"><span class="pre">prototype_parent/typeclass</span></code> - then
|
||||
the typeclass given by <code class="docutils literal notranslate"><span class="pre">settings.BASE_OBJECT_TYPECLASS</span></code> will be used.</p>
|
||||
<div><p>Note: The @spawn<code class="docutils literal notranslate"><span class="pre">command</span> <span class="pre">is</span> <span class="pre">more</span> <span class="pre">lenient</span> <span class="pre">about</span> <span class="pre">the</span> <span class="pre">prototype</span> <span class="pre">dictionary</span> <span class="pre">than</span> <span class="pre">shown</span> <span class="pre">here.</span> <span class="pre">So</span> <span class="pre">you</span> <span class="pre">can</span> <span class="pre">for</span> <span class="pre">example</span> <span class="pre">skip</span> <span class="pre">the</span></code>prototype_key<code class="docutils literal notranslate"><span class="pre">if</span> <span class="pre">you</span> <span class="pre">are</span> <span class="pre">just</span> <span class="pre">testing</span> <span class="pre">a</span> <span class="pre">throw-away</span> <span class="pre">prototype.</span> <span class="pre">A</span> <span class="pre">random</span> <span class="pre">hash</span> <span class="pre">will</span> <span class="pre">be</span> <span class="pre">used</span> <span class="pre">to</span> <span class="pre">please</span> <span class="pre">the</span> <span class="pre">validation.</span> <span class="pre">You</span> <span class="pre">could</span> <span class="pre">also</span> <span class="pre">skip</span> </code>prototype_parent/typeclass<code class="docutils literal notranslate"><span class="pre">-</span> <span class="pre">then</span> <span class="pre">the</span> <span class="pre">typeclass</span> <span class="pre">given</span> <span class="pre">by</span></code>settings.BASE_OBJECT_TYPECLASS` will be used.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="using-evennia-prototypes-spawner">
|
||||
<h2>Using evennia.prototypes.spawner()<a class="headerlink" href="#using-evennia-prototypes-spawner" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Using evennia.prototypes.spawner()<a class="headerlink" href="#using-evennia-prototypes-spawner" title="Permalink to this headline">¶</a></h3>
|
||||
<p>In code you access the spawner mechanism directly via the call</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">new_objects</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">prototypes</span><span class="o">.</span><span class="n">spawner</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="o">*</span><span class="n">prototypes</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
|
|
@ -460,18 +383,10 @@ matching list of created objects. Example:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Hint: Same as when using <code class="docutils literal notranslate"><span class="pre">@spawn</span></code>, when spawning from a one-time prototype dict like this, you can
|
||||
skip otherwise required keys, like <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> or <code class="docutils literal notranslate"><span class="pre">typeclass</span></code>/<code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code>. Defaults will
|
||||
be used.</p>
|
||||
<div><p>Hint: Same as when using <code class="docutils literal notranslate"><span class="pre">spawn</span></code>, when spawning from a one-time prototype dict like this, you can skip otherwise required keys, like <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> or <code class="docutils literal notranslate"><span class="pre">typeclass</span></code>/<code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code>. Defaults will be used.</p>
|
||||
</div></blockquote>
|
||||
<p>Note that no <code class="docutils literal notranslate"><span class="pre">location</span></code> will be set automatically when using <code class="docutils literal notranslate"><span class="pre">evennia.prototypes.spawner.spawn()</span></code>,
|
||||
you
|
||||
have to specify <code class="docutils literal notranslate"><span class="pre">location</span></code> explicitly in the prototype dict.</p>
|
||||
<p>If the prototypes you supply are using <code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> keywords, the spawner will read prototypes
|
||||
from modules
|
||||
in <code class="docutils literal notranslate"><span class="pre">settings.PROTOTYPE_MODULES</span></code> as well as those saved to the database to determine the body of
|
||||
available parents. The <code class="docutils literal notranslate"><span class="pre">spawn</span></code> command takes many optional keywords, you can find its definition <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.prototypes.spawner#spawn">in
|
||||
the api docs</a>.</p>
|
||||
<p>Note that no <code class="docutils literal notranslate"><span class="pre">location</span></code> will be set automatically when using <code class="docutils literal notranslate"><span class="pre">evennia.prototypes.spawner.spawn()</span></code>, you have to specify <code class="docutils literal notranslate"><span class="pre">location</span></code> explicitly in the prototype dict. If the prototypes you supply are using <code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> keywords, the spawner will read prototypes from modules in <code class="docutils literal notranslate"><span class="pre">settings.PROTOTYPE_MODULES</span></code> as well as those saved to the database to determine the body of available parents. The <code class="docutils literal notranslate"><span class="pre">spawn</span></code> command takes many optional keywords, you can find its definition <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.prototypes.spawner#spawn">in the api docs</a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
|
|||
|
|
@ -63,20 +63,20 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Scripts</a><ul>
|
||||
<li><a class="reference internal" href="#in-game-command-examples">In-game command examples</a></li>
|
||||
<li><a class="reference internal" href="#working-with-scripts">Working with Scripts</a><ul>
|
||||
<li><a class="reference internal" href="#code-examples">Code examples</a></li>
|
||||
<li><a class="reference internal" href="#defining-new-scripts">Defining new Scripts</a><ul>
|
||||
<li><a class="reference internal" href="#simple-storage-script">Simple storage script</a></li>
|
||||
<li><a class="reference internal" href="#timed-script">Timed Script</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#timed-scripts">Timed Scripts</a><ul>
|
||||
<li><a class="reference internal" href="#script-timers-vs-delay-repeat">Script timers vs delay/repeat</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#script-attached-to-another-object">Script attached to another object</a></li>
|
||||
<li><a class="reference internal" href="#other-script-methods">Other Script methods</a></li>
|
||||
<li><a class="reference internal" href="#the-global-scripts-container">The GLOBAL_SCRIPTS container</a></li>
|
||||
<li><a class="reference internal" href="#hints-dealing-with-script-errors">Hints: Dealing with Script Errors</a></li>
|
||||
<li><a class="reference internal" href="#dealing-with-script-errors">Dealing with Script Errors</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#using-global-scripts">Using GLOBAL_SCRIPTS</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -120,39 +120,20 @@
|
|||
<section class="tex2jax_ignore mathjax_ignore" id="scripts">
|
||||
<h1>Scripts<a class="headerlink" href="#scripts" title="Permalink to this headline">¶</a></h1>
|
||||
<p><a class="reference internal" href="../api/evennia.scripts.scripts.html#evennia-scripts-scripts"><span class="std std-ref">Script API reference</span></a></p>
|
||||
<p><em>Scripts</em> are the out-of-character siblings to the in-character
|
||||
<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>. Scripts are so flexible that the name “Script” is a bit limiting
|
||||
in itself - but we had to pick <em>something</em> to name them. Other possible names
|
||||
(depending on what you’d use them for) would be <code class="docutils literal notranslate"><span class="pre">OOBObjects</span></code>, <code class="docutils literal notranslate"><span class="pre">StorageContainers</span></code> or <code class="docutils literal notranslate"><span class="pre">TimerObjects</span></code>.</p>
|
||||
<p>If you ever consider creating an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> with a <code class="docutils literal notranslate"><span class="pre">None</span></code>-location just to store some game data,
|
||||
you should really be using a Script instead.</p>
|
||||
<p><em>Scripts</em> are the out-of-character siblings to the in-character <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>. Scripts are so flexible that the name “Script” is a bit limiting in itself - but we had to pick <em>something</em> to name them. Other possible names (depending on what you’d use them for) would be <code class="docutils literal notranslate"><span class="pre">OOBObjects</span></code>, <code class="docutils literal notranslate"><span class="pre">StorageContainers</span></code> or <code class="docutils literal notranslate"><span class="pre">TimerObjects</span></code>.</p>
|
||||
<p>If you ever consider creating an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> with a <code class="docutils literal notranslate"><span class="pre">None</span></code>-location just to store some game data, you should really be using a Script instead.</p>
|
||||
<ul class="simple">
|
||||
<li><p>Scripts are full <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities - they have <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and
|
||||
can be modified in the same way. But they have <em>no in-game existence</em>, so no
|
||||
location or command-execution like <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> and no connection to a particular
|
||||
player/session like <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>. This means they are perfectly suitable for acting
|
||||
as database-storage backends for game <em>systems</em>: Storing the current state of the economy,
|
||||
who is involved in the current fight, tracking an ongoing barter and so on. They are great as
|
||||
persistent system handlers.</p></li>
|
||||
<li><p>Scripts have an optional <em>timer component</em>. This means that you can set up the script
|
||||
to tick the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook on the Script at a certain interval. The timer can be controlled
|
||||
independently of the rest of the script as needed. This component is optional
|
||||
and complementary to other timing functions in Evennia, like
|
||||
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and
|
||||
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a>.</p></li>
|
||||
<li><p>Scripts can <em>attach</em> to Objects and Accounts via e.g. <code class="docutils literal notranslate"><span class="pre">obj.scripts.add/remove</span></code>. In the
|
||||
script you can then access the object/account as <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">self.account</span></code>. This can be used to
|
||||
dynamically extend other typeclasses but also to use the timer component to affect the parent object
|
||||
in various ways. For historical reasons, a Script <em>not</em> attached to an object is referred to as a
|
||||
<em>Global</em> Script.</p></li>
|
||||
<li><p>Scripts are full <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities - they have <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and can be modified in the same way. But they have <em>no in-game existence</em>, so no location or command-execution like <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> and no connection to a particular player/session like <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>. This means they are perfectly suitable for acting as database-storage backends for game <em>systems</em>: Storing the current state of the economy, who is involved in the current fight, tracking an ongoing barter and so on. They are great as persistent system handlers.</p></li>
|
||||
<li><p>Scripts have an optional <em>timer component</em>. This means that you can set up the script to tick the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook on the Script at a certain interval. The timer can be controlled independently of the rest of the script as needed. This component is optional and complementary to other timing functions in Evennia, like <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a>.</p></li>
|
||||
<li><p>Scripts can <em>attach</em> to Objects and Accounts via e.g. <code class="docutils literal notranslate"><span class="pre">obj.scripts.add/remove</span></code>. In the script you can then access the object/account as <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">self.account</span></code>. This can be used to dynamically extend other typeclasses but also to use the timer component to affect the parent object in various ways. For historical reasons, a Script <em>not</em> attached to an object is referred to as a <em>Global</em> Script.</p></li>
|
||||
</ul>
|
||||
<div class="versionchanged">
|
||||
<p><span class="versionmodified changed">Changed in version 1.0: </span>In previus Evennia versions, stopping the Script’s timer also meant deleting the Script object.
|
||||
Starting with this version, the timer can be start/stopped separately and <code class="docutils literal notranslate"><span class="pre">.delete()</span></code> must be called
|
||||
on the Script explicitly to delete it.</p>
|
||||
</div>
|
||||
<section id="in-game-command-examples">
|
||||
<h2>In-game command examples<a class="headerlink" href="#in-game-command-examples" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-scripts">
|
||||
<h2>Working with Scripts<a class="headerlink" href="#working-with-scripts" title="Permalink to this headline">¶</a></h2>
|
||||
<p>There are two main commands controlling scripts in the default cmdset:</p>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">addscript</span></code> command is used for attaching scripts to existing objects:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> addscript obj = bodyfunctions.BodyFunctions
|
||||
|
|
@ -169,9 +150,8 @@ on the Script explicitly to delete it.</p>
|
|||
<div class="versionchanged">
|
||||
<p><span class="versionmodified changed">Changed in version 1.0: </span>The <code class="docutils literal notranslate"><span class="pre">addscript</span></code> command used to be only <code class="docutils literal notranslate"><span class="pre">script</span></code> which was easy to confuse with <code class="docutils literal notranslate"><span class="pre">scripts</span></code>.</p>
|
||||
</div>
|
||||
</section>
|
||||
<section id="code-examples">
|
||||
<h2>Code examples<a class="headerlink" href="#code-examples" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Code examples<a class="headerlink" href="#code-examples" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Here are some examples of working with Scripts in-code (more details to follow in later
|
||||
sections).</p>
|
||||
<p>Create a new script:</p>
|
||||
|
|
@ -217,11 +197,11 @@ sections).</p>
|
|||
</div>
|
||||
</section>
|
||||
<section id="defining-new-scripts">
|
||||
<h2>Defining new Scripts<a class="headerlink" href="#defining-new-scripts" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Defining new Scripts<a class="headerlink" href="#defining-new-scripts" title="Permalink to this headline">¶</a></h3>
|
||||
<p>A Script is defined as a class and is created in the same way as other
|
||||
<a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">typeclassed</span></a> entities. The parent class is <code class="docutils literal notranslate"><span class="pre">evennia.DefaultScript</span></code>.</p>
|
||||
<section id="simple-storage-script">
|
||||
<h3>Simple storage script<a class="headerlink" href="#simple-storage-script" title="Permalink to this headline">¶</a></h3>
|
||||
<h4>Simple storage script<a class="headerlink" href="#simple-storage-script" title="Permalink to this headline">¶</a></h4>
|
||||
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/scripts.py</span></code> is an empty <code class="docutils literal notranslate"><span class="pre">Script</span></code> class already set up. You
|
||||
can use this as a base for your own scripts.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
|
||||
|
|
@ -259,13 +239,10 @@ you set in your <code class="docutils literal notranslate"><span class="pre">at_
|
|||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>See the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">create_script</span></a> and
|
||||
<a class="reference internal" href="../api/evennia.utils.search.html#evennia.utils.search.search_script" title="evennia.utils.search.search_script"><span class="xref myst py py-func">search_script</span></a> API documentation for more options
|
||||
on creating and finding Scripts.</p>
|
||||
<p>See the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">create_script</span></a> and <a class="reference internal" href="../api/evennia.utils.search.html#evennia.utils.search.search_script" title="evennia.utils.search.search_script"><span class="xref myst py py-func">search_script</span></a> API documentation for more options on creating and finding Scripts.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="timed-scripts">
|
||||
<h2>Timed Scripts<a class="headerlink" href="#timed-scripts" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="timed-script">
|
||||
<h4>Timed Script<a class="headerlink" href="#timed-script" title="Permalink to this headline">¶</a></h4>
|
||||
<p>There are several properties one can set on the Script to control its timer component.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
|
||||
|
||||
|
|
@ -293,8 +270,7 @@ to help identifying what does what.</p></li>
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">interval</span></code> (int): The amount of time (in seconds) between every ‘tick’ of the timer. Note that
|
||||
it’s generally bad practice to use sub-second timers for anything in a text-game - the player will
|
||||
not be able to appreciate the precision (and if you print it, it will just spam the screen). For
|
||||
calculations you can pretty much always do them on-demand, or at a much slower interval without the
|
||||
player being the wiser.</p></li>
|
||||
calculations you can pretty much always do them on-demand, or at a much slower interval without the player being the wiser.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">start_delay</span></code> (bool): If timer should start right away or wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds first.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">repeats</span></code> (int): If >0, the timer will only run this many times before stopping. Otherwise the
|
||||
number of repeats are infinite. If set to 1, the Script mimics a <code class="docutils literal notranslate"><span class="pre">delay</span></code> action.</p></li>
|
||||
|
|
@ -320,30 +296,18 @@ at which time the <code class="docutils literal notranslate"><span class="pre">m
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">.time_until_next_repeat()</span></code> - get the time until next time the timer fires.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">.remaining_repeats()</span></code> - get the number of repeats remaining, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if repeats are infinite.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">.reset_callcount()</span></code> - this resets the repeat counter to start over from 0. Only useful if <code class="docutils literal notranslate"><span class="pre">repeats>0</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">.force_repeat()</span></code> - this prematurely forces <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> to be called right away. Doing so will reset the
|
||||
countdown so that next call will again happen after <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">.force_repeat()</span></code> - this prematurely forces <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> to be called right away. Doing so will reset the countdown so that next call will again happen after <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
<section id="script-timers-vs-delay-repeat">
|
||||
<h3>Script timers vs delay/repeat<a class="headerlink" href="#script-timers-vs-delay-repeat" title="Permalink to this headline">¶</a></h3>
|
||||
<p>If the <em>only</em> goal is to get a repeat/delay effect, the
|
||||
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and
|
||||
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a> functions
|
||||
should generally be considered first. A Script is a lot ‘heavier’ to create/delete on the fly.
|
||||
In fact, for making a single delayed call (<code class="docutils literal notranslate"><span class="pre">script.repeats==1</span></code>), the <code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> call is
|
||||
probably always the better choice.</p>
|
||||
<p>For repeating tasks, the <code class="docutils literal notranslate"><span class="pre">utils.repeat</span></code> is optimized for quick repeating of a large number of objects. It
|
||||
uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to
|
||||
start/stop the repeating action for an object. The side effect is however that all objects set to tick
|
||||
at a given interval will <em>all do so at the same time</em>. This may or may not look strange in-game depending
|
||||
on the situation. By contrast the Script uses its own ticker that will operate independently from the
|
||||
tickers of all other Scripts.</p>
|
||||
<p>It’s also worth noting that once the script object has <em>already been created</em>,
|
||||
starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update
|
||||
methods of the script also offers a bit more fine-control than using <code class="docutils literal notranslate"><span class="pre">utils.delays/repeat</span></code>.</p>
|
||||
</section>
|
||||
<p>If the <em>only</em> goal is to get a repeat/delay effect, the <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a> functions should generally be considered first. A Script is a lot ‘heavier’ to create/delete on the fly. In fact, for making a single delayed call (<code class="docutils literal notranslate"><span class="pre">script.repeats==1</span></code>), the <code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> call is probably always the better choice.</p>
|
||||
<p>For repeating tasks, the <code class="docutils literal notranslate"><span class="pre">utils.repeat</span></code> is optimized for quick repeating of a large number of objects. It uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to start/stop the repeating action for an object. The side effect is however that all objects set to tick at a given interval will <em>all do so at the same time</em>. This may or may not look strange in-game depending on the situation. By contrast the Script uses its own ticker that will operate independently from the tickers of all other Scripts.</p>
|
||||
<p>It’s also worth noting that once the script object has <em>already been created</em>, starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update methods of the script also offers a bit more fine-control than using <code class="docutils literal notranslate"><span class="pre">utils.delays/repeat</span></code>.</p>
|
||||
</section>
|
||||
<section id="script-attached-to-another-object">
|
||||
<h2>Script attached to another object<a class="headerlink" href="#script-attached-to-another-object" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Script attached to another object<a class="headerlink" href="#script-attached-to-another-object" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Scripts can be attached to an <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a> or (more commonly) an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a>.
|
||||
If so, the ‘parent object’ will be available to the script as either <code class="docutils literal notranslate"><span class="pre">.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">.account</span></code>.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># mygame/typeclasses/scripts.py</span>
|
||||
|
|
@ -392,20 +356,16 @@ but only <code class="docutils literal notranslate"><span class="pre">scripts.We
|
|||
</div>
|
||||
</section>
|
||||
<section id="other-script-methods">
|
||||
<h2>Other Script methods<a class="headerlink" href="#other-script-methods" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Other Script methods<a class="headerlink" href="#other-script-methods" title="Permalink to this headline">¶</a></h3>
|
||||
<p>A Script has all the properties of a typeclassed object, such as <code class="docutils literal notranslate"><span class="pre">db</span></code> and <code class="docutils literal notranslate"><span class="pre">ndb</span></code>(see
|
||||
<a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclasses</span></a>). Setting <code class="docutils literal notranslate"><span class="pre">key</span></code> is useful in order to manage scripts (delete them by name
|
||||
etc). These are usually set up in the Script’s typeclass, but can also be assigned on the fly as
|
||||
keyword arguments to <code class="docutils literal notranslate"><span class="pre">evennia.create_script</span></code>.</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_script_creation()</span></code> - this is only called once - when the script is first created.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_reload()</span></code> - this is called whenever the server is warm-rebooted (e.g. with the
|
||||
<code class="docutils literal notranslate"><span class="pre">reload</span></code> command). It’s a good place to save non-persistent data you might want to survive a
|
||||
reload.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_reload()</span></code> - this is called whenever the server is warm-rebooted (e.g. with the <code class="docutils literal notranslate"><span class="pre">reload</span></code> command). It’s a good place to save non-persistent data you might want to survive a reload.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_shutdown()</span></code> - this is called when a system reset or systems shutdown is invoked.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_start()</span></code> - this is called when the server comes back (from reload/shutdown/reboot). It
|
||||
can be usuful for initializations and caching of non-persistent data when starting up a script’s
|
||||
functionality.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_start()</span></code> - this is called when the server comes back (from reload/shutdown/reboot). It can be usuful for initializations and caching of non-persistent data when starting up a script’s functionality.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_start()</span></code></p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">at_pause()</span></code></p></li>
|
||||
|
|
@ -413,12 +373,33 @@ functionality.</p></li>
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">delete()</span></code> - same as for other typeclassed entities, this will delete the Script. Of note is that
|
||||
it will also stop the timer (if it runs), leading to the <code class="docutils literal notranslate"><span class="pre">at_stop</span></code> hook being called.</p></li>
|
||||
</ul>
|
||||
<p>In addition, Scripts support <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> and <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Locks</span></a> etc like other
|
||||
Typeclassed entities.</p>
|
||||
<p>See also the methods involved in controlling a <a class="reference internal" href="#timed-scripts"><span class="std std-doc">Timed Script</span></a> above.</p>
|
||||
<p>In addition, Scripts support <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> and <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Locks</span></a> etc like other Typeclassed entities.</p>
|
||||
<p>See also the methods involved in controlling a <a class="reference internal" href="#timed-script"><span class="std std-doc">Timed Script</span></a> above.</p>
|
||||
</section>
|
||||
<section id="the-global-scripts-container">
|
||||
<h2>The GLOBAL_SCRIPTS container<a class="headerlink" href="#the-global-scripts-container" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="dealing-with-script-errors">
|
||||
<h3>Dealing with Script Errors<a class="headerlink" href="#dealing-with-script-errors" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Errors inside a timed, executing script can sometimes be rather terse or point to parts of the execution mechanism that is hard to interpret. One way to make it easier to debug scripts is to import Evennia’s native logger and wrap your functions in a try/catch block. Evennia’s logger can show you where the traceback occurred in your script.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
|
||||
|
||||
<span class="c1"># [...]</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="c1"># [...]</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">()</span>
|
||||
<span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">evennia</span><span class="o">/</span><span class="n">evennia</span><span class="o">/</span><span class="n">blob</span><span class="o">/</span><span class="n">master</span><span class="o">/</span><span class="n">evennia</span><span class="o">/</span><span class="n">contrib</span><span class="o">/</span><span class="n">tutorial_examples</span><span class="o">/</span><span class="n">example_batch_cmds</span><span class="o">.</span><span class="n">ev</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
<section id="using-global-scripts">
|
||||
<h2>Using GLOBAL_SCRIPTS<a class="headerlink" href="#using-global-scripts" title="Permalink to this headline">¶</a></h2>
|
||||
<p>A Script not attached to another entity is commonly referred to as a <em>Global</em> script since it’t available
|
||||
to access from anywhere. This means they need to be searched for in order to be used.</p>
|
||||
<p>Evennia supplies a convenient “container” <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS</span></code> to help organize your global
|
||||
|
|
@ -438,13 +419,7 @@ scripts. All you need is the Script’s <code class="docutils literal notranslat
|
|||
</div>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`.
|
||||
If you were to create two global scripts with the same `key` (even with different typeclasses),
|
||||
the `GLOBAL_SCRIPTS` container will only return one of them (which one depends on order in
|
||||
the database). Best is to organize your scripts so that this does not happen. Otherwise, use
|
||||
`evennia.search_scripts` to get exactly the script you want.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Note that global scripts appear as properties on <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> based on their <code class="docutils literal notranslate"><span class="pre">key</span></code>. If you were to create two global scripts with the same <code class="docutils literal notranslate"><span class="pre">key</span></code> (even with different typeclasses), the <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> container will only return one of them (which one depends on order in the database). Best is to organize your scripts so that this does not happen. Otherwise, use <code class="docutils literal notranslate"><span class="pre">evennia.search_scripts</span></code> to get exactly the script you want.</p>
|
||||
</div>
|
||||
<p>There are two ways to make a script appear as a property on <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>:</p>
|
||||
<ol class="simple">
|
||||
|
|
@ -469,18 +444,10 @@ script keys are globally unique.</p></li>
|
|||
<span class="p">}</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Above we add two scripts with keys <code class="docutils literal notranslate"><span class="pre">myscript</span></code> and <code class="docutils literal notranslate"><span class="pre">storagescript</span></code>respectively. The following dict
|
||||
can be empty - the <code class="docutils literal notranslate"><span class="pre">settings.BASE_SCRIPT_TYPECLASS</span></code> will then be used. Under the hood, the provided
|
||||
dict (along with the <code class="docutils literal notranslate"><span class="pre">key</span></code>) will be passed into <code class="docutils literal notranslate"><span class="pre">create_script</span></code> automatically, so
|
||||
all the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">same keyword arguments as for create_script</span></a> are
|
||||
supported here.</p>
|
||||
<p>Above we add two scripts with keys <code class="docutils literal notranslate"><span class="pre">myscript</span></code> and <code class="docutils literal notranslate"><span class="pre">storagescript</span></code>respectively. The following dict can be empty - the <code class="docutils literal notranslate"><span class="pre">settings.BASE_SCRIPT_TYPECLASS</span></code> will then be used. Under the hood, the provided dict (along with the <code class="docutils literal notranslate"><span class="pre">key</span></code>) will be passed into <code class="docutils literal notranslate"><span class="pre">create_script</span></code> automatically, so all the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">same keyword arguments as for create_script</span></a> are supported here.</p>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Before setting up Evennia to manage your script like this, make sure that your Script typeclass
|
||||
does not have any critical errors (test it separately). If there are, you'll see errors in your log
|
||||
and your Script will temporarily fall back to being a `DefaultScript` type.
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Before setting up Evennia to manage your script like this, make sure that your Script typeclass does not have any critical errors (test it separately). If there are, you’ll see errors in your log and your Script will temporarily fall back to being a <code class="docutils literal notranslate"><span class="pre">DefaultScript</span></code> type.</p>
|
||||
</div>
|
||||
<p>Moreover, a script defined this way is <em>guaranteed</em> to exist when you try to access it:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
|
||||
|
|
@ -494,29 +461,6 @@ and your Script will temporarily fall back to being a `DefaultScript` type.
|
|||
<p>That is, if the script is deleted, next time you get it from <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>, Evennia will use the
|
||||
information in settings to recreate it for you on the fly.</p>
|
||||
</section>
|
||||
<section id="hints-dealing-with-script-errors">
|
||||
<h2>Hints: Dealing with Script Errors<a class="headerlink" href="#hints-dealing-with-script-errors" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Errors inside a timed, executing script can sometimes be rather terse or point to
|
||||
parts of the execution mechanism that is hard to interpret. One way to make it
|
||||
easier to debug scripts is to import Evennia’s native logger and wrap your
|
||||
functions in a try/catch block. Evennia’s logger can show you where the
|
||||
traceback occurred in your script.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
|
||||
|
||||
<span class="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
|
||||
|
||||
<span class="c1"># [...]</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="c1"># [...]</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
|
||||
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Accounts" href="Accounts.html" />
|
||||
<link rel="prev" title="Typeclasses" href="Typeclasses.html" />
|
||||
<link rel="next" title="Typeclasses" href="Typeclasses.html" />
|
||||
<link rel="prev" title="Portal And Server" href="Portal-And-Server.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,10 +30,10 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Accounts.html" title="Accounts"
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -63,22 +63,26 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Sessions</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-sessions">Working with Sessions</a><ul>
|
||||
<li><a class="reference internal" href="#properties-on-sessions">Properties on Sessions</a></li>
|
||||
<li><a class="reference internal" href="#multisession-mode">Multisession mode</a></li>
|
||||
<li><a class="reference internal" href="#returning-data-to-the-session">Returning data to the session</a></li>
|
||||
<li><a class="reference internal" href="#customizing-the-session-object">Customizing the Session object</a></li>
|
||||
<li><a class="reference internal" href="#portal-and-server-sessions">Portal and Server Sessions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#portal-and-server-sessions">Portal and Server Sessions</a><ul>
|
||||
<li><a class="reference internal" href="#sessionhandlers">Sessionhandlers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Typeclasses.html"
|
||||
title="previous chapter">Typeclasses</a></p>
|
||||
<p class="topless"><a href="Portal-And-Server.html"
|
||||
title="previous chapter">Portal And Server</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Accounts.html"
|
||||
title="next chapter">Accounts</a></p>
|
||||
<p class="topless"><a href="Typeclasses.html"
|
||||
title="next chapter">Typeclasses</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -122,17 +126,17 @@ Evennia session, it is possible for a person to connect multiple times, for exam
|
|||
clients in multiple windows. Each such connection is represented by a session object.</p>
|
||||
<p>A session object has its own <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">cmdset</span></a>, usually the “unloggedin” cmdset. This is what is used to show the login screen and to handle commands to create a new account (or <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a> in evennia lingo) read initial help and to log into the game with an existing account. A session object can either be “logged in” or not. Logged in means that the user has authenticated. When this happens the session is associated with an Account object (which is what holds account-centric stuff). The account can then in turn puppet any number of objects/characters.</p>
|
||||
<p>A Session is not <em>persistent</em> - it is not a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a> and has no connection to the database. The Session will go away when a user disconnects and you will lose any custom data on it if the server reloads. The <code class="docutils literal notranslate"><span class="pre">.db</span></code> handler on Sessions is there to present a uniform API (so you can assume <code class="docutils literal notranslate"><span class="pre">.db</span></code> exists even if you don’t know if you receive an Object or a Session), but this is just an alias to <code class="docutils literal notranslate"><span class="pre">.ndb</span></code>. So don’t store any data on Sessions that you can’t afford to lose in a reload.</p>
|
||||
<section id="working-with-sessions">
|
||||
<h2>Working with Sessions<a class="headerlink" href="#working-with-sessions" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="properties-on-sessions">
|
||||
<h2>Properties on Sessions<a class="headerlink" href="#properties-on-sessions" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Properties on Sessions<a class="headerlink" href="#properties-on-sessions" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Here are some important properties available on (Server-)Sessions</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">sessid</span></code> - The unique session-id. This is an integer starting from 1.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">address</span></code> - The connected client’s address. Different protocols give different information here.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">logged_in</span></code> - <code class="docutils literal notranslate"><span class="pre">True</span></code> if the user authenticated to this session.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">account</span></code> - The <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a> this Session is attached to. If not logged in yet, this is
|
||||
<code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">puppet</span></code> - The <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Character/Object</span></a> currently puppeted by this Account/Session combo. If
|
||||
not logged in or in OOC mode, this is <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">account</span></code> - The <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a> this Session is attached to. If not logged in yet, this is <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">puppet</span></code> - The <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Character/Object</span></a> currently puppeted by this Account/Session combo. If not logged in or in OOC mode, this is <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">ndb</span></code> - The <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Non-persistent Attribute</span></a> handler.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">db</span></code> - As noted above, Sessions don’t have regular Attributes. This is an alias to <code class="docutils literal notranslate"><span class="pre">ndb</span></code>.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset</span></code> - The Session’s <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">CmdSetHandler</span></a></p></li>
|
||||
|
|
@ -146,67 +150,8 @@ last time this session was truly visibly active.</p></li>
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">cmd_total</span></code> - Total number of Commands passed through this Session.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="multisession-mode">
|
||||
<h2>Multisession mode<a class="headerlink" href="#multisession-mode" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The number of sessions possible to connect to a given account at the same time and how it works is given by the <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> setting:</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=0</span></code>: One session per account. When connecting with a new session the old one is disconnected. This is the default mode and emulates many classic mud code bases.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>┌──────┐ │ ┌───────┐ ┌───────┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├───►│Account├──►│Character│
|
||||
└──────┘ │ └───────┘ └───────┘ └─────────┘
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=1</span></code>: Many sessions per account, input/output from/to each session is treated the same. For the player this means they can connect to the game from multiple clients and see the same output in all of them. The result of a command given in one client (that is, through one Session) will be returned to <em>all</em> connected Sessions/clients with no distinction.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> │
|
||||
┌──────┐ │ ┌───────┐
|
||||
│Client├─┼──►│Session├──┐
|
||||
└──────┘ │ └───────┘ └──►┌───────┐ ┌─────────┐
|
||||
│ │Account├──►│Character│
|
||||
┌──────┐ │ ┌───────┐ ┌──►└───────┘ └─────────┘
|
||||
│Client├─┼──►│Session├──┘
|
||||
└──────┘ │ └───────┘
|
||||
│
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=2</span></code>: Many sessions per account, one character per session. In this mode, puppeting an Object/Character will link the puppet back only to the particular Session doing the puppeting. That is, input from that Session will make use of the CmdSet of that Object/Character and outgoing messages (such as the result of a <code class="docutils literal notranslate"><span class="pre">look</span></code>) will be passed back only to that puppeting Session. If another Session tries to puppet the same Character, the old Session will automatically un-puppet it. From the player’s perspective, this will mean that they can open separate game clients and play a different Character in each using one game account.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> │ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►│Character│
|
||||
└──────┘ │ └───────┘ │ │ └─────────┘
|
||||
│ └───────┘
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=3</span></code>: Many sessions per account <em>and</em> character. This is the full multi-puppeting mode, where multiple sessions may not only connect to the player account but multiple sessions may also puppet a single character at the same time. From the user’s perspective it means one can open multiple client windows, some for controlling different Characters and some that share a Character’s input/output like in mode 1. This mode otherwise works the same as mode 2.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> │ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►┌─────────┐
|
||||
└──────┘ │ └───────┘ │ │ │Character│
|
||||
│ │ │ ┌►└─────────┘
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┘ ▼
|
||||
│Client├─┼──►│Session├──┘ │ │
|
||||
└──────┘ │ └───────┘ └───────┘
|
||||
│
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<div><p>Note that even if multiple Sessions puppet one Character, there is only ever one instance of that Character.</p>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
<section id="returning-data-to-the-session">
|
||||
<h2>Returning data to the session<a class="headerlink" href="#returning-data-to-the-session" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Returning data to the session<a class="headerlink" href="#returning-data-to-the-session" title="Permalink to this headline">¶</a></h3>
|
||||
<p>When you use <code class="docutils literal notranslate"><span class="pre">msg()</span></code> to return data to a user, the object on which you call the <code class="docutils literal notranslate"><span class="pre">msg()</span></code> matters. The
|
||||
<code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> also matters, especially if greater than 1.</p>
|
||||
<p>For example, if you use <code class="docutils literal notranslate"><span class="pre">account.msg("hello")</span></code> there is no way for evennia to know which session it
|
||||
|
|
@ -231,44 +176,23 @@ script triggers the Command.</p></li>
|
|||
</ul>
|
||||
</section>
|
||||
<section id="customizing-the-session-object">
|
||||
<h2>Customizing the Session object<a class="headerlink" href="#customizing-the-session-object" title="Permalink to this headline">¶</a></h2>
|
||||
<p>When would one want to customize the Session object? Consider for example a character creation
|
||||
system: You might decide to keep this on the out-of-character level. This would mean that you create
|
||||
the character at the end of some sort of menu choice. The actual char-create cmdset would then
|
||||
normally be put on the account. This works fine as long as you are <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> below 2.
|
||||
For higher modes, replacing the Account cmdset will affect <em>all</em> your connected sessions, also those
|
||||
not involved in character creation. In this case you want to instead put the char-create cmdset on
|
||||
the Session level - then all other sessions will keep working normally despite you creating a new
|
||||
character in one of them.</p>
|
||||
<p>By default, the session object gets the <code class="docutils literal notranslate"><span class="pre">commands.default_cmdsets.UnloggedinCmdSet</span></code> when the user
|
||||
first connects. Once the session is authenticated it has <em>no</em> default sets. To add a “logged-in”
|
||||
cmdset to the Session, give the path to the cmdset class with <code class="docutils literal notranslate"><span class="pre">settings.CMDSET_SESSION</span></code>. This set
|
||||
<h3>Customizing the Session object<a class="headerlink" href="#customizing-the-session-object" title="Permalink to this headline">¶</a></h3>
|
||||
<p>When would one want to customize the Session object? Consider for example a character creation system: You might decide to keep this on the out-of-character level. This would mean that you create the character at the end of some sort of menu choice. The actual char-create cmdset would then normally be put on the account. This works fine as long as you are <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> below 2. For higher modes, replacing the Account cmdset will affect <em>all</em> your connected sessions, also those not involved in character creation. In this case you want to instead put the char-create cmdset on the Session level - then all other sessions will keep working normally despite you creating a new character in one of them.</p>
|
||||
<p>By default, the session object gets the <code class="docutils literal notranslate"><span class="pre">commands.default_cmdsets.UnloggedinCmdSet</span></code> when the user first connects. Once the session is authenticated it has <em>no</em> default sets. To add a “logged-in” cmdset to the Session, give the path to the cmdset class with <code class="docutils literal notranslate"><span class="pre">settings.CMDSET_SESSION</span></code>. This set
|
||||
will then henceforth always be present as soon as the account logs in.</p>
|
||||
<p>To customize further you can completely override the Session with your own subclass. To replace the
|
||||
default Session class, change <code class="docutils literal notranslate"><span class="pre">settings.SERVER_SESSION_CLASS</span></code> to point to your custom class. This is
|
||||
a dangerous practice and errors can easily make your game unplayable. Make sure to take heed of the
|
||||
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/server/session.py">original</a> and make your
|
||||
changes carefully.</p>
|
||||
<p>To customize further you can completely override the Session with your own subclass. To replace the default Session class, change <code class="docutils literal notranslate"><span class="pre">settings.SERVER_SESSION_CLASS</span></code> to point to your custom class. This is a dangerous practice and errors can easily make your game unplayable. Make sure to take heed of the <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/server/session.py">original</a> and make your changes carefully.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="portal-and-server-sessions">
|
||||
<h2>Portal and Server Sessions<a class="headerlink" href="#portal-and-server-sessions" title="Permalink to this headline">¶</a></h2>
|
||||
<p><em>Note: This is considered an advanced topic. You don’t need to know this on a first read-through.</em></p>
|
||||
<p>Evennia is split into two parts, the <a class="reference internal" href="Portal-And-Server.html"><span class="doc std std-doc">Portal and the Server</span></a>. Each side tracks
|
||||
its own Sessions, syncing them to each other.</p>
|
||||
<p>Evennia is split into two parts, the <a class="reference internal" href="Portal-And-Server.html"><span class="doc std std-doc">Portal and the Server</span></a>. Each side tracks its own Sessions, syncing them to each other.</p>
|
||||
<p>The “Session” we normally refer to is actually the <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code>. Its counter-part on the Portal
|
||||
side is the <code class="docutils literal notranslate"><span class="pre">PortalSession</span></code>. Whereas the server sessions deal with game states, the portal session
|
||||
deals with details of the connection-protocol itself. The two are also acting as backups of critical
|
||||
data such as when the server reboots.</p>
|
||||
<p>New Account connections are listened for and handled by the Portal using the [protocols](Portal-And-
|
||||
Server) it understands (such as telnet, ssh, webclient etc). When a new connection is established, a
|
||||
<code class="docutils literal notranslate"><span class="pre">PortalSession</span></code> is created on the Portal side. This session object looks different depending on
|
||||
which protocol is used to connect, but all still have a minimum set of attributes that are generic
|
||||
to all
|
||||
sessions.</p>
|
||||
<p>These common properties are piped from the Portal, through the AMP connection, to the Server, which
|
||||
is now informed a new connection has been established. On the Server side, a <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code> object
|
||||
is created to represent this. There is only one type of <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code>; It looks the same
|
||||
regardless of how the Account connects.</p>
|
||||
<p>New Account connections are listened for and handled by the Portal using the [protocols](Portal-And- Server) it understands (such as telnet, ssh, webclient etc). When a new connection is established, a <code class="docutils literal notranslate"><span class="pre">PortalSession</span></code> is created on the Portal side. This session object looks different depending on which protocol is used to connect, but all still have a minimum set of attributes that are generic to all sessions.</p>
|
||||
<p>These common properties are piped from the Portal, through the AMP connection, to the Server, which is now informed a new connection has been established. On the Server side, a <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code> object is created to represent this. There is only one type of <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code>; It looks the same regardless of how the Account connects.</p>
|
||||
<p>From now on, there is a one-to-one match between the <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code> on one side of the AMP
|
||||
connection and the <code class="docutils literal notranslate"><span class="pre">PortalSession</span></code> on the other. Data arriving to the Portal Session is sent on to
|
||||
its mirror Server session and vice versa.</p>
|
||||
|
|
@ -284,26 +208,21 @@ Portal side. When the Server comes back up, this data is returned by the Portal
|
|||
in sync. This way an Account’s login status and other connection-critical things can survive a
|
||||
server reboot (assuming the Portal is not stopped at the same time, obviously).</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="sessionhandlers">
|
||||
<h2>Sessionhandlers<a class="headerlink" href="#sessionhandlers" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Sessionhandlers<a class="headerlink" href="#sessionhandlers" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Both the Portal and Server each have a <em>sessionhandler</em> to manage the connections. These handlers
|
||||
are global entities contain all methods for relaying data across the AMP bridge. All types of
|
||||
Sessions hold a reference to their respective Sessionhandler (the property is called
|
||||
<code class="docutils literal notranslate"><span class="pre">sessionhandler</span></code>) so they can relay data. See <a class="reference internal" href="../Concepts/Protocols.html"><span class="doc std std-doc">protocols</span></a> for more info
|
||||
on building new protocols.</p>
|
||||
<p>To get all Sessions in the game (i.e. all currently connected clients), you access the server-side
|
||||
Session handler, which you get by</p>
|
||||
<code class="docutils literal notranslate"><span class="pre">sessionhandler</span></code>) so they can relay data. See <a class="reference internal" href="../Concepts/Protocols.html"><span class="doc std std-doc">protocols</span></a> for more info on building new protocols.</p>
|
||||
<p>To get all Sessions in the game (i.e. all currently connected clients), you access the server-side Session handler, which you get by</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.server.sessionhandler</span> <span class="kn">import</span> <span class="n">SESSION_HANDLER</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Note: The <code class="docutils literal notranslate"><span class="pre">SESSION_HANDLER</span></code> singleton has an older alias <code class="docutils literal notranslate"><span class="pre">SESSIONS</span></code> that is commonly seen in
|
||||
various places as well.</p>
|
||||
<div><p>Note: The <code class="docutils literal notranslate"><span class="pre">SESSION_HANDLER</span></code> singleton has an older alias <code class="docutils literal notranslate"><span class="pre">SESSIONS</span></code> that is commonly seen in various places as well.</p>
|
||||
</div></blockquote>
|
||||
<p>See the
|
||||
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/server/sessionhandler.py">sessionhandler.py</a>
|
||||
module for details on the capabilities of the <code class="docutils literal notranslate"><span class="pre">ServerSessionHandler</span></code>.</p>
|
||||
<p>See the <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/server/sessionhandler.py">sessionhandler.py</a> module for details on the capabilities of the <code class="docutils literal notranslate"><span class="pre">ServerSessionHandler</span></code>.</p>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -323,10 +242,10 @@ module for details on the capabilities of the <code class="docutils literal notr
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Accounts.html" title="Accounts"
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Typeclasses.html" title="Typeclasses"
|
||||
<a href="Portal-And-Server.html" title="Portal And Server"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@
|
|||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Game website" href="Website.html" />
|
||||
<link rel="prev" title="Locks" href="Locks.html" />
|
||||
<link rel="prev" title="TickerHandler" href="TickerHandler.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<a href="Website.html" title="Game website"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Locks.html" title="Locks"
|
||||
<a href="TickerHandler.html" title="TickerHandler"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -63,15 +63,17 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Signals</a><ul>
|
||||
<li><a class="reference internal" href="#attaching-a-handler-to-a-signal">Attaching a handler to a signal</a></li>
|
||||
<li><a class="reference internal" href="#working-with-signals">Working with Signals</a><ul>
|
||||
<li><a class="reference internal" href="#available-signals">Available signals</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Locks.html"
|
||||
title="previous chapter">Locks</a></p>
|
||||
<p class="topless"><a href="TickerHandler.html"
|
||||
title="previous chapter">TickerHandler</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Website.html"
|
||||
title="next chapter">Game website</a></p>
|
||||
|
|
@ -119,8 +121,8 @@ you can “attach” any number of event-handlers to these signals. You can atta
|
|||
any number of handlers and they’ll all fire whenever any entity triggers the
|
||||
signal.</p>
|
||||
<p>Evennia uses the <a class="reference external" href="https://docs.djangoproject.com/en/2.2/topics/signals/">Django Signal system</a>.</p>
|
||||
<section id="attaching-a-handler-to-a-signal">
|
||||
<h2>Attaching a handler to a signal<a class="headerlink" href="#attaching-a-handler-to-a-signal" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="working-with-signals">
|
||||
<h2>Working with Signals<a class="headerlink" href="#working-with-signals" title="Permalink to this headline">¶</a></h2>
|
||||
<p>First you create your handler</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||||
<span class="k">def</span> <span class="nf">myhandler</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||||
|
|
@ -146,9 +148,8 @@ like this:</p>
|
|||
<span class="n">signals</span><span class="o">.</span><span class="n">SIGNAL_ACCOUNT_POST_CONNECT</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">myhandler</span><span class="p">,</span> <span class="n">account</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="available-signals">
|
||||
<h2>Available signals<a class="headerlink" href="#available-signals" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Available signals<a class="headerlink" href="#available-signals" title="Permalink to this headline">¶</a></h3>
|
||||
<p>All signals (including some django-specific defaults) are available in the module
|
||||
<code class="docutils literal notranslate"><span class="pre">evennia.server.signals</span></code>
|
||||
(with a shortcut <code class="docutils literal notranslate"><span class="pre">evennia.signals</span></code>). Signals are named by the sender type. So <code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_*</span></code>
|
||||
|
|
@ -216,6 +217,7 @@ decorator (only relevant for unit testing)</p></li>
|
|||
<li><p><code class="docutils literal notranslate"><span class="pre">connection_creation</span></code> - sent when making initial connection to database.</p></li>
|
||||
</ul>
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
@ -237,7 +239,7 @@ decorator (only relevant for unit testing)</p></li>
|
|||
<a href="Website.html" title="Game website"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Locks.html" title="Locks"
|
||||
<a href="TickerHandler.html" title="TickerHandler"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -63,11 +63,13 @@
|
|||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Tags</a><ul>
|
||||
<li><a class="reference internal" href="#working-with-tags">Working with Tags</a><ul>
|
||||
<li><a class="reference internal" href="#properties-of-tags-and-aliases-and-permissions">Properties of Tags (and Aliases and Permissions)</a></li>
|
||||
<li><a class="reference internal" href="#adding-removing-tags">Adding/Removing Tags</a></li>
|
||||
<li><a class="reference internal" href="#searching-for-objects-with-a-given-tag">Searching for objects with a given tag</a></li>
|
||||
<li><a class="reference internal" href="#using-aliases-and-permissions">Using Aliases and Permissions</a></li>
|
||||
<li><a class="reference internal" href="#assorted-notes">Assorted notes</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#aliases-and-permissions">Aliases and Permissions</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -137,8 +139,10 @@
|
|||
<p>Above, the tags inform us that the <code class="docutils literal notranslate"><span class="pre">Sword</span></code> is both sharp and can be wielded. If that’s all they do, they could just be a normal Python flag. When tags become important is if there are a lot of objects with different combinations of tags. Maybe you have a magical spell that dulls <em>all</em> sharp-edged objects in the castle - whether sword, dagger, spear or kitchen knife! You can then just grab all objects with the <code class="docutils literal notranslate"><span class="pre">has_sharp_edge</span></code> tag.
|
||||
Another example would be a weather script affecting all rooms tagged as <code class="docutils literal notranslate"><span class="pre">outdoors</span></code> or finding all characters tagged with <code class="docutils literal notranslate"><span class="pre">belongs_to_fighter_guild</span></code>.</p>
|
||||
<p>In Evennia, Tags are technically also used to implement <code class="docutils literal notranslate"><span class="pre">Aliases</span></code> (alternative names for objects) and <code class="docutils literal notranslate"><span class="pre">Permissions</span></code> (simple strings for <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Locks</span></a> to check for).</p>
|
||||
<section id="working-with-tags">
|
||||
<h2>Working with Tags<a class="headerlink" href="#working-with-tags" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="properties-of-tags-and-aliases-and-permissions">
|
||||
<h2>Properties of Tags (and Aliases and Permissions)<a class="headerlink" href="#properties-of-tags-and-aliases-and-permissions" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Properties of Tags (and Aliases and Permissions)<a class="headerlink" href="#properties-of-tags-and-aliases-and-permissions" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Tags are <em>unique</em>. This means that there is only ever one Tag object with a given key and category.</p>
|
||||
<blockquote>
|
||||
<div><p>Not specifying a category (default) gives the tag a category of <code class="docutils literal notranslate"><span class="pre">None</span></code>, which is also considered a
|
||||
|
|
@ -172,10 +176,8 @@ free up the <em>category</em> property for any use you desire.</p></li>
|
|||
</ul>
|
||||
</section>
|
||||
<section id="adding-removing-tags">
|
||||
<h2>Adding/Removing Tags<a class="headerlink" href="#adding-removing-tags" title="Permalink to this headline">¶</a></h2>
|
||||
<p>You can tag any <em>typeclassed</em> object, namely <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>,
|
||||
<a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>. General tags are added by the <em>Taghandler</em>. The
|
||||
tag handler is accessed as a property <code class="docutils literal notranslate"><span class="pre">tags</span></code> on the relevant entity:</p>
|
||||
<h3>Adding/Removing Tags<a class="headerlink" href="#adding-removing-tags" title="Permalink to this headline">¶</a></h3>
|
||||
<p>You can tag any <em>typeclassed</em> object, namely <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>. General tags are added by the <em>Taghandler</em>. The tag handler is accessed as a property <code class="docutils literal notranslate"><span class="pre">tags</span></code> on the relevant entity:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">mychair</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">"furniture"</span><span class="p">)</span>
|
||||
<span class="n">mychair</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">"furniture"</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"luxurious"</span><span class="p">)</span>
|
||||
<span class="n">myroom</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">"dungeon#01"</span><span class="p">)</span>
|
||||
|
|
@ -198,7 +200,7 @@ You can also use the default <code class="docutils literal notranslate"><span cl
|
|||
<p>This tags the chair with a ‘furniture’ Tag (the one with a <code class="docutils literal notranslate"><span class="pre">None</span></code> category).</p>
|
||||
</section>
|
||||
<section id="searching-for-objects-with-a-given-tag">
|
||||
<h2>Searching for objects with a given tag<a class="headerlink" href="#searching-for-objects-with-a-given-tag" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Searching for objects with a given tag<a class="headerlink" href="#searching-for-objects-with-a-given-tag" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Usually tags are used as a quick way to find tagged database entities. You can retrieve all objects
|
||||
with a given Tag like this in code:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">import</span> <span class="nn">evennia</span>
|
||||
|
|
@ -222,14 +224,9 @@ with a given Tag like this in code:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p>Note that searching for just “furniture” will only return the objects tagged with the “furniture”
|
||||
tag that
|
||||
has a category of <code class="docutils literal notranslate"><span class="pre">None</span></code>. We must explicitly give the category to get the “luxurious” furniture.</p>
|
||||
<div><p>Note that searching for just “furniture” will only return the objects tagged with the “furniture” tag that has a category of <code class="docutils literal notranslate"><span class="pre">None</span></code>. We must explicitly give the category to get the “luxurious” furniture.</p>
|
||||
</div></blockquote>
|
||||
<p>Using any of the <code class="docutils literal notranslate"><span class="pre">search_tag</span></code> variants will all return <a class="reference external" href="https://docs.djangoproject.com/en/2.1/ref/models/querysets/">Django
|
||||
Querysets</a>, including if you only have
|
||||
one match. You can treat querysets as lists and iterate over them, or continue building search
|
||||
queries with them.</p>
|
||||
<p>Using any of the <code class="docutils literal notranslate"><span class="pre">search_tag</span></code> variants will all return <a class="reference external" href="https://docs.djangoproject.com/en/2.1/ref/models/querysets/">Django Querysets</a>, including if you only have one match. You can treat querysets as lists and iterate over them, or continue building search queries with them.</p>
|
||||
<p>Remember when searching that not setting a category means setting it to <code class="docutils literal notranslate"><span class="pre">None</span></code> - this does <em>not</em>
|
||||
mean that category is undefined, rather <code class="docutils literal notranslate"><span class="pre">None</span></code> is considered the default, unnamed category.</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">evennia</span>
|
||||
|
|
@ -244,16 +241,16 @@ mean that category is undefined, rather <code class="docutils literal notranslat
|
|||
<span class="n">objs</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_tag</span><span class="p">(</span><span class="s2">"foo"</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"bar"</span><span class="p">)</span>
|
||||
<span class="c1"># or</span>
|
||||
<span class="n">objs</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_tag</span><span class="p">(</span><span class="n">category</span><span class="o">=</span><span class="s2">"bar"</span><span class="p">)</span>
|
||||
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>There is also an in-game command that deals with assigning and using (<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object-</span></a>) tags:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> @tag/search furniture
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> tag/search furniture
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="using-aliases-and-permissions">
|
||||
<h2>Using Aliases and Permissions<a class="headerlink" href="#using-aliases-and-permissions" title="Permalink to this headline">¶</a></h2>
|
||||
</section>
|
||||
<section id="aliases-and-permissions">
|
||||
<h2>Aliases and Permissions<a class="headerlink" href="#aliases-and-permissions" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Aliases and Permissions are implemented using normal TagHandlers that simply save Tags with a
|
||||
different <code class="docutils literal notranslate"><span class="pre">tagtype</span></code>. These handlers are named <code class="docutils literal notranslate"><span class="pre">aliases</span></code> and <code class="docutils literal notranslate"><span class="pre">permissions</span></code> on all Objects. They are
|
||||
used in the same way as Tags above:</p>
|
||||
|
|
@ -267,17 +264,6 @@ used in the same way as Tags above:</p>
|
|||
<p>and so on. Similarly to how <code class="docutils literal notranslate"><span class="pre">@tag</span></code> works in-game, there is also the <code class="docutils literal notranslate"><span class="pre">@perm</span></code> command for assigning
|
||||
permissions and <code class="docutils literal notranslate"><span class="pre">@alias</span></code> command for aliases.</p>
|
||||
</section>
|
||||
<section id="assorted-notes">
|
||||
<h2>Assorted notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Generally, tags are enough on their own for grouping objects. Having no tag <code class="docutils literal notranslate"><span class="pre">category</span></code> is perfectly
|
||||
fine and the normal operation. Simply adding a new Tag for grouping objects is often better than
|
||||
making a new category. So think hard before deciding you really need to categorize your Tags.</p>
|
||||
<p>That said, tag categories can be useful if you build some game system that uses tags. You can then
|
||||
use tag categories to make sure to separate tags created with this system from any other tags
|
||||
created elsewhere. You can then supply custom search methods that <em>only</em> find objects tagged with
|
||||
tags of that category. An example of this
|
||||
is found in the <a class="reference internal" href="../Concepts/Zones.html"><span class="doc std std-doc">Zone tutorial</span></a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Locks" href="Locks.html" />
|
||||
<link rel="next" title="Signals" href="Signals.html" />
|
||||
<link rel="prev" title="MonitorHandler" href="MonitorHandler.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Locks.html" title="Locks"
|
||||
<a href="Signals.html" title="Signals"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="MonitorHandler.html" title="MonitorHandler"
|
||||
|
|
@ -75,8 +75,8 @@
|
|||
<p class="topless"><a href="MonitorHandler.html"
|
||||
title="previous chapter">MonitorHandler</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Locks.html"
|
||||
title="next chapter">Locks</a></p>
|
||||
<p class="topless"><a href="Signals.html"
|
||||
title="next chapter">Signals</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -237,7 +237,7 @@ same time without input from something else.</p>
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Locks.html" title="Locks"
|
||||
<a href="Signals.html" title="Signals"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="MonitorHandler.html" title="MonitorHandler"
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Sessions" href="Sessions.html" />
|
||||
<link rel="prev" title="Core Components" href="Components-Overview.html" />
|
||||
<link rel="next" title="Accounts" href="Accounts.html" />
|
||||
<link rel="prev" title="Sessions" href="Sessions.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,10 +30,10 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
<a href="Accounts.html" title="Accounts"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Components-Overview.html" title="Core Components"
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||||
|
|
@ -64,25 +64,29 @@
|
|||
<ul>
|
||||
<li><a class="reference internal" href="#">Typeclasses</a><ul>
|
||||
<li><a class="reference internal" href="#difference-between-typeclasses-and-classes">Difference between typeclasses and classes</a></li>
|
||||
<li><a class="reference internal" href="#working-with-typeclasses">Working with typeclasses</a><ul>
|
||||
<li><a class="reference internal" href="#creating-a-new-typeclass">Creating a new typeclass</a></li>
|
||||
<li><a class="reference internal" href="#about-typeclass-properties">About typeclass properties</a></li>
|
||||
<li><a class="reference internal" href="#overloading-hooks">Overloading hooks</a></li>
|
||||
<li><a class="reference internal" href="#querying-for-typeclasses">Querying for typeclasses</a></li>
|
||||
<li><a class="reference internal" href="#updating-existing-typeclass-instances">Updating existing typeclass instances</a></li>
|
||||
<li><a class="reference internal" href="#swap-typeclass">Swap typeclass</a></li>
|
||||
<li><a class="reference internal" href="#how-typeclasses-actually-work">How typeclasses actually work</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#how-typeclasses-actually-work">How typeclasses actually work</a><ul>
|
||||
<li><a class="reference internal" href="#caveats">Caveats</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#will-i-run-out-of-dbrefs">Will I run out of dbrefs?</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Components-Overview.html"
|
||||
title="previous chapter">Core Components</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Sessions.html"
|
||||
title="next chapter">Sessions</a></p>
|
||||
title="previous chapter">Sessions</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Accounts.html"
|
||||
title="next chapter">Accounts</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -115,57 +119,52 @@
|
|||
|
||||
<section class="tex2jax_ignore mathjax_ignore" id="typeclasses">
|
||||
<h1>Typeclasses<a class="headerlink" href="#typeclasses" title="Permalink to this headline">¶</a></h1>
|
||||
<p><em>Typeclasses</em> form the core of Evennia’s data storage. It allows Evennia to represent any number of
|
||||
different game entities as Python classes, without having to modify the database schema for every
|
||||
new type.</p>
|
||||
<p><em>Typeclasses</em> form the core of Evennia’s data storage. It allows Evennia to represent any number of different game entities as Python classes, without having to modify the database schema for every new type.</p>
|
||||
<p>In Evennia the most important game entities, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a> are all Python classes inheriting, at varying distance, from <code class="docutils literal notranslate"><span class="pre">evennia.typeclasses.models.TypedObject</span></code>. In the documentation we refer to these objects as being “typeclassed” or even “being a typeclass”.</p>
|
||||
<p>This is how the inheritance looks for the typeclasses in Evennia:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">TypedObject</span>
|
||||
<span class="n">_________________</span><span class="o">|</span><span class="n">_________________________________</span>
|
||||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||||
<span class="mi">1</span><span class="p">:</span> <span class="n">AccountDB</span> <span class="n">ObjectDB</span> <span class="n">ScriptDB</span> <span class="n">ChannelDB</span>
|
||||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||||
<span class="mi">2</span><span class="p">:</span> <span class="n">DefaultAccount</span> <span class="n">DefaultObject</span> <span class="n">DefaultScript</span> <span class="n">DefaultChannel</span>
|
||||
<span class="o">|</span> <span class="n">DefaultCharacter</span> <span class="o">|</span> <span class="o">|</span>
|
||||
<span class="o">|</span> <span class="n">DefaultRoom</span> <span class="o">|</span> <span class="o">|</span>
|
||||
<span class="o">|</span> <span class="n">DefaultExit</span> <span class="o">|</span> <span class="o">|</span>
|
||||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||||
<span class="mi">3</span><span class="p">:</span> <span class="n">Account</span> <span class="n">Object</span> <span class="n">Script</span> <span class="n">Channel</span>
|
||||
<span class="n">Character</span>
|
||||
<span class="n">Room</span>
|
||||
<span class="n">Exit</span>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> ┌───────────┐
|
||||
│TypedObject│
|
||||
└─────▲─────┘
|
||||
┌───────────────┬────────┴──────┬────────────────┐
|
||||
┌────┴────┐ ┌────┴───┐ ┌────┴────┐ ┌────┴───┐
|
||||
1: │AccountDB│ │ScriptDB│ │ChannelDB│ │ObjectDB│
|
||||
└────▲────┘ └────▲───┘ └────▲────┘ └────▲───┘
|
||||
┌───────┴──────┐ ┌──────┴──────┐ ┌──────┴───────┐ ┌──────┴──────┐
|
||||
2: │DefaultAccount│ │DefaultScript│ │DefaultChannel│ │DefaultObject│
|
||||
└───────▲──────┘ └──────▲──────┘ └──────▲───────┘ └──────▲──────┘
|
||||
│ │ │ │ Evennia
|
||||
────────┼───────────────┼───────────────┼────────────────┼─────────
|
||||
│ │ │ │ Gamedir
|
||||
┌───┴───┐ ┌───┴──┐ ┌───┴───┐ ┌──────┐ │
|
||||
3: │Account│ │Script│ │Channel│ │Object├─┤
|
||||
└───────┘ └──────┘ └───────┘ └──────┘ │
|
||||
┌─────────┐ │
|
||||
│Character├─┤
|
||||
└─────────┘ │
|
||||
┌────┐ │
|
||||
│Room├─┤
|
||||
└────┘ │
|
||||
┌────┐ │
|
||||
│Exit├─┘
|
||||
└────┘
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p><strong>Level 1</strong> above is the “database model” level. This describes the database tables and fields
|
||||
(this is technically a <a class="reference external" href="https://docs.djangoproject.com/en/2.2/topics/db/models/">Django model</a>).</p></li>
|
||||
<li><p><strong>Level 2</strong> is where we find Evennia’s default implementations of the various game entities, on
|
||||
top of the database. These classes define all the hook methods that Evennia calls in various
|
||||
situations. <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is a little special since it’s the parent for <code class="docutils literal notranslate"><span class="pre">DefaultCharacter</span></code>,
|
||||
<code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code> and <code class="docutils literal notranslate"><span class="pre">DefaultExit</span></code>. They are all grouped under level 2 because they all represents
|
||||
defaults to build from.</p></li>
|
||||
<li><p><strong>Level 3</strong>, finally, holds empty template classes created in your game directory. This is the
|
||||
level you are meant to modify and tweak as you please, overloading the defaults as befits your game.
|
||||
The templates inherit directly from their defaults, so <code class="docutils literal notranslate"><span class="pre">Object</span></code> inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> and
|
||||
<code class="docutils literal notranslate"><span class="pre">Room</span></code> inherits from <code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code>.</p></li>
|
||||
<li><p><strong>Level 1</strong> above is the “database model” level. This describes the database tables and fields (this is technically a <a class="reference external" href="https://docs.djangoproject.com/en/2.2/topics/db/models/">Django model</a>).</p></li>
|
||||
<li><p><strong>Level 2</strong> is where we find Evennia’s default implementations of the various game entities, on top of the database. These classes define all the hook methods that Evennia calls in various situations. <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is a little special since it’s the parent for <code class="docutils literal notranslate"><span class="pre">DefaultCharacter</span></code>, <code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code> and <code class="docutils literal notranslate"><span class="pre">DefaultExit</span></code>. They are all grouped under level 2 because they all represents defaults to build from.</p></li>
|
||||
<li><p><strong>Level 3</strong>, finally, holds empty template classes created in your game directory. This is the level you are meant to modify and tweak as you please, overloading the defaults as befits your game. The templates inherit directly from their defaults, so <code class="docutils literal notranslate"><span class="pre">Object</span></code> inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> and <code class="docutils literal notranslate"><span class="pre">Room</span></code> inherits from <code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code>.</p></li>
|
||||
</ul>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">typeclass/list</span></code> command will provide a list of all typeclasses known to
|
||||
Evennia. This can be useful for getting a feel for what is available. Note
|
||||
however that if you add a new module with a class in it but do not import that
|
||||
module from anywhere, the <code class="docutils literal notranslate"><span class="pre">typeclass/list</span></code> will not find it. To make it known
|
||||
to Evennia you must import that module from somewhere.</p>
|
||||
<blockquote>
|
||||
<div><p>This diagram doesn’t include the <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> mixin for <code class="docutils literal notranslate"><span class="pre">Object</span></code>, <code class="docutils literal notranslate"><span class="pre">Character</span></code>, <code class="docutils literal notranslate"><span class="pre">Room</span></code> and <code class="docutils literal notranslate"><span class="pre">Exit</span></code>. This establishes a common parent for those classes, for shared properties. See <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> for more details.</p>
|
||||
</div></blockquote>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">typeclass/list</span></code> command will provide a list of all typeclasses known to Evennia. This can be useful for getting a feel for what is available. Note however that if you add a new module with a class in it but do not import that module from anywhere, the <code class="docutils literal notranslate"><span class="pre">typeclass/list</span></code> will not find it. To make it known to Evennia you must import that module from somewhere.</p>
|
||||
<section id="difference-between-typeclasses-and-classes">
|
||||
<h2>Difference between typeclasses and classes<a class="headerlink" href="#difference-between-typeclasses-and-classes" title="Permalink to this headline">¶</a></h2>
|
||||
<p>All Evennia classes inheriting from class in the table above share one important feature and two
|
||||
important limitations. This is why we don’t simply call them “classes” but “typeclasses”.</p>
|
||||
<span class="xref myst"></span>important limitations. This is why we don’t simply call them “classes” but “typeclasses”.</p>
|
||||
<ol>
|
||||
<li><p>A typeclass can save itself to the database. This means that some properties (actually not that
|
||||
many) on the class actually represents database fields and can only hold very specific data types.
|
||||
This is detailed <a class="reference internal" href="#about-typeclass-properties"><span class="std std-doc">below</span></a>.</p></li>
|
||||
<li><p>Due to its connection to the database, the typeclass’ name must be <em>unique</em> across the <em>entire</em>
|
||||
server namespace. That is, there must never be two same-named classes defined anywhere. So the below
|
||||
code would give an error (since <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is now globally found both in this module and in the
|
||||
default library):</p>
|
||||
<li><p>A typeclass can save itself to the database. This means that some properties (actually not that many) on the class actually represents database fields and can only hold very specific data types.</p></li>
|
||||
<li><p>Due to its connection to the database, the typeclass’ name must be <em>unique</em> across the <em>entire</em> server namespace. That is, there must never be two same-named classes defined anywhere. So the below code would give an error (since <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is now globally found both in this module and in the default library):</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span> <span class="k">as</span> <span class="n">BaseObject</span>
|
||||
<span class="k">class</span> <span class="nc">DefaultObject</span><span class="p">(</span><span class="n">BaseObject</span><span class="p">):</span>
|
||||
<span class="k">pass</span>
|
||||
|
|
@ -184,8 +183,10 @@ default library):</p>
|
|||
<p>Apart from this, a typeclass works like any normal Python class and you can
|
||||
treat it as such.</p>
|
||||
</section>
|
||||
<section id="working-with-typeclasses">
|
||||
<h2>Working with typeclasses<a class="headerlink" href="#working-with-typeclasses" title="Permalink to this headline">¶</a></h2>
|
||||
<section id="creating-a-new-typeclass">
|
||||
<h2>Creating a new typeclass<a class="headerlink" href="#creating-a-new-typeclass" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Creating a new typeclass<a class="headerlink" href="#creating-a-new-typeclass" title="Permalink to this headline">¶</a></h3>
|
||||
<p>It’s easy to work with Typeclasses. Either you use an existing typeclass or you create a new Python class inheriting from an existing typeclass. Here is an example of creating a new type of Object:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
|
||||
|
||||
|
|
@ -222,9 +223,6 @@ could point to it as <code class="docutils literal notranslate"><span class="pre
|
|||
functions take a lot of extra keywords allowing you to set things like <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and
|
||||
<a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> all in one go. These keywords don’t use the <code class="docutils literal notranslate"><span class="pre">db_*</span></code> prefix. This will also automatically
|
||||
save the new instance to the database, so you don’t need to call <code class="docutils literal notranslate"><span class="pre">save()</span></code> explicitly.</p>
|
||||
</section>
|
||||
<section id="about-typeclass-properties">
|
||||
<h2>About typeclass properties<a class="headerlink" href="#about-typeclass-properties" title="Permalink to this headline">¶</a></h2>
|
||||
<p>An example of a database field is <code class="docutils literal notranslate"><span class="pre">db_key</span></code>. This stores the “name” of the entity you are modifying
|
||||
and can thus only hold a string. This is one way of making sure to update the <code class="docutils literal notranslate"><span class="pre">db_key</span></code>:</p>
|
||||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">chair</span><span class="o">.</span><span class="n">db_key</span> <span class="o">=</span> <span class="s2">"Table"</span>
|
||||
|
|
@ -282,14 +280,11 @@ entities using <a class="reference internal" href="../Evennia-API.html"><span cl
|
|||
available.</p>
|
||||
</section>
|
||||
<section id="overloading-hooks">
|
||||
<h2>Overloading hooks<a class="headerlink" href="#overloading-hooks" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The way to customize typeclasses is usually to overload <em>hook methods</em> on them. Hooks are methods
|
||||
that Evennia call in various situations. An example is the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> hook on <code class="docutils literal notranslate"><span class="pre">Objects</span></code>,
|
||||
which is only called once, the very first time this object is saved to the database. Other examples
|
||||
are the <code class="docutils literal notranslate"><span class="pre">at_login</span></code> hook of Accounts and the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook of Scripts.</p>
|
||||
<h3>Overloading hooks<a class="headerlink" href="#overloading-hooks" title="Permalink to this headline">¶</a></h3>
|
||||
<p>The way to customize typeclasses is usually to overload <em>hook methods</em> on them. Hooks are methods that Evennia call in various situations. An example is the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> hook on <code class="docutils literal notranslate"><span class="pre">Objects</span></code>, which is only called once, the very first time this object is saved to the database. Other examples are the <code class="docutils literal notranslate"><span class="pre">at_login</span></code> hook of Accounts and the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook of Scripts.</p>
|
||||
</section>
|
||||
<section id="querying-for-typeclasses">
|
||||
<h2>Querying for typeclasses<a class="headerlink" href="#querying-for-typeclasses" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Querying for typeclasses<a class="headerlink" href="#querying-for-typeclasses" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Most of the time you search for objects in the database by using convenience methods like the
|
||||
<code class="docutils literal notranslate"><span class="pre">caller.search()</span></code> of <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> or the search functions like <code class="docutils literal notranslate"><span class="pre">evennia.search_objects</span></code>.</p>
|
||||
<p>You can however also query for them directly using <a class="reference external" href="https://docs.djangoproject.com/en/1.7/topics/db/queries/">Django’s query
|
||||
|
|
@ -323,7 +318,7 @@ example for Scripts:</p>
|
|||
you will always query all children on the database model.</p>
|
||||
</section>
|
||||
<section id="updating-existing-typeclass-instances">
|
||||
<h2>Updating existing typeclass instances<a class="headerlink" href="#updating-existing-typeclass-instances" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Updating existing typeclass instances<a class="headerlink" href="#updating-existing-typeclass-instances" title="Permalink to this headline">¶</a></h3>
|
||||
<p>If you already have created instances of Typeclasses, you can modify the <em>Python code</em> at any time -
|
||||
due to how Python inheritance works your changes will automatically be applied to all children once you have reloaded the server.</p>
|
||||
<p>However, database-saved data, like <code class="docutils literal notranslate"><span class="pre">db_*</span></code> fields, <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> etc, are
|
||||
|
|
@ -359,7 +354,7 @@ line break, that’s only for readability in the wiki):</p>
|
|||
retroactively update objects more than necessary.</p>
|
||||
</section>
|
||||
<section id="swap-typeclass">
|
||||
<h2>Swap typeclass<a class="headerlink" href="#swap-typeclass" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Swap typeclass<a class="headerlink" href="#swap-typeclass" title="Permalink to this headline">¶</a></h3>
|
||||
<p>If you want to swap an already existing typeclass, there are two ways to do so: From in-game and via code. From inside the game you can use the default <code class="docutils literal notranslate"><span class="pre">@typeclass</span></code> command:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">typeclass</span> <span class="n">objname</span> <span class="o">=</span> <span class="n">path</span><span class="o">.</span><span class="n">to</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">typeclass</span>
|
||||
</pre></div>
|
||||
|
|
@ -376,20 +371,21 @@ retroactively update objects more than necessary.</p>
|
|||
</div>
|
||||
<p>The arguments to this method are described <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.typeclasses.models#typedobjectswap_typeclass">in the API docs here</a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="how-typeclasses-actually-work">
|
||||
<h2>How typeclasses actually work<a class="headerlink" href="#how-typeclasses-actually-work" title="Permalink to this headline">¶</a></h2>
|
||||
<p><em>This is considered an advanced section.</em></p>
|
||||
<p>Technically, typeclasses are <a class="reference external" href="https://docs.djangoproject.com/en/1.7/topics/db/models/#proxy-models">Django proxy models</a>. The only database
|
||||
models that are “real” in the typeclass system (that is, are represented by actual tables in the database) are <code class="docutils literal notranslate"><span class="pre">AccountDB</span></code>, <code class="docutils literal notranslate"><span class="pre">ObjectDB</span></code>, <code class="docutils literal notranslate"><span class="pre">ScriptDB</span></code> and <code class="docutils literal notranslate"><span class="pre">ChannelDB</span></code> (there are also <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> but they are not typeclasses themselves). All the subclasses of them are “proxies”, extending them with Python code without actually modifying the database layout.</p>
|
||||
<p>Evennia modifies Django’s proxy model in various ways to allow them to work without any boiler plate (for example you don’t need to set the Django “proxy” property in the model <code class="docutils literal notranslate"><span class="pre">Meta</span></code> subclass, Evennia handles this for you using metaclasses). Evennia also makes sure you can query subclasses as well as patches django to allow multiple inheritance from the same base class.</p>
|
||||
</section>
|
||||
<section id="caveats">
|
||||
<h2>Caveats<a class="headerlink" href="#caveats" title="Permalink to this headline">¶</a></h2>
|
||||
<h3>Caveats<a class="headerlink" href="#caveats" title="Permalink to this headline">¶</a></h3>
|
||||
<p>Evennia uses the <em>idmapper</em> to cache its typeclasses (Django proxy models) in memory. The idmapper allows things like on-object handlers and properties to be stored on typeclass instances and to not get lost as long as the server is running (they will only be cleared on a Server reload). Django does not work like this by default; by default every time you search for an object in the database you’ll get a <em>different</em> instance of that object back and anything you stored on it that was not in the database would be lost. The bottom line is that Evennia’s Typeclass instances subside in memory a lot longer than vanilla Django model instance do.</p>
|
||||
<p>There is one caveat to consider with this, and that relates to [making your own models](New-
|
||||
Models): Foreign relationships to typeclasses are cached by Django and that means that if you were to change an object in a foreign relationship via some other means than via that relationship, the object seeing the relationship may not reliably update but will still see its old cached version. Due to typeclasses staying so long in memory, stale caches of such relationships could be more
|
||||
visible than common in Django. See the <a class="reference external" href="https://github.com/evennia/evennia/issues/1098">closed issue #1098 and its comments</a> for examples and solutions.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="will-i-run-out-of-dbrefs">
|
||||
<h2>Will I run out of dbrefs?<a class="headerlink" href="#will-i-run-out-of-dbrefs" title="Permalink to this headline">¶</a></h2>
|
||||
<p>Evennia does not re-use its <code class="docutils literal notranslate"><span class="pre">#dbrefs</span></code>. This means new objects get an ever-increasing <code class="docutils literal notranslate"><span class="pre">#dbref</span></code>, also if you delete older objects. There are technical and safety reasons for this. But you may wonder if this means you have to worry about a big game ‘running out’ of dbref integers eventually.</p>
|
||||
|
|
@ -415,10 +411,10 @@ visible than common in Django. See the <a class="reference external" href="https
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
<a href="Accounts.html" title="Accounts"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Components-Overview.html" title="Core Components"
|
||||
<a href="Sessions.html" title="Sessions"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||||
|
|
|
|||
|
|
@ -158,16 +158,62 @@
|
|||
</section>
|
||||
<section id="multisession-mode-and-multi-playing">
|
||||
<h2>Multisession mode and multi-playing<a class="headerlink" href="#multisession-mode-and-multi-playing" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The multisession modes are described in detail in the <a class="reference internal" href="../Components/Sessions.html#multisession-mode"><span class="std std-doc">Session documentation</span></a>. In brief, this is controlled by a <a class="reference internal" href="../Setup/Settings.html"><span class="doc std std-doc">setting</span></a>. Here’s the default:</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>MULTISESSION_MODE = 0
|
||||
<p>The number of sessions possible to connect to a given account at the same time and how it works is given by the <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> setting:</p>
|
||||
<ul>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=0</span></code>: One session per account. When connecting with a new session the old one is disconnected. This is the default mode and emulates many classic mud code bases.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>┌──────┐ │ ┌───────┐ ┌───────┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├───►│Account├──►│Character│
|
||||
└──────┘ │ └───────┘ └───────┘ └─────────┘
|
||||
</pre></div>
|
||||
</div>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=0</span></code>: One <a class="reference internal" href="../Components/Sessions.html"><span class="doc std std-doc">Session</span></a> per <a class="reference internal" href="../Components/Accounts.html"><span class="doc std std-doc">Account</span></a>, routed to one <a class="reference internal" href="../Components/Objects.html"><span class="doc std std-doc">puppet</span></a>. If connecting with a new session/client, it will kick the previous one.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=1</span></code>: Multiple sessions per Account, all routed to one puppet. Allows you to control one puppet from multiple client windows.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=2</span></code>: Multiple sessions per Account, each routed to a different puppet. This allows for multi-playing.</p></li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=3</span></code>: Multiple sessions per account, And multiple sessions per puppet. This is full multi-playing, including being able to control each puppet from multiple clients.</p></li>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=1</span></code>: Many sessions per account, input/output from/to each session is treated the same. For the player this means they can connect to the game from multiple clients and see the same output in all of them. The result of a command given in one client (that is, through one Session) will be returned to <em>all</em> connected Sessions/clients with no distinction.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> │
|
||||
┌──────┐ │ ┌───────┐
|
||||
│Client├─┼──►│Session├──┐
|
||||
└──────┘ │ └───────┘ └──►┌───────┐ ┌─────────┐
|
||||
│ │Account├──►│Character│
|
||||
┌──────┐ │ ┌───────┐ ┌──►└───────┘ └─────────┘
|
||||
│Client├─┼──►│Session├──┘
|
||||
└──────┘ │ └───────┘
|
||||
│
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=2</span></code>: Many sessions per account, one character per session. In this mode, puppeting an Object/Character will link the puppet back only to the particular Session doing the puppeting. That is, input from that Session will make use of the CmdSet of that Object/Character and outgoing messages (such as the result of a <code class="docutils literal notranslate"><span class="pre">look</span></code>) will be passed back only to that puppeting Session. If another Session tries to puppet the same Character, the old Session will automatically un-puppet it. From the player’s perspective, this will mean that they can open separate game clients and play a different Character in each using one game account.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> │ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►│Character│
|
||||
└──────┘ │ └───────┘ │ │ └─────────┘
|
||||
│ └───────┘
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=3</span></code>: Many sessions per account <em>and</em> character. This is the full multi-puppeting mode, where multiple sessions may not only connect to the player account but multiple sessions may also puppet a single character at the same time. From the user’s perspective it means one can open multiple client windows, some for controlling different Characters and some that share a Character’s input/output like in mode 1. This mode otherwise works the same as mode 2.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> │ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►┌─────────┐
|
||||
└──────┘ │ └───────┘ │ │ │Character│
|
||||
│ │ │ ┌►└─────────┘
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┘ ▼
|
||||
│Client├─┼──►│Session├──┘ │ │
|
||||
└──────┘ │ └───────┘ └───────┘
|
||||
│
|
||||
</pre></div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<div><p>Note that even if multiple Sessions puppet one Character, there is only ever one instance of that Character.</p>
|
||||
</div></blockquote>
|
||||
<p>Mode <code class="docutils literal notranslate"><span class="pre">0</span></code> is the default and mimics how many legacy codebases work, especially in the DIKU world. The equivalence of higher modes are often ‘hacked’ into existing servers to allow for players to have multiple characters.</p>
|
||||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>MAX_NR_SIMULTANEOUS_PUPPETS = 1
|
||||
</pre></div>
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@
|
|||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>GUEST_ENABLED = True
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Henceforth users can use <code class="docutils literal notranslate"><span class="pre">connect</span> <span class="pre">guest</span></code> (in the default command set) to login with a guest account. You may need to change your <a class="reference internal" href="../Components/Connection-Screen.html"><span class="doc std std-doc">Connection Screen</span></a> to inform them of this possibility. Guest accounts work differently from normal accounts - they are automatically <em>deleted</em> whenever the user logs off or the server resets (but not during a reload). They are literally re- usable throw-away accounts.</p>
|
||||
<p>Henceforth users can use <code class="docutils literal notranslate"><span class="pre">connect</span> <span class="pre">guest</span></code> (in the default command set) to login with a guest account. You may need to change your <span class="xref myst">Connection Screen</span> to inform them of this possibility. Guest accounts work differently from normal accounts - they are automatically <em>deleted</em> whenever the user logs off or the server resets (but not during a reload). They are literally re- usable throw-away accounts.</p>
|
||||
<p>You can add a few more variables to your <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> file to customize your guests:</p>
|
||||
<ul class="simple">
|
||||
<li><p><code class="docutils literal notranslate"><span class="pre">BASE_GUEST_TYPECLASS</span></code> - the python-path to the default <a class="reference internal" href="../Components/Typeclasses.html"><span class="doc std std-doc">typeclass</span></a> for guests. Defaults to <code class="docutils literal notranslate"><span class="pre">"typeclasses.accounts.Guest"</span></code>.</p></li>
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ An _Account_ represents a unique game account - one player playing the game. Whe
|
|||
The Account object has no in-game representation. In order to actually get on the game the Account must *puppet* an [Object](./Objects.md) (normally a [Character](./Objects.md#characters)).
|
||||
|
||||
Exactly how many Sessions can interact with an Account and its Puppets at once is determined by
|
||||
Evennia's [MULTISESSION_MODE](./Sessions.md#multisession-mode) setting.
|
||||
Evennia's [MULTISESSION_MODE](../Concepts/Connection-Styles.md#multisession-mode-and-multiplaying)
|
||||
|
||||
Apart from storing login information and other account-specific data, the Account object is what is chatting on Evennia's default [Channels](./Channels.md). It is also a good place to store [Permissions](./Locks.md) to be consistent between different in-game characters. It can also hold player-level configuration options.
|
||||
|
||||
|
|
@ -29,7 +29,7 @@ This re-puppets the latest character.
|
|||
Note that the Account object can have, and often does have, a different set of [Permissions](./Permissions.md) from the Character they control. Normally you should put your permissions on the Account level - this will overrule permissions set on the Character level. For the permissions of the Character to come into play the default `quell` command can be used. This allows for exploring the game using a different permission set (but you can't escalate your permissions this way - for hierarchical permissions like `Builder`, `Admin` etc, the *lower* of the permissions on the Character/Account will always be used).
|
||||
|
||||
|
||||
## How to customize your own Account types
|
||||
## Working with Accounts
|
||||
|
||||
You will usually not want more than one Account typeclass for all new accounts.
|
||||
|
||||
|
|
@ -66,7 +66,7 @@ You should now see the Attributes on yourself.
|
|||
> If you wanted Evennia to default to a completely *different* Account class located elsewhere, you > must point Evennia to it. Add `BASE_ACCOUNT_TYPECLASS` to your settings file, and give the python path to your custom class as its value. By default this points to `typeclasses.accounts.Account`, the empty template we used above.
|
||||
|
||||
|
||||
## Properties on Accounts
|
||||
### Properties on Accounts
|
||||
|
||||
Beyond those properties assigned to all typeclassed objects (see [Typeclasses](./Typeclasses.md)), the Account also has the following custom properties:
|
||||
|
||||
|
|
|
|||
|
|
@ -25,27 +25,13 @@ class MyObject(DefaultObject):
|
|||
|
||||
```
|
||||
|
||||
_Attributes_ allow you to to store arbitrary data on objects and make sure the data survives a server reboot. An Attribute can store pretty much any
|
||||
Python data structure and data type, like numbers, strings, lists, dicts etc. You can also
|
||||
store (references to) database objects like characters and rooms.
|
||||
_Attributes_ allow you to to store arbitrary data on objects and make sure the data survives a server reboot. An Attribute can store pretty much any Python data structure and data type, like numbers, strings, lists, dicts etc. You can also store (references to) database objects like characters and rooms.
|
||||
|
||||
- [What can be stored in an Attribute](#what-types-of-data-can-i-save-in-an-attribute) is a must-read to avoid being surprised, also for experienced developers. Attributes can store _almost_ everything
|
||||
but you need to know the quirks.
|
||||
- [NAttributes](#in-memory-attributes-nattributes) are the in-memory, non-persistent
|
||||
siblings of Attributes.
|
||||
- [Managing Attributes In-game](#managing-attributes-in-game) for in-game builder commands.
|
||||
## Working with Attributes
|
||||
|
||||
## Managing Attributes in Code
|
||||
|
||||
Attributes are usually handled in code. All [Typeclassed](./Typeclasses.md) entities
|
||||
([Accounts](./Accounts.md), [Objects](./Objects.md), [Scripts](./Scripts.md) and
|
||||
[Channels](./Channels.md)) can (and usually do) have Attributes associated with them. There
|
||||
Attributes are usually handled in code. All [Typeclassed](./Typeclasses.md) entities ([Accounts](./Accounts.md), [Objects](./Objects.md), [Scripts](./Scripts.md) and [Channels](./Channels.md)) can (and usually do) have Attributes associated with them. There
|
||||
are three ways to manage Attributes, all of which can be mixed.
|
||||
|
||||
- [Using the `.db` property shortcut](#using-db)
|
||||
- [Using the `.attributes` manager (`AttributeManager`)](#using-attributes)
|
||||
- [Using `AttributeProperty` for assigning Attributes in a way similar to Django fields](#using-attributeproperty)
|
||||
|
||||
### Using .db
|
||||
|
||||
The simplest way to get/set Attributes is to use the `.db` shortcut. This allows for setting and getting Attributes that lack a _category_ (having category `None`)
|
||||
|
|
@ -115,8 +101,7 @@ neck_armor = obj.attributes.get("neck", category="armor")
|
|||
|
||||
If you don't specify a category, the Attribute's `category` will be `None` and can thus also be found via `.db`. `None` is considered a category of its own, so you won't find `None`-category Attributes mixed with Attributes having categories.
|
||||
|
||||
Here are the methods of the `AttributeHandler`. See
|
||||
the [AttributeHandler API](evennia.typeclasses.attributes.AttributeHandler) for more details.
|
||||
Here are the methods of the `AttributeHandler`. See the [AttributeHandler API](evennia.typeclasses.attributes.AttributeHandler) for more details.
|
||||
|
||||
- `has(...)` - this checks if the object has an Attribute with this key. This is equivalent
|
||||
to doing `obj.db.attrname` except you can also check for a specific `category.
|
||||
|
|
@ -214,16 +199,46 @@ char.db.sleepy # now returns True!
|
|||
char.attributes.get("sleepy") # now returns True
|
||||
|
||||
char.sleepy # now returns True, involves db access
|
||||
|
||||
```
|
||||
|
||||
You can e.g. `del char.strength` to set the value back to the default (the value defined
|
||||
in the `AttributeProperty`).
|
||||
You can e.g. `del char.strength` to set the value back to the default (the value defined in the `AttributeProperty`).
|
||||
|
||||
See the [AttributeProperty API](evennia.typeclasses.attributes.AttributeProperty) for more details on how to create it with special options, like giving access-restrictions.
|
||||
|
||||
### Properties of Attributes
|
||||
|
||||
## Managing Attributes in-game
|
||||
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
|
||||
[this section](./Attributes.md#what-types-of-data-can-i-save-in-an-attribute) 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.md) is an example of using
|
||||
Attributes in this way). To modify this property you need to use the [Attribute Handler](#attributes)
|
||||
- `strvalue` - this is a separate value field that only accepts strings. This severely 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.md) use it). It is only
|
||||
accessible via the [Attribute Handler](#attributes).
|
||||
|
||||
There are also two special properties:
|
||||
|
||||
- `attrtype` - this is used internally by Evennia to separate [Nicks](./Nicks.md), from Attributes (Nicks
|
||||
use Attributes behind the scenes).
|
||||
- `model` - this is a *natural-key* describing the model this Attribute is attached to. This is on
|
||||
the form *appname.modelclass*, like `objects.objectdb`. It is used by the Attribute and
|
||||
NickHandler to quickly sort matches in the database. Neither this nor `attrtype` should normally
|
||||
need to be modified.
|
||||
|
||||
Non-database attributes are not stored in the database and have no equivalence
|
||||
to `category` nor `strvalue`, `attrtype` or `model`.
|
||||
|
||||
|
||||
### Managing Attributes in-game
|
||||
|
||||
Attributes are mainly used by code. But one can also allow the builder to use Attributes to
|
||||
'turn knobs' in-game. For example a builder could want to manually tweak the "level" Attribute of an
|
||||
|
|
@ -261,7 +276,7 @@ string.
|
|||
|
||||
For the last line you'll get a warning and the value instead will be saved as a string `"[1, 2, foo]"`.
|
||||
|
||||
## Locking and checking Attributes
|
||||
### Locking and checking Attributes
|
||||
|
||||
While the `set` command is limited to builders, individual Attributes are usually not
|
||||
locked down. You may want to lock certain sensitive Attributes, in particular for games
|
||||
|
|
@ -313,6 +328,7 @@ To check the `lockstring` you provided, make sure you include `accessing_obj` an
|
|||
The same keywords are available to use with `obj.attributes.set()` and `obj.attributes.remove()`,
|
||||
those will check for the `attredit` lock type.
|
||||
|
||||
|
||||
## What types of data can I save in an Attribute?
|
||||
|
||||
The database doesn't know anything about Python objects, so Evennia must *serialize* Attribute
|
||||
|
|
@ -519,37 +535,6 @@ The result of this operation will be a structure only consisting of normal Pytho
|
|||
instead of `_SaverList`, `dict` instead of `_SaverDict` and so on). If you update it, you need to
|
||||
explicitly save it back to the Attribute for it to save.
|
||||
|
||||
## 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
|
||||
[this section](./Attributes.md#what-types-of-data-can-i-save-in-an-attribute) 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.md) is an example of using
|
||||
Attributes in this way). To modify this property you need to use the [Attribute Handler](#attributes)
|
||||
- `strvalue` - this is a separate value field that only accepts strings. This severely 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.md) use it). It is only
|
||||
accessible via the [Attribute Handler](#attributes).
|
||||
|
||||
There are also two special properties:
|
||||
|
||||
- `attrtype` - this is used internally by Evennia to separate [Nicks](./Nicks.md), from Attributes (Nicks
|
||||
use Attributes behind the scenes).
|
||||
- `model` - this is a *natural-key* describing the model this Attribute is attached to. This is on
|
||||
the form *appname.modelclass*, like `objects.objectdb`. It is used by the Attribute and
|
||||
NickHandler to quickly sort matches in the database. Neither this nor `attrtype` should normally
|
||||
need to be modified.
|
||||
|
||||
Non-database attributes are not stored in the database and have no equivalence
|
||||
to `category` nor `strvalue`, `attrtype` or `model`.
|
||||
|
||||
## In-memory Attributes (NAttributes)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,61 +1,31 @@
|
|||
# Batch Code Processor
|
||||
|
||||
|
||||
For an introduction and motivation to using batch processors, see [here](./Batch-Processors.md). This
|
||||
page describes the Batch-*code* processor. The Batch-*command* one is covered [here](Batch-Command-
|
||||
Processor).
|
||||
|
||||
## Basic Usage
|
||||
For an introduction and motivation to using batch processors, see [here](./Batch-Processors.md). This page describes the Batch-*code* processor. The Batch-*command* one is covered [here](Batch-Command- Processor).
|
||||
|
||||
The batch-code processor is a superuser-only function, invoked by
|
||||
|
||||
> @batchcode path.to.batchcodefile
|
||||
> batchcode path.to.batchcodefile
|
||||
|
||||
Where `path.to.batchcodefile` is the path to a *batch-code file*. Such a file should have a name
|
||||
ending in "`.py`" (but you shouldn't include that in the path). The path is given like a python path
|
||||
relative to a folder you define to hold your batch files, set by `BATCH_IMPORT_PATH` in your
|
||||
settings. Default folder is (assuming your game is called "mygame") `mygame/world/`. So if you want
|
||||
to run the example batch file in `mygame/world/batch_code.py`, you could simply use
|
||||
Where `path.to.batchcodefile` is the path to a *batch-code file*. Such a file should have a name ending in "`.py`" (but you shouldn't include that in the path). The path is given like a python path relative to a folder you define to hold your batch files, set by `BATCH_IMPORT_PATH` in your settings. Default folder is (assuming your game is called "mygame") `mygame/world/`. So if you want to run the example batch file in `mygame/world/batch_code.py`, you could simply use
|
||||
|
||||
> @batchcode batch_code
|
||||
> batchcode batch_code
|
||||
|
||||
This will try to run through the entire batch file in one go. For more gradual, *interactive*
|
||||
control you can use the `/interactive` switch. The switch `/debug` will put the processor in
|
||||
*debug* mode. Read below for more info.
|
||||
This will try to run through the entire batch file in one go. For more gradual, *interactive* control you can use the `/interactive` switch. The switch `/debug` will put the processor in *debug* mode. Read below for more info.
|
||||
|
||||
## The batch file
|
||||
|
||||
A batch-code file is a normal Python file. The difference is that since the batch processor loads
|
||||
and executes the file rather than importing it, you can reliably update the file, then call it
|
||||
again, over and over and see your changes without needing to `@reload` the server. This makes for
|
||||
easy testing. In the batch-code file you have also access to the following global variables:
|
||||
A batch-code file is a normal Python file. The difference is that since the batch processor loads and executes the file rather than importing it, you can reliably update the file, then call it again, over and over and see your changes without needing to `reload` the server. This makes for easy testing. In the batch-code file you have also access to the following global variables:
|
||||
|
||||
- `caller` - This is a reference to the object running the batchprocessor.
|
||||
- `DEBUG` - This is a boolean that lets you determine if this file is currently being run in debug-
|
||||
mode or not. See below how this can be useful.
|
||||
- `DEBUG` - This is a boolean that lets you determine if this file is currently being run in debug-mode or not. See below how this can be useful.
|
||||
|
||||
Running a plain Python file through the processor will just execute the file from beginning to end.
|
||||
If you want to get more control over the execution you can use the processor's *interactive* mode.
|
||||
This runs certain code blocks on their own, rerunning only that part until you are happy with it. In
|
||||
order to do this you need to add special markers to your file to divide it up into smaller chunks.
|
||||
These take the form of comments, so the file remains valid Python.
|
||||
Running a plain Python file through the processor will just execute the file from beginning to end. If you want to get more control over the execution you can use the processor's *interactive* mode. This runs certain code blocks on their own, rerunning only that part until you are happy with it. In order to do this you need to add special markers to your file to divide it up into smaller chunks. These take the form of comments, so the file remains valid Python.
|
||||
|
||||
Here are the rules of syntax of the batch-code `*.py` file.
|
||||
|
||||
- `#CODE` as the first on a line marks the start of a *code* block. It will last until the beginning
|
||||
of another marker or the end of the file. Code blocks contain functional python code. Each `#CODE`
|
||||
block will be run in complete isolation from other parts of the file, so make sure it's self-
|
||||
contained.
|
||||
- `#HEADER` as the first on a line marks the start of a *header* block. It lasts until the next
|
||||
marker or the end of the file. This is intended to hold imports and variables you will need for all
|
||||
other blocks .All python code defined in a header block will always be inserted at the top of every
|
||||
`#CODE` blocks in the file. You may have more than one `#HEADER` block, but that is equivalent to
|
||||
having one big one. Note that you can't exchange data between code blocks, so editing a header-
|
||||
variable in one code block won't affect that variable in any other code block!
|
||||
- `#INSERT path.to.file` will insert another batchcode (Python) file at that position.
|
||||
- A `#` that is not starting a `#HEADER`, `#CODE` or `#INSERT` instruction is considered a comment.
|
||||
- Inside a block, normal Python syntax rules apply. For the sake of indentation, each block acts as
|
||||
a separate python module.
|
||||
- `#CODE` as the first on a line marks the start of a *code* block. It will last until the beginning of another marker or the end of the file. Code blocks contain functional python code. Each `#CODE` block will be run in complete isolation from other parts of the file, so make sure it's self- contained.
|
||||
- `#HEADER` as the first on a line marks the start of a *header* block. It lasts until the next marker or the end of the file. This is intended to hold imports and variables you will need for all other blocks .All python code defined in a header block will always be inserted at the top of every `#CODE` blocks in the file. You may have more than one `#HEADER` block, but that is equivalent to having one big one. Note that you can't exchange data between code blocks, so editing a header- variable in one code block won't affect that variable in any other code block!
|
||||
- `#INSERT path.to.file` will insert another batchcode (Python) file at that position. - A `#` that is not starting a `#HEADER`, `#CODE` or `#INSERT` instruction is considered a comment.
|
||||
- Inside a block, normal Python syntax rules apply. For the sake of indentation, each block acts as a separate python module.
|
||||
|
||||
Below is a version of the example file found in `evennia/contrib/tutorial_examples/`.
|
||||
|
||||
|
|
@ -105,37 +75,25 @@ This uses Evennia's Python API to create three objects in sequence.
|
|||
|
||||
Try to run the example script with
|
||||
|
||||
> @batchcode/debug tutorial_examples.example_batch_code
|
||||
> batchcode/debug tutorial_examples.example_batch_code
|
||||
|
||||
The batch script will run to the end and tell you it completed. You will also get messages that the
|
||||
button and the two pieces of furniture were created. Look around and you should see the button
|
||||
there. But you won't see any chair nor a table! This is because we ran this with the `/debug`
|
||||
switch, which is directly visible as `DEBUG==True` inside the script. In the above example we
|
||||
handled this state by deleting the chair and table again.
|
||||
The batch script will run to the end and tell you it completed. You will also get messages that the button and the two pieces of furniture were created. Look around and you should see the button there. But you won't see any chair nor a table! This is because we ran this with the `/debug` switch, which is directly visible as `DEBUG==True` inside the script. In the above example we handled this state by deleting the chair and table again.
|
||||
|
||||
The debug mode is intended to be used when you test out a batchscript. Maybe you are looking for
|
||||
bugs in your code or try to see if things behave as they should. Running the script over and over
|
||||
would then create an ever-growing stack of chairs and tables, all with the same name. You would have
|
||||
to go back and painstakingly delete them later.
|
||||
The debug mode is intended to be used when you test out a batchscript. Maybe you are looking for bugs in your code or try to see if things behave as they should. Running the script over and over would then create an ever-growing stack of chairs and tables, all with the same name. You would have to go back and painstakingly delete them later.
|
||||
|
||||
## Interactive mode
|
||||
|
||||
Interactive mode works very similar to the [batch-command processor counterpart](Batch-Command-
|
||||
Processor). It allows you more step-wise control over how the batch file is executed. This is useful
|
||||
for debugging or for picking and choosing only particular blocks to run. Use `@batchcode` with the
|
||||
`/interactive` flag to enter interactive mode.
|
||||
Interactive mode works very similar to the [batch-command processor counterpart](Batch-Command- Processor). It allows you more step-wise control over how the batch file is executed. This is useful for debugging or for picking and choosing only particular blocks to run. Use `batchcode` with the `/interactive` flag to enter interactive mode.
|
||||
|
||||
> @batchcode/interactive tutorial_examples.batch_code
|
||||
> batchcode/interactive tutorial_examples.batch_code
|
||||
|
||||
You should see the following:
|
||||
|
||||
01/02: red_button = create_object(red_button.RedButton, [...] (hh for help)
|
||||
|
||||
This shows that you are on the first `#CODE` block, the first of only two commands in this batch
|
||||
file. Observe that the block has *not* actually been executed at this point!
|
||||
This shows that you are on the first `#CODE` block, the first of only two commands in this batch file. Observe that the block has *not* actually been executed at this point!
|
||||
|
||||
To take a look at the full code snippet you are about to run, use `ll` (a batch-processor version of
|
||||
`look`).
|
||||
To take a look at the full code snippet you are about to run, use `ll` (a batch-processor version of `look`).
|
||||
|
||||
```python
|
||||
from evennia.utils import create, search
|
||||
|
|
@ -151,23 +109,16 @@ To take a look at the full code snippet you are about to run, use `ll` (a batch-
|
|||
caller.msg("A red button was created.")
|
||||
```
|
||||
|
||||
Compare with the example code given earlier. Notice how the content of `#HEADER` has been pasted at
|
||||
the top of the `#CODE` block. Use `pp` to actually execute this block (this will create the button
|
||||
Compare with the example code given earlier. Notice how the content of `#HEADER` has been pasted at the top of the `#CODE` block. Use `pp` to actually execute this block (this will create the button
|
||||
and give you a message). Use `nn` (next) to go to the next command. Use `hh` for a list of commands.
|
||||
|
||||
If there are tracebacks, fix them in the batch file, then use `rr` to reload the file. You will
|
||||
still be at the same code block and can rerun it easily with `pp` as needed. This makes for a simple
|
||||
debug cycle. It also allows you to rerun individual troublesome blocks - as mentioned, in a large
|
||||
batch file this can be very useful (don't forget the `/debug` mode either).
|
||||
If there are tracebacks, fix them in the batch file, then use `rr` to reload the file. You will still be at the same code block and can rerun it easily with `pp` as needed. This makes for a simple debug cycle. It also allows you to rerun individual troublesome blocks - as mentioned, in a large batch file this can be very useful (don't forget the `/debug` mode either).
|
||||
|
||||
Use `nn` and `bb` (next and back) to step through the file; e.g. `nn 12` will jump 12 steps forward
|
||||
(without processing any blocks in between). All normal commands of Evennia should work too while
|
||||
working in interactive mode.
|
||||
Use `nn` and `bb` (next and back) to step through the file; e.g. `nn 12` will jump 12 steps forward (without processing any blocks in between). All normal commands of Evennia should work too while working in interactive mode.
|
||||
|
||||
## Limitations and Caveats
|
||||
|
||||
The batch-code processor is by far the most flexible way to build a world in Evennia. There are
|
||||
however some caveats you need to keep in mind.
|
||||
The batch-code processor is by far the most flexible way to build a world in Evennia. There are however some caveats you need to keep in mind.
|
||||
|
||||
### Safety
|
||||
Or rather the lack of it. There is a reason only *superusers* are allowed to run the batch-code
|
||||
|
|
@ -180,23 +131,12 @@ command processor is much safer since the user running it is still 'inside' the
|
|||
really do anything outside what the game commands allow them to.
|
||||
|
||||
### No communication between code blocks
|
||||
Global variables won't work in code batch files, each block is executed as stand-alone environments.
|
||||
`#HEADER` blocks are literally pasted on top of each `#CODE` block so updating some header-variable
|
||||
in your block will not make that change available in another block. Whereas a python execution
|
||||
limitation, allowing this would also lead to very hard-to-debug code when using the interactive mode
|
||||
- this would be a classical example of "spaghetti code".
|
||||
Global variables won't work in code batch files, each block is executed as stand-alone environments. `#HEADER` blocks are literally pasted on top of each `#CODE` block so updating some header-variable in your block will not make that change available in another block. Whereas a python execution limitation, allowing this would also lead to very hard-to-debug code when using the interactive mode - this would be a classical example of "spaghetti code".
|
||||
|
||||
The main practical issue with this is when building e.g. a room in one code block and later want to
|
||||
connect that room with a room you built in the current block. There are two ways to do this:
|
||||
The main practical issue with this is when building e.g. a room in one code block and later want to connect that room with a room you built in the current block. There are two ways to do this:
|
||||
|
||||
- Perform a database search for the name of the room you created (since you cannot know in advance
|
||||
which dbref it got assigned). The problem is that a name may not be unique (you may have a lot of "A
|
||||
dark forest" rooms). There is an easy way to handle this though - use [Tags](./Tags.md) or *Aliases*. You
|
||||
can assign any number of tags and/or aliases to any object. Make sure that one of those tags or
|
||||
aliases is unique to the room (like "room56") and you will henceforth be able to always uniquely
|
||||
search and find it later.
|
||||
- Use the `caller` global property as an inter-block storage. For example, you could have a
|
||||
dictionary of room references in an `ndb`:
|
||||
- Perform a database search for the name of the room you created (since you cannot know in advance which dbref it got assigned). The problem is that a name may not be unique (you may have a lot of "A dark forest" rooms). There is an easy way to handle this though - use [Tags](./Tags.md) or *Aliases*. You can assign any number of tags and/or aliases to any object. Make sure that one of those tags or aliases is unique to the room (like "room56") and you will henceforth be able to always uniquely search and find it later.
|
||||
- Use the `caller` global property as an inter-block storage. For example, you could have a dictionary of room references in an `ndb`:
|
||||
```python
|
||||
#HEADER
|
||||
if caller.ndb.all_rooms is None:
|
||||
|
|
@ -211,18 +151,13 @@ dictionary of room references in an `ndb`:
|
|||
# in another node we want to access the castle
|
||||
castle = caller.ndb.all_rooms.get("castle")
|
||||
```
|
||||
Note how we check in `#HEADER` if `caller.ndb.all_rooms` doesn't already exist before creating the
|
||||
dict. Remember that `#HEADER` is copied in front of every `#CODE` block. Without that `if` statement
|
||||
Note how we check in `#HEADER` if `caller.ndb.all_rooms` doesn't already exist before creating the dict. Remember that `#HEADER` is copied in front of every `#CODE` block. Without that `if` statement
|
||||
we'd be wiping the dict every block!
|
||||
|
||||
### Don't treat a batchcode file like any Python file
|
||||
Despite being a valid Python file, a batchcode file should *only* be run by the batchcode processor.
|
||||
You should not do things like define Typeclasses or Commands in them, or import them into other
|
||||
code. Importing a module in Python will execute base level of the module, which in the case of your
|
||||
average batchcode file could mean creating a lot of new objects every time.
|
||||
|
||||
Despite being a valid Python file, a batchcode file should *only* be run by the batchcode processor. You should not do things like define Typeclasses or Commands in them, or import them into other code. Importing a module in Python will execute base level of the module, which in the case of your average batchcode file could mean creating a lot of new objects every time.
|
||||
|
||||
### Don't let code rely on the batch-file's real file path
|
||||
|
||||
When you import things into your batchcode file, don't use relative imports but always import with
|
||||
paths starting from the root of your game directory or evennia library. Code that relies on the
|
||||
batch file's "actual" location *will fail*. Batch code files are read as text and the strings
|
||||
executed. When the code runs it has no knowledge of what file those strings where once a part of.
|
||||
When you import things into your batchcode file, don't use relative imports but always import with paths starting from the root of your game directory or evennia library. Code that relies on the batch file's "actual" location *will fail*. Batch code files are read as text and the strings executed. When the code runs it has no knowledge of what file those strings where once a part of.
|
||||
|
|
@ -5,11 +5,9 @@ For an introduction and motivation to using batch processors, see [here](./Batch
|
|||
page describes the Batch-*command* processor. The Batch-*code* one is covered [here](Batch-Code-
|
||||
Processor).
|
||||
|
||||
## Basic Usage
|
||||
|
||||
The batch-command processor is a superuser-only function, invoked by
|
||||
|
||||
> @batchcommand path.to.batchcmdfile
|
||||
> batchcommand path.to.batchcmdfile
|
||||
|
||||
Where `path.to.batchcmdfile` is the path to a *batch-command file* with the "`.ev`" file ending.
|
||||
This path is given like a python path relative to a folder you define to hold your batch files, set
|
||||
|
|
@ -17,7 +15,7 @@ with `BATCH_IMPORT_PATH` in your settings. Default folder is (assuming your game
|
|||
folder) `mygame/world`. So if you want to run the example batch file in
|
||||
`mygame/world/batch_cmds.ev`, you could use
|
||||
|
||||
> @batchcommand batch_cmds
|
||||
> batchcommand batch_cmds
|
||||
|
||||
A batch-command file contains a list of Evennia in-game commands separated by comments. The
|
||||
processor will run the batch file from beginning to end. Note that *it will not stop if commands in
|
||||
|
|
@ -32,23 +30,12 @@ them in-game, except you have more freedom with line breaks.
|
|||
|
||||
Here are the rules of syntax of an `*.ev` file. You'll find it's really, really simple:
|
||||
|
||||
- All lines having the `#` (hash)-symbol *as the first one on the line* are considered *comments*.
|
||||
All non-comment lines are treated as a command and/or their arguments.
|
||||
- Comment lines have an actual function -- they mark the *end of the previous command definition*.
|
||||
So never put two commands directly after one another in the file - separate them with a comment, or
|
||||
the second of the two will be considered an argument to the first one. Besides, using plenty of
|
||||
comments is good practice anyway.
|
||||
- A line that starts with the word `#INSERT` is a comment line but also signifies a special
|
||||
instruction. The syntax is `#INSERT <path.batchfile>` and tries to import a given batch-cmd file
|
||||
into this one. The inserted batch file (file ending `.ev`) will run normally from the point of the
|
||||
`#INSERT` instruction.
|
||||
- Extra whitespace in a command definition is *ignored*. - A completely empty line translates in to
|
||||
a line break in texts. Two empty lines thus means a new paragraph (this is obviously only relevant
|
||||
for commands accepting such formatting, such as the `@desc` command).
|
||||
- All lines having the `#` (hash)-symbol *as the first one on the line* are considered *comments*. All non-comment lines are treated as a command and/or their arguments.
|
||||
- Comment lines have an actual function -- they mark the *end of the previous command definition*. So never put two commands directly after one another in the file - separate them with a comment, or the second of the two will be considered an argument to the first one. Besides, using plenty of comments is good practice anyway.
|
||||
- A line that starts with the word `#INSERT` is a comment line but also signifies a special instruction. The syntax is `#INSERT <path.batchfile>` and tries to import a given batch-cmd file into this one. The inserted batch file (file ending `.ev`) will run normally from the point of the `#INSERT` instruction.
|
||||
- Extra whitespace in a command definition is *ignored*. - A completely empty line translates in to a line break in texts. Two empty lines thus means a new paragraph (this is obviously only relevant for commands accepting such formatting, such as the `@desc` command).
|
||||
- The very last command in the file is not required to end with a comment.
|
||||
- You *cannot* nest another `@batchcommand` statement into your batch file. If you want to link many
|
||||
batch-files together, use the `#INSERT` batch instruction instead. You also cannot launch the
|
||||
`@batchcode` command from your batch file, the two batch processors are not compatible.
|
||||
- You *cannot* nest another `batchcommand` statement into your batch file. If you want to link many batch-files together, use the `#INSERT` batch instruction instead. You also cannot launch the `batchcode` command from your batch file, the two batch processors are not compatible.
|
||||
|
||||
Below is a version of the example file found in `evennia/contrib/tutorial_examples/batch_cmds.ev`.
|
||||
|
||||
|
|
@ -97,21 +84,15 @@ Below is a version of the example file found in `evennia/contrib/tutorial_exampl
|
|||
|
||||
To test this, run `@batchcommand` on the file:
|
||||
|
||||
> @batchcommand contrib.tutorial_examples.batch_cmds
|
||||
> batchcommand contrib.tutorial_examples.batch_cmds
|
||||
|
||||
A button will be created, described and dropped in Limbo. All commands will be executed by the user
|
||||
calling the command.
|
||||
A button will be created, described and dropped in Limbo. All commands will be executed by the user calling the command.
|
||||
|
||||
> Note that if you interact with the button, you might find that its description changes, loosing
|
||||
your custom-set description above. This is just the way this particular object works.
|
||||
> Note that if you interact with the button, you might find that its description changes, loosing your custom-set description above. This is just the way this particular object works.
|
||||
|
||||
## Interactive mode
|
||||
|
||||
Interactive mode allows you to more step-wise control over how the batch file is executed. This is
|
||||
useful for debugging and also if you have a large batch file and is only updating a small part of it
|
||||
-- running the entire file again would be a waste of time (and in the case of `@create`-ing objects
|
||||
you would to end up with multiple copies of same-named objects, for example). Use `@batchcommand`
|
||||
with the `/interactive` flag to enter interactive mode.
|
||||
Interactive mode allows you to more step-wise control over how the batch file is executed. This is useful for debugging and also if you have a large batch file and is only updating a small part of it -- running the entire file again would be a waste of time (and in the case of `create`-ing objects you would to end up with multiple copies of same-named objects, for example). Use `batchcommand` with the `/interactive` flag to enter interactive mode.
|
||||
|
||||
> @batchcommand/interactive tutorial_examples.batch_cmds
|
||||
|
||||
|
|
@ -119,64 +100,31 @@ You will see this:
|
|||
|
||||
01/04: @create button:tutorial_examples.red_button.RedButton (hh for help)
|
||||
|
||||
This shows that you are on the `@create` command, the first out of only four commands in this batch
|
||||
file. Observe that the command `@create` has *not* been actually processed at this point!
|
||||
This shows that you are on the `@create` command, the first out of only four commands in this batch file. Observe that the command `@create` has *not* been actually processed at this point!
|
||||
|
||||
To take a look at the full command you are about to run, use `ll` (a batch-processor version of
|
||||
`look`). Use `pp` to actually process the current command (this will actually `@create` the button)
|
||||
-- and make sure it worked as planned. Use `nn` (next) to go to the next command. Use `hh` for a
|
||||
list of commands.
|
||||
`look`). Use `pp` to actually process the current command (this will actually `@create` the button) -- and make sure it worked as planned. Use `nn` (next) to go to the next command. Use `hh` for a list of commands.
|
||||
|
||||
If there are errors, fix them in the batch file, then use `rr` to reload the file. You will still be
|
||||
at the same command and can rerun it easily with `pp` as needed. This makes for a simple debug
|
||||
cycle. It also allows you to rerun individual troublesome commands - as mentioned, in a large batch
|
||||
file this can be very useful. Do note that in many cases, commands depend on the previous ones (e.g.
|
||||
if `@create` in the example above had failed, the following commands would have had nothing to
|
||||
operate on).
|
||||
If there are errors, fix them in the batch file, then use `rr` to reload the file. You will still be at the same command and can rerun it easily with `pp` as needed. This makes for a simple debug cycle. It also allows you to rerun individual troublesome commands - as mentioned, in a large batch file this can be very useful. Do note that in many cases, commands depend on the previous ones (e.g. if `create` in the example above had failed, the following commands would have had nothing to operate on).
|
||||
|
||||
Use `nn` and `bb` (next and back) to step through the file; e.g. `nn 12` will jump 12 steps forward
|
||||
(without processing any command in between). All normal commands of Evennia should work too while
|
||||
working in interactive mode.
|
||||
Use `nn` and `bb` (next and back) to step through the file; e.g. `nn 12` will jump 12 steps forward (without processing any command in between). All normal commands of Evennia should work too while working in interactive mode.
|
||||
|
||||
## Limitations and Caveats
|
||||
|
||||
The batch-command processor is great for automating smaller builds or for testing new commands and
|
||||
objects repeatedly without having to write so much. There are several caveats you have to be aware
|
||||
of when using the batch-command processor for building larger, complex worlds though.
|
||||
The batch-command processor is great for automating smaller builds or for testing new commands and objects repeatedly without having to write so much. There are several caveats you have to be aware of when using the batch-command processor for building larger, complex worlds though.
|
||||
|
||||
The main issue is that when you run a batch-command script you (*you*, as in your superuser
|
||||
character) are actually moving around in the game creating and building rooms in sequence, just as
|
||||
if you had been entering those commands manually, one by one. You have to take this into account
|
||||
when creating the file, so that you can 'walk' (or teleport) to the right places in order.
|
||||
character) are actually moving around in the game creating and building rooms in sequence, just as if you had been entering those commands manually, one by one. You have to take this into account when creating the file, so that you can 'walk' (or teleport) to the right places in order.
|
||||
|
||||
This also means there are several pitfalls when designing and adding certain types of objects. Here
|
||||
are some examples:
|
||||
This also means there are several pitfalls when designing and adding certain types of objects. Here are some examples:
|
||||
|
||||
- *Rooms that change your [Command Set](./Command-Sets.md)*: Imagine that you build a 'dark' room, which
|
||||
severely limits the cmdsets of those entering it (maybe you have to find the light switch to
|
||||
proceed). In your batch script you would create this room, then teleport to it - and promptly be
|
||||
shifted into the dark state where none of your normal build commands work ...
|
||||
- *Auto-teleportation*: Rooms that automatically teleport those that enter them to another place
|
||||
(like a trap room, for example). You would be teleported away too.
|
||||
- *Mobiles*: If you add aggressive mobs, they might attack you, drawing you into combat. If they
|
||||
have AI they might even follow you around when building - or they might move away from you before
|
||||
you've had time to finish describing and equipping them!
|
||||
- *Rooms that change your [Command Set](./Command-Sets.md)*: Imagine that you build a 'dark' room, which severely limits the cmdsets of those entering it (maybe you have to find the light switch to proceed). In your batch script you would create this room, then teleport to it - and promptly be shifted into the dark state where none of your normal build commands work ...
|
||||
- *Auto-teleportation*: Rooms that automatically teleport those that enter them to another place (like a trap room, for example). You would be teleported away too.
|
||||
- *Mobiles*: If you add aggressive mobs, they might attack you, drawing you into combat. If they have AI they might even follow you around when building - or they might move away from you before you've had time to finish describing and equipping them!
|
||||
|
||||
The solution to all these is to plan ahead. Make sure that superusers are never affected by whatever
|
||||
effects are in play. Add an on/off switch to objects and make sure it's always set to *off* upon
|
||||
creation. It's all doable, one just needs to keep it in mind.
|
||||
The solution to all these is to plan ahead. Make sure that superusers are never affected by whatever effects are in play. Add an on/off switch to objects and make sure it's always set to *off* upon creation. It's all doable, one just needs to keep it in mind.
|
||||
|
||||
## Assorted notes
|
||||
## Editor highlighting for .ev files
|
||||
|
||||
The fact that you build as 'yourself' can also be considered an advantage however, should you ever
|
||||
decide to change the default command to allow others than superusers to call the processor. Since
|
||||
normal access-checks are still performed, a malevolent builder with access to the processor should
|
||||
not be able to do all that much damage (this is the main drawback of the [Batch Code
|
||||
Processor](./Batch-Code-Processor.md))
|
||||
|
||||
- [GNU Emacs](https://www.gnu.org/software/emacs/) users might find it interesting to use emacs'
|
||||
*evennia mode*. This is an Emacs major mode found in `evennia/utils/evennia-mode.el`. It offers
|
||||
correct syntax highlighting and indentation with `<tab>` when editing `.ev` files in Emacs. See the
|
||||
header of that file for installation instructions.
|
||||
- [VIM](https://www.vim.org/) users can use amfl's [vim-evennia](https://github.com/amfl/vim-evennia)
|
||||
mode instead, see its readme for install instructions.
|
||||
- [GNU Emacs](https://www.gnu.org/software/emacs/) users might find it interesting to use emacs' *evennia mode*. This is an Emacs major mode found in `evennia/utils/evennia-mode.el`. It offers correct syntax highlighting and indentation with `<tab>` when editing `.ev` files in Emacs. See the header of that file for installation instructions.
|
||||
- [VIM](https://www.vim.org/) users can use amfl's [vim-evennia](https://github.com/amfl/vim-evennia) mode instead, see its readme for install instructions.
|
||||
|
|
@ -1,33 +1,23 @@
|
|||
# Batch Processors
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 2
|
||||
|
||||
Building a game world is a lot of work, especially when starting out. Rooms should be created,
|
||||
descriptions have to be written, objects must be detailed and placed in their proper places. In many
|
||||
Batch-Command-Processor.md
|
||||
Batch-Code-Processor.md
|
||||
```
|
||||
|
||||
Building a game world is a lot of work, especially when starting out. Rooms should be created, descriptions have to be written, objects must be detailed and placed in their proper places. In many
|
||||
traditional MUD setups you had to do all this online, line by line, over a telnet session.
|
||||
|
||||
Evennia already moves away from much of this by shifting the main coding work to external Python
|
||||
modules. But also building would be helped if one could do some or all of it externally. Enter
|
||||
Evennia's *batch processors* (there are two of them). The processors allows you, as a game admin, to
|
||||
build your game completely offline in normal text files (*batch files*) that the processors
|
||||
understands. Then, when you are ready, you use the processors to read it all into Evennia (and into
|
||||
the database) in one go.
|
||||
|
||||
You can of course still build completely online should you want to - this is certainly the easiest
|
||||
way to go when learning and for small build projects. But for major building work, the advantages of
|
||||
using the batch-processors are many:
|
||||
- It's hard to compete with the comfort of a modern desktop text editor; Compared to a traditional
|
||||
MUD line input, you can get much better overview and many more features. Also, accidentally pressing
|
||||
Return won't immediately commit things to the database.
|
||||
- You might run external spell checkers on your batch files. In the case of one of the batch-
|
||||
processors (the one that deals with Python code), you could also run external debuggers and code
|
||||
analyzers on your file to catch problems before feeding it to Evennia.
|
||||
- The batch files (as long as you keep them) are records of your work. They make a natural starting
|
||||
point for quickly re-building your world should you ever decide to start over.
|
||||
- If you are an Evennia developer, using a batch file is a fast way to setup a test-game after
|
||||
having reset the database.
|
||||
- The batch files might come in useful should you ever decide to distribute all or part of your
|
||||
world to others.
|
||||
Evennia already moves away from much of this by shifting the main coding work to external Python modules. But also building would be helped if one could do some or all of it externally. Enter Evennia's *batch processors* (there are two of them). The processors allows you, as a game admin, to build your game completely offline in normal text files (*batch files*) that the processors understands. Then, when you are ready, you use the processors to read it all into Evennia (and into the database) in one go.
|
||||
|
||||
You can of course still build completely online should you want to - this is certainly the easiest way to go when learning and for small build projects. But for major building work, the advantages of using the batch-processors are many:
|
||||
- It's hard to compete with the comfort of a modern desktop text editor; Compared to a traditional MUD line input, you can get much better overview and many more features. Also, accidentally pressing Return won't immediately commit things to the database.
|
||||
- You might run external spell checkers on your batch files. In the case of one of the batch- processors (the one that deals with Python code), you could also run external debuggers and code analyzers on your file to catch problems before feeding it to Evennia.
|
||||
- The batch files (as long as you keep them) are records of your work. They make a natural starting point for quickly re-building your world should you ever decide to start over.
|
||||
- If you are an Evennia developer, using a batch file is a fast way to setup a test-game after having reset the database.
|
||||
- The batch files might come in useful should you ever decide to distribute all or part of your world to others.
|
||||
|
||||
There are two batch processors, the Batch-*command* processor and the Batch-*code* processor. The
|
||||
first one is the simpler of the two. It doesn't require any programming knowledge - you basically
|
||||
|
|
@ -35,48 +25,23 @@ just list in-game commands in a text file. The code-processor on the other hand
|
|||
powerful but also more complex - it lets you use Evennia's API to code your world in full-fledged
|
||||
Python code.
|
||||
|
||||
- The [Batch Command Processor](./Batch-Command-Processor.md)
|
||||
- The [Batch Code Processor](./Batch-Code-Processor.md)
|
||||
|
||||
If you plan to use international characters in your batchfiles you are wise to read about *file
|
||||
encodings* below.
|
||||
|
||||
## A note on File Encodings
|
||||
|
||||
As mentioned, both the processors take text files as input and then proceed to process them. As long
|
||||
as you stick to the standard [ASCII](https://en.wikipedia.org/wiki/Ascii) character set (which means
|
||||
the normal English characters, basically) you should not have to worry much about this section.
|
||||
As mentioned, both the processors take text files as input and then proceed to process them. As long as you stick to the standard [ASCII](https://en.wikipedia.org/wiki/Ascii) character set (which means the normal English characters, basically) you should not have to worry much about this section.
|
||||
|
||||
Many languages however use characters outside the simple `ASCII` table. Common examples are various
|
||||
apostrophes and umlauts but also completely different symbols like those of the greek or cyrillic
|
||||
alphabets.
|
||||
Many languages however use characters outside the simple `ASCII` table. Common examples are various apostrophes and umlauts but also completely different symbols like those of the greek or cyrillic alphabets.
|
||||
|
||||
First, we should make it clear that Evennia itself handles international characters just fine. It
|
||||
(and Django) uses [unicode](https://en.wikipedia.org/wiki/Unicode) strings internally.
|
||||
First, we should make it clear that Evennia itself handles international characters just fine. It (and Django) uses [unicode](https://en.wikipedia.org/wiki/Unicode) strings internally.
|
||||
|
||||
The problem is that when reading a text file like the batchfile, we need to know how to decode the
|
||||
byte-data stored therein to universal unicode. That means we need an *encoding* (a mapping) for how
|
||||
the file stores its data. There are many, many byte-encodings used around the world, with opaque
|
||||
names such as `Latin-1`, `ISO-8859-3` or `ARMSCII-8` to pick just a few examples. Problem is that
|
||||
it's practially impossible to determine which encoding was used to save a file just by looking at it
|
||||
(it's just a bunch of bytes!). You have to *know*.
|
||||
The problem is that when reading a text file like the batchfile, we need to know how to decode the byte-data stored therein to universal unicode. That means we need an *encoding* (a mapping) for how the file stores its data. There are many, many byte-encodings used around the world, with opaque names such as `Latin-1`, `ISO-8859-3` or `ARMSCII-8` to pick just a few examples. Problem is that it's practially impossible to determine which encoding was used to save a file just by looking at it (it's just a bunch of bytes!). You have to *know*.
|
||||
|
||||
With this little introduction it should be clear that Evennia can't guess but has to *assume* an
|
||||
encoding when trying to load a batchfile. The text editor and Evennia must speak the same "language"
|
||||
so to speak. Evennia will by default first try the international `UTF-8` encoding, but you can have
|
||||
Evennia try any sequence of different encodings by customizing the `ENCODINGS` list in your settings
|
||||
file. Evennia will use the first encoding in the list that do not raise any errors. Only if none
|
||||
work will the server give up and return an error message.
|
||||
With this little introduction it should be clear that Evennia can't guess but has to *assume* an encoding when trying to load a batchfile. The text editor and Evennia must speak the same "language" so to speak. Evennia will by default first try the international `UTF-8` encoding, but you can have Evennia try any sequence of different encodings by customizing the `ENCODINGS` list in your settings file. Evennia will use the first encoding in the list that do not raise any errors. Only if none work will the server give up and return an error message.
|
||||
|
||||
You can often change the text editor encoding (this depends on your editor though), otherwise you
|
||||
need to add the editor's encoding to Evennia's `ENCODINGS` list. If you are unsure, write a test
|
||||
file with lots of non-ASCII letters in the editor of your choice, then import to make sure it works
|
||||
as it should.
|
||||
You can often change the text editor encoding (this depends on your editor though), otherwise you need to add the editor's encoding to Evennia's `ENCODINGS` list. If you are unsure, write a test file with lots of non-ASCII letters in the editor of your choice, then import to make sure it works as it should.
|
||||
|
||||
More help with encodings can be found in the entry [Text Encodings](../Concepts/Text-Encodings.md) and also in the
|
||||
Wikipedia article [here](https://en.wikipedia.org/wiki/Text_encodings).
|
||||
More help with encodings can be found in the entry [Text Encodings](../Concepts/Text-Encodings.md) and also in the Wikipedia article [here](https://en.wikipedia.org/wiki/Text_encodings).
|
||||
|
||||
**A footnote for the batch-code processor**: Just because *Evennia* can parse your file and your
|
||||
fancy special characters, doesn't mean that *Python* allows their use. Python syntax only allows
|
||||
international characters inside *strings*. In all other source code only `ASCII` set characters are
|
||||
fancy special characters, doesn't mean that *Python* allows their use. Python syntax only allows international characters inside *strings*. In all other source code only `ASCII` set characters are
|
||||
allowed.
|
||||
|
|
|
|||
|
|
@ -27,16 +27,14 @@ Channels can be used both for chats between [Accounts](./Accounts.md) and betwee
|
|||
|
||||
```
|
||||
|
||||
## Using channels in-game
|
||||
|
||||
In the default command set, channels are all handled via the mighty
|
||||
[channel
|
||||
command](evennia.commands.default.comms.CmdChannel), `channel` (or
|
||||
`chan`). By default, this command will assume all entities dealing with
|
||||
channels are `Accounts`.
|
||||
## Working with channels
|
||||
|
||||
### Viewing and joining channels
|
||||
|
||||
In the default command set, channels are all handled via the mighty [channel command](evennia.commands.default.comms.CmdChannel), `channel` (or `chan`). By default, this command will assume all entities dealing with channels are `Accounts`.
|
||||
|
||||
Viewing channels
|
||||
|
||||
channel - shows your subscriptions
|
||||
channel/all - shows all subs available to you
|
||||
channel/who - shows who subscribes to this channel
|
||||
|
|
@ -52,7 +50,7 @@ unsubscribing), you can mute it:
|
|||
channel/mute channelname
|
||||
channel/unmute channelname
|
||||
|
||||
### Chat on channels
|
||||
### Talk on channels
|
||||
|
||||
To speak on a channel, do
|
||||
|
||||
|
|
@ -141,8 +139,7 @@ Banning adds the user to the channels blacklist. This means they will not be
|
|||
able to _rejoin_ if you boot them. You will need to run `channel/boot` to
|
||||
actually kick them out.
|
||||
|
||||
See the [Channel command](evennia.commands.default.comms.CmdChannel) api
|
||||
docs (and in-game help) for more details.
|
||||
See the [Channel command](evennia.commands.default.comms.CmdChannel) api docs (and in-game help) for more details.
|
||||
|
||||
Admin-level users can also modify channel's [locks](./Locks.md):
|
||||
|
||||
|
|
@ -159,11 +156,7 @@ Channels use three lock-types by default:
|
|||
|
||||
#### Restricting channel administration
|
||||
|
||||
By default everyone can use the channel command ([evennia.commands.default.comms.CmdChannel](evennia.commands.default.comms.CmdChannel))
|
||||
to create channels and will then control the channels they created (to boot/ban
|
||||
people etc). If you as a developer does not want regular players to do this
|
||||
(perhaps you want only staff to be able to spawn new channels), you can
|
||||
override the `channel` command and change its `locks` property.
|
||||
By default everyone can use the channel command ([evennia.commands.default.comms.CmdChannel](evennia.commands.default.comms.CmdChannel)) to create channels and will then control the channels they created (to boot/ban people etc). If you as a developer does not want regular players to do this (perhaps you want only staff to be able to spawn new channels), you can override the `channel` command and change its `locks` property.
|
||||
|
||||
The default `help` command has the following `locks` property:
|
||||
|
||||
|
|
@ -203,19 +196,19 @@ channels you could override the `help` command and change the lockstring to:
|
|||
Add this custom command to your default cmdset and regular users wil now get an
|
||||
access-denied error when trying to use use these switches.
|
||||
|
||||
## Allowing Characters to use Channels
|
||||
## Using channels in code
|
||||
|
||||
The default `channel` command ([evennia.commands.default.comms.CmdChannel](evennia.commands.default.comms.CmdChannel))
|
||||
sits in the `Account` [command set](./Command-Sets.md). It is set up such that it will
|
||||
always operate on `Accounts`, even if you were to add it to the
|
||||
`CharacterCmdSet`.
|
||||
For most common changes, the default channel, the recipient hooks and possibly
|
||||
overriding the `channel` command will get you very far. But you can also tweak
|
||||
channels themselves.
|
||||
|
||||
It's a one-line change to make this command accept non-account callers. But for
|
||||
convenience we provide a version for Characters/Objects. Just import
|
||||
[evennia.commands.default.comms.CmdObjectChannel](evennia.commands.default.comms.CmdObjectChannel)
|
||||
and inherit from that instead.
|
||||
### Allowing Characters to use Channels
|
||||
|
||||
## Customizing channel output and behavior
|
||||
The default `channel` command ([evennia.commands.default.comms.CmdChannel](evennia.commands.default.comms.CmdChannel)) sits in the `Account` [command set](./Command-Sets.md). It is set up such that it will always operate on `Accounts`, even if you were to add it to the `CharacterCmdSet`.
|
||||
|
||||
It's a one-line change to make this command accept non-account callers. But for convenience we provide a version for Characters/Objects. Just import [evennia.commands.default.comms.CmdObjectChannel](evennia.commands.default.comms.CmdObjectChannel) and inherit from that instead.
|
||||
|
||||
### Customizing channel output and behavior
|
||||
|
||||
When distributing a message, the channel will call a series of hooks on itself
|
||||
and (more importantly) on each recipient. So you can customize things a lot by
|
||||
|
|
@ -243,21 +236,11 @@ Note that `Accounts` and `Objects` both have their have separate sets of hooks.
|
|||
So make sure you modify the set actually used by your subcribers (or both).
|
||||
Default channels all use `Account` subscribers.
|
||||
|
||||
## Channels in code
|
||||
### Channel class
|
||||
|
||||
For most common changes, the default channel, the recipient hooks and possibly
|
||||
overriding the `channel` command will get you very far. But you can also tweak
|
||||
channels themselves.
|
||||
Channels are [Typeclassed](./Typeclasses.md) entities. This means they are persistent in the database, can have [attributes](./Attributes.md) and [Tags](./Tags.md) and can be easily extended.
|
||||
|
||||
Channels are [Typeclassed](./Typeclasses.md) entities. This means they are
|
||||
persistent in the database, can have [attributes](./Attributes.md) and [Tags](./Tags.md)
|
||||
and can be easily extended.
|
||||
|
||||
To change which channel typeclass Evennia uses for default commands, change
|
||||
`settings.BASE_CHANNEL_TYPECLASS`. The base command class is
|
||||
[`evennia.comms.comms.DefaultChannel`](evennia.comms.comms.DefaultChannel).
|
||||
There is an empty child class in `mygame/typeclasses/channels.py`, same
|
||||
as for other typelass-bases.
|
||||
To change which channel typeclass Evennia uses for default commands, change `settings.BASE_CHANNEL_TYPECLASS`. The base command class is [`evennia.comms.comms.DefaultChannel`](evennia.comms.comms.DefaultChannel). There is an empty child class in `mygame/typeclasses/channels.py`, same as for other typelass-bases.
|
||||
|
||||
In code you create a new channel with `evennia.create_channel` or
|
||||
`Channel.create`:
|
||||
|
|
@ -294,11 +277,10 @@ In code you create a new channel with `evennia.create_channel` or
|
|||
The Channel's `.connect` method will accept both `Account` and `Object` subscribers
|
||||
and will handle them transparently.
|
||||
|
||||
The channel has many more hooks, both hooks shared with all typeclasses as well
|
||||
as special ones related to muting/banning etc. See the channel class for
|
||||
The channel has many more hooks, both hooks shared with all typeclasses as well as special ones related to muting/banning etc. See the channel class for
|
||||
details.
|
||||
|
||||
## Channel logging
|
||||
### Channel logging
|
||||
|
||||
```{versionchanged} 0.7
|
||||
|
||||
|
|
@ -309,11 +291,7 @@ details.
|
|||
Channels stopped supporting Msg and TmpMsg, using only log files.
|
||||
```
|
||||
|
||||
The channel messages are not stored in the database. A channel is instead
|
||||
always logged to a regular text log-file
|
||||
`mygame/server/logs/channel_<channelname>.log`. This is where `channels/history channelname`
|
||||
gets its data from. A channel's log will rotate when it grows too big, which
|
||||
thus also automatically limits the max amount of history a user can view with
|
||||
The channel messages are not stored in the database. A channel is instead always logged to a regular text log-file `mygame/server/logs/channel_<channelname>.log`. This is where `channels/history channelname` gets its data from. A channel's log will rotate when it grows too big, which thus also automatically limits the max amount of history a user can view with
|
||||
`/history`.
|
||||
|
||||
The log file name is set on the channel class as the `log_file` property. This
|
||||
|
|
@ -321,7 +299,6 @@ is a string that takes the formatting token `{channelname}` to be replaced with
|
|||
the (lower-case) name of the channel. By default the log is written to in the
|
||||
channel's `at_post_channel_msg` method.
|
||||
|
||||
|
||||
### Properties on Channels
|
||||
|
||||
Channels have all the standard properties of a Typeclassed entity (`key`,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
Evennia comes with many utilities to help with common coding tasks. Most are accessible directly
|
||||
from the flat API, otherwise you can find them in the `evennia/utils/` folder.
|
||||
|
||||
> This is just a small selection of the tools in `evennia/utils`. It's worth to browse [the directory](evennia.utils) and in particular the content of [evennia/utils/utils.py](evennia.utils.utils) directly to find more useful stuff.
|
||||
|
||||
## Searching
|
||||
|
||||
A common thing to do is to search for objects. There it's easiest to use the `search` method defined
|
||||
|
|
@ -13,13 +15,9 @@ on all objects. This will search for objects in the same location and inside the
|
|||
obj = self.search(objname)
|
||||
```
|
||||
|
||||
The most common time one needs to do this is inside a command body. `obj =
|
||||
self.caller.search(objname)` will search inside the caller's (typically, the character that typed
|
||||
the command) `.contents` (their "inventory") and `.location` (their "room").
|
||||
The most common time one needs to do this is inside a command body. `obj = self.caller.search(objname)` will search inside the caller's (typically, the character that typed the command) `.contents` (their "inventory") and `.location` (their "room").
|
||||
|
||||
Give the keyword `global_search=True` to extend search to encompass entire database. Aliases will
|
||||
also be matched by this search. You will find multiple examples of this functionality in the default
|
||||
command set.
|
||||
Give the keyword `global_search=True` to extend search to encompass entire database. Aliases will also be matched by this search. You will find multiple examples of this functionality in the default command set.
|
||||
|
||||
If you need to search for objects in a code module you can use the functions in
|
||||
`evennia.utils.search`. You can access these as shortcuts `evennia.search_*`.
|
||||
|
|
@ -29,42 +27,39 @@ If you need to search for objects in a code module you can use the functions in
|
|||
obj = search_object(objname)
|
||||
```
|
||||
|
||||
- [`evennia.search_account`](evennia.accounts.manager.AccountDBManager.search_account)
|
||||
- [`evennia.search_object`](evennia.objects.manager.ObjectDBManager.search_object)
|
||||
- [`evennia.search(object)_by_tag`](evennia.utils.search.search_tag)
|
||||
- [`evennia.search_script`](evennia.scripts.manager.ScriptDBManager.search_script)
|
||||
- [`evennia.search_channel`](evennia.comms.managers.ChannelDBManager.search_channel)
|
||||
- [`evennia.search_message`](evennia.comms.managers.MsgManager.search_message)
|
||||
- [`evennia.search_help`](evennia.help.manager.HelpEntryManager.search_help)
|
||||
- [evennia.search_account](evennia.accounts.manager.AccountDBManager.search_account)
|
||||
- [evennia.search_object](evennia.objects.manager.ObjectDBManager.search_object)
|
||||
- [evennia.search(object)_by_tag](evennia.utils.search.search_tag)
|
||||
- [evennia.search_script](evennia.scripts.manager.ScriptDBManager.search_script)
|
||||
- [evennia.search_channel](evennia.comms.managers.ChannelDBManager.search_channel)
|
||||
- [evennia.search_message](evennia.comms.managers.MsgManager.search_message)
|
||||
- [evennia.search_help](evennia.help.manager.HelpEntryManager.search_help)
|
||||
|
||||
Note that these latter methods will always return a `list` of results, even if the list has one or
|
||||
zero entries.
|
||||
Note that these latter methods will always return a `list` of results, even if the list has one or zero entries.
|
||||
|
||||
## Create
|
||||
|
||||
Apart from the in-game build commands (`@create` etc), you can also build all of Evennia's game
|
||||
entities directly in code (for example when defining new create commands).
|
||||
Apart from the in-game build commands (`@create` etc), you can also build all of Evennia's game entities directly in code (for example when defining new create commands).
|
||||
|
||||
```python
|
||||
import evennia
|
||||
|
||||
myobj = evennia.create_objects("game.gamesrc.objects.myobj.MyObj", key="MyObj")
|
||||
```
|
||||
|
||||
- [`evennia.create_account`](evennia.utils.create.create_account)
|
||||
- [`evennia.create_object`](evennia.utils.create.create_object)
|
||||
- [`evennia.create_script`](evennia.utils.create.create_script)
|
||||
- [`evennia.create_channel`](evennia.utils.create.create_channel)
|
||||
- [`evennia.create_help_entry`](evennia.utils.create.create_help_entry)
|
||||
- [`evennia.create_message`](evennia.utils.create.create_message)
|
||||
- [evennia.create_account](evennia.utils.create.create_account)
|
||||
- [evennia.create_object](evennia.utils.create.create_object)
|
||||
- [evennia.create_script](evennia.utils.create.create_script)
|
||||
- [evennia.create_channel](evennia.utils.create.create_channel)
|
||||
- [evennia.create_help_entry](evennia.utils.create.create_help_entry)
|
||||
- [evennia.create_message](evennia.utils.create.create_message)
|
||||
|
||||
Each of these create-functions have a host of arguments to further customize the created entity. See
|
||||
`evennia/utils/create.py` for more information.
|
||||
Each of these create-functions have a host of arguments to further customize the created entity. See `evennia/utils/create.py` for more information.
|
||||
|
||||
## Logging
|
||||
|
||||
Normally you can use Python `print` statements to see output to the terminal/log. The `print`
|
||||
statement should only be used for debugging though. For producion output, use the `logger` which
|
||||
will create proper logs either to terminal or to file.
|
||||
statement should only be used for debugging though. For producion output, use the `logger` which will create proper logs either to terminal or to file.
|
||||
|
||||
```python
|
||||
from evennia import logger
|
||||
|
|
@ -75,8 +70,7 @@ will create proper logs either to terminal or to file.
|
|||
logger.log_dep("This feature is deprecated")
|
||||
```
|
||||
|
||||
There is a special log-message type, `log_trace()` that is intended to be called from inside a
|
||||
traceback - this can be very useful for relaying the traceback message back to log without having it
|
||||
There is a special log-message type, `log_trace()` that is intended to be called from inside a traceback - this can be very useful for relaying the traceback message back to log without having it
|
||||
kill the server.
|
||||
|
||||
```python
|
||||
|
|
@ -86,25 +80,21 @@ kill the server.
|
|||
logger.log_trace("This text will show beneath the traceback itself.")
|
||||
```
|
||||
|
||||
The `log_file` logger, finally, is a very useful logger for outputting arbitrary log messages. This
|
||||
is a heavily optimized asynchronous log mechanism using
|
||||
[threads](https://en.wikipedia.org/wiki/Thread_%28computing%29) to avoid overhead. You should be
|
||||
able to use it for very heavy custom logging without fearing disk-write delays.
|
||||
The `log_file` logger, finally, is a very useful logger for outputting arbitrary log messages. This is a heavily optimized asynchronous log mechanism using [threads](https://en.wikipedia.org/wiki/Thread_%28computing%29) to avoid overhead. You should be able to use it for very heavy custom logging without fearing disk-write delays.
|
||||
|
||||
```python
|
||||
logger.log_file(message, filename="mylog.log")
|
||||
```
|
||||
|
||||
If not an absolute path is given, the log file will appear in the `mygame/server/logs/` directory.
|
||||
If the file already exists, it will be appended to. Timestamps on the same format as the normal
|
||||
Evennia logs will be automatically added to each entry. If a filename is not specified, output will
|
||||
be written to a file `game/logs/game.log`.
|
||||
If not an absolute path is given, the log file will appear in the `mygame/server/logs/` directory. If the file already exists, it will be appended to. Timestamps on the same format as the normal Evennia logs will be automatically added to each entry. If a filename is not specified, output will be written to a file `game/logs/game.log`.
|
||||
|
||||
See also the [Debugging](../Coding/Debugging.md) documentation for help with finding elusive bugs.
|
||||
|
||||
## Time Utilities
|
||||
|
||||
### Game time
|
||||
|
||||
Evennia tracks the current server time. You can access this time via the `evennia.gametime`
|
||||
shortcut:
|
||||
Evennia tracks the current server time. You can access this time via the `evennia.gametime` shortcut:
|
||||
|
||||
```python
|
||||
from evennia import gametime
|
||||
|
|
@ -131,13 +121,8 @@ gametime.reset_gametime()
|
|||
|
||||
```
|
||||
|
||||
The setting `TIME_FACTOR` determines how fast/slow in-game time runs compared to the real world. The
|
||||
setting `TIME_GAME_EPOCH` sets the starting game epoch (in seconds). The functions from the
|
||||
`gametime` module all return their times in seconds. You can convert this to whatever units of time
|
||||
you desire for your game. You can use the `@time` command to view the server time info.
|
||||
|
||||
You can also *schedule* things to happen at specific in-game times using the
|
||||
[gametime.schedule](evennia.utils.gametime.schedule) function:
|
||||
The setting `TIME_FACTOR` determines how fast/slow in-game time runs compared to the real world. The setting `TIME_GAME_EPOCH` sets the starting game epoch (in seconds). The functions from the `gametime` module all return their times in seconds. You can convert this to whatever units of time you desire for your game. You can use the `@time` command to view the server time info.
|
||||
You can also *schedule* things to happen at specific in-game times using the [gametime.schedule](evennia.utils.gametime.schedule) function:
|
||||
|
||||
```python
|
||||
import evennia
|
||||
|
|
@ -151,9 +136,7 @@ gametime.schedule(church_clock, hour=2)
|
|||
|
||||
### utils.time_format()
|
||||
|
||||
This function takes a number of seconds as input (e.g. from the `gametime` module above) and
|
||||
converts it to a nice text output in days, hours etc. It's useful when you want to show how old
|
||||
something is. It converts to four different styles of output using the *style* keyword:
|
||||
This function takes a number of seconds as input (e.g. from the `gametime` module above) and converts it to a nice text output in days, hours etc. It's useful when you want to show how old something is. It converts to four different styles of output using the *style* keyword:
|
||||
|
||||
- style 0 - `5d:45m:12s` (standard colon output)
|
||||
- style 1 - `5d` (shows only the longest time unit)
|
||||
|
|
@ -162,6 +145,8 @@ something is. It converts to four different styles of output using the *style* k
|
|||
|
||||
### utils.delay()
|
||||
|
||||
This allows for making a delayed call.
|
||||
|
||||
```python
|
||||
from evennia import utils
|
||||
|
||||
|
|
@ -169,44 +154,23 @@ def _callback(obj, text):
|
|||
obj.msg(text)
|
||||
|
||||
# wait 10 seconds before sending "Echo!" to obj (which we assume is defined)
|
||||
deferred = utils.delay(10, _callback, obj, "Echo!", persistent=False)
|
||||
utils.delay(10, _callback, obj, "Echo!", persistent=False)
|
||||
|
||||
# code here will run immediately, not waiting for the delay to fire!
|
||||
|
||||
```
|
||||
|
||||
This creates an asynchronous delayed call. It will fire the given callback function after the given
|
||||
number of seconds. This is a very light wrapper over a Twisted
|
||||
[Deferred](https://twistedmatrix.com/documents/current/core/howto/defer.html). Normally this is run
|
||||
non-persistently, which means that if the server is `@reload`ed before the delay is over, the
|
||||
callback will never run (the server forgets it). If setting `persistent` to True, the delay will be
|
||||
stored in the database and survive a `@reload` - but for this to work it is susceptible to the same
|
||||
limitations incurred when saving to an [Attribute](./Attributes.md).
|
||||
See [The Asynchronous process](../Concepts/Async-Process.md#delay) for more information.
|
||||
|
||||
The `deferred` return object can usually be ignored, but calling its `.cancel()` method will abort
|
||||
the delay prematurely.
|
||||
## Finding Classes
|
||||
|
||||
`utils.delay` is the lightest form of delayed call in Evennia. For other way to create time-bound
|
||||
tasks, see the [TickerHandler](./TickerHandler.md) and [Scripts](./Scripts.md).
|
||||
|
||||
> Note that many delayed effects can be achieved without any need for an active timer. For example
|
||||
if you have a trait that should recover a point every 5 seconds you might just need its value when
|
||||
it's needed, but checking the current time and calculating on the fly what value it should have.
|
||||
|
||||
## Object Classes
|
||||
### utils.inherits_from()
|
||||
|
||||
This useful function takes two arguments - an object to check and a parent. It returns `True` if
|
||||
object inherits from parent *at any distance* (as opposed to Python's in-built `is_instance()` that
|
||||
This useful function takes two arguments - an object to check and a parent. It returns `True` if object inherits from parent *at any distance* (as opposed to Python's in-built `is_instance()` that
|
||||
will only catch immediate dependence). This function also accepts as input any combination of
|
||||
classes, instances or python-paths-to-classes.
|
||||
|
||||
Note that Python code should usually work with [duck
|
||||
typing](https://en.wikipedia.org/wiki/Duck_typing). But in Evennia's case it can sometimes be useful
|
||||
to check if an object inherits from a given [Typeclass](./Typeclasses.md) as a way of identification. Say
|
||||
for example that we have a typeclass *Animal*. This has a subclass *Felines* which in turn has a
|
||||
subclass *HouseCat*. Maybe there are a bunch of other animal types too, like horses and dogs. Using
|
||||
`inherits_from` will allow you to check for all animals in one go:
|
||||
Note that Python code should usually work with [duck typing](https://en.wikipedia.org/wiki/Duck_typing). But in Evennia's case it can sometimes be useful to check if an object inherits from a given [Typeclass](./Typeclasses.md) as a way of identification. Say for example that we have a typeclass *Animal*. This has a subclass *Felines* which in turn has a subclass *HouseCat*. Maybe there are a bunch of other animal types too, like horses and dogs. Using `inherits_from` will allow you to check for all animals in one go:
|
||||
|
||||
```python
|
||||
from evennia import utils
|
||||
|
|
@ -214,8 +178,6 @@ subclass *HouseCat*. Maybe there are a bunch of other animal types too, like hor
|
|||
obj.msg("The bouncer stops you in the door. He says: 'No talking animals allowed.'")
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Text utilities
|
||||
|
||||
In a text game, you are naturally doing a lot of work shuffling text back and forth. Here is a *non-
|
||||
|
|
@ -224,8 +186,7 @@ If nothing else it can be good to look here before starting to develop a solutio
|
|||
|
||||
### utils.fill()
|
||||
|
||||
This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also
|
||||
indents as needed.
|
||||
This flood-fills a text to a given width (shuffles the words to make each line evenly wide). It also indents as needed.
|
||||
|
||||
```python
|
||||
outtxt = fill(intxt, width=78, indent=4)
|
||||
|
|
@ -244,11 +205,7 @@ can be useful in listings when showing multiple lines would mess up things.
|
|||
|
||||
### utils.dedent()
|
||||
|
||||
This solves what may at first glance appear to be a trivial problem with text - removing
|
||||
indentations. It is used to shift entire paragraphs to the left, without disturbing any further
|
||||
formatting they may have. A common case for this is when using Python triple-quoted strings in code
|
||||
- they will retain whichever indentation they have in the code, and to make easily-readable source
|
||||
code one usually don't want to shift the string to the left edge.
|
||||
This solves what may at first glance appear to be a trivial problem with text - removing indentations. It is used to shift entire paragraphs to the left, without disturbing any further formatting they may have. A common case for this is when using Python triple-quoted strings in code - they will retain whichever indentation they have in the code, and to make easily-readable source code one usually don't want to shift the string to the left edge.
|
||||
|
||||
```python
|
||||
#python code is entered at a given indentation
|
||||
|
|
@ -267,31 +224,6 @@ help entries).
|
|||
|
||||
### to_str() and to_bytes()
|
||||
|
||||
Evennia supplies two utility functions for converting text to the correct
|
||||
encodings. `to_str()` and `to_bytes()`. Unless you are adding a custom protocol and
|
||||
need to send byte-data over the wire, `to_str` is the only one you'll need.
|
||||
Evennia supplies two utility functions for converting text to the correct encodings. `to_str()` and `to_bytes()`. Unless you are adding a custom protocol and need to send byte-data over the wire, `to_str` is the only one you'll need.
|
||||
|
||||
The difference from Python's in-built `str()` and `bytes()` operators are that
|
||||
the Evennia ones makes use of the `ENCODINGS` setting and will try very hard to
|
||||
never raise a traceback but instead echo errors through logging. See
|
||||
[here](../Concepts/Text-Encodings.md) for more info.
|
||||
|
||||
### Ansi Coloring Tools
|
||||
- [evennia.utils.ansi](evennia.utils.ansi)
|
||||
|
||||
## Display utilities
|
||||
### Making ascii tables
|
||||
|
||||
The [EvTable](evennia.utils.evtable.EvTable) class (`evennia/utils/evtable.py`) can be used
|
||||
to create correctly formatted text tables. There is also
|
||||
[EvForm](evennia.utils.evform.EvForm) (`evennia/utils/evform.py`). This reads a fixed-format
|
||||
text template from a file in order to create any level of sophisticated ascii layout. Both evtable
|
||||
and evform have lots of options and inputs so see the header of each module for help.
|
||||
|
||||
The third-party [PrettyTable](https://code.google.com/p/prettytable/) module is also included in
|
||||
Evennia. PrettyTable is considered deprecated in favor of EvTable since PrettyTable cannot handle
|
||||
ANSI colour. PrettyTable can be found in `evennia/utils/prettytable/`. See its homepage above for
|
||||
instructions.
|
||||
|
||||
### Menus
|
||||
- [evennia.EvMenu](evennia.utils.evmenu.EvMenu)
|
||||
The difference from Python's in-built `str()` and `bytes()` operators are that the Evennia ones makes use of the `ENCODINGS` setting and will try very hard to never raise a traceback but instead echo errors through logging. See [here](../Concepts/Text-Encodings.md) for more info.
|
||||
|
|
@ -13,8 +13,7 @@ There are two components to having a command running - the *Command* class and t
|
|||
1. A *Command* is a python class containing all the functioning code for what a command does - for example, a *get* command would contain code for picking up objects.
|
||||
1. A *Command Set* (often referred to as a CmdSet or cmdset) is like a container for one or more Commands. A given Command can go into any number of different command sets. Only by putting the command set on a character object you will make all the commands therein available to use by that character. You can also store command sets on normal objects if you want users to be able to use the object in various ways. Consider a "Tree" object with a cmdset defining the commands *climb* and *chop down*. Or a "Clock" with a cmdset containing the single command *check time*.
|
||||
|
||||
This page goes into full detail about how to use Commands. To fully use them you must also read the page detailing [Command Sets](./Command-Sets.md). There is also a step-by-step [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md) that will get you started quickly without the
|
||||
extra explanations.
|
||||
This page goes into full detail about how to use Commands. To fully use them you must also read the page detailing [Command Sets](./Command-Sets.md). There is also a step-by-step [Adding Command Tutorial](../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.md) that will get you started quickly without the extra explanations.
|
||||
|
||||
## Defining Commands
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,15 @@
|
|||
|
||||
These are the 'building blocks' out of which Evennia is built. This documentation is complementary to, and often goes deeper than, the doc-strings of each component in the [API](../Evennia-API.md).
|
||||
|
||||
## Basic entites
|
||||
## Base components
|
||||
|
||||
These are base pieces used to make an Evennia game. Most are long-lived and are persisted in the database.
|
||||
|
||||
```{toctree}
|
||||
:maxdepth: 2
|
||||
|
||||
Typeclasses.md
|
||||
Portal-And-Server.md
|
||||
Sessions.md
|
||||
Typeclasses.md
|
||||
Accounts.md
|
||||
Objects.md
|
||||
Scripts.md
|
||||
|
|
@ -22,7 +22,7 @@ Tags.md
|
|||
Prototypes.md
|
||||
Help-System.md
|
||||
Permissions.md
|
||||
Portal-And-Server.md
|
||||
Locks.md
|
||||
```
|
||||
|
||||
## Commands
|
||||
|
|
@ -35,10 +35,7 @@ Evennia's Command system handle everything sent to the server by the user.
|
|||
Commands.md
|
||||
Command-Sets.md
|
||||
Default-Commands.md
|
||||
Connection-Screen.md
|
||||
Batch-Processors.md
|
||||
Batch-Code-Processor.md
|
||||
Batch-Command-Processor.md
|
||||
Inputfuncs.md
|
||||
```
|
||||
|
||||
|
|
@ -59,7 +56,6 @@ EvTable.md
|
|||
FuncParser.md
|
||||
MonitorHandler.md
|
||||
TickerHandler.md
|
||||
Locks.md
|
||||
Signals.md
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,36 +0,0 @@
|
|||
# Connection Screen
|
||||
|
||||
|
||||
When you first connect to your game you are greeted by Evennia's default connection screen.
|
||||
|
||||
|
||||
==============================================================
|
||||
Welcome to Evennia, version Beta-ra4d24e8a3cab+!
|
||||
|
||||
If you have an existing account, connect to it by typing:
|
||||
connect <username> <password>
|
||||
If you need to create an account, type (without the <>'s):
|
||||
create <username> <password>
|
||||
|
||||
If you have spaces in your username, enclose it in quotes.
|
||||
Enter help for more info. look will re-show this screen.
|
||||
==============================================================
|
||||
|
||||
Effective, but not very exciting. You will most likely want to change this to be more unique for
|
||||
your game. This is simple:
|
||||
|
||||
1. Edit `mygame/server/conf/connection_screens.py`.
|
||||
1. [Reload](../Setup/Running-Evennia.md) Evennia.
|
||||
|
||||
Evennia will look into this module and locate all *globally defined strings* in it. These strings
|
||||
are used as the text in your connection screen and are shown to the user at startup. If more than
|
||||
one such string/screen is defined in the module, a *random* screen will be picked from among those
|
||||
available.
|
||||
|
||||
## Commands available at the Connection Screen
|
||||
|
||||
You can also customize the [Commands](./Commands.md) available to use while the connection screen is
|
||||
shown (`connect`, `create` etc). These commands are a bit special since when the screen is running
|
||||
the account is not yet logged in. A command is made available at the login screen by adding them to
|
||||
`UnloggedinCmdSet` in `mygame/commands/default_cmdset.py`. See [Commands](./Commands.md) and the
|
||||
tutorial section on how to add new commands to a default command set.
|
||||
|
|
@ -29,7 +29,7 @@ cleanup and exit messages to the user must be handled by this function.
|
|||
It has no other mechanical function.
|
||||
- `persistent` (default `False`): if set to `True`, the editor will survive a reboot.
|
||||
|
||||
## Example of usage
|
||||
## Working with EvEditor
|
||||
|
||||
This is an example command for setting a specific Attribute using the editor.
|
||||
|
||||
|
|
@ -65,7 +65,7 @@ class CmdSetTestAttr(Command):
|
|||
key=key)
|
||||
```
|
||||
|
||||
## Persistent editor
|
||||
### Persistent editor
|
||||
|
||||
If you set the `persistent` keyword to `True` when creating the editor, it will remain open even
|
||||
when reloading the game. In order to be persistent, an editor needs to have its callback functions
|
||||
|
|
@ -107,7 +107,7 @@ class CmdSetTestAttr(Command):
|
|||
key=key, persistent=True)
|
||||
```
|
||||
|
||||
## Line editor usage
|
||||
### Line editor usage
|
||||
|
||||
The editor mimics the `VIM` editor as best as possible. The below is an excerpt of the return from
|
||||
the in-editor help command (`:h`).
|
||||
|
|
@ -154,28 +154,19 @@ the in-editor help command (`:h`).
|
|||
<txt> - longer string, usually not needed to be enclosed in quotes.
|
||||
```
|
||||
|
||||
## The EvEditor to edit code
|
||||
### The EvEditor to edit code
|
||||
|
||||
The `EvEditor` is also used to edit some Python code in Evennia. The `@py` command supports an
|
||||
`/edit` switch that will open the EvEditor in code mode. This mode isn't significantly different
|
||||
from the standard one, except it handles automatic indentation of blocks and a few options to
|
||||
control this behavior.
|
||||
The `EvEditor` is also used to edit some Python code in Evennia. The `py` command supports an `/edit` switch that will open the EvEditor in code mode. This mode isn't significantly different from the standard one, except it handles automatic indentation of blocks and a few options to control this behavior.
|
||||
|
||||
- `:<` to remove a level of indentation for the future lines.
|
||||
- `:+` to add a level of indentation for the future lines.
|
||||
- `:=` to disable automatic indentation altogether.
|
||||
|
||||
Automatic indentation is there to make code editing more simple. Python needs correct indentation,
|
||||
not as an aesthetic addition, but as a requirement to determine beginning and ending of blocks. The
|
||||
EvEditor will try to guess the next level of indentation. If you type a block "if", for instance,
|
||||
the EvEditor will propose you an additional level of indentation at the next line. This feature
|
||||
cannot be perfect, however, and sometimes, you will have to use the above options to handle
|
||||
indentation.
|
||||
Automatic indentation is there to make code editing more simple. Python needs correct indentation, not as an aesthetic addition, but as a requirement to determine beginning and ending of blocks. The EvEditor will try to guess the next level of indentation. If you type a block "if", for instance, the EvEditor will propose you an additional level of indentation at the next line. This feature cannot be perfect, however, and sometimes, you will have to use the above options to handle indentation.
|
||||
|
||||
`:=` can be used to turn automatic indentation off completely. This can be very useful when trying
|
||||
to paste several lines of code that are already correctly indented, for instance.
|
||||
|
||||
To see the EvEditor in code mode, you can use the `@py/edit` command. Type in your code (on one or
|
||||
several lines). You can then use the `:w` option (save without quitting) and the code you have
|
||||
To see the EvEditor in code mode, you can use the `@py/edit` command. Type in your code (on one or several lines). You can then use the `:w` option (save without quitting) and the code you have
|
||||
typed will be executed. The `:!` will do the same thing. Executing code while not closing the
|
||||
editor can be useful if you want to test the code you have typed but add new lines after your test.
|
||||
|
|
|
|||
|
|
@ -1,44 +1,27 @@
|
|||
# EvMenu
|
||||
|
||||
EvMenu is used for generate branching multi-choice menus. Each menu 'node' can
|
||||
accepts specific options as input or free-form input. Depending what the player
|
||||
chooses, they are forwarded to different nodes in the menu.
|
||||
|
||||
## Introduction
|
||||
|
||||
The `EvMenu` utility class is located in [evennia/utils/evmenu.py](evennia.utils.evmenu).
|
||||
It allows for easily adding interactive menus to the game; for example to implement Character
|
||||
creation, building commands or similar. Below is an example of offering NPC conversation choices:
|
||||
|
||||
### Examples
|
||||
|
||||
This section gives some examples of how menus work in-game. A menu is a state
|
||||
(it's actually a custom cmdset) where menu-specific commands are made available
|
||||
to you. An EvMenu is usually started from inside a command, but could also
|
||||
just be put in a file and run with `py`.
|
||||
|
||||
This is how the example menu will look in-game:
|
||||
|
||||
```
|
||||
```shell
|
||||
Is your answer yes or no?
|
||||
_________________________________________
|
||||
[Y]es! - Answer yes.
|
||||
[N]o! - Answer no.
|
||||
[A]bort - Answer neither, and abort.
|
||||
```
|
||||
|
||||
If you pick (for example) Y(es), you will see
|
||||
|
||||
```
|
||||
> Y
|
||||
You chose yes!
|
||||
|
||||
Thanks for your answer. Goodbye!
|
||||
```
|
||||
|
||||
After which the menu will end (in this example at least - it could also continue
|
||||
on to other questions and choices or even repeat the same node over and over!)
|
||||
_EvMenu_ is used for generate branching multi-choice menus. Each menu 'node' can
|
||||
accepts specific options as input or free-form input. Depending what the player
|
||||
chooses, they are forwarded to different nodes in the menu.
|
||||
|
||||
Here's the full EvMenu code for this example:
|
||||
The `EvMenu` utility class is located in [evennia/utils/evmenu.py](evennia.utils.evmenu).
|
||||
It allows for easily adding interactive menus to the game; for example to implement Character
|
||||
creation, building commands or similar. Below is an example of offering NPC conversation choices:
|
||||
|
||||
This is how the example menu at the top of this page will look in code:
|
||||
|
||||
```python
|
||||
from evennia.utils import evmenu
|
||||
|
|
@ -229,39 +212,14 @@ EvMenu(caller, menu_data,
|
|||
|
||||
```
|
||||
|
||||
- `caller` (Object or Account): is a reference to the object using the menu. This object will get a
|
||||
new [CmdSet](./Command-Sets.md) assigned to it, for handling the menu.
|
||||
- `menu_data` (str, module or dict): is a module or python path to a module where the global-level
|
||||
functions will each be considered to be a menu node. Their names in the module will be the names
|
||||
by which they are referred to in the module. Importantly, function names starting with an
|
||||
underscore
|
||||
`_` will be ignored by the loader. Alternatively, this can be a direct mapping
|
||||
- `caller` (Object or Account): is a reference to the object using the menu. This object will get a new [CmdSet](./Command-Sets.md) assigned to it, for handling the menu.
|
||||
- `menu_data` (str, module or dict): is a module or python path to a module where the global-level functions will each be considered to be a menu node. Their names in the module will be the names by which they are referred to in the module. Importantly, function names starting with an underscore `_` will be ignored by the loader. Alternatively, this can be a direct mapping
|
||||
`{"nodename":function, ...}`.
|
||||
- `startnode` (str): is the name of the menu-node to start the menu at. Changing this means that
|
||||
you can jump into a menu tree at different positions depending on circumstance and thus possibly
|
||||
re-use menu entries.
|
||||
- `cmdset_mergetype` (str): This is usually one of "Replace" or "Union" (see [CmdSets](Command-
|
||||
Sets).
|
||||
The first means that the menu is exclusive - the user has no access to any other commands while
|
||||
in the menu. The Union mergetype means the menu co-exists with previous commands (and may
|
||||
overload
|
||||
them, so be careful as to what to name your menu entries in this case).
|
||||
- `cmdset_priority` (int): The priority with which to merge in the menu cmdset. This allows for
|
||||
advanced usage.
|
||||
- `auto_quit`, `auto_look`, `auto_help` (bool): If either of these are `True`, the menu
|
||||
automatically makes a `quit`, `look` or `help` command available to the user. The main reason why
|
||||
you'd want to turn this off is if you want to use the aliases "q", "l" or "h" for something in
|
||||
your
|
||||
menu. Nevertheless, at least `quit` is highly recommend - if `False`, the menu *must* itself
|
||||
supply
|
||||
an "exit node" (a node without any options), or the user will be stuck in the menu until the
|
||||
server
|
||||
reloads (or eternally if the menu is `persistent`)!
|
||||
- `cmd_on_exit` (str): This command string will be executed right *after* the menu has closed down.
|
||||
From experience, it's useful to trigger a "look" command to make sure the user is aware of the
|
||||
change of state; but any command can be used. If set to `None`, no command will be triggered
|
||||
after
|
||||
exiting the menu.
|
||||
- `startnode` (str): is the name of the menu-node to start the menu at. Changing this means that you can jump into a menu tree at different positions depending on circumstance and thus possibly re-use menu entries.
|
||||
- `cmdset_mergetype` (str): This is usually one of "Replace" or "Union" (see [CmdSets](Command- Sets). The first means that the menu is exclusive - the user has no access to any other commands while in the menu. The Union mergetype means the menu co-exists with previous commands (and may overload them, so be careful as to what to name your menu entries in this case).
|
||||
- `cmdset_priority` (int): The priority with which to merge in the menu cmdset. This allows for advanced usage.
|
||||
- `auto_quit`, `auto_look`, `auto_help` (bool): If either of these are `True`, the menu automatically makes a `quit`, `look` or `help` command available to the user. The main reason why you'd want to turn this off is if you want to use the aliases "q", "l" or "h" for something in your menu. Nevertheless, at least `quit` is highly recommend - if `False`, the menu *must* itself supply an "exit node" (a node without any options), or the user will be stuck in the menu until the server reloads (or eternally if the menu is `persistent`)!
|
||||
- `cmd_on_exit` (str): This command string will be executed right *after* the menu has closed down. From experience, it's useful to trigger a "look" command to make sure the user is aware of the change of state; but any command can be used. If set to `None`, no command will be triggered after exiting the menu.
|
||||
- `persistent` (bool) - if `True`, the menu will survive a reload (so the user will not be kicked
|
||||
out by the reload - make sure they can exit on their own!)
|
||||
- `startnode_input` (str or (str, dict) tuple): Pass an input text or a input text + kwargs to the
|
||||
|
|
@ -272,9 +230,7 @@ after
|
|||
- `debug` (bool): If set, the `menudebug` command will be made available in the menu. Use it to
|
||||
list the current state of the menu and use `menudebug <variable>` to inspect a specific state
|
||||
variable from the list.
|
||||
- All other keyword arguments will be available as initial data for the nodes. They will be
|
||||
available in all nodes as properties on `caller.ndb._evmenu` (see below). These will also
|
||||
survive a `@reload` if the menu is `persistent`.
|
||||
- All other keyword arguments will be available as initial data for the nodes. They will be available in all nodes as properties on `caller.ndb._evmenu` (see below). These will also survive a `reload` if the menu is `persistent`.
|
||||
|
||||
You don't need to store the EvMenu instance anywhere - the very act of initializing it will store it
|
||||
as `caller.ndb._evmenu` on the `caller`. This object will be deleted automatically when the menu
|
||||
|
|
@ -282,7 +238,6 @@ is exited and you can also use it to store your own temporary variables for acce
|
|||
menu. Temporary variables you store on a persistent `_evmenu` as it runs will
|
||||
*not* survive a `@reload`, only those you set as part of the original `EvMenu` call.
|
||||
|
||||
|
||||
## The Menu nodes
|
||||
|
||||
The EvMenu nodes consist of functions on one of these forms.
|
||||
|
|
@ -506,7 +461,7 @@ manipulated for every iteration.
|
|||
> *deprecated* as of Evennia 0.8. Use `goto` for all functionality where you'd before use `exec`.
|
||||
|
||||
|
||||
## Temporary storage
|
||||
### Temporary storage
|
||||
|
||||
When the menu starts, the EvMenu instance is stored on the caller as `caller.ndb._evmenu`. Through
|
||||
this object you can in principle reach the menu's internal state if you know what you are doing.
|
||||
|
|
@ -519,7 +474,7 @@ that this will remain after the menu closes though, so you need to handle any ne
|
|||
yourself.
|
||||
|
||||
|
||||
## Customizing Menu formatting
|
||||
### Customizing Menu formatting
|
||||
|
||||
The `EvMenu` display of nodes, options etc are controlled by a series of formatting methods on the
|
||||
`EvMenu` class. To customize these, simply create a new child class of `EvMenu` and override as
|
||||
|
|
@ -737,7 +692,189 @@ evmenu.template2menu(caller, template_string, goto_callables)
|
|||
|
||||
```
|
||||
|
||||
## Examples:
|
||||
## Asking for one-line input
|
||||
|
||||
This describes two ways for asking for simple questions from the user. Using Python's `input`
|
||||
will *not* work in Evennia. `input` will *block* the entire server for *everyone* until that one
|
||||
player has entered their text, which is not what you want.
|
||||
|
||||
### The `yield` way
|
||||
|
||||
In the `func` method of your Commands (only) you can use Python's built-in `yield` command to
|
||||
request input in a similar way to `input`. It looks like this:
|
||||
|
||||
```python
|
||||
result = yield("Please enter your answer:")
|
||||
```
|
||||
|
||||
This will send "Please enter your answer" to the Command's `self.caller` and then pause at that
|
||||
point. All other players at the server will be unaffected. Once caller enteres a reply, the code
|
||||
execution will continue and you can do stuff with the `result`. Here is an example:
|
||||
|
||||
```python
|
||||
from evennia import Command
|
||||
class CmdTestInput(Command):
|
||||
key = "test"
|
||||
def func(self):
|
||||
result = yield("Please enter something:")
|
||||
self.caller.msg(f"You entered {result}.")
|
||||
result2 = yield("Now enter something else:")
|
||||
self.caller.msg(f"You now entered {result2}.")
|
||||
```
|
||||
|
||||
Using `yield` is simple and intuitive, but it will only access input from `self.caller` and you
|
||||
cannot abort or time out the pause until the player has responded. Under the hood, it is actually
|
||||
just a wrapper calling `get_input` described in the following section.
|
||||
|
||||
> Important Note: In Python you *cannot mix `yield` and `return <value>` in the same method*. It has
|
||||
> to do with `yield` turning the method into a
|
||||
> [generator](https://www.learnpython.org/en/Generators). A `return` without an argument works, you
|
||||
> can just not do `return <value>`. This is usually not something you need to do in `func()` anyway,
|
||||
> but worth keeping in mind.
|
||||
|
||||
### The `get_input` way
|
||||
|
||||
The evmenu module offers a helper function named `get_input`. This is wrapped by the `yield`
|
||||
statement which is often easier and more intuitive to use. But `get_input` offers more flexibility
|
||||
and power if you need it. While in the same module as `EvMenu`, `get_input` is technically unrelated
|
||||
to it. The `get_input` allows you to ask and receive simple one-line input from the user without
|
||||
launching the full power of a menu to do so. To use, call `get_input` like this:
|
||||
|
||||
```python
|
||||
get_input(caller, prompt, callback)
|
||||
```
|
||||
|
||||
Here `caller` is the entity that should receive the prompt for input given as `prompt`. The
|
||||
`callback` is a callable `function(caller, prompt, user_input)` that you define to handle the answer
|
||||
from the user. When run, the caller will see `prompt` appear on their screens and *any* text they
|
||||
enter will be sent into the callback for whatever processing you want.
|
||||
|
||||
Below is a fully explained callback and example call:
|
||||
|
||||
```python
|
||||
from evennia import Command
|
||||
from evennia.utils.evmenu import get_input
|
||||
|
||||
def callback(caller, prompt, user_input):
|
||||
"""
|
||||
This is a callback you define yourself.
|
||||
|
||||
Args:
|
||||
caller (Account or Object): The one being asked
|
||||
for input
|
||||
prompt (str): A copy of the current prompt
|
||||
user_input (str): The input from the account.
|
||||
|
||||
Returns:
|
||||
repeat (bool): If not set or False, exit the
|
||||
input prompt and clean up. If returning anything
|
||||
True, stay in the prompt, which means this callback
|
||||
will be called again with the next user input.
|
||||
"""
|
||||
caller.msg(f"When asked '{prompt}', you answered '{user_input}'.")
|
||||
|
||||
get_input(caller, "Write something! ", callback)
|
||||
```
|
||||
|
||||
This will show as
|
||||
|
||||
```
|
||||
Write something!
|
||||
> Hello
|
||||
When asked 'Write something!', you answered 'Hello'.
|
||||
|
||||
```
|
||||
|
||||
Normally, the `get_input` function quits after any input, but as seen in the example docs, you could
|
||||
return True from the callback to repeat the prompt until you pass whatever check you want.
|
||||
|
||||
> Note: You *cannot* link consecutive questions by putting a new `get_input` call inside the
|
||||
> callback If you want that you should use an EvMenu instead (see the [Repeating the same
|
||||
> node](./EvMenu.md#example-repeating-the-same-node) example above). Otherwise you can either peek at the
|
||||
> implementation of `get_input` and implement your own mechanism (it's just using cmdset nesting) or
|
||||
> you can look at [this extension suggested on the mailing
|
||||
> list](https://groups.google.com/forum/#!category-topic/evennia/evennia-questions/16pi0SfMO5U).
|
||||
|
||||
|
||||
#### Example: Yes/No prompt
|
||||
|
||||
Below is an example of a Yes/No prompt using the `get_input` function:
|
||||
|
||||
```python
|
||||
def yesno(caller, prompt, result):
|
||||
if result.lower() in ("y", "yes", "n", "no"):
|
||||
# do stuff to handle the yes/no answer
|
||||
# ...
|
||||
# if we return None/False the prompt state
|
||||
# will quit after this
|
||||
else:
|
||||
# the answer is not on the right yes/no form
|
||||
caller.msg("Please answer Yes or No. \n{prompt}")
|
||||
@ # returning True will make sure the prompt state is not exited
|
||||
return True
|
||||
|
||||
# ask the question
|
||||
get_input(caller, "Is Evennia great (Yes/No)?", yesno)
|
||||
```
|
||||
|
||||
## The `@list_node` decorator
|
||||
|
||||
The `evennia.utils.evmenu.list_node` is an advanced decorator for use with `EvMenu` node functions.
|
||||
It is used to quickly create menus for manipulating large numbers of items.
|
||||
|
||||
|
||||
```
|
||||
text here
|
||||
______________________________________________
|
||||
|
||||
1. option1 7. option7 13. option13
|
||||
2. option2 8. option8 14. option14
|
||||
3. option3 9. option9 [p]revius page
|
||||
4. option4 10. option10 page 2
|
||||
5. option5 11. option11 [n]ext page
|
||||
6. option6 12. option12
|
||||
|
||||
```
|
||||
|
||||
The menu will automatically create an multi-page option listing that one can flip through. One can
|
||||
inpect each entry and then select them with prev/next. This is how it is used:
|
||||
|
||||
|
||||
```python
|
||||
from evennia.utils.evmenu import list_node
|
||||
|
||||
|
||||
...
|
||||
|
||||
_options(caller):
|
||||
return ['option1', 'option2', ... 'option100']
|
||||
|
||||
_select(caller, menuchoice, available_choices):
|
||||
# analyze choice
|
||||
return "next_node"
|
||||
|
||||
@list_node(options, select=_select, pagesize=10)
|
||||
def node_mylist(caller, raw_string, **kwargs):
|
||||
...
|
||||
|
||||
return text, options
|
||||
|
||||
```
|
||||
|
||||
The `options` argument to `list_node` is either a list, a generator or a callable returning a list
|
||||
of strings for each option that should be displayed in the node.
|
||||
|
||||
The `select` is a callable in the example above but could also be the name of a menu node. If a
|
||||
callable, the `menuchoice` argument holds the selection done and `available_choices` holds all the
|
||||
options available. The callable should return the menu to go to depending on the selection (or
|
||||
`None` to rerun the same node). If the name of a menu node, the selection will be passed as
|
||||
`selection` kwarg to that node.
|
||||
|
||||
The decorated node itself should return `text` to display in the node. It must return at least an
|
||||
empty dictionary for its options. It returning options, those will supplement the options
|
||||
auto-created by the `list_node` decorator.
|
||||
|
||||
## Example Menus
|
||||
|
||||
- **[Simple branching menu](./EvMenu.md#example-simple-branching-menu)** - choose from options
|
||||
- **[Dynamic goto](./EvMenu.md#example-dynamic-goto)** - jumping to different nodes based on response
|
||||
|
|
@ -754,8 +891,7 @@ helper function accessed as `evennia.utils.evmenu.get_input`).
|
|||
|
||||
### Example: Simple branching menu
|
||||
|
||||
Below is an example of a simple branching menu node leading to different other nodes depending on
|
||||
choice:
|
||||
Below is an example of a simple branching menu node leading to different other nodes depending on choice:
|
||||
|
||||
```python
|
||||
# in mygame/world/mychargen.py
|
||||
|
|
@ -993,9 +1129,7 @@ use
|
|||
|
||||
### Example: Repeating the same node
|
||||
|
||||
Sometimes you want to make a chain of menu nodes one after another, but you don't want the user to
|
||||
be able to continue to the next node until you have verified that what they input in the previous
|
||||
node is ok. A common example is a login menu:
|
||||
Sometimes you want to make a chain of menu nodes one after another, but you don't want the user to be able to continue to the next node until you have verified that what they input in the previous node is ok. A common example is a login menu:
|
||||
|
||||
|
||||
```python
|
||||
|
|
@ -1116,196 +1250,3 @@ function - for example you can't use other Python keywords like `if` inside the
|
|||
Unless you are dealing with a relatively simple dynamic menu, defining menus with lambda's is
|
||||
probably more work than it's worth: You can create dynamic menus by instead making each node
|
||||
function more clever. See the [NPC shop tutorial](../Howtos/Tutorial-NPC-Merchants.md) for an example of this.
|
||||
|
||||
|
||||
## Ask for simple input
|
||||
|
||||
This describes two ways for asking for simple questions from the user. Using Python's `input`
|
||||
will *not* work in Evennia. `input` will *block* the entire server for *everyone* until that one
|
||||
player has entered their text, which is not what you want.
|
||||
|
||||
### The `yield` way
|
||||
|
||||
In the `func` method of your Commands (only) you can use Python's built-in `yield` command to
|
||||
request input in a similar way to `input`. It looks like this:
|
||||
|
||||
```python
|
||||
result = yield("Please enter your answer:")
|
||||
```
|
||||
|
||||
This will send "Please enter your answer" to the Command's `self.caller` and then pause at that
|
||||
point. All other players at the server will be unaffected. Once caller enteres a reply, the code
|
||||
execution will continue and you can do stuff with the `result`. Here is an example:
|
||||
|
||||
```python
|
||||
from evennia import Command
|
||||
class CmdTestInput(Command):
|
||||
key = "test"
|
||||
def func(self):
|
||||
result = yield("Please enter something:")
|
||||
self.caller.msg(f"You entered {result}.")
|
||||
result2 = yield("Now enter something else:")
|
||||
self.caller.msg(f"You now entered {result2}.")
|
||||
```
|
||||
|
||||
Using `yield` is simple and intuitive, but it will only access input from `self.caller` and you
|
||||
cannot abort or time out the pause until the player has responded. Under the hood, it is actually
|
||||
just a wrapper calling `get_input` described in the following section.
|
||||
|
||||
> Important Note: In Python you *cannot mix `yield` and `return <value>` in the same method*. It has
|
||||
> to do with `yield` turning the method into a
|
||||
> [generator](https://www.learnpython.org/en/Generators). A `return` without an argument works, you
|
||||
> can just not do `return <value>`. This is usually not something you need to do in `func()` anyway,
|
||||
> but worth keeping in mind.
|
||||
|
||||
### The `get_input` way
|
||||
|
||||
The evmenu module offers a helper function named `get_input`. This is wrapped by the `yield`
|
||||
statement which is often easier and more intuitive to use. But `get_input` offers more flexibility
|
||||
and power if you need it. While in the same module as `EvMenu`, `get_input` is technically unrelated
|
||||
to it. The `get_input` allows you to ask and receive simple one-line input from the user without
|
||||
launching the full power of a menu to do so. To use, call `get_input` like this:
|
||||
|
||||
```python
|
||||
get_input(caller, prompt, callback)
|
||||
```
|
||||
|
||||
Here `caller` is the entity that should receive the prompt for input given as `prompt`. The
|
||||
`callback` is a callable `function(caller, prompt, user_input)` that you define to handle the answer
|
||||
from the user. When run, the caller will see `prompt` appear on their screens and *any* text they
|
||||
enter will be sent into the callback for whatever processing you want.
|
||||
|
||||
Below is a fully explained callback and example call:
|
||||
|
||||
```python
|
||||
from evennia import Command
|
||||
from evennia.utils.evmenu import get_input
|
||||
|
||||
def callback(caller, prompt, user_input):
|
||||
"""
|
||||
This is a callback you define yourself.
|
||||
|
||||
Args:
|
||||
caller (Account or Object): The one being asked
|
||||
for input
|
||||
prompt (str): A copy of the current prompt
|
||||
user_input (str): The input from the account.
|
||||
|
||||
Returns:
|
||||
repeat (bool): If not set or False, exit the
|
||||
input prompt and clean up. If returning anything
|
||||
True, stay in the prompt, which means this callback
|
||||
will be called again with the next user input.
|
||||
"""
|
||||
caller.msg(f"When asked '{prompt}', you answered '{user_input}'.")
|
||||
|
||||
get_input(caller, "Write something! ", callback)
|
||||
```
|
||||
|
||||
This will show as
|
||||
|
||||
```
|
||||
Write something!
|
||||
> Hello
|
||||
When asked 'Write something!', you answered 'Hello'.
|
||||
|
||||
```
|
||||
|
||||
Normally, the `get_input` function quits after any input, but as seen in the example docs, you could
|
||||
return True from the callback to repeat the prompt until you pass whatever check you want.
|
||||
|
||||
> Note: You *cannot* link consecutive questions by putting a new `get_input` call inside the
|
||||
> callback If you want that you should use an EvMenu instead (see the [Repeating the same
|
||||
> node](./EvMenu.md#example-repeating-the-same-node) example above). Otherwise you can either peek at the
|
||||
> implementation of `get_input` and implement your own mechanism (it's just using cmdset nesting) or
|
||||
> you can look at [this extension suggested on the mailing
|
||||
> list](https://groups.google.com/forum/#!category-topic/evennia/evennia-questions/16pi0SfMO5U).
|
||||
|
||||
|
||||
#### Example: Yes/No prompt
|
||||
|
||||
Below is an example of a Yes/No prompt using the `get_input` function:
|
||||
|
||||
```python
|
||||
def yesno(caller, prompt, result):
|
||||
if result.lower() in ("y", "yes", "n", "no"):
|
||||
# do stuff to handle the yes/no answer
|
||||
# ...
|
||||
# if we return None/False the prompt state
|
||||
# will quit after this
|
||||
else:
|
||||
# the answer is not on the right yes/no form
|
||||
caller.msg("Please answer Yes or No. \n{prompt}")
|
||||
@ # returning True will make sure the prompt state is not exited
|
||||
return True
|
||||
|
||||
# ask the question
|
||||
get_input(caller, "Is Evennia great (Yes/No)?", yesno)
|
||||
```
|
||||
|
||||
## The `@list_node` decorator
|
||||
|
||||
The `evennia.utils.evmenu.list_node` is an advanced decorator for use with `EvMenu` node functions.
|
||||
It is used to quickly create menus for manipulating large numbers of items.
|
||||
|
||||
|
||||
```
|
||||
text here
|
||||
______________________________________________
|
||||
|
||||
1. option1 7. option7 13. option13
|
||||
2. option2 8. option8 14. option14
|
||||
3. option3 9. option9 [p]revius page
|
||||
4. option4 10. option10 page 2
|
||||
5. option5 11. option11 [n]ext page
|
||||
6. option6 12. option12
|
||||
|
||||
```
|
||||
|
||||
The menu will automatically create an multi-page option listing that one can flip through. One can
|
||||
inpect each entry and then select them with prev/next. This is how it is used:
|
||||
|
||||
|
||||
```python
|
||||
from evennia.utils.evmenu import list_node
|
||||
|
||||
|
||||
...
|
||||
|
||||
_options(caller):
|
||||
return ['option1', 'option2', ... 'option100']
|
||||
|
||||
_select(caller, menuchoice, available_choices):
|
||||
# analyze choice
|
||||
return "next_node"
|
||||
|
||||
@list_node(options, select=_select, pagesize=10)
|
||||
def node_mylist(caller, raw_string, **kwargs):
|
||||
...
|
||||
|
||||
return text, options
|
||||
|
||||
```
|
||||
|
||||
The `options` argument to `list_node` is either a list, a generator or a callable returning a list
|
||||
of strings for each option that should be displayed in the node.
|
||||
|
||||
The `select` is a callable in the example above but could also be the name of a menu node. If a
|
||||
callable, the `menuchoice` argument holds the selection done and `available_choices` holds all the
|
||||
options available. The callable should return the menu to go to depending on the selection (or
|
||||
`None` to rerun the same node). If the name of a menu node, the selection will be passed as
|
||||
`selection` kwarg to that node.
|
||||
|
||||
The decorated node itself should return `text` to display in the node. It must return at least an
|
||||
empty dictionary for its options. It returning options, those will supplement the options
|
||||
auto-created by the `list_node` decorator.
|
||||
|
||||
|
||||
## Assorted notes
|
||||
|
||||
The EvMenu is implemented using [Commands](./Commands.md). When you start a new EvMenu, the user of the
|
||||
menu will be assigned a [CmdSet](./Command-Sets.md) with the commands they need to navigate the menu.
|
||||
This means that if you were to, from inside the menu, assign a new command set to the caller, *you
|
||||
may override the Menu Cmdset and kill the menu*. If you want to assign cmdsets to the caller as part
|
||||
of the menu, you should store the cmdset on `caller.ndb._evmenu` and wait to actually assign it
|
||||
until the exit node.
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@ page of text at a time. It is usually used via its access function, `evmore.msg`
|
|||
|
||||
The name comes from the famous unix pager utility *more* which performs just this function.
|
||||
|
||||
## Using EvMore
|
||||
|
||||
To use the pager, just pass the long text through it:
|
||||
|
||||
```python
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
# The Inline Function Parser
|
||||
# FuncParser inline text parsing
|
||||
|
||||
The [FuncParser](evennia.utils.funcparser.FuncParser) extracts and executes 'inline functions' embedded in a string on the form `$funcname(args, kwargs)`. Under the hood, this will lead to a call to a Python function you control. The inline function call will be replaced by the return from the function.
|
||||
|
||||
|
|
@ -36,30 +36,20 @@ parser.parse("This is an escaped $$pow(4) and so is this \$pow(3)")
|
|||
"This is an escaped $pow(4) and so is this $pow(3)"
|
||||
```
|
||||
|
||||
## Uses in default Evennia
|
||||
## Working with FuncParser
|
||||
|
||||
The FuncParser can be applied to any string. Out of the box it's applied in a few situations:
|
||||
|
||||
- _Outgoing messages_. All messages sent from the server is processed through FuncParser and every
|
||||
callable is provided the [Session](./Sessions.md) of the object receiving the message. This potentially
|
||||
allows a message to be modified on the fly to look different for different recipients.
|
||||
- _Prototype values_. A [Prototype](./Prototypes.md) dict's values are run through the parser such that every
|
||||
callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders
|
||||
to safely call functions to set non-string values to prototype values, get random values, reference
|
||||
- _Outgoing messages_. All messages sent from the server is processed through FuncParser and every callable is provided the [Session](./Sessions.md) of the object receiving the message. This potentially allows a message to be modified on the fly to look different for different recipients.
|
||||
- _Prototype values_. A [Prototype](./Prototypes.md) dict's values are run through the parser such that every callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders to safely call functions to set non-string values to prototype values, get random values, reference
|
||||
other fields of the prototype, and more.
|
||||
- _Actor-stance in messages to others_. In the
|
||||
[Object.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method,
|
||||
the outgoing string is parsed for special `$You()` and `$conj()` callables to decide if a given recipient
|
||||
- _Actor-stance in messages to others_. In the [Object.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method, the outgoing string is parsed for special `$You()` and `$conj()` callables to decide if a given recipient
|
||||
should see "You" or the character's name.
|
||||
|
||||
```{important}
|
||||
The inline-function parser is not intended as a 'softcode' programming language. It does not
|
||||
have things like loops and conditionals, for example. While you could in principle extend it to
|
||||
do very advanced things and allow builders a lot of power, all-out coding is something
|
||||
Evennia expects you to do in a proper text editor, outside of the game, not from inside it.
|
||||
```
|
||||
|
||||
## Using the FuncParser
|
||||
The inline-function parser is not intended as a 'softcode' programming language. It does not have things like loops and conditionals, for example. While you could in principle extend it to do very advanced things and allow builders a lot of power, all-out coding is something Evennia expects you to do in a proper text editor, outside of the game, not from inside it.
|
||||
```
|
||||
|
||||
You can apply inline function parsing to any string. The
|
||||
[FuncParser](evennia.utils.funcparser.FuncParser) is imported as `evennia.utils.funcparser`.
|
||||
|
|
@ -129,8 +119,7 @@ _test('foo', bar='4', mydefault=2, myreserved=[1, 2, 3],
|
|||
funcparser=<FuncParser>, raise_errors=False)
|
||||
```
|
||||
|
||||
The `mydefault=2` kwarg could be overwritten if we made the call as `$test(mydefault=...)`
|
||||
but `myreserved=[1, 2, 3]` will _always_ be sent as-is and will override a call `$test(myreserved=...)`.
|
||||
The `mydefault=2` kwarg could be overwritten if we made the call as `$test(mydefault=...)` but `myreserved=[1, 2, 3]` will _always_ be sent as-is and will override a call `$test(myreserved=...)`.
|
||||
The `funcparser`/`raise_errors` kwargs are also always included as reserved kwargs.
|
||||
|
||||
## Defining custom callables
|
||||
|
|
@ -143,21 +132,16 @@ def funcname(*args, **kwargs):
|
|||
return something
|
||||
```
|
||||
|
||||
> The `*args` and `**kwargs` must always be included. If you are unsure how `*args` and `**kwargs` work in Python,
|
||||
> [read about them here](https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3).
|
||||
> The `*args` and `**kwargs` must always be included. If you are unsure how `*args` and `**kwargs` work in Python, [read about them here](https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3).
|
||||
|
||||
The input from the innermost `$funcname(...)` call in your callable will always be a `str`. Here's
|
||||
an example of an `$toint` function; it converts numbers to integers.
|
||||
|
||||
"There's a $toint(22.0)% chance of survival."
|
||||
|
||||
What will enter the `$toint` callable (as `args[0]`) is the _string_ `"22.0"`. The function is responsible
|
||||
for converting this to a number so that we can convert it to an integer. We must also properly handle invalid
|
||||
inputs (like non-numbers).
|
||||
What will enter the `$toint` callable (as `args[0]`) is the _string_ `"22.0"`. The function is responsible for converting this to a number so that we can convert it to an integer. We must also properly handle invalid inputs (like non-numbers).
|
||||
|
||||
If you want to mark an error, raise `evennia.utils.funcparser.ParsingError`. This stops the entire parsing
|
||||
of the string and may or may not raise the exception depending on what you set `raise_errors` to when you
|
||||
created the parser.
|
||||
If you want to mark an error, raise `evennia.utils.funcparser.ParsingError`. This stops the entire parsing of the string and may or may not raise the exception depending on what you set `raise_errors` to when you created the parser.
|
||||
|
||||
However, if you _nest_ functions, the return of the innermost function may be something other than
|
||||
a string. Let's introduce the `$eval` function, which evaluates simple expressions using
|
||||
|
|
@ -170,20 +154,16 @@ Since the `$eval` is the innermost call, it will get a string as input - the str
|
|||
It evaluates this and returns the `float` `22.0`. This time the outermost `$toint` will be called with
|
||||
this `float` instead of with a string.
|
||||
|
||||
> It's important to safely validate your inputs since users may end up nesting your callables in any order.
|
||||
> See the next section for useful tools to help with this.
|
||||
> It's important to safely validate your inputs since users may end up nesting your callables in any order. See the next section for useful tools to help with this.
|
||||
|
||||
In these examples, the result will be embedded in the larger string, so the result of the entire parsing
|
||||
will be a string:
|
||||
In these examples, the result will be embedded in the larger string, so the result of the entire parsing will be a string:
|
||||
|
||||
```python
|
||||
parser.parse(above_string)
|
||||
"There's a 22% chance of survival."
|
||||
```
|
||||
|
||||
However, if you use the `parse_to_any` (or `parse(..., return_str=False)`) and
|
||||
_don't add any extra string around the outermost function call_,
|
||||
you'll get the return type of the outermost callable back:
|
||||
However, if you use the `parse_to_any` (or `parse(..., return_str=False)`) and _don't add any extra string around the outermost function call_, you'll get the return type of the outermost callable back:
|
||||
|
||||
```python
|
||||
parser.parse_to_any("$toint($eval(10 * 2.2)")
|
||||
|
|
@ -245,9 +225,7 @@ non-developer players/builders and some things (such as complex
|
|||
classes/callables etc) are just not safe/possible to convert from string
|
||||
representation.
|
||||
|
||||
In `evennia.utils.utils` is a helper called
|
||||
[safe_convert_to_types](evennia.utils.utils.safe_convert_to_types). This function
|
||||
automates the conversion of simple data types in a safe way:
|
||||
In `evennia.utils.utils` is a helper called [safe_convert_to_types](evennia.utils.utils.safe_convert_to_types). This function automates the conversion of simple data types in a safe way:
|
||||
|
||||
```python
|
||||
from evennia.utils.utils import safe_convert_to_types
|
||||
|
|
@ -265,44 +243,23 @@ def _process_callable(*args, **kwargs):
|
|||
|
||||
```
|
||||
|
||||
In other words, in the callable `$process(expression, local, extra1=..,
|
||||
extra2=...)`, the first argument will be handled by the 'py' converter
|
||||
(described below), the second will passed through regular Python `str`,
|
||||
kwargs will be handled by `int` and `str` respectively. You can supply
|
||||
your own converter function as long as it takes one argument and returns
|
||||
the converted result.
|
||||
|
||||
In other words,
|
||||
In other words, in the callable `$process(expression, local, extra1=.., extra2=...)`, the first argument will be handled by the 'py' converter (described below), the second will passed through regular Python `str`, kwargs will be handled by `int` and `str` respectively. You can supply your own converter function as long as it takes one argument and returns the converted result.
|
||||
|
||||
```python
|
||||
args, kwargs = safe_convert_to_type(
|
||||
(tuple_of_arg_converters, dict_of_kwarg_converters), *args, **kwargs)
|
||||
```
|
||||
|
||||
The special converter `"py"` will try to convert a string argument to a Python structure with the help of the
|
||||
following tools (which you may also find useful to experiment with on your own):
|
||||
The special converter `"py"` will try to convert a string argument to a Python structure with the help of the following tools (which you may also find useful to experiment with on your own):
|
||||
|
||||
- [ast.literal_eval](https://docs.python.org/3.8/library/ast.html#ast.literal_eval) is an in-built Python
|
||||
function. It
|
||||
_only_ supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and `None`. That's
|
||||
it - no arithmetic or modifications of data is allowed. This is good for converting individual values and
|
||||
lists/dicts from the input line to real Python objects.
|
||||
- [simpleeval](https://pypi.org/project/simpleeval/) is a third-party tool included with Evennia. This
|
||||
allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings
|
||||
with `+-/*` as well as do simple comparisons like `4 > 3` and more. It does _not_ accept more complex
|
||||
containers like lists/dicts etc, so this and `literal_eval` are complementary to each other.
|
||||
- [ast.literal_eval](https://docs.python.org/3.8/library/ast.html#ast.literal_eval) is an in-built Python function. It _only_ supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and `None`. That's it - no arithmetic or modifications of data is allowed. This is good for converting individual values and lists/dicts from the input line to real Python objects.
|
||||
- [simpleeval](https://pypi.org/project/simpleeval/) is a third-party tool included with Evennia. This allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings with `+-/*` as well as do simple comparisons like `4 > 3` and more. It does _not_ accept more complex containers like lists/dicts etc, so this and `literal_eval` are complementary to each other.
|
||||
|
||||
```{warning}
|
||||
It may be tempting to run use Python's in-built ``eval()`` or ``exec()`` functions as converters since
|
||||
these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
|
||||
know that ONLY developers will ever modify the string going into the callable. The parser is intended
|
||||
for untrusted users (if you were trusted you'd have access to Python already). Letting untrusted users
|
||||
pass strings to ``eval``/``exec`` is a MAJOR security risk. It allows the caller to run arbitrary
|
||||
Python code on your server. This is the path to maliciously deleted hard drives. Just don't do it and
|
||||
sleep better at night.
|
||||
It may be tempting to run use Python's in-built ``eval()`` or ``exec()`` functions as converters since these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really know that ONLY developers will ever modify the string going into the callable. The parser is intended for untrusted users (if you were trusted you'd have access to Python already). Letting untrusted users pass strings to ``eval``/``exec`` is a MAJOR security risk. It allows the caller to run arbitrary Python code on your server. This is the path to maliciously deleted hard drives. Just don't do it and sleep better at night.
|
||||
```
|
||||
|
||||
## Default callables
|
||||
## Default funcparser callables
|
||||
|
||||
These are some example callables you can import and add your parser. They are divided into
|
||||
global-level dicts in `evennia.utils.funcparser`. Just import the dict(s) and merge/add one or
|
||||
|
|
@ -312,47 +269,27 @@ more to them when you create your `FuncParser` instance to have those callables
|
|||
|
||||
These are the 'base' callables.
|
||||
|
||||
- `$eval(expression)` ([code](evennia.utils.funcparser.funcparser_callable_eval)) -
|
||||
this uses `literal_eval` and `simple_eval` (see previous section) attemt to convert a string expression
|
||||
to a python object. This handles e.g. lists of literals `[1, 2, 3]` and simple expressions like `"1 + 2"`.
|
||||
- `$toint(number)` ([code](evennia.utils.funcparser.funcparser_callable_toint)) -
|
||||
always converts an output to an integer, if possible.
|
||||
- `$eval(expression)` ([code](evennia.utils.funcparser.funcparser_callable_eval)) - this uses `literal_eval` and `simple_eval` (see previous section) attemt to convert a string expression to a python object. This handles e.g. lists of literals `[1, 2, 3]` and simple expressions like `"1 + 2"`.
|
||||
- `$toint(number)` ([code](evennia.utils.funcparser.funcparser_callable_toint)) - always converts an output to an integer, if possible.
|
||||
- `$add/sub/mult/div(obj1, obj2)` ([code](evennia.utils.funcparser.funcparser_callable_add)) -
|
||||
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with
|
||||
`$eval`, this could for example be used also to add two lists together, which is not possible with `eval`;
|
||||
for example `$add($eval([1,2,3]), $eval([4,5,6])) -> [1, 2, 3, 4, 5, 6]`.
|
||||
- `$round(float, significant)` ([code](evennia.utils.funcparser.funcparser_callable_round)) -
|
||||
rounds an input float into the number of provided significant digits. For example `$round(3.54343, 3) -> 3.543`.
|
||||
- `$random([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_random)) -
|
||||
this works like the Python `random()` function, but will randomize to an integer value if both start/end are
|
||||
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with `$eval`, this could for example be used also to add two lists together, which is not possible with `eval`; for example `$add($eval([1,2,3]), $eval([4,5,6])) -> [1, 2, 3, 4, 5, 6]`.
|
||||
- `$round(float, significant)` ([code](evennia.utils.funcparser.funcparser_callable_round)) - rounds an input float into the number of provided significant digits. For example `$round(3.54343, 3) -> 3.543`.
|
||||
- `$random([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_random)) - this works like the Python `random()` function, but will randomize to an integer value if both start/end are
|
||||
integers. Without argument, will return a float between 0 and 1.
|
||||
- `$randint([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_randint)) -
|
||||
works like the `randint()` python function and always returns an integer.
|
||||
- `$choice(list)` ([code](evennia.utils.funcparser.funcparser_callable_choice)) -
|
||||
the input will automatically be parsed the same way as `$eval` and is expected to be an iterable. A random
|
||||
element of this list will be returned.
|
||||
- `$pad(text[, width, align, fillchar])` ([code](evennia.utils.funcparser.funcparser_callable_pad)) -
|
||||
this will pad content. `$pad("Hello", 30, c, -)` will lead to a text centered in a 30-wide block surrounded by `-`
|
||||
characters.
|
||||
- `$crop(text, width=78, suffix='[...]')` ([code](evennia.utils.funcparser.funcparser_callable_crop)) -
|
||||
this will crop a text longer than the width, by default ending it with a `[...]`-suffix that also fits within
|
||||
the width. If no width is given, the client width or `settings.DEFAULT_CLIENT_WIDTH` will be used.
|
||||
- `$space(num)` ([code](evennia.utils.funcparser.funcparser_callable_space)) -
|
||||
this will insert `num` spaces.
|
||||
- `$just(string, width=40, align=c, indent=2)` ([code](evennia.utils.funcparser.funcparser_callable_justify)) -
|
||||
justifies the text to a given width, aligning it left/right/center or 'f' for full (spread text across width).
|
||||
- `$randint([start, [end]])` ([code](evennia.utils.funcparser.funcparser_callable_randint)) - works like the `randint()` python function and always returns an integer.
|
||||
- `$choice(list)` ([code](evennia.utils.funcparser.funcparser_callable_choice)) - the input will automatically be parsed the same way as `$eval` and is expected to be an iterable. A random element of this list will be returned.
|
||||
- `$pad(text[, width, align, fillchar])` ([code](evennia.utils.funcparser.funcparser_callable_pad)) - this will pad content. `$pad("Hello", 30, c, -)` will lead to a text centered in a 30-wide block surrounded by `-` characters.
|
||||
- `$crop(text, width=78, suffix='[...]')` ([code](evennia.utils.funcparser.funcparser_callable_crop)) - this will crop a text longer than the width, by default ending it with a `[...]`-suffix that also fits within the width. If no width is given, the client width or `settings.DEFAULT_CLIENT_WIDTH` will be used.
|
||||
- `$space(num)` ([code](evennia.utils.funcparser.funcparser_callable_space)) - this will insert `num` spaces.
|
||||
- `$just(string, width=40, align=c, indent=2)` ([code](evennia.utils.funcparser.funcparser_callable_justify)) - justifies the text to a given width, aligning it left/right/center or 'f' for full (spread text across width).
|
||||
- `$ljust` - shortcut to justify-left. Takes all other kwarg of `$just`.
|
||||
- `$rjust` - shortcut to right justify.
|
||||
- `$cjust` - shortcut to center justify.
|
||||
- `$clr(startcolor, text[, endcolor])` ([code](evennia.utils.funcparser.funcparser_callable_clr)) -
|
||||
color text. The color is given with one or two characters without the preceeding `|`. If no endcolor is
|
||||
given, the string will go back to neutral, so `$clr(r, Hello)` is equivalent to `|rHello|n`.
|
||||
- `$clr(startcolor, text[, endcolor])` ([code](evennia.utils.funcparser.funcparser_callable_clr)) - color text. The color is given with one or two characters without the preceeding `|`. If no endcolor is given, the string will go back to neutral, so `$clr(r, Hello)` is equivalent to `|rHello|n`.
|
||||
|
||||
### `evennia.utils.funcparser.SEARCHING_CALLABLES`
|
||||
|
||||
These are callables that requires access-checks in order to search for objects. So they require some
|
||||
extra reserved kwargs to be passed when running the parser:
|
||||
|
||||
These are callables that requires access-checks in order to search for objects. So they require some extra reserved kwargs to be passed when running the parser:
|
||||
```python
|
||||
|
||||
parser.parse_to_any(string, caller=<object or account>, access="control", ...)
|
||||
|
|
@ -361,30 +298,23 @@ parser.parse_to_any(string, caller=<object or account>, access="control", ...)
|
|||
The `caller` is required, it's the the object to do the access-check for. The `access` kwarg is the
|
||||
[lock type](./Locks.md) to check, default being `"control"`.
|
||||
|
||||
- `$search(query,type=account|script,return_list=False)` ([code](evennia.utils.funcparser.funcparser_callable_search)) -
|
||||
this will look up and try to match an object by key or alias. Use the `type` kwarg to
|
||||
search for `account` or `script` instead. By default this will return nothing if there are more than one
|
||||
match; if `return_list` is `True` a list of 0, 1 or more matches will be returned instead.
|
||||
- `$search(query,type=account|script,return_list=False)` ([code](evennia.utils.funcparser.funcparser_callable_search)) - this will look up and try to match an object by key or alias. Use the `type` kwarg to search for `account` or `script` instead. By default this will return nothing if there are more than one match; if `return_list` is `True` a list of 0, 1 or more matches will be returned instead.
|
||||
- `$obj(query)`, `$dbref(query)` - legacy aliases for `$search`.
|
||||
- `$objlist(query)` - legacy alias for `$search`, always returning a list.
|
||||
|
||||
|
||||
### `evennia.utils.funcparser.ACTOR_STANCE_CALLABLES`
|
||||
|
||||
These are used to implement actor-stance emoting. They are used by the
|
||||
[DefaultObject.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method
|
||||
by default. You can read a lot more about this on the page
|
||||
These are used to implement actor-stance emoting. They are used by the [DefaultObject.msg_contents](evennia.objects.objects.DefaultObject.msg_contents) method by default. You can read a lot more about this on the page
|
||||
[Change messages per receiver](../Concepts/Change-Message-Per-Receiver.md).
|
||||
|
||||
On the parser side, all these inline functions require extra kwargs be passed into the parser
|
||||
(done by `msg_contents` by default):
|
||||
On the parser side, all these inline functions require extra kwargs be passed into the parser (done by `msg_contents` by default):
|
||||
|
||||
```python
|
||||
parser.parse(string, caller=<obj>, receiver=<obj>, mapping={'key': <obj>, ...})
|
||||
```
|
||||
|
||||
Here the `caller` is the one sending the message and `receiver` the one to see it. The `mapping` contains
|
||||
references to other objects accessible via these callables.
|
||||
Here the `caller` is the one sending the message and `receiver` the one to see it. The `mapping` contains references to other objects accessible via these callables.
|
||||
|
||||
- `$you([key])` ([code](evennia.utils.funcparser.funcparser_callable_you)) -
|
||||
if no `key` is given, this represents the `caller`, otherwise an object from `mapping`
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
# Help System
|
||||
|
||||
Evennia has an extensive help system covering both command-help and regular
|
||||
free-form help documentation. It supports subtopics and if failing to find a
|
||||
match it will provide suggestsions, first from alternative topics and then by
|
||||
finding mentions of the search term in help entries.
|
||||
|
||||
|
||||
> help theatre
|
||||
|
||||
```shell
|
||||
> help theatre
|
||||
```
|
||||
|
||||
```shell
|
||||
------------------------------------------------------------------------------
|
||||
Help for The theatre (aliases: the hub, curtains)
|
||||
|
||||
|
|
@ -22,9 +19,11 @@ Subtopics:
|
|||
------------------------------------------------------------------------------
|
||||
```
|
||||
|
||||
> help evennia
|
||||
|
||||
```shell
|
||||
> help evennia
|
||||
```
|
||||
|
||||
```shell
|
||||
------------------------------------------------------------------------------
|
||||
No help found
|
||||
|
||||
|
|
@ -36,7 +35,7 @@ Suggestions:
|
|||
-----------------------------------------------------------------------------
|
||||
```
|
||||
|
||||
## Using the help system from in-game
|
||||
Evennia has an extensive help system covering both command-help and regular free-form help documentation. It supports subtopics and if failing to find a match it will provide suggestsions, first from alternative topics and then by finding mentions of the search term in help entries.
|
||||
|
||||
The help system is accessed in-game by use of the `help` command:
|
||||
|
||||
|
|
@ -44,6 +43,16 @@ The help system is accessed in-game by use of the `help` command:
|
|||
|
||||
Sub-topics are accessed as `help <topic>/<subtopic>/...`.
|
||||
|
||||
## Working with three types of help entries
|
||||
|
||||
There are three ways to generate help entries:
|
||||
|
||||
- In the database
|
||||
- As Python modules
|
||||
- From Command doc strings
|
||||
|
||||
### Database-stored help entries
|
||||
|
||||
Creating a new help entry from in-game is done with
|
||||
|
||||
sethelp <topic>[;aliases] [,category] [,lockstring] = <text>
|
||||
|
|
@ -52,205 +61,24 @@ For example
|
|||
|
||||
sethelp The Gods;pantheon, Lore = In the beginning all was dark ...
|
||||
|
||||
Use the `/edit` switch to open the EvEditor for more convenient in-game writing
|
||||
(but note that devs can also create help entries outside the game using their
|
||||
regular code editor, see below).
|
||||
This will create a new help entry in the database. Use the `/edit` switch to open the EvEditor for more convenient in-game writing (but note that devs can also create help entries outside the game using their regular code editor, see below).
|
||||
|
||||
> You can also create help entries as Python modules, outside of the game. See
|
||||
> _FileHelp_ entries below.
|
||||
|
||||
## Sources of help entries
|
||||
|
||||
Evennia collects help entries from three sources:
|
||||
|
||||
- _Auto-generated command help_ - this is literally the doc-strings of
|
||||
the [Command classes](./Commands.md). The idea is that the command docs are
|
||||
easier to maintain and keep up-to-date if the developer can change them at the
|
||||
same time as they do the code.
|
||||
- _Database-stored help entries_ - These are created in-game (using the
|
||||
default `sethelp` command as exemplified in the previous section).
|
||||
- _File-stored help entries_ - These are created outside the game, as dicts in
|
||||
normal Python modules. They allows developers to write and maintain their help
|
||||
files using a proper text editor.
|
||||
|
||||
### The Help Entry
|
||||
|
||||
All help entries (no matter the source) have the following properties:
|
||||
|
||||
- `key` - This is the main topic-name. For Commands, this is literally the
|
||||
command's `key`.
|
||||
- `aliases` - Alternate names for the help entry. This can be useful if the main
|
||||
name is hard to remember.
|
||||
- `help_category` - The general grouping of the entry. This is optional. If not
|
||||
given it will use the default category given by
|
||||
`settings.COMMAND_DEFAULT_HELP_CATEGORY` for Commands and
|
||||
`settings.DEFAULT_HELP_CATEGORY` for file+db help entries.
|
||||
- `locks` - Lock string (for commands) or LockHandler (all help entries).
|
||||
This defines who may read this entry. See the next section.
|
||||
- `tags` - This is not used by default, but could be used to further organize
|
||||
help entries.
|
||||
- `text` - The actual help entry text. This will be dedented and stripped of
|
||||
extra space at beginning and end.
|
||||
|
||||
A `text` that scrolls off the screen will automatically be paginated by
|
||||
the [EvMore](./EvMore.md) pager (you can control this with
|
||||
`settings.HELP_MORE_ENABLED=False`). If you use EvMore and want to control
|
||||
exactly where the pager should break the page, mark the break with the control
|
||||
character `\f`.
|
||||
|
||||
#### Subtopics
|
||||
|
||||
```{versionadded} 1.0
|
||||
```
|
||||
|
||||
Rather than making a very long help entry, the `text` may also be broken up
|
||||
into _subtopics_. A list of the next level of subtopics are shown below the
|
||||
main help text and allows the user to read more about some particular detail
|
||||
that wouldn't fit in the main text.
|
||||
|
||||
Subtopics use a markup slightly similar to markdown headings. The top level
|
||||
heading must be named `# subtopics` (non case-sensitive) and the following
|
||||
headers must be sub-headings to this (so `## subtopic name` etc). All headings
|
||||
are non-case sensitive (the help command will format them). The topics can be
|
||||
nested at most to a depth of 5 (which is probably too many levels already). The
|
||||
parser uses fuzzy matching to find the subtopic, so one does not have to type
|
||||
it all out exactly.
|
||||
|
||||
Below is an example of a `text` with sub topics.
|
||||
|
||||
```
|
||||
The theatre is the heart of the city, here you can find ...
|
||||
(This is the main help text, what you get with `help theatre`)
|
||||
|
||||
# subtopics
|
||||
|
||||
## lore
|
||||
|
||||
The theatre holds many mysterious things...
|
||||
(`help theatre/lore`)
|
||||
|
||||
### the grand opening
|
||||
|
||||
The grand opening is the name for a mysterious event where ghosts appeared ...
|
||||
(`this is a subsub-topic to lore, accessible as `help theatre/lore/grand` or
|
||||
any other partial match).
|
||||
|
||||
### the Phantom
|
||||
|
||||
Deep under the theatre, rumors has it a monster hides ...
|
||||
(another subsubtopic, accessible as `help theatre/lore/phantom`)
|
||||
|
||||
## layout
|
||||
|
||||
The theatre is a two-story building situated at ...
|
||||
(`help theatre/layout`)
|
||||
|
||||
## dramatis personae
|
||||
|
||||
There are many interesting people prowling the halls of the theatre ...
|
||||
(`help theatre/dramatis` or `help theathre/drama` or `help theatre/personae` would work)
|
||||
|
||||
### Primadonna Ada
|
||||
|
||||
Everyone knows the primadonna! She is ...
|
||||
(A subtopic under dramatis personae, accessible as `help theatre/drama/ada` etc)
|
||||
|
||||
### The gatekeeper
|
||||
|
||||
He always keeps an eye on the door and ...
|
||||
(`help theatre/drama/gate`)
|
||||
|
||||
```
|
||||
### Command Auto-help system
|
||||
|
||||
The auto-help system uses the `__doc__` strings of your command classes and
|
||||
formats this to a nice- looking help entry. This makes for a very easy way to
|
||||
keep the help updated - just document your commands well and updating the help
|
||||
file is just a `reload` away.
|
||||
|
||||
Example (from a module with command definitions):
|
||||
The [HelpEntry](evennia.help.models.HelpEntry) stores database help. It is _not_ a Typeclassed entity and can't be extended using the typeclass mechanism.
|
||||
|
||||
Here's how to create a database-help entry in code:
|
||||
```python
|
||||
class CmdMyCmd(Command):
|
||||
"""
|
||||
mycmd - my very own command
|
||||
|
||||
Usage:
|
||||
mycmd[/switches] <args>
|
||||
|
||||
Switches:
|
||||
test - test the command
|
||||
run - do something else
|
||||
|
||||
This is my own command that does this and that.
|
||||
|
||||
"""
|
||||
# [...]
|
||||
|
||||
locks = "cmd:all();read:all()" # default
|
||||
help_category = "General" # default
|
||||
auto_help = True # default
|
||||
|
||||
# [...]
|
||||
```
|
||||
|
||||
The text at the very top of the command class definition is the class'
|
||||
`__doc__`-string and will be shown to users looking for help. Try to use a
|
||||
consistent format - all default commands are using the structure shown above.
|
||||
|
||||
You can limit access to the help entry by the `view` and/or `read` locks on the
|
||||
Command. See [the section below](./Help-System.md#locking-help-entries) for details.
|
||||
|
||||
You should also supply the `help_category` class property if you can; this helps
|
||||
to group help entries together for people to more easily find them. See the
|
||||
`help` command in-game to see the default categories. If you don't specify the
|
||||
category, `settings.COMMAND_DEFAULT_HELP_CATEGORY` (default is "General") is
|
||||
used.
|
||||
|
||||
If you don't want your command to be picked up by the auto-help system at all
|
||||
(like if you want to write its docs manually using the info in the next section
|
||||
or you use a [cmdset](./Command-Sets.md) that has its own help functionality) you
|
||||
can explicitly set `auto_help` class property to `False` in your command
|
||||
definition.
|
||||
|
||||
Alternatively, you can keep the advantages of *auto-help* in commands, but
|
||||
control the display of command helps. You can do so by overriding the command's
|
||||
`get_help(caller, cmdset)` method. By default, this method will return the
|
||||
class docstring. You could modify it to add custom behavior: the text returned
|
||||
by this method will be displayed to the character asking for help in this
|
||||
command.
|
||||
|
||||
### Database-help entries
|
||||
|
||||
These are most commonly created in-game using the `sethelp` command. If you need to create one
|
||||
manually, you can do so with `evennia.create_help_entry()`:
|
||||
|
||||
```python
|
||||
|
||||
from evennia import create_help_entry
|
||||
entry = create_help_entry("emote",
|
||||
"Emoting is important because ...",
|
||||
category="Roleplaying", locks="view:all()")
|
||||
```
|
||||
|
||||
The entity being created is a [evennia.help.models.HelpEntry](evennia.help.models.HelpEntry)
|
||||
object. This is _not_ a [Typeclassed](./Typeclasses.md) entity and is not meant to
|
||||
be modified to any great degree. It holds the properties listed earlier. The
|
||||
text is stored in a field `entrytext`. It does not provide a `get_help` method
|
||||
like commands, stores and returns the `entrytext` directly.
|
||||
|
||||
You can search for (db-)-`HelpEntry` objects using `evennia.search_help` but note that
|
||||
this will not return the two other types of help entries.
|
||||
|
||||
### File-help entries
|
||||
### File-stored help entries
|
||||
|
||||
```{versionadded} 1.0
|
||||
```
|
||||
|
||||
File-help entries are created by the game development team outside of the game. The
|
||||
help entries are defined in normal Python modules (`.py` file ending) containing
|
||||
a `dict` to represent each entry. They require a server `reload` before any changes
|
||||
apply.
|
||||
File-help entries are created by the game development team outside of the game. The help entries are defined in normal Python modules (`.py` file ending) containing a `dict` to represent each entry. They require a server `reload` before any changes apply.
|
||||
|
||||
- Evennia will look through all modules given by
|
||||
`settings.FILE_HELP_ENTRY_MODULES`. This should be a list of python-paths for
|
||||
|
|
@ -308,26 +136,37 @@ The help entry text will be dedented and will retain paragraphs. You should try
|
|||
to keep your strings a reasonable width (it will look better). Just reload the
|
||||
server and the file-based help entries will be available to view.
|
||||
|
||||
## Entry priority
|
||||
### Command-help entries
|
||||
|
||||
Should you have clashing help-entries between the three types of available
|
||||
entries, the priority is
|
||||
The `__docstring__` of [Command classes](./Commands.md) are automatically extracted into a help entry. You set `help_category` directly on the class.
|
||||
|
||||
Command-auto-help > Db-help > File-help
|
||||
```python
|
||||
from evennia import Command
|
||||
|
||||
So if you create a db-help entry 'foo', it will replace any file-based help
|
||||
entry 'foo'. But if there is a Command 'foo', that's the help you'll get when
|
||||
you enter `help foo`.
|
||||
class MyCommand(Command):
|
||||
"""
|
||||
This command is great!
|
||||
|
||||
The reasoning for this is that commands must always be understood in order to
|
||||
play the game. Meanwhile db-based help can be kept up-to-date from in-game
|
||||
builders and may be less 'static' than the file-based ones.
|
||||
Usage:
|
||||
mycommand [argument]
|
||||
|
||||
The `sethelp` command (which only deals with creating db-based help entries)
|
||||
will warn you if a new help entry might shadow/be shadowed by a
|
||||
same/similar-named command or file-based help entry.
|
||||
When this command is called, great things happen. If you
|
||||
pass an argument, even GREATER things HAPPEN!
|
||||
|
||||
## Locking help entries
|
||||
"""
|
||||
|
||||
key = "mycommand"
|
||||
|
||||
locks: "cmd:all();read:all()" # default
|
||||
help_category = "General" # default
|
||||
auto_help = True # default
|
||||
|
||||
# ...
|
||||
```
|
||||
|
||||
When you update your code, the command's help will follow. The idea is that the command docs are easier to maintain and keep up-to-date if the developer can change them at the same time as they do the code.
|
||||
|
||||
### Locking help entries
|
||||
|
||||
The default `help` command gather all available commands and help entries
|
||||
together so they can be searched or listed. By setting locks on the command/help
|
||||
|
|
@ -374,32 +213,101 @@ help_entry = {
|
|||
the new 'read' lock-type to control access to the entry itself.
|
||||
```
|
||||
|
||||
## Customizing the look of the help system
|
||||
### Customizing the look of the help system
|
||||
|
||||
This is done almost exclusively by overriding the `help` command
|
||||
[evennia.commands.default.help.CmdHelp](evennia.commands.default.help.CmdHelp).
|
||||
This is done almost exclusively by overriding the `help` command [evennia.commands.default.help.CmdHelp](evennia.commands.default.help.CmdHelp).
|
||||
|
||||
Since the available commands may vary from moment to moment, `help` is
|
||||
responsible for collating the three sources of help-entries (commands/db/file)
|
||||
together and search through them on the fly. It also does all the formatting of
|
||||
the output.
|
||||
Since the available commands may vary from moment to moment, `help` is responsible for collating the three sources of help-entries (commands/db/file) together and search through them on the fly. It also does all the formatting of the output.
|
||||
|
||||
To make it easier to tweak the look, the parts of the code that changes the visual presentation and entity searching has been broken out into separate methods on the command class. Override these in your version of `help` to change the display or tweak as you please. See the api link above for details.
|
||||
|
||||
## Subtopics
|
||||
|
||||
```{versionadded} 1.0
|
||||
```
|
||||
|
||||
Rather than making a very long help entry, the `text` may also be broken up into _subtopics_. A list of the next level of subtopics are shown below the main help text and allows the user to read more about some particular detail that wouldn't fit in the main text.
|
||||
|
||||
Subtopics use a markup slightly similar to markdown headings. The top level heading must be named `# subtopics` (non case-sensitive) and the following headers must be sub-headings to this (so `## subtopic name` etc). All headings are non-case sensitive (the help command will format them). The topics can be nested at most to a depth of 5 (which is probably too many levels already). The parser uses fuzzy matching to find the subtopic, so one does not have to type it all out exactly.
|
||||
|
||||
Below is an example of a `text` with sub topics.
|
||||
|
||||
```
|
||||
The theatre is the heart of the city, here you can find ...
|
||||
(This is the main help text, what you get with `help theatre`)
|
||||
|
||||
# subtopics
|
||||
|
||||
## lore
|
||||
|
||||
The theatre holds many mysterious things...
|
||||
(`help theatre/lore`)
|
||||
|
||||
### the grand opening
|
||||
|
||||
The grand opening is the name for a mysterious event where ghosts appeared ...
|
||||
(`this is a subsub-topic to lore, accessible as `help theatre/lore/grand` or
|
||||
any other partial match).
|
||||
|
||||
### the Phantom
|
||||
|
||||
Deep under the theatre, rumors has it a monster hides ...
|
||||
(another subsubtopic, accessible as `help theatre/lore/phantom`)
|
||||
|
||||
## layout
|
||||
|
||||
The theatre is a two-story building situated at ...
|
||||
(`help theatre/layout`)
|
||||
|
||||
## dramatis personae
|
||||
|
||||
There are many interesting people prowling the halls of the theatre ...
|
||||
(`help theatre/dramatis` or `help theathre/drama` or `help theatre/personae` would work)
|
||||
|
||||
### Primadonna Ada
|
||||
|
||||
Everyone knows the primadonna! She is ...
|
||||
(A subtopic under dramatis personae, accessible as `help theatre/drama/ada` etc)
|
||||
|
||||
### The gatekeeper
|
||||
|
||||
He always keeps an eye on the door and ...
|
||||
(`help theatre/drama/gate`)
|
||||
|
||||
```
|
||||
|
||||
To make it easier to tweak the look, the parts of the code that changes the
|
||||
visual presentation and entity searching has been broken out into separate
|
||||
methods on the command class. Override these in your version of `help` to change
|
||||
the display or tweak as you please. See the api link above for details.
|
||||
|
||||
## Technical notes
|
||||
|
||||
Since it needs to search so different types of data, the help system has to
|
||||
collect all possibilities in memory before searching through the entire set. It
|
||||
uses the [Lunr](https://github.com/yeraydiazdiaz/lunr.py) search engine to
|
||||
search through the main bulk of help entries. Lunr is a mature engine used for
|
||||
web-pages and produces much more sensible results than previous solutions.
|
||||
#### Help-entry clashes
|
||||
|
||||
Once the main entry has been found, subtopics are then searched with
|
||||
simple `==`, `startswith` and `in` matching (there are so relatively few of them
|
||||
at that point).
|
||||
Should you have clashing help-entries (of the same name) between the three types of available entries, the priority is
|
||||
|
||||
Command-auto-help > Db-help > File-help
|
||||
|
||||
The `sethelp` command (which only deals with creating db-based help entries) will warn you if a new help entry might shadow/be shadowed by a same/similar-named command or file-based help entry.
|
||||
|
||||
#### The Help Entry container
|
||||
|
||||
All help entries (no matter the source) are parsed into an object with the following properties:
|
||||
|
||||
- `key` - This is the main topic-name. For Commands, this is literally the command's `key`.
|
||||
- `aliases` - Alternate names for the help entry. This can be useful if the main name is hard to remember.
|
||||
- `help_category` - The general grouping of the entry. This is optional. If not given it will use the default category given by `settings.COMMAND_DEFAULT_HELP_CATEGORY` for Commands and
|
||||
`settings.DEFAULT_HELP_CATEGORY` for file+db help entries.
|
||||
- `locks` - Lock string (for commands) or LockHandler (all help entries). This defines who may read this entry. See the next section.
|
||||
- `tags` - This is not used by default, but could be used to further organize help entries.
|
||||
- `text` - The actual help entry text. This will be dedented and stripped of extra space at beginning and end.
|
||||
|
||||
#### Help pagination
|
||||
|
||||
A `text` that scrolls off the screen will automatically be paginated by the [EvMore](./EvMore.md) pager (you can control this with `settings.HELP_MORE_ENABLED=False`). If you use EvMore and want to control exactly where the pager should break the page, mark the break with the control character `\f`.
|
||||
|
||||
#### Search engine
|
||||
|
||||
Since it needs to search so different types of data, the help system has to collect all possibilities in memory before searching through the entire set. It uses the [Lunr](https://github.com/yeraydiazdiaz/lunr.py) search engine to search through the main bulk of help entries. Lunr is a mature engine used for web-pages and produces much more sensible results than previous solutions.
|
||||
|
||||
Once the main entry has been found, subtopics are then searched with simple `==`, `startswith` and `in` matching (there are so relatively few of them at that point).
|
||||
|
||||
```{versionchanged} 1.0
|
||||
Replaced the old bag-of-words algorithm with lunr package.
|
||||
|
|
|
|||
|
|
@ -1,34 +1,49 @@
|
|||
# Inputfuncs
|
||||
|
||||
```
|
||||
Internet│
|
||||
┌─────┐ │ ┌────────┐
|
||||
┌──────┐ │Text │ │ ┌────────────┐ ┌─────────┐ │Command │
|
||||
│Client├────┤JSON ├─┼──►commandtuple├────►Inputfunc├────►DB query│
|
||||
└──────┘ │etc │ │ └────────────┘ └─────────┘ │etc │
|
||||
└─────┘ │ └────────┘
|
||||
│Evennia
|
||||
|
||||
An *inputfunc* is an Evennia function that handles a particular input (an [inputcommand](../Concepts/OOB.md)) from
|
||||
the client. The inputfunc is the last destination for the inputcommand along the [ingoing message
|
||||
path](../Concepts/Messagepath.md#the-ingoing-message-path). The inputcommand always has the form `(commandname,
|
||||
(args), {kwargs})` and Evennia will use this to try to find and call an inputfunc on the form
|
||||
```
|
||||
|
||||
The Inputfunc is the last fixed step on the [Ingoing message path](../Concepts/Messagepath.md#ingoing-message-path). The available Inputfuncs are looked up and called using `commandtuple` structures sent from the client. The job of the Inputfunc is to perform whatever action is requested, by firing a Command, performing a database query or whatever is needed.
|
||||
|
||||
Given a `commandtuple` on the form
|
||||
|
||||
(commandname, (args), {kwargs})
|
||||
|
||||
Evennia will try to find and call an Inputfunc on the form
|
||||
|
||||
```python
|
||||
def commandname(session, *args, **kwargs):
|
||||
# ...
|
||||
def commandname(session, *args, **kwargs):
|
||||
# ...
|
||||
|
||||
```
|
||||
Or, if no match was found, it will call an inputfunc named "default" on this form
|
||||
|
||||
```python
|
||||
def default(session, cmdname, *args, **kwargs):
|
||||
# cmdname is the name of the mismatched inputcommand
|
||||
def default(session, cmdname, *args, **kwargs):
|
||||
# cmdname is the name of the mismatched inputcommand
|
||||
|
||||
```
|
||||
|
||||
The default inputfuncs are found in [evennia/server/inputfuncs.py](evennia.server.inputfuncs).
|
||||
|
||||
## Adding your own inputfuncs
|
||||
|
||||
This is simple. Add a function on the above form to `mygame/server/conf/inputfuncs.py`. Your
|
||||
function must be in the global, outermost scope of that module and not start with an underscore
|
||||
(`_`) to be recognized as an inputfunc. Reload the server. That's it. To overload a default
|
||||
inputfunc (see below), just add a function with the same name.
|
||||
1. Add a function on the above form to `mygame/server/conf/inputfuncs.py`. Your function must be in the global, outermost scope of that module and not start with an underscore (`_`) to be recognized as an inputfunc. i
|
||||
2. `reload` the server.
|
||||
|
||||
The modules Evennia looks into for inputfuncs are defined in the list `settings.INPUT_FUNC_MODULES`.
|
||||
This list will be imported from left to right and later imported functions will replace earlier
|
||||
ones.
|
||||
To overload a default inputfunc (see below), just add a function with the same name. You can also extend the settings-list `INPUT_FUNC_MODULES`.
|
||||
|
||||
INPUT_FUNC_MODULES += ["path.to.my.inputfunc.module"]
|
||||
|
||||
All global-level functions with a name not starting with `_` in these module(s) will be used by Evennia as an inputfunc. The list is imported from left to right, so latter imported functions will replace earlier ones.
|
||||
|
||||
## Default inputfuncs
|
||||
|
||||
|
|
@ -40,23 +55,19 @@ Evennia defines a few default inputfuncs to handle the common cases. These are d
|
|||
- Input: `("text", (textstring,), {})`
|
||||
- Output: Depends on Command triggered
|
||||
|
||||
This is the most common of inputcommands, and the only one supported by every traditional mud. The
|
||||
argument is usually what the user sent from their command line. Since all text input from the user
|
||||
like this is considered a [Command](./Commands.md), this inputfunc will do things like nick-replacement
|
||||
and then pass on the input to the central Commandhandler.
|
||||
This is the most common of inputs, and the only one supported by every traditional mud. The argument is usually what the user sent from their command line. Since all text input from the user
|
||||
like this is considered a [Command](./Commands.md), this inputfunc will do things like nick-replacement and then pass on the input to the central Commandhandler.
|
||||
|
||||
### echo
|
||||
|
||||
- Input: `("echo", (args), {})`
|
||||
- Output: `("text", ("Echo returns: %s" % args), {})`
|
||||
|
||||
This is a test input, which just echoes the argument back to the session as text. Can be used for
|
||||
testing custom client input.
|
||||
This is a test input, which just echoes the argument back to the session as text. Can be used for testing custom client input.
|
||||
|
||||
### default
|
||||
|
||||
The default function, as mentioned above, absorbs all non-recognized inputcommands. The default one
|
||||
will just log an error.
|
||||
The default function, as mentioned above, absorbs all non-recognized inputcommands. The default one will just log an error.
|
||||
|
||||
### client_options
|
||||
|
||||
|
|
@ -85,24 +96,21 @@ as an outputcommand `("client_options", (), {key=value, ...})`-
|
|||
- nomarkup (bool): Strip all text tags
|
||||
- raw (bool): Leave text tags unparsed
|
||||
|
||||
> Note that there are two GMCP aliases to this inputfunc - `hello` and `supports_set`, which means
|
||||
it will be accessed via the GMCP `Hello` and `Supports.Set` instructions assumed by some clients.
|
||||
> Note that there are two GMCP aliases to this inputfunc - `hello` and `supports_set`, which means it will be accessed via the GMCP `Hello` and `Supports.Set` instructions assumed by some clients.
|
||||
|
||||
### get_client_options
|
||||
|
||||
- Input: `("get_client_options, (), {key:value, ...})`
|
||||
- Output: `("client_options, (), {key:value, ...})`
|
||||
|
||||
This is a convenience wrapper that retrieves the current options by sending "get" to
|
||||
`client_options` above.
|
||||
This is a convenience wrapper that retrieves the current options by sending "get" to `client_options` above.
|
||||
|
||||
### get_inputfuncs
|
||||
|
||||
- Input: `("get_inputfuncs", (), {})`
|
||||
- Output: `("get_inputfuncs", (), {funcname:docstring, ...})`
|
||||
|
||||
Returns an outputcommand on the form `("get_inputfuncs", (), {funcname:docstring, ...})` - a list of
|
||||
all the available inputfunctions along with their docstrings.
|
||||
Returns an outputcommand on the form `("get_inputfuncs", (), {funcname:docstring, ...})` - a list of all the available inputfunctions along with their docstrings.
|
||||
|
||||
### login
|
||||
|
||||
|
|
@ -111,16 +119,14 @@ all the available inputfunctions along with their docstrings.
|
|||
- Input: `("login", (username, password), {})`
|
||||
- Output: Depends on login hooks
|
||||
|
||||
This performs the inputfunc version of a login operation on the current Session.
|
||||
This performs the inputfunc version of a login operation on the current Session. It's meant to be used by custom client setups.
|
||||
|
||||
### get_value
|
||||
|
||||
Input: `("get_value", (name, ), {})`
|
||||
Output: `("get_value", (value, ), {})`
|
||||
|
||||
Retrieves a value from the Character or Account currently controlled by this Session. Takes one
|
||||
argument, This will only accept particular white-listed names, you'll need to overload the function
|
||||
to expand. By default the following values can be retrieved:
|
||||
Retrieves a value from the Character or Account currently controlled by this Session. Takes one argument, This will only accept particular white-listed names, you'll need to overload the function to expand. By default the following values can be retrieved:
|
||||
|
||||
- "name" or "key": The key of the Account or puppeted Character.
|
||||
- "location": Name of the current location, or "None".
|
||||
|
|
@ -128,17 +134,11 @@ to expand. By default the following values can be retrieved:
|
|||
|
||||
### repeat
|
||||
|
||||
- Input: `("repeat", (), {"callback":funcname,
|
||||
"interval": secs, "stop": False})`
|
||||
- Input: `("repeat", (), {"callback":funcname, "interval": secs, "stop": False})`
|
||||
- Output: Depends on the repeated function. Will return `("text", (repeatlist),{}` with a list of
|
||||
accepted names if given an unfamiliar callback name.
|
||||
|
||||
This will tell evennia to repeatedly call a named function at a given interval. Behind the scenes
|
||||
this will set up a [Ticker](./TickerHandler.md). Only previously acceptable functions are possible to
|
||||
repeat-call in this way, you'll need to overload this inputfunc to add the ones you want to offer.
|
||||
By default only two example functions are allowed, "test1" and "test2", which will just echo a text
|
||||
back at the given interval. Stop the repeat by sending `"stop": True` (note that you must include
|
||||
both the callback name and interval for Evennia to know what to stop).
|
||||
This will tell evennia to repeatedly call a named function at a given interval. Behind the scenes this will set up a [Ticker](./TickerHandler.md). Only previously acceptable functions are possible to repeat-call in this way, you'll need to overload this inputfunc to add the ones you want to offer. By default only two example functions are allowed, "test1" and "test2", which will just echo a text back at the given interval. Stop the repeat by sending `"stop": True` (note that you must include both the callback name and interval for Evennia to know what to stop).
|
||||
|
||||
### unrepeat
|
||||
|
||||
|
|
@ -153,20 +153,15 @@ This is a convenience wrapper for sending "stop" to the `repeat` inputfunc.
|
|||
- Input: `("monitor", (), ("name":field_or_argname, stop=False)`
|
||||
- Output (on change): `("monitor", (), {"name":name, "value":value})`
|
||||
|
||||
This sets up on-object monitoring of Attributes or database fields. Whenever the field or Attribute
|
||||
changes in any way, the outputcommand will be sent. This is using the
|
||||
[MonitorHandler](./MonitorHandler.md) behind the scenes. Pass the "stop" key to stop monitoring. Note
|
||||
that you must supply the name also when stopping to let the system know which monitor should be
|
||||
cancelled.
|
||||
This sets up on-object monitoring of Attributes or database fields. Whenever the field or Attribute changes in any way, the outputcommand will be sent. This is using the [MonitorHandler](./MonitorHandler.md) behind the scenes. Pass the "stop" key to stop monitoring. Note that you must supply the name also when stopping to let the system know which monitor should be cancelled.
|
||||
|
||||
Only fields/attributes in a whitelist are allowed to be used, you have to overload this function to
|
||||
add more. By default the following fields/attributes can be monitored:
|
||||
Only fields/attributes in a whitelist are allowed to be used, you have to overload this function to add more. By default the following fields/attributes can be monitored:
|
||||
|
||||
- "name": The current character name
|
||||
- "location": The current location
|
||||
- "desc": The description Argument
|
||||
|
||||
## unmonitor
|
||||
### unmonitor
|
||||
|
||||
- Input: `("unmonitor", (), {"name":name})`
|
||||
- Output: None
|
||||
|
|
|
|||
|
|
@ -2,14 +2,11 @@
|
|||
|
||||
|
||||
For most games it is a good idea to restrict what people can do. In Evennia such restrictions are
|
||||
applied and checked by something called *locks*. All Evennia entities ([Commands](./Commands.md),
|
||||
[Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md), [Help System](./Help-System.md),
|
||||
[messages](./Msg.md) and [channels](./Channels.md)) are accessed through locks.
|
||||
applied and checked by something called *locks*. All Evennia entities ([Commands](./Commands.md), [Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts](./Accounts.md), [Help System](./Help-System.md), [messages](./Msg.md) and [channels](./Channels.md)) are accessed through locks.
|
||||
|
||||
A lock can be thought of as an "access rule" restricting a particular use of an Evennia entity.
|
||||
Whenever another entity wants that kind of access the lock will analyze that entity in different
|
||||
ways to determine if access should be granted or not. Evennia implements a "lockdown" philosophy -
|
||||
all entities are inaccessible unless you explicitly define a lock that allows some or full access.
|
||||
ways to determine if access should be granted or not. Evennia implements a "lockdown" philosophy - all entities are inaccessible unless you explicitly define a lock that allows some or full access.
|
||||
|
||||
Let's take an example: An object has a lock on itself that restricts how people may "delete" that
|
||||
object. Apart from knowing that it restricts deletion, the lock also knows that only players with
|
||||
|
|
@ -18,7 +15,7 @@ on the object, the `delete` command makes sure to check if this player is really
|
|||
It calls the lock, which in turn checks if the player's id is `34`. Only then will it allow `delete`
|
||||
to go on with its job.
|
||||
|
||||
## Setting and checking a lock
|
||||
## Working with locks
|
||||
|
||||
The in-game command for setting locks on objects is `lock`:
|
||||
|
||||
|
|
@ -46,7 +43,7 @@ command:
|
|||
return
|
||||
```
|
||||
|
||||
## Defining locks
|
||||
### Defining locks
|
||||
|
||||
Defining a lock (i.e. an access restriction) in Evennia is done by adding simple strings of lock
|
||||
definitions to the object's `locks` property using `obj.locks.add()`.
|
||||
|
|
@ -92,32 +89,27 @@ the default command set) actually checks for, as in the example of `delete` abov
|
|||
|
||||
Below are the access_types checked by the default commandset.
|
||||
|
||||
- [Commands](./Commands.md)
|
||||
- `cmd` - this defines who may call this command at all.
|
||||
- [Objects](./Objects.md):
|
||||
- `control` - who is the "owner" of the object. Can set locks, delete it etc. Defaults to the
|
||||
creator of the object.
|
||||
- `call` - who may call Object-commands stored on this Object except for the Object itself. By
|
||||
default, Objects share their Commands with anyone in the same location (e.g. so you can 'press' a
|
||||
`Button` object in the room). For Characters and Mobs (who likely only use those Commands for
|
||||
themselves and don't want to share them) this should usually be turned off completely, using
|
||||
something like `call:false()`.
|
||||
- `examine` - who may examine this object's properties.
|
||||
- `delete` - who may delete the object.
|
||||
- `edit` - who may edit properties and attributes of the object.
|
||||
- `view` - if the `look` command will display/list this object in descriptions
|
||||
- [Commands](./Commands.md)
|
||||
- `cmd` - this defines who may call this command at all.
|
||||
- [Objects](./Objects.md):
|
||||
- `control` - who is the "owner" of the object. Can set locks, delete it etc. Defaults to the creator of the object.
|
||||
- `call` - who may call Object-commands stored on this Object except for the Object itself. By default, Objects share their Commands with anyone in the same location (e.g. so you can 'press' a `Button` object in the room). For Characters and Mobs (who likely only use those Commands for themselves and don't want to share them) this should usually be turned off completely, using something like `call:false()`.
|
||||
- `examine` - who may examine this object's properties.
|
||||
- `delete` - who may delete the object.
|
||||
- `edit` - who may edit properties and attributes of the object.
|
||||
- `view` - if the `look` command will display/list this object in descriptions
|
||||
and if you will be able to see its description. Note that if
|
||||
you target it specifically by name, the system will still find it, just
|
||||
not be able to look at it. See `search` lock to completely hide the item.
|
||||
- `search` - this controls if the object can be found with the
|
||||
- `search` - this controls if the object can be found with the
|
||||
`DefaultObject.search` method (usually referred to with `caller.search`
|
||||
in Commands). This is how to create entirely 'undetectable' in-game objects.
|
||||
If not setting this lock excplicitly, all objects are assumed searchable.
|
||||
Note that if you are aiming to make some _permanently invisible game system,
|
||||
using a [Script](./Scripts.md) is a better bet.
|
||||
- `get`- who may pick up the object and carry it around.
|
||||
- `puppet` - who may "become" this object and control it as their "character".
|
||||
- `attrcreate` - who may create new attributes on the object (default True)
|
||||
- `get`- who may pick up the object and carry it around.
|
||||
- `puppet` - who may "become" this object and control it as their "character".
|
||||
- `attrcreate` - who may create new attributes on the object (default True)
|
||||
- [Characters](./Objects.md#characters):
|
||||
- Same as for Objects
|
||||
- [Exits](./Objects.md#exits):
|
||||
|
|
@ -141,15 +133,11 @@ boot listeners etc.
|
|||
- `examine` - who may view this help entry (usually everyone)
|
||||
- `edit` - who may edit this help entry.
|
||||
|
||||
So to take an example, whenever an exit is to be traversed, a lock of the type *traverse* will be
|
||||
checked. Defining a suitable lock type for an exit object would thus involve a lockstring `traverse:
|
||||
<lock functions>`.
|
||||
So to take an example, whenever an exit is to be traversed, a lock of the type *traverse* will be checked. Defining a suitable lock type for an exit object would thus involve a lockstring `traverse: <lock functions>`.
|
||||
|
||||
### Custom access_types
|
||||
|
||||
As stated above, the `access_type` part of the lock is simply the 'name' or 'type' of the lock. The
|
||||
text is an arbitrary string that must be unique for an object. If adding a lock with the same
|
||||
`access_type` as one that already exists on the object, the new one override the old one.
|
||||
As stated above, the `access_type` part of the lock is simply the 'name' or 'type' of the lock. The text is an arbitrary string that must be unique for an object. If adding a lock with the same `access_type` as one that already exists on the object, the new one override the old one.
|
||||
|
||||
For example, if you wanted to create a bulletin board system and wanted to restrict who can either
|
||||
read a board or post to a board. You could then define locks such as:
|
||||
|
|
@ -172,7 +160,7 @@ trying to read the board):
|
|||
|
||||
### Lock functions
|
||||
|
||||
A lock function is a normal Python function put in a place Evennia looks for such functions. The
|
||||
A _lock function_ is a normal Python function put in a place Evennia looks for such functions. The
|
||||
modules Evennia looks at is the list `settings.LOCK_FUNC_MODULES`. *All functions* in any of those
|
||||
modules will automatically be considered a valid lock function. The default ones are found in
|
||||
`evennia/locks/lockfuncs.py` and you can start adding your own in `mygame/server/conf/lockfuncs.py`.
|
||||
|
|
@ -240,7 +228,7 @@ permissions and dbrefs of *Accounts*, not on Characters.
|
|||
- `serversetting(settingname, value)` - Only returns True if Evennia has a given setting or a
|
||||
setting set to a given value.
|
||||
|
||||
## Checking simple strings
|
||||
### 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
|
||||
|
|
@ -253,10 +241,9 @@ has a method `check_lockstring(accessing_obj, lockstring, bypass_superuser=False
|
|||
return
|
||||
```
|
||||
|
||||
Note here that the `access_type` can be left to a dummy value since this method does not actually do
|
||||
a Lock lookup.
|
||||
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
|
||||
### Default locks
|
||||
|
||||
Evennia sets up a few basic locks on all new objects and accounts (if we didn't, noone would have
|
||||
any access to anything from the start). This is all defined in the root [Typeclasses](./Typeclasses.md)
|
||||
|
|
@ -307,7 +294,7 @@ This is how the `create` command sets up new objects. In sequence, this permissi
|
|||
owner of this object be the creator (the one running `create`). Builders may examine the object
|
||||
whereas only Admins and the creator may delete it. Everyone can pick it up.
|
||||
|
||||
## A complete example of setting locks on an object
|
||||
### A complete example of setting locks on an object
|
||||
|
||||
Assume we have two objects - one is ourselves (not superuser) and the other is an [Object](./Objects.md)
|
||||
called `box`.
|
||||
|
|
@ -374,14 +361,6 @@ If you wanted to set this up in python code, it would look something like this:
|
|||
|
||||
## On Django's permission system
|
||||
|
||||
Django also implements a comprehensive permission/security system of its own. The reason we don't
|
||||
use that is because it is app-centric (app in the Django sense). Its permission strings are of the
|
||||
form `appname.permstring` and it automatically adds three of them for each database model in the app
|
||||
- for the app evennia/object this would be for example 'object.create', 'object.admin' and
|
||||
'object.edit'. This makes a lot of sense for a web application, not so much for a MUD, especially
|
||||
when we try to hide away as much of the underlying architecture as possible.
|
||||
Django also implements a comprehensive permission/security system of its own. The reason we don't use that is because it is app-centric (app in the Django sense). Its permission strings are of the form `appname.permstring` and it automatically adds three of them for each database model in the app - for the app evennia/object this would be for example 'object.create', 'object.admin' and 'object.edit'. This makes a lot of sense for a web application, not so much for a MUD, especially when we try to hide away as much of the underlying architecture as possible.
|
||||
|
||||
The django permissions are not completely gone however. We use it for validating passwords during
|
||||
login. It is also used exclusively for managing Evennia's web-based admin site, which is a graphical
|
||||
front-end for the database of Evennia. You edit and assign such permissions directly from the web
|
||||
interface. It's stand-alone from the permissions described above.
|
||||
The django permissions are not completely gone however. We use it for validating passwords during login. It is also used exclusively for managing Evennia's web-based admin site, which is a graphical front-end for the database of Evennia. You edit and assign such permissions directly from the web interface. It's stand-alone from the permissions described above.
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
# Msg
|
||||
|
||||
The [Msg](evennia.comms.models.Msg) object represents a database-saved
|
||||
piece of communication. Think of it as a discrete piece of email - it contains
|
||||
a message, some metadata and will always have a sender and one or more
|
||||
recipients.
|
||||
The [Msg](evennia.comms.models.Msg) object represents a database-saved piece of communication. Think of it as a discrete piece of email - it contains a message, some metadata and will always have a sender and one or more recipients.
|
||||
|
||||
Once created, a Msg is normally not changed. It is persitently saved in the
|
||||
database. This allows for comprehensive logging of communications. Here are some
|
||||
good uses for `Msg` objects:
|
||||
Once created, a Msg is normally not changed. It is persitently saved in the database. This allows for comprehensive logging of communications. Here are some good uses for `Msg` objects:
|
||||
|
||||
- page/tells (the `page` command is how Evennia uses them out of the box)
|
||||
- messages in a bulletin board
|
||||
- game-wide email stored in 'mailboxes'.
|
||||
|
||||
|
||||
```{important}
|
||||
|
||||
A `Msg` does not have any in-game representation. So if you want to use them
|
||||
|
|
@ -29,13 +23,9 @@ good uses for `Msg` objects:
|
|||
Channels dropped Msg-support. Now only used in `page` command by default.
|
||||
```
|
||||
|
||||
## Msg in code
|
||||
|
||||
The Msg is intended to be used exclusively in code, to build other game systems. It is _not_
|
||||
a [Typeclassed](./Typeclasses.md) entity, which means it cannot (easily) be overridden. It
|
||||
doesn't support Attributes (but it _does_ support [Tags](./Tags.md)). It tries to be lean
|
||||
and small since a new one is created for every message.
|
||||
## Working with Msg
|
||||
|
||||
The Msg is intended to be used exclusively in code, to build other game systems. It is _not_ a [Typeclassed](./Typeclasses.md) entity, which means it cannot (easily) be overridden. It doesn't support Attributes (but it _does_ support [Tags](./Tags.md)). It tries to be lean and small since a new one is created for every message.
|
||||
You create a new message with `evennia.create_message`:
|
||||
|
||||
```python
|
||||
|
|
@ -88,8 +78,4 @@ You can search for `Msg` objects in various ways:
|
|||
|
||||
## TempMsg
|
||||
|
||||
[evennia.comms.models.TempMsg](evennia.comms.models.TempMsg) is an object
|
||||
that implements the same API as the regular `Msg`, but which has no database
|
||||
component (and thus cannot be searched). It's meant to plugged into systems
|
||||
expecting a `Msg` but where you just want to process the message without saving
|
||||
it.
|
||||
[evennia.comms.models.TempMsg](evennia.comms.models.TempMsg) is an object that implements the same API as the regular `Msg`, but which has no database component (and thus cannot be searched). It's meant to plugged into systems expecting a `Msg` but where you just want to process the message without saving it.
|
||||
|
|
|
|||
|
|
@ -49,9 +49,9 @@ Here are the import paths for the relevant child classes in the game dir
|
|||
- `mygame.typeclasses.rooms.Room` (inherits from `DefaultRoom`)
|
||||
- `mygame.typeclasses.exits.Exit` (inherits from `DefaultExit`)
|
||||
|
||||
## How to create your own object types
|
||||
## Working with Objects
|
||||
|
||||
You can easily add your own in-game behavior by either modifying one of the typeclasses in your game dir or by inheriting from them.
|
||||
You can easily add your own in-game behavior by either modifying one of the typeclasses in your game dir or by inheriting from them.
|
||||
|
||||
You can put your new typeclass directly in the relevant module, or you could organize your code in some other way. Here we assume we make a new module `mygame/typeclasses/flowers.py`:
|
||||
|
||||
|
|
@ -71,13 +71,11 @@ You can put your new typeclass directly in the relevant module, or you could org
|
|||
self.db.desc = "This is a pretty rose with thorns."
|
||||
```
|
||||
|
||||
Now you just need to point to the class *Rose* with the `create` command
|
||||
to make a new rose:
|
||||
Now you just need to point to the class *Rose* with the `create` command to make a new rose:
|
||||
|
||||
create/drop MyRose:flowers.Rose
|
||||
|
||||
What the `create` command actually *does* is to use the [evennia.create_object](evennia.utils.create.create_object)
|
||||
function. You can do the same thing yourself in code:
|
||||
What the `create` command actually *does* is to use the [evennia.create_object](evennia.utils.create.create_object) function. You can do the same thing yourself in code:
|
||||
|
||||
```python
|
||||
from evennia import create_object
|
||||
|
|
@ -91,31 +89,9 @@ your own building commands).
|
|||
|
||||
This particular Rose class doesn't really do much, all it does it make sure the attribute
|
||||
`desc`(which is what the `look` command looks for) is pre-set, which is pretty pointless since you
|
||||
will usually want to change this at build time (using the `desc` command or using the
|
||||
[Spawner](./Prototypes.md)).
|
||||
will usually want to change this at build time (using the `desc` command or using the [Spawner](./Prototypes.md)).
|
||||
|
||||
## Adding common functionality
|
||||
|
||||
`Object`, `Character`, `Room` and `Exit` also inherit from `mygame.typeclasses.objects.ObjectParent`.
|
||||
This is an empty 'mixin' class. Optionally, you can modify this class if you want to easily add some _common_ functionality to all your Objects, Characters, Rooms and Exits at once. You can still customize each subclass separately (see the Python docs on [multiple inheritance](https://docs.python.org/3/tutorial/classes.html#multiple-inheritance) for details).
|
||||
|
||||
Here is an example:
|
||||
|
||||
```python
|
||||
# in mygame/typeclasses/objects.py
|
||||
# ...
|
||||
|
||||
from evennia.objects.objects import DefaultObject
|
||||
|
||||
class ObjectParent:
|
||||
def at_pre_get(self, getter, **kwargs):
|
||||
# make all entities by default un-pickable
|
||||
return False
|
||||
```
|
||||
|
||||
Now all of `Object`, `Exit`. `Room` and `Character` default to not being able to be picked up using the `get` command.
|
||||
|
||||
## Properties and functions on Objects
|
||||
### Properties and functions on Objects
|
||||
|
||||
Beyond the properties assigned to all [typeclassed](./Typeclasses.md) objects (see that page for a list
|
||||
of those), the Object also has the following custom properties:
|
||||
|
|
@ -149,23 +125,46 @@ The Object also has a host of useful utility functions. See the function headers
|
|||
|
||||
The Object Typeclass defines many more *hook methods* beyond `at_object_creation`. Evennia calls these hooks at various points. When implementing your custom objects, you will inherit from the base parent and overload these hooks with your own custom code. See `evennia.objects.objects` for an updated list of all the available hooks or the [API for DefaultObject here](evennia.objects.objects.DefaultObject).
|
||||
|
||||
## Subclasses of `Object`
|
||||
|
||||
There are three special subclasses of *Object* in default Evennia - *Characters*, *Rooms* and *Exits*. The reason they are separated is because these particular object types are fundamental, something you will always need and in some cases requires some extra attention in order to be recognized by the game engine (there is nothing stopping you from redefining them though). In practice they are all pretty similar to the base Object.
|
||||
## Characters
|
||||
|
||||
### Characters
|
||||
The [DefaultCharacters](evennia.objects.objects.DefaultCharacter) is the root class for player in-game entities. They are usually _puppeted_ by [Accounts](./Accounts.md).
|
||||
|
||||
Characters are objects controlled by [Accounts](./Accounts.md). When a new Account logs in to Evennia for the first time, a new `Character` object is created and the Account object is assigned to the `account` attribute. A `Character` object must have a [Default Commandset](./Command-Sets.md) set on itself at creation, or the account will not be able to issue any commands! If you just inherit your own class from `evennia.DefaultCharacter` and make sure to use `super()` to call the parent methods you should be fine. In `mygame/typeclasses/characters.py` is an empty `Character` class ready for you to modify.
|
||||
When a new Account logs in to Evennia for the first time, a new `Character` object is created and the Account object is assigned to the `account` attribute (but Evennia supports [alternative connection-styles](../Concepts/Connection-Styles.md) if so desired).
|
||||
|
||||
### Rooms
|
||||
A `Character` object must have a [Default Commandset](./Command-Sets.md) set on itself at creation, or the account will not be able to issue any commands!
|
||||
|
||||
*Rooms* are the root containers of all other objects. The only thing really separating a room from any other object is that they have no `location` of their own and that default commands like `@dig` creates objects of this class - so if you want to expand your rooms with more functionality, just inherit from `ev.DefaultRoom`. In `mygame/typeclasses/rooms.py` is an empty `Room` class ready for you to modify.
|
||||
If you want to change the default character created by the default commands, you can change it in settings:
|
||||
|
||||
### Exits
|
||||
BASE_CHARACTER_TYPECLASS = "typeclasses.characters.Character"
|
||||
|
||||
This deafult points at the empty class in `mygame/typeclasses/characters.py` , ready for you to modify as you please.
|
||||
|
||||
## Rooms
|
||||
|
||||
[Rooms](evennia.objects.objects.DefaultRoom) are the root containers of all other objects.
|
||||
|
||||
The only thing really separating a room from any other object is that they have no `location` of their own and that default commands like `dig` creates objects of this class - so if you want to expand your rooms with more functionality, just inherit from `evennia.DefaultRoom`.
|
||||
|
||||
To change the default room created by `dig`, `tunnel` and other commands, change it in settings:
|
||||
|
||||
BASE_ROOM_TYPECLASS = "typeclases.rooms.Room"
|
||||
|
||||
The empty class in `mygame/typeclasses/rooms.py` is a good place to start!
|
||||
|
||||
## Exits
|
||||
|
||||
*Exits* are objects connecting other objects (usually *Rooms*) together. An object named *North* or *in* might be an exit, as well as *door*, *portal* or *jump out the window*. An exit has two things that separate them from other objects. Firstly, their *destination* property is set and points to a valid object. This fact makes it easy and fast to locate exits in the database. Secondly, exits define a special [Transit Command](./Commands.md) on themselves when they are created. This command is named the same as the exit object and will, when called, handle the practicalities of moving the character to the Exits's *destination* - this allows you to just enter the name of the exit on its own to move around, just as you would expect.
|
||||
|
||||
The exit functionality is all defined on the Exit typeclass, so you could in principle completely change how exits work in your game (it's not recommended though, unless you really know what you are doing). Exits are [locked](./Locks.md) using an access_type called *traverse* and also make use of a few hook methods for giving feedback if the traversal fails. See `evennia.DefaultExit` for more info. In `mygame/typeclasses/exits.py` there is an empty `Exit` class for you to modify.
|
||||
The exit functionality is all defined on the Exit typeclass, so you could in principle completely change how exits work in your game (it's not recommended though, unless you really know what you are doing). Exits are [locked](./Locks.md) using an access_type called *traverse* and also make use of a few hook methods for giving feedback if the traversal fails. See `evennia.DefaultExit` for more info.
|
||||
|
||||
Exits are normally overridden on a case-by-case basis, but if you want to change the default exit createad by rooms like `dig` , `tunnel` or `open` you can change it in settings:
|
||||
|
||||
BASE_EXIT_TYPECLASS = "typeclasses.exits.Exit"
|
||||
|
||||
In `mygame/typeclasses/exits.py` there is an empty `Exit` class for you to modify.
|
||||
|
||||
### Exit details
|
||||
|
||||
The process of traversing an exit is as follows:
|
||||
|
||||
|
|
@ -182,4 +181,25 @@ The process of traversing an exit is as follows:
|
|||
1. `obj.at_post_move(source)`
|
||||
1. On the Exit object, `at_post_traverse(obj, source)` is triggered.
|
||||
|
||||
If the move fails for whatever reason, the Exit will look for an Attribute `err_traverse` on itself and display this as an error message. If this is not found, the Exit will instead call `at_failed_traverse(obj)` on itself.
|
||||
If the move fails for whatever reason, the Exit will look for an Attribute `err_traverse` on itself and display this as an error message. If this is not found, the Exit will instead call `at_failed_traverse(obj)` on itself.
|
||||
|
||||
## Adding common functionality
|
||||
|
||||
`Object`, `Character`, `Room` and `Exit` also inherit from `mygame.typeclasses.objects.ObjectParent`.
|
||||
This is an empty 'mixin' class. Optionally, you can modify this class if you want to easily add some _common_ functionality to all your Objects, Characters, Rooms and Exits at once. You can still customize each subclass separately (see the Python docs on [multiple inheritance](https://docs.python.org/3/tutorial/classes.html#multiple-inheritance) for details).
|
||||
|
||||
Here is an example:
|
||||
|
||||
```python
|
||||
# in mygame/typeclasses/objects.py
|
||||
# ...
|
||||
|
||||
from evennia.objects.objects import DefaultObject
|
||||
|
||||
class ObjectParent:
|
||||
def at_pre_get(self, getter, **kwargs):
|
||||
# make all entities by default un-pickable
|
||||
return False
|
||||
```
|
||||
|
||||
Now all of `Object`, `Exit`. `Room` and `Character` default to not being able to be picked up using the `get` command.
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ This makes the superuser impossible to lock out, but makes it unsuitable to actu
|
|||
test the game's locks and restrictions with (see `quell` below). Usually there is no need to have
|
||||
but one superuser.
|
||||
|
||||
## Managing Permissions
|
||||
## Working with Permissions
|
||||
|
||||
In-game, you use the `perm` command to add and remove permissions
|
||||
|
||||
|
|
@ -49,7 +49,7 @@ typeclassed entities as the property `.permissions`:
|
|||
obj.permissions.remove("Blacksmith")
|
||||
```
|
||||
|
||||
## The permission hierarchy
|
||||
### The permission hierarchy
|
||||
|
||||
Selected permission strings can be organized in a *permission hierarchy* by editing the tuple
|
||||
`settings.PERMISSION_HIERARCHY`. Evennia's default permission hierarchy is as follows
|
||||
|
|
@ -67,7 +67,7 @@ Selected permission strings can be organized in a *permission hierarchy* by edit
|
|||
|
||||
When checking a hierarchical permission (using one of the methods to follow), you will pass checks for your level and all *below* you. That is, even if the check explicitly checks for "Builder" level access, you will actually pass if you have one of "Builder", "Admin" or "Developer". By contrast, if you check for a non-hierarchical permission, like "Blacksmith" you *must* have exactly that permission to pass.
|
||||
|
||||
## Checking permissions
|
||||
### Checking permissions
|
||||
|
||||
It's important to note that you check for the permission of a *puppeted* [Object](./Objects.md) (like a Character), the check will always first use the permissions of any `Account` connected to that Object before checking for permissions on the Object. In the case of hierarchical permissions (Admins, Builders etc), the Account permission will always be used (this stops an Account from escalating their permission by puppeting a high-level Character). If the permission looked for is not in the hierarchy, an exact match is required, first on the Account and if not found there (or if no Account is connected), then on the Object itself.
|
||||
|
||||
|
|
@ -165,16 +165,6 @@ An example of a puppet with a connected account:
|
|||
# precedence.
|
||||
```
|
||||
|
||||
## Superusers
|
||||
|
||||
There is normally only one *superuser* account and that is the one first created
|
||||
when starting Evennia (User #1). This is sometimes known as the "Owner" or "God"
|
||||
user. A superuser has more than full access - it completely *bypasses* all
|
||||
locks and will always pass the `PermissionHandler.check()` check. This allows
|
||||
for the superuser to always have access to everything in an emergency. But it
|
||||
could also hide any eventual errors you might have made in your lock definitions. So
|
||||
when trying out game systems you should either use quelling (see below) or make
|
||||
a second Developer-level character that does not bypass such checks.
|
||||
|
||||
## Quelling
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,5 @@
|
|||
# Portal And Server
|
||||
|
||||
|
||||
Evennia consists of two processes, known as *Portal* and *Server*. They can be controlled from
|
||||
inside the game or from the command line as described [in the Running-Evennia doc](../Setup/Running-Evennia.md).
|
||||
|
||||
In short, the Portal knows everything about internet protocols (telnet, websockets etc), but knows very little about the game.
|
||||
|
||||
In contrast, the Server knows everything about the game. It knows that a player has connected but now _how_ they connected.
|
||||
|
||||
The effect of this is that you can fully `reload` the Server and have players still connected to the game. One the server comes back up, it will re-connect to the Portal and re-sync all players as if nothing happened.
|
||||
|
||||
```
|
||||
Internet│ ┌──────────┐ ┌─┐ ┌─┐ ┌─────────┐
|
||||
│ │Portal │ │S│ ┌───┐ │S│ │Server │
|
||||
|
|
@ -24,4 +14,13 @@ Internet│ ┌──────────┐ ┌─┐ ┌─┐
|
|||
│Evennia
|
||||
```
|
||||
|
||||
The Server and Portal are glued together via an AMP (Asynchronous Messaging Protocol) connection. This allows the two programs to communicate seamlessly on the same machine.
|
||||
The _Portal_ and _Server_ consitutes the two main halves of Evennia.
|
||||
|
||||
These are two separate `twistd` processes and can be controlled from inside the game or from the command line as described [in the Running-Evennia doc](../Setup/Running-Evennia.md).
|
||||
|
||||
- The Portal knows everything about internet protocols (telnet, websockets etc), but knows very little about the game.
|
||||
- The Server knows everything about the game. It knows that a player has connected but now _how_ they connected.
|
||||
|
||||
The effect of this is that you can fully `reload` the Server and have players still connected to the game. One the server comes back up, it will re-connect to the Portal and re-sync all players as if nothing happened.
|
||||
|
||||
The Portal and Server are intended to always run on the same machine. They are glued together via an AMP (Asynchronous Messaging Protocol) connection. This allows the two programs to communicate seamlessly.
|
||||
|
|
@ -1,53 +1,36 @@
|
|||
# Spawner and Prototypes
|
||||
|
||||
```shell
|
||||
> spawn goblin
|
||||
|
||||
The *spawner* is a system for defining and creating individual objects from a base template called a
|
||||
*prototype*. It is only designed for use with in-game [Objects](./Objects.md), not any other type of
|
||||
entity.
|
||||
Spawned Goblin Grunt(#45)
|
||||
```
|
||||
|
||||
The normal way to create a custom object in Evennia is to make a [Typeclass](./Typeclasses.md). If you
|
||||
haven't read up on Typeclasses yet, think of them as normal Python classes that save to the database
|
||||
behind the scenes. Say you wanted to create a "Goblin" enemy. A common way to do this would be to
|
||||
first create a `Mobile` typeclass that holds everything common to mobiles in the game, like generic
|
||||
AI, combat code and various movement methods. A `Goblin` subclass is then made to inherit from
|
||||
`Mobile`. The `Goblin` class adds stuff unique to goblins, like group-based AI (because goblins are
|
||||
smarter in a group), the ability to panic, dig for gold etc.
|
||||
The *spawner* is a system for defining and creating individual objects from a base template called a *prototype*. It is only designed for use with in-game [Objects](./Objects.md), not any other type of entity.
|
||||
|
||||
But now it's time to actually start to create some goblins and put them in the world. What if we
|
||||
wanted those goblins to not all look the same? Maybe we want grey-skinned and green-skinned goblins
|
||||
or some goblins that can cast spells or which wield different weapons? We *could* make subclasses of
|
||||
`Goblin`, like `GreySkinnedGoblin` and `GoblinWieldingClub`. But that seems a bit excessive (and a
|
||||
lot of Python code for every little thing). Using classes can also become impractical when wanting
|
||||
to combine them - what if we want a grey-skinned goblin shaman wielding a spear - setting up a web
|
||||
of classes inheriting each other with multiple inheritance can be tricky.
|
||||
The normal way to create a custom object in Evennia is to make a [Typeclass](./Typeclasses.md). If you haven't read up on Typeclasses yet, think of them as normal Python classes that save to the database behind the scenes. Say you wanted to create a "Goblin" enemy. A common way to do this would be to first create a `Mobile` typeclass that holds everything common to mobiles in the game, like generic AI, combat code and various movement methods. A `Goblin` subclass is then made to inherit from `Mobile`. The `Goblin` class adds stuff unique to goblins, like group-based AI (because goblins are smarter in a group), the ability to panic, dig for gold etc.
|
||||
|
||||
This is what the *prototype* is for. It is a Python dictionary that describes these per-instance
|
||||
changes to an object. The prototype also has the advantage of allowing an in-game builder to
|
||||
customize an object without access to the Python backend. Evennia also allows for saving and
|
||||
searching prototypes so other builders can find and use (and tweak) them later. Having a library of
|
||||
interesting prototypes is a good reasource for builders. The OLC system allows for creating, saving,
|
||||
loading and manipulating prototypes using a menu system.
|
||||
But now it's time to actually start to create some goblins and put them in the world. What if we wanted those goblins to not all look the same? Maybe we want grey-skinned and green-skinned goblins or some goblins that can cast spells or which wield different weapons? We *could* make subclasses of `Goblin`, like `GreySkinnedGoblin` and `GoblinWieldingClub`. But that seems a bit excessive (and a lot of Python code for every little thing). Using classes can also become impractical when wanting to combine them - what if we want a grey-skinned goblin shaman wielding a spear - setting up a web of classes inheriting each other with multiple inheritance can be tricky.
|
||||
|
||||
This is what the *prototype* is for. It is a Python dictionary that describes these per-instance changes to an object. The prototype also has the advantage of allowing an in-game builder to customize an object without access to the Python backend. Evennia also allows for saving and searching prototypes so other builders can find and use (and tweak) them later. Having a library of interesting prototypes is a good reasource for builders. The OLC system allows for creating, saving, loading and manipulating prototypes using a menu system.
|
||||
|
||||
The *spawner* takes a prototype and uses it to create (spawn) new, custom objects.
|
||||
|
||||
## Using the OLC
|
||||
## Working with Prototypes
|
||||
|
||||
Enter the `olc` command or `@spawn/olc` to enter the prototype wizard. This is a menu system for
|
||||
### Using the OLC
|
||||
|
||||
Enter the `olc` command or `spawn/olc` to enter the prototype wizard. This is a menu system for
|
||||
creating, loading, saving and manipulating prototypes. It's intended to be used by in-game builders
|
||||
and will give a better understanding of prototypes in general. Use `help` on each node of the menu
|
||||
for more information. Below are further details about how prototypes work and how they are used.
|
||||
|
||||
## The prototype
|
||||
### The prototype
|
||||
|
||||
The prototype dictionary can either be created for you by the OLC (see above), be written manually
|
||||
in a Python module (and then referenced by the `@spawn` command/OLC), or created on-the-fly and
|
||||
manually loaded into the spawner function or `@spawn` command.
|
||||
The prototype dictionary can either be created for you by the OLC (see above), be written manually in a Python module (and then referenced by the `spawn` command/OLC), or created on-the-fly and
|
||||
manually loaded into the spawner function or `spawn` command.
|
||||
|
||||
The dictionary defines all possible database-properties of an Object. It has a fixed set of allowed
|
||||
keys. When preparing to store the prototype in the database (or when using the OLC), some
|
||||
of these keys are mandatory. When just passing a one-time prototype-dict to the spawner the system
|
||||
is
|
||||
more lenient and will use defaults for keys not explicitly provided.
|
||||
The dictionary defines all possible database-properties of an Object. It has a fixed set of allowed keys. When preparing to store the prototype in the database (or when using the OLC), some of these keys are mandatory. When just passing a one-time prototype-dict to the spawner the system is more lenient and will use defaults for keys not explicitly provided.
|
||||
|
||||
In dictionary form, a prototype can look something like this:
|
||||
|
||||
|
|
@ -60,15 +43,9 @@ In dictionary form, a prototype can look something like this:
|
|||
```
|
||||
If you wanted to load it into the spawner in-game you could just put all on one line:
|
||||
|
||||
@spawn {"prototype_key="house", "key": "Large house", ...}
|
||||
spawn {"prototype_key="house", "key": "Large house", ...}
|
||||
|
||||
> Note that the prototype dict as given on the command line must be a valid Python structure -
|
||||
so you need to put quotes around strings etc. For security reasons, a dict inserted from-in game
|
||||
cannot have any
|
||||
other advanced Python functionality, such as executable code, `lambda` etc. If builders are supposed
|
||||
to be able to use such features, you need to offer them through [$protfuncs](Spawner-and-
|
||||
Prototypes#protfuncs), embedded runnable functions that you have full control to check and vet
|
||||
before running.
|
||||
> Note that the prototype dict as given on the command line must be a valid Python structure - so you need to put quotes around strings etc. For security reasons, a dict inserted from-in game cannot have any other advanced Python functionality, such as executable code, `lambda` etc. If builders are supposed to be able to use such features, you need to offer them through [$protfuncs](Spawner-and- Prototypes#protfuncs), embedded runnable functions that you have full control to check and vet before running.
|
||||
|
||||
### Prototype keys
|
||||
|
||||
|
|
@ -84,54 +61,31 @@ All keys starting with `prototype_` are for book keeping.
|
|||
- `prototype_desc` - this is optional and used when listing the prototype in in-game listings.
|
||||
- `protototype_tags` - this is optional and allows for tagging the prototype in order to find it
|
||||
easier later.
|
||||
- `prototype_locks` - two lock types are supported: `edit` and `spawn`. The first lock restricts
|
||||
the copying and editing of the prototype when loaded through the OLC. The second determines who
|
||||
- `prototype_locks` - two lock types are supported: `edit` and `spawn`. The first lock restricts the copying and editing of the prototype when loaded through the OLC. The second determines who
|
||||
may use the prototype to create new objects.
|
||||
|
||||
|
||||
The remaining keys determine actual aspects of the objects to spawn from this prototype:
|
||||
|
||||
- `key` - the main object identifier. Defaults to "Spawned Object *X*", where *X* is a random
|
||||
integer.
|
||||
- `typeclass` - A full python-path (from your gamedir) to the typeclass you want to use. If not
|
||||
set, the `prototype_parent` should be
|
||||
defined, with `typeclass` defined somewhere in the parent chain. When creating a one-time
|
||||
prototype
|
||||
dict just for spawning, one could omit this - `settings.BASE_OBJECT_TYPECLASS` will be used
|
||||
instead.
|
||||
- `key` - the main object identifier. Defaults to "Spawned Object *X*", where *X* is a random integer.
|
||||
- `typeclass` - A full python-path (from your gamedir) to the typeclass you want to use. If not set, the `prototype_parent` should be defined, with `typeclass` defined somewhere in the parent chain. When creating a one-time prototype dict just for spawning, one could omit this - `settings.BASE_OBJECT_TYPECLASS` will be used instead.
|
||||
- `location` - this should be a `#dbref`.
|
||||
- `home` - a valid `#dbref`. Defaults to `location` or `settings.DEFAULT_HOME` if location does not
|
||||
exist.
|
||||
- `home` - a valid `#dbref`. Defaults to `location` or `settings.DEFAULT_HOME` if location does not exist.
|
||||
- `destination` - a valid `#dbref`. Only used by exits.
|
||||
- `permissions` - list of permission strings, like `["Accounts", "may_use_red_door"]`
|
||||
- `locks` - a [lock-string](./Locks.md) like `"edit:all();control:perm(Builder)"`
|
||||
- `aliases` - list of strings for use as aliases
|
||||
- `tags` - list [Tags](./Tags.md). These are given as tuples `(tag, category, data)`.
|
||||
- `attrs` - list of [Attributes](./Attributes.md). These are given as tuples `(attrname, value,
|
||||
category, lockstring)`
|
||||
- Any other keywords are interpreted as non-category [Attributes](./Attributes.md) and their values.
|
||||
This is convenient for simple Attributes - use `attrs` for full control of Attributes.
|
||||
- `attrs` - list of [Attributes](./Attributes.md). These are given as tuples `(attrname, value, category, lockstring)`
|
||||
- Any other keywords are interpreted as non-category [Attributes](./Attributes.md) and their values. This is convenient for simple Attributes - use `attrs` for full control of Attributes.
|
||||
|
||||
#### More on prototype inheritance
|
||||
|
||||
- A prototype can inherit by defining a `prototype_parent` pointing to the name
|
||||
(`prototype_key` of another prototype). If a list of `prototype_keys`, this
|
||||
will be stepped through from left to right, giving priority to the first in
|
||||
the list over those appearing later. That is, if your inheritance is
|
||||
`prototype_parent = ('A', 'B,' 'C')`, and all parents contain colliding keys,
|
||||
then the one from `A` will apply.
|
||||
- The prototype keys that start with `prototype_*` are all unique to each
|
||||
prototype. They are _never_ inherited from parent to child.
|
||||
- The prototype fields `'attr': [(key, value, category, lockstring),...]`
|
||||
and `'tags': [(key, category, data), ...]` are inherited in a _complementary_
|
||||
fashion. That means that only colliding key+category matches will be replaced, not the entire list.
|
||||
Remember that the category `None` is also considered a valid category!
|
||||
- Adding an Attribute as a simple `key:value` will under the hood be translated
|
||||
into an Attribute tuple `(key, value, None, '')` and may replace an Attribute
|
||||
in the parent if it the same key and a `None` category.
|
||||
- All other keys (`permissions`, `destination`, `aliases` etc) are completely
|
||||
_replaced_ by the child's value if given. For the parent's value to be
|
||||
retained, the child must not define these keys at all.
|
||||
- A prototype can inherit by defining a `prototype_parent` pointing to the name (`prototype_key` of another prototype). If a list of `prototype_keys`, this will be stepped through from left to right, giving priority to the first in the list over those appearing later. That is, if your inheritance is `prototype_parent = ('A', 'B,' 'C')`, and all parents contain colliding keys, then the one from `A` will apply.
|
||||
- The prototype keys that start with `prototype_*` are all unique to each prototype. They are _never_ inherited from parent to child.
|
||||
- The prototype fields `'attr': [(key, value, category, lockstring),...]` and `'tags': [(key, category, data), ...]` are inherited in a _complementary_ fashion. That means that only colliding key+category matches will be replaced, not the entire list. Remember that the category `None` is also considered a valid category!
|
||||
- Adding an Attribute as a simple `key:value` will under the hood be translated into an Attribute tuple `(key, value, None, '')` and may replace an Attribute in the parent if it the same key and a `None` category.
|
||||
- All other keys (`permissions`, `destination`, `aliases` etc) are completely _replaced_ by the child's value if given. For the parent's value to be retained, the child must not define these keys at all.
|
||||
|
||||
### Prototype values
|
||||
|
||||
|
|
@ -144,17 +98,14 @@ It can be a hard-coded value:
|
|||
|
||||
```
|
||||
|
||||
It can also be a *callable*. This callable is called without arguments whenever the prototype is
|
||||
used to
|
||||
spawn a new object:
|
||||
It can also be a *callable*. This callable is called without arguments whenever the prototype is used to spawn a new object:
|
||||
|
||||
```python
|
||||
{"key": _get_a_random_goblin_name, ...}
|
||||
|
||||
```
|
||||
|
||||
By use of Python `lambda` one can wrap the callable so as to make immediate settings in the
|
||||
prototype:
|
||||
By use of Python `lambda` one can wrap the callable so as to make immediate settings in the prototype:
|
||||
|
||||
```python
|
||||
{"key": lambda: random.choice(("Urfgar", "Rick the smelly", "Blargh the foul", ...)), ...}
|
||||
|
|
@ -163,19 +114,16 @@ prototype:
|
|||
|
||||
#### Protfuncs
|
||||
|
||||
Finally, the value can be a *prototype function* (*Protfunc*). These look like simple function calls
|
||||
that you embed in strings and that has a `$` in front, like
|
||||
Finally, the value can be a *prototype function* (*Protfunc*). These look like simple function calls that you embed in strings and that has a `$` in front, like
|
||||
|
||||
```python
|
||||
{"key": "$choice(Urfgar, Rick the smelly, Blargh the foul)",
|
||||
"attrs": {"desc": "This is a large $red(and very red) demon. "
|
||||
"He has $randint(2,5) skulls in a chain around his neck."}
|
||||
```
|
||||
At execution time, the place of the protfunc will be replaced with the result of that protfunc being
|
||||
called (this is always a string). A protfunc is a [FuncParser function](./FuncParser.md) run
|
||||
every time the prototype is used to spawn a new object.
|
||||
At execution time, the place of the protfunc will be replaced with the result of that protfunc being called (this is always a string). A protfunc is a [FuncParser function](./FuncParser.md) run every time the prototype is used to spawn a new object.
|
||||
|
||||
Here is how a protfunc is defined (same as an inlinefunc).
|
||||
Here is how a protfunc is defined (same as other funcparser functions).
|
||||
|
||||
```python
|
||||
# this is a silly example, you can just color the text red with |r directly!
|
||||
|
|
@ -189,13 +137,9 @@ def red(*args, **kwargs):
|
|||
return f"|r{args[0]}|n"
|
||||
```
|
||||
|
||||
> Note that we must make sure to validate input and raise `ValueError` if that fails. Also, it is
|
||||
*not* possible to use keywords in the call to the protfunc (so something like `$echo(text,
|
||||
align=left)` is invalid). The `kwargs` requred is for internal evennia use and not used at all for
|
||||
protfuncs (only by inlinefuncs).
|
||||
> Note that we must make sure to validate input and raise `ValueError` if that fails. Also, it is *not* possible to use keywords in the call to the protfunc (so something like `$echo(text, align=left)` is invalid). The `kwargs` requred is for internal evennia use and not used at all for protfuncs (only by inlinefuncs).
|
||||
|
||||
To make this protfunc available to builders in-game, add it to a new module and add the path to that
|
||||
module to `settings.PROT_FUNC_MODULES`:
|
||||
To make this protfunc available to builders in-game, add it to a new module and add the path to that module to `settings.PROT_FUNC_MODULES`:
|
||||
|
||||
```python
|
||||
# in mygame/server/conf/settings.py
|
||||
|
|
@ -203,56 +147,38 @@ module to `settings.PROT_FUNC_MODULES`:
|
|||
PROT_FUNC_MODULES += ["world.myprotfuncs"]
|
||||
|
||||
```
|
||||
All *global callables* in your added module will be considered a new protfunc. To avoid this (e.g.
|
||||
to have helper functions that are not protfuncs on their own), name your function something starting
|
||||
with `_`.
|
||||
All *global callables* in your added module will be considered a new protfunc. To avoid this (e.g. to have helper functions that are not protfuncs on their own), name your function something starting with `_`.
|
||||
|
||||
The default protfuncs available out of the box are defined in `evennia/prototypes/profuncs.py`. To
|
||||
override the ones available, just add the same-named function in your own protfunc module.
|
||||
The default protfuncs available out of the box are defined in `evennia/prototypes/profuncs.py`. To override the ones available, just add the same-named function in your own protfunc module.
|
||||
|
||||
| Protfunc | Description |
|
||||
| --- | --- |
|
||||
| `$random()` | Returns random value in range [0, 1) |
|
||||
| `$randint(start, end)` | Returns random value in range [start, end] |
|
||||
| `$randint(start, end)` | Returns random value in range [start, end] |
|
||||
| `$left_justify(<text>)` | Left-justify text |
|
||||
| `$right_justify(<text>)` | Right-justify text to screen width |
|
||||
| `$center_justify(<text>)` | Center-justify text to screen width |
|
||||
| `$full_justify(<text>)` | Spread text across screen width by adding spaces |
|
||||
| `$protkey(<name>)` | Returns value of another key in this prototype (self-reference) |
|
||||
| `$add(<value1>, <value2>)` | Returns value1 + value2. Can also be lists, dicts etc |
|
||||
| `$sub(<value1>, <value2>)` | Returns value1 - value2 |
|
||||
| `$mult(<value1>, <value2>)` | Returns value1 * value2 |
|
||||
| `$div(<value1>, <value2>)` | Returns value2 / value1 |
|
||||
| `$toint(<value>)` | Returns value converted to integer (or value if not possible) |
|
||||
| `$eval(<code>)` | Returns result of [literal-eval](https://docs.python.org/2/library/ast.html#ast.literal_eval) of code string. Only simple python expressions. |
|
||||
| `$right_justify(<text>)` | Right-justify text to screen width |
|
||||
| `$center_justify(<text>)` | Center-justify text to screen width |
|
||||
| `$full_justify(<text>)` | Spread text across screen width by adding spaces |
|
||||
| `$protkey(<name>)` | Returns value of another key in this prototype (self-reference) |
|
||||
| `$add(<value1>, <value2>)` | Returns value1 + value2. Can also be lists, dicts etc |
|
||||
| `$sub(<value1>, <value2>)` | Returns value1 - value2 |
|
||||
| `$mult(<value1>, <value2>)` | Returns value1 * value2 |
|
||||
| `$div(<value1>, <value2>)` | Returns value2 / value1 |
|
||||
| `$toint(<value>)` | Returns value converted to integer (or value if not possible) |
|
||||
| `$eval(<code>)` | Returns result of [literal-eval](https://docs.python.org/2/library/ast.html#ast.literal_eval) of code string. Only simple python expressions. |
|
||||
| `$obj(<query>)` | Returns object #dbref searched globally by key, tag or #dbref. Error if more than one found. |
|
||||
| `$objlist(<query>)` | Like `$obj`, except always returns a list of zero, one or more results. |
|
||||
| `$dbref(dbref)` | Returns argument if it is formed as a #dbref (e.g. #1234), otherwise error. |
|
||||
|
||||
For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing
|
||||
real Python functions is a lot more powerful and flexible. Their main use is to allow in-game
|
||||
builders to
|
||||
do limited coding/scripting for their prototypes without giving them direct access to raw Python.
|
||||
For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing real Python functions is a lot more powerful and flexible. Their main use is to allow in-game builders to do limited coding/scripting for their prototypes without giving them direct access to raw Python.
|
||||
|
||||
## Storing prototypes
|
||||
## Database prototypes
|
||||
|
||||
A prototype can be defined and stored in two ways, either in the database or as a dict in a module.
|
||||
Stored as [Scripts](./Scripts.md) in the database. These are sometimes referred to as *database- prototypes* This is the only way for in-game builders to modify and add prototypes. They have the advantage of being easily modifiable and sharable between builders but you need to work with them using in-game tools.
|
||||
|
||||
### Database prototypes
|
||||
## Module-based prototypes
|
||||
|
||||
Stored as [Scripts](./Scripts.md) in the database. These are sometimes referred to as *database-
|
||||
prototypes* This is the only way for in-game builders to modify and add prototypes. They have the
|
||||
advantage of being easily modifiable and sharable between builders but you need to work with them
|
||||
using in-game tools.
|
||||
|
||||
### Module-based prototypes
|
||||
|
||||
These prototypes are defined as dictionaries assigned to global variables in one of the modules
|
||||
defined in `settings.PROTOTYPE_MODULES`. They can only be modified from outside the game so they are
|
||||
are necessarily "read-only" from in-game and cannot be modified (but copies of them could be made
|
||||
into database-prototypes). These were the only prototypes available before Evennia 0.8. Module based
|
||||
prototypes can be useful in order for developers to provide read-only "starting" or "base"
|
||||
prototypes to build from or if they just prefer to work offline in an external code editor.
|
||||
These prototypes are defined as dictionaries assigned to global variables in one of the modules defined in `settings.PROTOTYPE_MODULES`. They can only be modified from outside the game so they are are necessarily "read-only" from in-game and cannot be modified (but copies of them could be made into database-prototypes). These were the only prototypes available before Evennia 0.8. Module based prototypes can be useful in order for developers to provide read-only "starting" or "base" prototypes to build from or if they just prefer to work offline in an external code editor.
|
||||
|
||||
By default `mygame/world/prototypes.py` is set up for you to add your own prototypes. *All global
|
||||
dicts* in this module will be considered by Evennia to be a prototype. You could also tell Evennia
|
||||
|
|
@ -283,28 +209,23 @@ Here is an example of a prototype defined in a module:
|
|||
> that you always add `prototype_key` to be consistent.
|
||||
|
||||
|
||||
## Using @spawn
|
||||
## Spawning
|
||||
|
||||
The spawner can be used from inside the game through the Builder-only `@spawn` command. Assuming the
|
||||
"goblin" typeclass is available to the system (either as a database-prototype or read from module),
|
||||
you can spawn a new goblin with
|
||||
The spawner can be used from inside the game through the Builder-only `@spawn` command. Assuming the "goblin" typeclass is available to the system (either as a database-prototype or read from module), you can spawn a new goblin with
|
||||
|
||||
@spawn goblin
|
||||
spawn goblin
|
||||
|
||||
You can also specify the prototype directly as a valid Python dictionary:
|
||||
|
||||
@spawn {"prototype_key": "shaman", \
|
||||
spawn {"prototype_key": "shaman", \
|
||||
"key":"Orc shaman", \
|
||||
"prototype_parent": "goblin", \
|
||||
"weapon": "wooden staff", \
|
||||
"health": 20}
|
||||
|
||||
> Note: The `@spawn` command is more lenient about the prototype dictionary than shown here. So you
|
||||
can for example skip the `prototype_key` if you are just testing a throw-away prototype. A random
|
||||
hash will be used to please the validation. You could also skip `prototype_parent/typeclass` - then
|
||||
the typeclass given by `settings.BASE_OBJECT_TYPECLASS` will be used.
|
||||
> Note: The @spawn` command is more lenient about the prototype dictionary than shown here. So you can for example skip the `prototype_key` if you are just testing a throw-away prototype. A random hash will be used to please the validation. You could also skip `prototype_parent/typeclass` - then the typeclass given by `settings.BASE_OBJECT_TYPECLASS` will be used.
|
||||
|
||||
## Using evennia.prototypes.spawner()
|
||||
### Using evennia.prototypes.spawner()
|
||||
|
||||
In code you access the spawner mechanism directly via the call
|
||||
|
||||
|
|
@ -319,16 +240,6 @@ matching list of created objects. Example:
|
|||
obj1, obj2 = evennia.prototypes.spawner.spawn({"key": "Obj1", "desc": "A test"},
|
||||
{"key": "Obj2", "desc": "Another test"})
|
||||
```
|
||||
> Hint: Same as when using `@spawn`, when spawning from a one-time prototype dict like this, you can
|
||||
skip otherwise required keys, like `prototype_key` or `typeclass`/`prototype_parent`. Defaults will
|
||||
be used.
|
||||
> Hint: Same as when using `spawn`, when spawning from a one-time prototype dict like this, you can skip otherwise required keys, like `prototype_key` or `typeclass`/`prototype_parent`. Defaults will be used.
|
||||
|
||||
Note that no `location` will be set automatically when using `evennia.prototypes.spawner.spawn()`,
|
||||
you
|
||||
have to specify `location` explicitly in the prototype dict.
|
||||
|
||||
If the prototypes you supply are using `prototype_parent` keywords, the spawner will read prototypes
|
||||
from modules
|
||||
in `settings.PROTOTYPE_MODULES` as well as those saved to the database to determine the body of
|
||||
available parents. The `spawn` command takes many optional keywords, you can find its definition [in
|
||||
the api docs](github:evennia.prototypes.spawner#spawn).
|
||||
Note that no `location` will be set automatically when using `evennia.prototypes.spawner.spawn()`, you have to specify `location` explicitly in the prototype dict. If the prototypes you supply are using `prototype_parent` keywords, the spawner will read prototypes from modules in `settings.PROTOTYPE_MODULES` as well as those saved to the database to determine the body of available parents. The `spawn` command takes many optional keywords, you can find its definition [in the api docs](github:evennia.prototypes.spawner#spawn).
|
||||
|
|
@ -2,32 +2,13 @@
|
|||
|
||||
[Script API reference](evennia.scripts.scripts)
|
||||
|
||||
*Scripts* are the out-of-character siblings to the in-character
|
||||
[Objects](./Objects.md). Scripts are so flexible that the name "Script" is a bit limiting
|
||||
in itself - but we had to pick _something_ to name them. Other possible names
|
||||
(depending on what you'd use them for) would be `OOBObjects`, `StorageContainers` or `TimerObjects`.
|
||||
*Scripts* are the out-of-character siblings to the in-character [Objects](./Objects.md). Scripts are so flexible that the name "Script" is a bit limiting in itself - but we had to pick _something_ to name them. Other possible names (depending on what you'd use them for) would be `OOBObjects`, `StorageContainers` or `TimerObjects`.
|
||||
|
||||
If you ever consider creating an [Object](./Objects.md) with a `None`-location just to store some game data,
|
||||
you should really be using a Script instead.
|
||||
If you ever consider creating an [Object](./Objects.md) with a `None`-location just to store some game data, you should really be using a Script instead.
|
||||
|
||||
- Scripts are full [Typeclassed](./Typeclasses.md) entities - they have [Attributes](./Attributes.md) and
|
||||
can be modified in the same way. But they have _no in-game existence_, so no
|
||||
location or command-execution like [Objects](./Objects.md) and no connection to a particular
|
||||
player/session like [Accounts](./Accounts.md). This means they are perfectly suitable for acting
|
||||
as database-storage backends for game _systems_: Storing the current state of the economy,
|
||||
who is involved in the current fight, tracking an ongoing barter and so on. They are great as
|
||||
persistent system handlers.
|
||||
- Scripts have an optional _timer component_. This means that you can set up the script
|
||||
to tick the `at_repeat` hook on the Script at a certain interval. The timer can be controlled
|
||||
independently of the rest of the script as needed. This component is optional
|
||||
and complementary to other timing functions in Evennia, like
|
||||
[evennia.utils.delay](evennia.utils.utils.delay) and
|
||||
[evennia.utils.repeat](evennia.utils.utils.repeat).
|
||||
- Scripts can _attach_ to Objects and Accounts via e.g. `obj.scripts.add/remove`. In the
|
||||
script you can then access the object/account as `self.obj` or `self.account`. This can be used to
|
||||
dynamically extend other typeclasses but also to use the timer component to affect the parent object
|
||||
in various ways. For historical reasons, a Script _not_ attached to an object is referred to as a
|
||||
_Global_ Script.
|
||||
- Scripts are full [Typeclassed](./Typeclasses.md) entities - they have [Attributes](./Attributes.md) and can be modified in the same way. But they have _no in-game existence_, so no location or command-execution like [Objects](./Objects.md) and no connection to a particular player/session like [Accounts](./Accounts.md). This means they are perfectly suitable for acting as database-storage backends for game _systems_: Storing the current state of the economy, who is involved in the current fight, tracking an ongoing barter and so on. They are great as persistent system handlers.
|
||||
- Scripts have an optional _timer component_. This means that you can set up the script to tick the `at_repeat` hook on the Script at a certain interval. The timer can be controlled independently of the rest of the script as needed. This component is optional and complementary to other timing functions in Evennia, like [evennia.utils.delay](evennia.utils.utils.delay) and [evennia.utils.repeat](evennia.utils.utils.repeat).
|
||||
- Scripts can _attach_ to Objects and Accounts via e.g. `obj.scripts.add/remove`. In the script you can then access the object/account as `self.obj` or `self.account`. This can be used to dynamically extend other typeclasses but also to use the timer component to affect the parent object in various ways. For historical reasons, a Script _not_ attached to an object is referred to as a _Global_ Script.
|
||||
|
||||
```{versionchanged} 1.0
|
||||
In previus Evennia versions, stopping the Script's timer also meant deleting the Script object.
|
||||
|
|
@ -36,7 +17,7 @@ you should really be using a Script instead.
|
|||
|
||||
```
|
||||
|
||||
## In-game command examples
|
||||
## Working with Scripts
|
||||
|
||||
There are two main commands controlling scripts in the default cmdset:
|
||||
|
||||
|
|
@ -53,10 +34,10 @@ The `scripts` command is used to view all scripts and perform operations on them
|
|||
> scripts/delete #566
|
||||
|
||||
```{versionchanged} 1.0
|
||||
The `addscript` command used to be only `script` which was easy to confuse with `scripts`.
|
||||
The `addscript` command used to be only `script` which was easy to confuse with `scripts`.
|
||||
```
|
||||
|
||||
## Code examples
|
||||
### Code examples
|
||||
|
||||
Here are some examples of working with Scripts in-code (more details to follow in later
|
||||
sections).
|
||||
|
|
@ -111,13 +92,13 @@ new_script.delete()
|
|||
timed_script.delete()
|
||||
```
|
||||
|
||||
## Defining new Scripts
|
||||
### Defining new Scripts
|
||||
|
||||
A Script is defined as a class and is created in the same way as other
|
||||
[typeclassed](./Typeclasses.md) entities. The parent class is `evennia.DefaultScript`.
|
||||
|
||||
|
||||
### Simple storage script
|
||||
#### Simple storage script
|
||||
|
||||
In `mygame/typeclasses/scripts.py` is an empty `Script` class already set up. You
|
||||
can use this as a base for your own scripts.
|
||||
|
|
@ -162,12 +143,9 @@ evennia.create_script('typeclasses.scripts.MyScript', key="another name",
|
|||
|
||||
```
|
||||
|
||||
See the [create_script](evennia.utils.create.create_script) and
|
||||
[search_script](evennia.utils.search.search_script) API documentation for more options
|
||||
on creating and finding Scripts.
|
||||
See the [create_script](evennia.utils.create.create_script) and [search_script](evennia.utils.search.search_script) API documentation for more options on creating and finding Scripts.
|
||||
|
||||
|
||||
## Timed Scripts
|
||||
#### Timed Script
|
||||
|
||||
There are several properties one can set on the Script to control its timer component.
|
||||
|
||||
|
|
@ -199,8 +177,7 @@ Supported properties are:
|
|||
- `interval` (int): The amount of time (in seconds) between every 'tick' of the timer. Note that
|
||||
it's generally bad practice to use sub-second timers for anything in a text-game - the player will
|
||||
not be able to appreciate the precision (and if you print it, it will just spam the screen). For
|
||||
calculations you can pretty much always do them on-demand, or at a much slower interval without the
|
||||
player being the wiser.
|
||||
calculations you can pretty much always do them on-demand, or at a much slower interval without the player being the wiser.
|
||||
- `start_delay` (bool): If timer should start right away or wait `interval` seconds first.
|
||||
- `repeats` (int): If >0, the timer will only run this many times before stopping. Otherwise the
|
||||
number of repeats are infinite. If set to 1, the Script mimics a `delay` action.
|
||||
|
|
@ -226,30 +203,17 @@ The timer component is controlled with methods on the Script class:
|
|||
- `.time_until_next_repeat()` - get the time until next time the timer fires.
|
||||
- `.remaining_repeats()` - get the number of repeats remaining, or `None` if repeats are infinite.
|
||||
- `.reset_callcount()` - this resets the repeat counter to start over from 0. Only useful if `repeats>0`.
|
||||
- `.force_repeat()` - this prematurely forces `at_repeat` to be called right away. Doing so will reset the
|
||||
countdown so that next call will again happen after `interval` seconds.
|
||||
- `.force_repeat()` - this prematurely forces `at_repeat` to be called right away. Doing so will reset the countdown so that next call will again happen after `interval` seconds.
|
||||
|
||||
### Script timers vs delay/repeat
|
||||
|
||||
If the _only_ goal is to get a repeat/delay effect, the
|
||||
[evennia.utils.delay](evennia.utils.utils.delay) and
|
||||
[evennia.utils.repeat](evennia.utils.utils.repeat) functions
|
||||
should generally be considered first. A Script is a lot 'heavier' to create/delete on the fly.
|
||||
In fact, for making a single delayed call (`script.repeats==1`), the `utils.delay` call is
|
||||
probably always the better choice.
|
||||
If the _only_ goal is to get a repeat/delay effect, the [evennia.utils.delay](evennia.utils.utils.delay) and [evennia.utils.repeat](evennia.utils.utils.repeat) functions should generally be considered first. A Script is a lot 'heavier' to create/delete on the fly. In fact, for making a single delayed call (`script.repeats==1`), the `utils.delay` call is probably always the better choice.
|
||||
|
||||
For repeating tasks, the `utils.repeat` is optimized for quick repeating of a large number of objects. It
|
||||
uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to
|
||||
start/stop the repeating action for an object. The side effect is however that all objects set to tick
|
||||
at a given interval will _all do so at the same time_. This may or may not look strange in-game depending
|
||||
on the situation. By contrast the Script uses its own ticker that will operate independently from the
|
||||
tickers of all other Scripts.
|
||||
For repeating tasks, the `utils.repeat` is optimized for quick repeating of a large number of objects. It uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to start/stop the repeating action for an object. The side effect is however that all objects set to tick at a given interval will _all do so at the same time_. This may or may not look strange in-game depending on the situation. By contrast the Script uses its own ticker that will operate independently from the tickers of all other Scripts.
|
||||
|
||||
It's also worth noting that once the script object has _already been created_,
|
||||
starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update
|
||||
methods of the script also offers a bit more fine-control than using `utils.delays/repeat`.
|
||||
It's also worth noting that once the script object has _already been created_, starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update methods of the script also offers a bit more fine-control than using `utils.delays/repeat`.
|
||||
|
||||
## Script attached to another object
|
||||
### Script attached to another object
|
||||
|
||||
Scripts can be attached to an [Account](./Accounts.md) or (more commonly) an [Object](./Objects.md).
|
||||
If so, the 'parent object' will be available to the script as either `.obj` or `.account`.
|
||||
|
|
@ -303,7 +267,7 @@ You can also attach the script as part of creating it:
|
|||
create_script('typeclasses.weather.Weather', obj=myroom)
|
||||
```
|
||||
|
||||
## Other Script methods
|
||||
### Other Script methods
|
||||
|
||||
A Script has all the properties of a typeclassed object, such as `db` and `ndb`(see
|
||||
[Typeclasses](./Typeclasses.md)). Setting `key` is useful in order to manage scripts (delete them by name
|
||||
|
|
@ -311,13 +275,9 @@ etc). These are usually set up in the Script's typeclass, but can also be assign
|
|||
keyword arguments to `evennia.create_script`.
|
||||
|
||||
- `at_script_creation()` - this is only called once - when the script is first created.
|
||||
- `at_server_reload()` - this is called whenever the server is warm-rebooted (e.g. with the
|
||||
`reload` command). It's a good place to save non-persistent data you might want to survive a
|
||||
reload.
|
||||
- `at_server_reload()` - this is called whenever the server is warm-rebooted (e.g. with the `reload` command). It's a good place to save non-persistent data you might want to survive a reload.
|
||||
- `at_server_shutdown()` - this is called when a system reset or systems shutdown is invoked.
|
||||
- `at_server_start()` - this is called when the server comes back (from reload/shutdown/reboot). It
|
||||
can be usuful for initializations and caching of non-persistent data when starting up a script's
|
||||
functionality.
|
||||
- `at_server_start()` - this is called when the server comes back (from reload/shutdown/reboot). It can be usuful for initializations and caching of non-persistent data when starting up a script's functionality.
|
||||
- `at_repeat()`
|
||||
- `at_start()`
|
||||
- `at_pause()`
|
||||
|
|
@ -325,12 +285,34 @@ reload.
|
|||
- `delete()` - same as for other typeclassed entities, this will delete the Script. Of note is that
|
||||
it will also stop the timer (if it runs), leading to the `at_stop` hook being called.
|
||||
|
||||
In addition, Scripts support [Attributes](./Attributes.md), [Tags](./Tags.md) and [Locks](./Locks.md) etc like other
|
||||
Typeclassed entities.
|
||||
In addition, Scripts support [Attributes](./Attributes.md), [Tags](./Tags.md) and [Locks](./Locks.md) etc like other Typeclassed entities.
|
||||
|
||||
See also the methods involved in controlling a [Timed Script](#timed-scripts) above.
|
||||
See also the methods involved in controlling a [Timed Script](#timed-script) above.
|
||||
|
||||
## The GLOBAL_SCRIPTS container
|
||||
### Dealing with Script Errors
|
||||
|
||||
Errors inside a timed, executing script can sometimes be rather terse or point to parts of the execution mechanism that is hard to interpret. One way to make it easier to debug scripts is to import Evennia's native logger and wrap your functions in a try/catch block. Evennia's logger can show you where the traceback occurred in your script.
|
||||
|
||||
```python
|
||||
|
||||
from evennia.utils import logger
|
||||
|
||||
class Weather(Script):
|
||||
|
||||
# [...]
|
||||
|
||||
def at_repeat(self):
|
||||
|
||||
try:
|
||||
# [...]
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
https://github.com/evennia/evennia/blob/master/evennia/contrib/tutorial_examples/example_batch_cmds.ev
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Using GLOBAL_SCRIPTS
|
||||
|
||||
A Script not attached to another entity is commonly referred to as a _Global_ script since it't available
|
||||
to access from anywhere. This means they need to be searched for in order to be used.
|
||||
|
|
@ -338,7 +320,6 @@ to access from anywhere. This means they need to be searched for in order to be
|
|||
Evennia supplies a convenient "container" `evennia.GLOBAL_SCRIPTS` to help organize your global
|
||||
scripts. All you need is the Script's `key`.
|
||||
|
||||
|
||||
```python
|
||||
from evennia import GLOBAL_SCRIPTS
|
||||
|
||||
|
|
@ -354,11 +335,7 @@ GLOBAL_SCRIPTS.weather.db.current_weather = "Cloudy"
|
|||
```
|
||||
|
||||
```{warning}
|
||||
Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`.
|
||||
If you were to create two global scripts with the same `key` (even with different typeclasses),
|
||||
the `GLOBAL_SCRIPTS` container will only return one of them (which one depends on order in
|
||||
the database). Best is to organize your scripts so that this does not happen. Otherwise, use
|
||||
`evennia.search_scripts` to get exactly the script you want.
|
||||
Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`. If you were to create two global scripts with the same `key` (even with different typeclasses), the `GLOBAL_SCRIPTS` container will only return one of them (which one depends on order in the database). Best is to organize your scripts so that this does not happen. Otherwise, use `evennia.search_scripts` to get exactly the script you want.
|
||||
```
|
||||
|
||||
There are two ways to make a script appear as a property on `GLOBAL_SCRIPTS`:
|
||||
|
|
@ -386,16 +363,10 @@ GLOBAL_SCRIPTS = {
|
|||
}
|
||||
```
|
||||
|
||||
Above we add two scripts with keys `myscript` and `storagescript`respectively. The following dict
|
||||
can be empty - the `settings.BASE_SCRIPT_TYPECLASS` will then be used. Under the hood, the provided
|
||||
dict (along with the `key`) will be passed into `create_script` automatically, so
|
||||
all the [same keyword arguments as for create_script](evennia.utils.create.create_script) are
|
||||
supported here.
|
||||
|
||||
Above we add two scripts with keys `myscript` and `storagescript`respectively. The following dict can be empty - the `settings.BASE_SCRIPT_TYPECLASS` will then be used. Under the hood, the provided dict (along with the `key`) will be passed into `create_script` automatically, so all the [same keyword arguments as for create_script](evennia.utils.create.create_script) are supported here.
|
||||
```{warning}
|
||||
Before setting up Evennia to manage your script like this, make sure that your Script typeclass
|
||||
does not have any critical errors (test it separately). If there are, you'll see errors in your log
|
||||
and your Script will temporarily fall back to being a `DefaultScript` type.
|
||||
|
||||
Before setting up Evennia to manage your script like this, make sure that your Script typeclass does not have any critical errors (test it separately). If there are, you'll see errors in your log and your Script will temporarily fall back to being a `DefaultScript` type.
|
||||
```
|
||||
|
||||
Moreover, a script defined this way is *guaranteed* to exist when you try to access it:
|
||||
|
|
@ -413,25 +384,3 @@ That is, if the script is deleted, next time you get it from `GLOBAL_SCRIPTS`, E
|
|||
information in settings to recreate it for you on the fly.
|
||||
|
||||
|
||||
## Hints: Dealing with Script Errors
|
||||
|
||||
Errors inside a timed, executing script can sometimes be rather terse or point to
|
||||
parts of the execution mechanism that is hard to interpret. One way to make it
|
||||
easier to debug scripts is to import Evennia's native logger and wrap your
|
||||
functions in a try/catch block. Evennia's logger can show you where the
|
||||
traceback occurred in your script.
|
||||
|
||||
```python
|
||||
|
||||
from evennia.utils import logger
|
||||
|
||||
class Weather(Script):
|
||||
|
||||
# [...]
|
||||
|
||||
def at_repeat(self):
|
||||
|
||||
try:
|
||||
# [...]
|
||||
except Exception:
|
||||
logger.log_trace()
|
||||
|
|
|
|||
|
|
@ -15,17 +15,17 @@ A session object has its own [cmdset](./Command-Sets.md), usually the "unloggedi
|
|||
|
||||
A Session is not *persistent* - it is not a [Typeclass](./Typeclasses.md) and has no connection to the database. The Session will go away when a user disconnects and you will lose any custom data on it if the server reloads. The `.db` handler on Sessions is there to present a uniform API (so you can assume `.db` exists even if you don't know if you receive an Object or a Session), but this is just an alias to `.ndb`. So don't store any data on Sessions that you can't afford to lose in a reload.
|
||||
|
||||
## Properties on Sessions
|
||||
## Working with Sessions
|
||||
|
||||
### Properties on Sessions
|
||||
|
||||
Here are some important properties available on (Server-)Sessions
|
||||
|
||||
- `sessid` - The unique session-id. This is an integer starting from 1.
|
||||
- `address` - The connected client's address. Different protocols give different information here.
|
||||
- `logged_in` - `True` if the user authenticated to this session.
|
||||
- `account` - The [Account](./Accounts.md) this Session is attached to. If not logged in yet, this is
|
||||
`None`.
|
||||
- `puppet` - The [Character/Object](./Objects.md) currently puppeted by this Account/Session combo. If
|
||||
not logged in or in OOC mode, this is `None`.
|
||||
- `account` - The [Account](./Accounts.md) this Session is attached to. If not logged in yet, this is `None`.
|
||||
- `puppet` - The [Character/Object](./Objects.md) currently puppeted by this Account/Session combo. If not logged in or in OOC mode, this is `None`.
|
||||
- `ndb` - The [Non-persistent Attribute](./Attributes.md) handler.
|
||||
- `db` - As noted above, Sessions don't have regular Attributes. This is an alias to `ndb`.
|
||||
- `cmdset` - The Session's [CmdSetHandler](./Command-Sets.md)
|
||||
|
|
@ -38,61 +38,7 @@ Session statistics are mainly used internally by Evennia.
|
|||
last time this session was truly visibly active.
|
||||
- `cmd_total` - Total number of Commands passed through this Session.
|
||||
|
||||
## Multisession mode
|
||||
|
||||
The number of sessions possible to connect to a given account at the same time and how it works is given by the `MULTISESSION_MODE` setting:
|
||||
|
||||
* `MULTISESSION_MODE=0`: One session per account. When connecting with a new session the old one is disconnected. This is the default mode and emulates many classic mud code bases.
|
||||
```
|
||||
┌──────┐ │ ┌───────┐ ┌───────┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├───►│Account├──►│Character│
|
||||
└──────┘ │ └───────┘ └───────┘ └─────────┘
|
||||
```
|
||||
* `MULTISESSION_MODE=1`: Many sessions per account, input/output from/to each session is treated the same. For the player this means they can connect to the game from multiple clients and see the same output in all of them. The result of a command given in one client (that is, through one Session) will be returned to *all* connected Sessions/clients with no distinction.
|
||||
```
|
||||
│
|
||||
┌──────┐ │ ┌───────┐
|
||||
│Client├─┼──►│Session├──┐
|
||||
└──────┘ │ └───────┘ └──►┌───────┐ ┌─────────┐
|
||||
│ │Account├──►│Character│
|
||||
┌──────┐ │ ┌───────┐ ┌──►└───────┘ └─────────┘
|
||||
│Client├─┼──►│Session├──┘
|
||||
└──────┘ │ └───────┘
|
||||
│
|
||||
```
|
||||
|
||||
* `MULTISESSION_MODE=2`: Many sessions per account, one character per session. In this mode, puppeting an Object/Character will link the puppet back only to the particular Session doing the puppeting. That is, input from that Session will make use of the CmdSet of that Object/Character and outgoing messages (such as the result of a `look`) will be passed back only to that puppeting Session. If another Session tries to puppet the same Character, the old Session will automatically un-puppet it. From the player's perspective, this will mean that they can open separate game clients and play a different Character in each using one game account.
|
||||
```
|
||||
│ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►│Character│
|
||||
└──────┘ │ └───────┘ │ │ └─────────┘
|
||||
│ └───────┘
|
||||
```
|
||||
* `MULTISESSION_MODE=3`: Many sessions per account *and* character. This is the full multi-puppeting mode, where multiple sessions may not only connect to the player account but multiple sessions may also puppet a single character at the same time. From the user's perspective it means one can open multiple client windows, some for controlling different Characters and some that share a Character's input/output like in mode 1. This mode otherwise works the same as mode 2.
|
||||
```
|
||||
│ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►┌─────────┐
|
||||
└──────┘ │ └───────┘ │ │ │Character│
|
||||
│ │ │ ┌►└─────────┘
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┘ ▼
|
||||
│Client├─┼──►│Session├──┘ │ │
|
||||
└──────┘ │ └───────┘ └───────┘
|
||||
│
|
||||
```
|
||||
|
||||
> Note that even if multiple Sessions puppet one Character, there is only ever one instance of that Character.
|
||||
|
||||
## Returning data to the session
|
||||
### Returning data to the session
|
||||
|
||||
When you use `msg()` to return data to a user, the object on which you call the `msg()` matters. The
|
||||
`MULTISESSION_MODE` also matters, especially if greater than 1.
|
||||
|
|
@ -120,51 +66,29 @@ This is a *handler* that tracks all Sessions attached to or puppeting them. Use
|
|||
it (it's always a single one). It will be `None` if no session is involved, like when a mob or
|
||||
script triggers the Command.
|
||||
|
||||
## Customizing the Session object
|
||||
### Customizing the Session object
|
||||
|
||||
When would one want to customize the Session object? Consider for example a character creation
|
||||
system: You might decide to keep this on the out-of-character level. This would mean that you create
|
||||
the character at the end of some sort of menu choice. The actual char-create cmdset would then
|
||||
normally be put on the account. This works fine as long as you are `MULTISESSION_MODE` below 2.
|
||||
For higher modes, replacing the Account cmdset will affect *all* your connected sessions, also those
|
||||
not involved in character creation. In this case you want to instead put the char-create cmdset on
|
||||
the Session level - then all other sessions will keep working normally despite you creating a new
|
||||
character in one of them.
|
||||
When would one want to customize the Session object? Consider for example a character creation system: You might decide to keep this on the out-of-character level. This would mean that you create the character at the end of some sort of menu choice. The actual char-create cmdset would then normally be put on the account. This works fine as long as you are `MULTISESSION_MODE` below 2. For higher modes, replacing the Account cmdset will affect *all* your connected sessions, also those not involved in character creation. In this case you want to instead put the char-create cmdset on the Session level - then all other sessions will keep working normally despite you creating a new character in one of them.
|
||||
|
||||
By default, the session object gets the `commands.default_cmdsets.UnloggedinCmdSet` when the user
|
||||
first connects. Once the session is authenticated it has *no* default sets. To add a "logged-in"
|
||||
cmdset to the Session, give the path to the cmdset class with `settings.CMDSET_SESSION`. This set
|
||||
By default, the session object gets the `commands.default_cmdsets.UnloggedinCmdSet` when the user first connects. Once the session is authenticated it has *no* default sets. To add a "logged-in" cmdset to the Session, give the path to the cmdset class with `settings.CMDSET_SESSION`. This set
|
||||
will then henceforth always be present as soon as the account logs in.
|
||||
|
||||
To customize further you can completely override the Session with your own subclass. To replace the
|
||||
default Session class, change `settings.SERVER_SESSION_CLASS` to point to your custom class. This is
|
||||
a dangerous practice and errors can easily make your game unplayable. Make sure to take heed of the
|
||||
[original](https://github.com/evennia/evennia/blob/master/evennia/server/session.py) and make your
|
||||
changes carefully.
|
||||
To customize further you can completely override the Session with your own subclass. To replace the default Session class, change `settings.SERVER_SESSION_CLASS` to point to your custom class. This is a dangerous practice and errors can easily make your game unplayable. Make sure to take heed of the [original](https://github.com/evennia/evennia/blob/master/evennia/server/session.py) and make your changes carefully.
|
||||
|
||||
## Portal and Server Sessions
|
||||
|
||||
*Note: This is considered an advanced topic. You don't need to know this on a first read-through.*
|
||||
|
||||
Evennia is split into two parts, the [Portal and the Server](./Portal-And-Server.md). Each side tracks
|
||||
its own Sessions, syncing them to each other.
|
||||
Evennia is split into two parts, the [Portal and the Server](./Portal-And-Server.md). Each side tracks its own Sessions, syncing them to each other.
|
||||
|
||||
The "Session" we normally refer to is actually the `ServerSession`. Its counter-part on the Portal
|
||||
side is the `PortalSession`. Whereas the server sessions deal with game states, the portal session
|
||||
deals with details of the connection-protocol itself. The two are also acting as backups of critical
|
||||
data such as when the server reboots.
|
||||
|
||||
New Account connections are listened for and handled by the Portal using the [protocols](Portal-And-
|
||||
Server) it understands (such as telnet, ssh, webclient etc). When a new connection is established, a
|
||||
`PortalSession` is created on the Portal side. This session object looks different depending on
|
||||
which protocol is used to connect, but all still have a minimum set of attributes that are generic
|
||||
to all
|
||||
sessions.
|
||||
New Account connections are listened for and handled by the Portal using the [protocols](Portal-And- Server) it understands (such as telnet, ssh, webclient etc). When a new connection is established, a `PortalSession` is created on the Portal side. This session object looks different depending on which protocol is used to connect, but all still have a minimum set of attributes that are generic to all sessions.
|
||||
|
||||
These common properties are piped from the Portal, through the AMP connection, to the Server, which
|
||||
is now informed a new connection has been established. On the Server side, a `ServerSession` object
|
||||
is created to represent this. There is only one type of `ServerSession`; It looks the same
|
||||
regardless of how the Account connects.
|
||||
These common properties are piped from the Portal, through the AMP connection, to the Server, which is now informed a new connection has been established. On the Server side, a `ServerSession` object is created to represent this. There is only one type of `ServerSession`; It looks the same regardless of how the Account connects.
|
||||
|
||||
From now on, there is a one-to-one match between the `ServerSession` on one side of the AMP
|
||||
connection and the `PortalSession` on the other. Data arriving to the Portal Session is sent on to
|
||||
|
|
@ -181,22 +105,17 @@ Portal side. When the Server comes back up, this data is returned by the Portal
|
|||
in sync. This way an Account's login status and other connection-critical things can survive a
|
||||
server reboot (assuming the Portal is not stopped at the same time, obviously).
|
||||
|
||||
## Sessionhandlers
|
||||
### Sessionhandlers
|
||||
|
||||
Both the Portal and Server each have a *sessionhandler* to manage the connections. These handlers
|
||||
are global entities contain all methods for relaying data across the AMP bridge. All types of
|
||||
Sessions hold a reference to their respective Sessionhandler (the property is called
|
||||
`sessionhandler`) so they can relay data. See [protocols](../Concepts/Protocols.md) for more info
|
||||
on building new protocols.
|
||||
`sessionhandler`) so they can relay data. See [protocols](../Concepts/Protocols.md) for more info on building new protocols.
|
||||
|
||||
To get all Sessions in the game (i.e. all currently connected clients), you access the server-side
|
||||
Session handler, which you get by
|
||||
To get all Sessions in the game (i.e. all currently connected clients), you access the server-side Session handler, which you get by
|
||||
```
|
||||
from evennia.server.sessionhandler import SESSION_HANDLER
|
||||
```
|
||||
> Note: The `SESSION_HANDLER` singleton has an older alias `SESSIONS` that is commonly seen in
|
||||
various places as well.
|
||||
> Note: The `SESSION_HANDLER` singleton has an older alias `SESSIONS` that is commonly seen in various places as well.
|
||||
|
||||
See the
|
||||
[sessionhandler.py](https://github.com/evennia/evennia/blob/master/evennia/server/sessionhandler.py)
|
||||
module for details on the capabilities of the `ServerSessionHandler`.
|
||||
See the [sessionhandler.py](https://github.com/evennia/evennia/blob/master/evennia/server/sessionhandler.py) module for details on the capabilities of the `ServerSessionHandler`.
|
||||
|
|
@ -18,7 +18,7 @@ signal.
|
|||
Evennia uses the [Django Signal system](https://docs.djangoproject.com/en/2.2/topics/signals/).
|
||||
|
||||
|
||||
## Attaching a handler to a signal
|
||||
## Working with Signals
|
||||
|
||||
First you create your handler
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ account = search_account("foo")[0]
|
|||
signals.SIGNAL_ACCOUNT_POST_CONNECT.connect(myhandler, account)
|
||||
```
|
||||
|
||||
## Available signals
|
||||
### Available signals
|
||||
|
||||
All signals (including some django-specific defaults) are available in the module
|
||||
`evennia.server.signals`
|
||||
|
|
|
|||
|
|
@ -29,8 +29,9 @@ Another example would be a weather script affecting all rooms tagged as `outdoor
|
|||
|
||||
In Evennia, Tags are technically also used to implement `Aliases` (alternative names for objects) and `Permissions` (simple strings for [Locks](./Locks.md) to check for).
|
||||
|
||||
## Working with Tags
|
||||
|
||||
## Properties of Tags (and Aliases and Permissions)
|
||||
### Properties of Tags (and Aliases and Permissions)
|
||||
|
||||
Tags are *unique*. This means that there is only ever one Tag object with a given key and category.
|
||||
|
||||
|
|
@ -63,11 +64,9 @@ each entity type for correctly storing the data behind the scenes.
|
|||
*Aliases* and *Permissions*. The Taghandlers using this special field are especially intended to
|
||||
free up the *category* property for any use you desire.
|
||||
|
||||
## Adding/Removing Tags
|
||||
### Adding/Removing Tags
|
||||
|
||||
You can tag any *typeclassed* object, namely [Objects](./Objects.md), [Accounts](./Accounts.md),
|
||||
[Scripts](./Scripts.md) and [Channels](./Channels.md). General tags are added by the *Taghandler*. The
|
||||
tag handler is accessed as a property `tags` on the relevant entity:
|
||||
You can tag any *typeclassed* object, namely [Objects](./Objects.md), [Accounts](./Accounts.md), [Scripts](./Scripts.md) and [Channels](./Channels.md). General tags are added by the *Taghandler*. The tag handler is accessed as a property `tags` on the relevant entity:
|
||||
|
||||
```python
|
||||
mychair.tags.add("furniture")
|
||||
|
|
@ -92,7 +91,7 @@ You can also use the default `@tag` command:
|
|||
|
||||
This tags the chair with a 'furniture' Tag (the one with a `None` category).
|
||||
|
||||
## Searching for objects with a given tag
|
||||
### Searching for objects with a given tag
|
||||
|
||||
Usually tags are used as a quick way to find tagged database entities. You can retrieve all objects
|
||||
with a given Tag like this in code:
|
||||
|
|
@ -118,14 +117,9 @@ with a given Tag like this in code:
|
|||
accounts = evennia.search_tag_account("guestaccount")
|
||||
```
|
||||
|
||||
> Note that searching for just "furniture" will only return the objects tagged with the "furniture"
|
||||
tag that
|
||||
has a category of `None`. We must explicitly give the category to get the "luxurious" furniture.
|
||||
> Note that searching for just "furniture" will only return the objects tagged with the "furniture" tag that has a category of `None`. We must explicitly give the category to get the "luxurious" furniture.
|
||||
|
||||
Using any of the `search_tag` variants will all return [Django
|
||||
Querysets](https://docs.djangoproject.com/en/2.1/ref/models/querysets/), including if you only have
|
||||
one match. You can treat querysets as lists and iterate over them, or continue building search
|
||||
queries with them.
|
||||
Using any of the `search_tag` variants will all return [Django Querysets](https://docs.djangoproject.com/en/2.1/ref/models/querysets/), including if you only have one match. You can treat querysets as lists and iterate over them, or continue building search queries with them.
|
||||
|
||||
Remember when searching that not setting a category means setting it to `None` - this does *not*
|
||||
mean that category is undefined, rather `None` is considered the default, unnamed category.
|
||||
|
|
@ -143,16 +137,13 @@ objs = evennia.search_tag("foo")
|
|||
objs = evennia.search_tag("foo", category="bar")
|
||||
# or
|
||||
objs = evennia.search_tag(category="bar")
|
||||
|
||||
```
|
||||
|
||||
|
||||
|
||||
There is also an in-game command that deals with assigning and using ([Object-](./Objects.md)) tags:
|
||||
|
||||
@tag/search furniture
|
||||
tag/search furniture
|
||||
|
||||
## Using Aliases and Permissions
|
||||
## Aliases and Permissions
|
||||
|
||||
Aliases and Permissions are implemented using normal TagHandlers that simply save Tags with a
|
||||
different `tagtype`. These handlers are named `aliases` and `permissions` on all Objects. They are
|
||||
|
|
@ -169,14 +160,3 @@ used in the same way as Tags above:
|
|||
and so on. Similarly to how `@tag` works in-game, there is also the `@perm` command for assigning
|
||||
permissions and `@alias` command for aliases.
|
||||
|
||||
## Assorted notes
|
||||
|
||||
Generally, tags are enough on their own for grouping objects. Having no tag `category` is perfectly
|
||||
fine and the normal operation. Simply adding a new Tag for grouping objects is often better than
|
||||
making a new category. So think hard before deciding you really need to categorize your Tags.
|
||||
|
||||
That said, tag categories can be useful if you build some game system that uses tags. You can then
|
||||
use tag categories to make sure to separate tags created with this system from any other tags
|
||||
created elsewhere. You can then supply custom search methods that *only* find objects tagged with
|
||||
tags of that category. An example of this
|
||||
is found in the [Zone tutorial](../Concepts/Zones.md).
|
||||
|
|
@ -1,61 +1,55 @@
|
|||
# Typeclasses
|
||||
|
||||
*Typeclasses* form the core of Evennia's data storage. It allows Evennia to represent any number of
|
||||
different game entities as Python classes, without having to modify the database schema for every
|
||||
new type.
|
||||
*Typeclasses* form the core of Evennia's data storage. It allows Evennia to represent any number of different game entities as Python classes, without having to modify the database schema for every new type.
|
||||
|
||||
In Evennia the most important game entities, [Accounts](./Accounts.md), [Objects](./Objects.md), [Scripts](./Scripts.md) and [Channels](./Channels.md) are all Python classes inheriting, at varying distance, from `evennia.typeclasses.models.TypedObject`. In the documentation we refer to these objects as being "typeclassed" or even "being a typeclass".
|
||||
|
||||
This is how the inheritance looks for the typeclasses in Evennia:
|
||||
|
||||
```
|
||||
TypedObject
|
||||
_________________|_________________________________
|
||||
| | | |
|
||||
1: AccountDB ObjectDB ScriptDB ChannelDB
|
||||
| | | |
|
||||
2: DefaultAccount DefaultObject DefaultScript DefaultChannel
|
||||
| DefaultCharacter | |
|
||||
| DefaultRoom | |
|
||||
| DefaultExit | |
|
||||
| | | |
|
||||
3: Account Object Script Channel
|
||||
Character
|
||||
Room
|
||||
Exit
|
||||
┌───────────┐
|
||||
│TypedObject│
|
||||
└─────▲─────┘
|
||||
┌───────────────┬────────┴──────┬────────────────┐
|
||||
┌────┴────┐ ┌────┴───┐ ┌────┴────┐ ┌────┴───┐
|
||||
1: │AccountDB│ │ScriptDB│ │ChannelDB│ │ObjectDB│
|
||||
└────▲────┘ └────▲───┘ └────▲────┘ └────▲───┘
|
||||
┌───────┴──────┐ ┌──────┴──────┐ ┌──────┴───────┐ ┌──────┴──────┐
|
||||
2: │DefaultAccount│ │DefaultScript│ │DefaultChannel│ │DefaultObject│
|
||||
└───────▲──────┘ └──────▲──────┘ └──────▲───────┘ └──────▲──────┘
|
||||
│ │ │ │ Evennia
|
||||
────────┼───────────────┼───────────────┼────────────────┼─────────
|
||||
│ │ │ │ Gamedir
|
||||
┌───┴───┐ ┌───┴──┐ ┌───┴───┐ ┌──────┐ │
|
||||
3: │Account│ │Script│ │Channel│ │Object├─┤
|
||||
└───────┘ └──────┘ └───────┘ └──────┘ │
|
||||
┌─────────┐ │
|
||||
│Character├─┤
|
||||
└─────────┘ │
|
||||
┌────┐ │
|
||||
│Room├─┤
|
||||
└────┘ │
|
||||
┌────┐ │
|
||||
│Exit├─┘
|
||||
└────┘
|
||||
```
|
||||
|
||||
- **Level 1** above is the "database model" level. This describes the database tables and fields
|
||||
(this is technically a [Django model](https://docs.djangoproject.com/en/2.2/topics/db/models/)).
|
||||
- **Level 2** is where we find Evennia's default implementations of the various game entities, on
|
||||
top of the database. These classes define all the hook methods that Evennia calls in various
|
||||
situations. `DefaultObject` is a little special since it's the parent for `DefaultCharacter`,
|
||||
`DefaultRoom` and `DefaultExit`. They are all grouped under level 2 because they all represents
|
||||
defaults to build from.
|
||||
- **Level 3**, finally, holds empty template classes created in your game directory. This is the
|
||||
level you are meant to modify and tweak as you please, overloading the defaults as befits your game.
|
||||
The templates inherit directly from their defaults, so `Object` inherits from `DefaultObject` and
|
||||
`Room` inherits from `DefaultRoom`.
|
||||
- **Level 1** above is the "database model" level. This describes the database tables and fields (this is technically a [Django model](https://docs.djangoproject.com/en/2.2/topics/db/models/)).
|
||||
- **Level 2** is where we find Evennia's default implementations of the various game entities, on top of the database. These classes define all the hook methods that Evennia calls in various situations. `DefaultObject` is a little special since it's the parent for `DefaultCharacter`, `DefaultRoom` and `DefaultExit`. They are all grouped under level 2 because they all represents defaults to build from.
|
||||
- **Level 3**, finally, holds empty template classes created in your game directory. This is the level you are meant to modify and tweak as you please, overloading the defaults as befits your game. The templates inherit directly from their defaults, so `Object` inherits from `DefaultObject` and `Room` inherits from `DefaultRoom`.
|
||||
|
||||
The `typeclass/list` command will provide a list of all typeclasses known to
|
||||
Evennia. This can be useful for getting a feel for what is available. Note
|
||||
however that if you add a new module with a class in it but do not import that
|
||||
module from anywhere, the `typeclass/list` will not find it. To make it known
|
||||
to Evennia you must import that module from somewhere.
|
||||
> This diagram doesn't include the `ObjectParent` mixin for `Object`, `Character`, `Room` and `Exit`. This establishes a common parent for those classes, for shared properties. See [Objects](./Objects.md) for more details.
|
||||
|
||||
The `typeclass/list` command will provide a list of all typeclasses known to Evennia. This can be useful for getting a feel for what is available. Note however that if you add a new module with a class in it but do not import that module from anywhere, the `typeclass/list` will not find it. To make it known to Evennia you must import that module from somewhere.
|
||||
|
||||
|
||||
## Difference between typeclasses and classes
|
||||
|
||||
All Evennia classes inheriting from class in the table above share one important feature and two
|
||||
important limitations. This is why we don't simply call them "classes" but "typeclasses".
|
||||
[]()important limitations. This is why we don't simply call them "classes" but "typeclasses".
|
||||
|
||||
1. A typeclass can save itself to the database. This means that some properties (actually not that
|
||||
many) on the class actually represents database fields and can only hold very specific data types.
|
||||
This is detailed [below](./Typeclasses.md#about-typeclass-properties).
|
||||
1. Due to its connection to the database, the typeclass' name must be *unique* across the _entire_
|
||||
server namespace. That is, there must never be two same-named classes defined anywhere. So the below
|
||||
code would give an error (since `DefaultObject` is now globally found both in this module and in the
|
||||
default library):
|
||||
1. A typeclass can save itself to the database. This means that some properties (actually not that many) on the class actually represents database fields and can only hold very specific data types.
|
||||
1. Due to its connection to the database, the typeclass' name must be *unique* across the _entire_ server namespace. That is, there must never be two same-named classes defined anywhere. So the below code would give an error (since `DefaultObject` is now globally found both in this module and in the default library):
|
||||
|
||||
```python
|
||||
from evennia import DefaultObject as BaseObject
|
||||
|
|
@ -63,8 +57,8 @@ default library):
|
|||
pass
|
||||
```
|
||||
|
||||
1. A typeclass' `__init__` method should normally not be overloaded. This has mostly to do with the fact that the `__init__` method is not called in a predictable way. Instead Evennia suggest you use the `at_*_creation` hooks (like `at_object_creation` for Objects) for setting things the very first time the typeclass is saved to the database or the `at_init` hook which is called every time the object is cached to memory. If you know what you are doing and want to use `__init__`, it *must* both accept arbitrary keyword arguments and use `super` to call its parent:
|
||||
|
||||
1. A typeclass' `__init__` method should normally not be overloaded. This has mostly to do with the fact that the `__init__` method is not called in a predictable way. Instead Evennia suggest you use the `at_*_creation` hooks (like `at_object_creation` for Objects) for setting things the very first time the typeclass is saved to the database or the `at_init` hook which is called every time the object is cached to memory. If you know what you are doing and want to use `__init__`, it *must* both accept arbitrary keyword arguments and use `super` to call its parent:
|
||||
|
||||
```python
|
||||
def __init__(self, **kwargs):
|
||||
# my content
|
||||
|
|
@ -75,8 +69,9 @@ default library):
|
|||
Apart from this, a typeclass works like any normal Python class and you can
|
||||
treat it as such.
|
||||
|
||||
## Working with typeclasses
|
||||
|
||||
## Creating a new typeclass
|
||||
### Creating a new typeclass
|
||||
|
||||
It's easy to work with Typeclasses. Either you use an existing typeclass or you create a new Python class inheriting from an existing typeclass. Here is an example of creating a new type of Object:
|
||||
|
||||
|
|
@ -123,8 +118,6 @@ functions take a lot of extra keywords allowing you to set things like [Attribut
|
|||
[Tags](./Tags.md) all in one go. These keywords don't use the `db_*` prefix. This will also automatically
|
||||
save the new instance to the database, so you don't need to call `save()` explicitly.
|
||||
|
||||
## About typeclass properties
|
||||
|
||||
An example of a database field is `db_key`. This stores the "name" of the entity you are modifying
|
||||
and can thus only hold a string. This is one way of making sure to update the `db_key`:
|
||||
|
||||
|
|
@ -187,14 +180,11 @@ respective pages for [Objects](./Objects.md), [Scripts](./Scripts.md), [Accounts
|
|||
entities using [Evennia's flat API](../Evennia-API.md) to explore which properties and methods they have
|
||||
available.
|
||||
|
||||
## Overloading hooks
|
||||
### Overloading hooks
|
||||
|
||||
The way to customize typeclasses is usually to overload *hook methods* on them. Hooks are methods
|
||||
that Evennia call in various situations. An example is the `at_object_creation` hook on `Objects`,
|
||||
which is only called once, the very first time this object is saved to the database. Other examples
|
||||
are the `at_login` hook of Accounts and the `at_repeat` hook of Scripts.
|
||||
The way to customize typeclasses is usually to overload *hook methods* on them. Hooks are methods that Evennia call in various situations. An example is the `at_object_creation` hook on `Objects`, which is only called once, the very first time this object is saved to the database. Other examples are the `at_login` hook of Accounts and the `at_repeat` hook of Scripts.
|
||||
|
||||
## Querying for typeclasses
|
||||
### Querying for typeclasses
|
||||
|
||||
Most of the time you search for objects in the database by using convenience methods like the
|
||||
`caller.search()` of [Commands](./Commands.md) or the search functions like `evennia.search_objects`.
|
||||
|
|
@ -235,7 +225,7 @@ matches = ScriptDB.objects.filter(db_key__contains="Combat")
|
|||
When querying from the database model parent you don't need to use `filter_family` or `get_family` -
|
||||
you will always query all children on the database model.
|
||||
|
||||
## Updating existing typeclass instances
|
||||
### Updating existing typeclass instances
|
||||
|
||||
If you already have created instances of Typeclasses, you can modify the *Python code* at any time -
|
||||
due to how Python inheritance works your changes will automatically be applied to all children once you have reloaded the server.
|
||||
|
|
@ -278,7 +268,7 @@ py from typeclasses.furniture import Furniture;
|
|||
It is recommended that you plan your game properly before starting to build, to avoid having to
|
||||
retroactively update objects more than necessary.
|
||||
|
||||
## Swap typeclass
|
||||
### Swap typeclass
|
||||
|
||||
If you want to swap an already existing typeclass, there are two ways to do so: From in-game and via code. From inside the game you can use the default `@typeclass` command:
|
||||
|
||||
|
|
@ -309,7 +299,7 @@ models that are "real" in the typeclass system (that is, are represented by actu
|
|||
|
||||
Evennia modifies Django's proxy model in various ways to allow them to work without any boiler plate (for example you don't need to set the Django "proxy" property in the model `Meta` subclass, Evennia handles this for you using metaclasses). Evennia also makes sure you can query subclasses as well as patches django to allow multiple inheritance from the same base class.
|
||||
|
||||
## Caveats
|
||||
### Caveats
|
||||
|
||||
Evennia uses the *idmapper* to cache its typeclasses (Django proxy models) in memory. The idmapper allows things like on-object handlers and properties to be stored on typeclass instances and to not get lost as long as the server is running (they will only be cleared on a Server reload). Django does not work like this by default; by default every time you search for an object in the database you'll get a *different* instance of that object back and anything you stored on it that was not in the database would be lost. The bottom line is that Evennia's Typeclass instances subside in memory a lot longer than vanilla Django model instance do.
|
||||
|
||||
|
|
|
|||
|
|
@ -54,14 +54,57 @@ class UnloggedinCmdSet(default_cmds.UnloggedinCmdSet):
|
|||
|
||||
## Multisession mode and multi-playing
|
||||
|
||||
The multisession modes are described in detail in the [Session documentation](../Components/Sessions.md#multisession-mode). In brief, this is controlled by a [setting](../Setup/Settings.md). Here's the default:
|
||||
The number of sessions possible to connect to a given account at the same time and how it works is given by the `MULTISESSION_MODE` setting:
|
||||
|
||||
MULTISESSION_MODE = 0
|
||||
* `MULTISESSION_MODE=0`: One session per account. When connecting with a new session the old one is disconnected. This is the default mode and emulates many classic mud code bases.
|
||||
```
|
||||
┌──────┐ │ ┌───────┐ ┌───────┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├───►│Account├──►│Character│
|
||||
└──────┘ │ └───────┘ └───────┘ └─────────┘
|
||||
```
|
||||
* `MULTISESSION_MODE=1`: Many sessions per account, input/output from/to each session is treated the same. For the player this means they can connect to the game from multiple clients and see the same output in all of them. The result of a command given in one client (that is, through one Session) will be returned to *all* connected Sessions/clients with no distinction.
|
||||
```
|
||||
│
|
||||
┌──────┐ │ ┌───────┐
|
||||
│Client├─┼──►│Session├──┐
|
||||
└──────┘ │ └───────┘ └──►┌───────┐ ┌─────────┐
|
||||
│ │Account├──►│Character│
|
||||
┌──────┐ │ ┌───────┐ ┌──►└───────┘ └─────────┘
|
||||
│Client├─┼──►│Session├──┘
|
||||
└──────┘ │ └───────┘
|
||||
│
|
||||
```
|
||||
|
||||
- `MULTISESSION_MODE=0`: One [Session](../Components/Sessions.md) per [Account](../Components/Accounts.md), routed to one [puppet](../Components/Objects.md). If connecting with a new session/client, it will kick the previous one.
|
||||
- `MULTISESSION_MODE=1`: Multiple sessions per Account, all routed to one puppet. Allows you to control one puppet from multiple client windows.
|
||||
- `MULTISESSION_MODE=2`: Multiple sessions per Account, each routed to a different puppet. This allows for multi-playing.
|
||||
- `MULTISESSION_MODE=3`: Multiple sessions per account, And multiple sessions per puppet. This is full multi-playing, including being able to control each puppet from multiple clients.
|
||||
* `MULTISESSION_MODE=2`: Many sessions per account, one character per session. In this mode, puppeting an Object/Character will link the puppet back only to the particular Session doing the puppeting. That is, input from that Session will make use of the CmdSet of that Object/Character and outgoing messages (such as the result of a `look`) will be passed back only to that puppeting Session. If another Session tries to puppet the same Character, the old Session will automatically un-puppet it. From the player's perspective, this will mean that they can open separate game clients and play a different Character in each using one game account.
|
||||
```
|
||||
│ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►│Character│
|
||||
└──────┘ │ └───────┘ │ │ └─────────┘
|
||||
│ └───────┘
|
||||
```
|
||||
* `MULTISESSION_MODE=3`: Many sessions per account *and* character. This is the full multi-puppeting mode, where multiple sessions may not only connect to the player account but multiple sessions may also puppet a single character at the same time. From the user's perspective it means one can open multiple client windows, some for controlling different Characters and some that share a Character's input/output like in mode 1. This mode otherwise works the same as mode 2.
|
||||
```
|
||||
│ ┌───────┐
|
||||
┌──────┐ │ ┌───────┐ │Account│ ┌─────────┐
|
||||
│Client├─┼──►│Session├──┐ │ │ ┌►│Character│
|
||||
└──────┘ │ └───────┘ └──┼───────┼──┘ └─────────┘
|
||||
│ │ │
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┐
|
||||
│Client├─┼──►│Session├──┘ │ │ └►┌─────────┐
|
||||
└──────┘ │ └───────┘ │ │ │Character│
|
||||
│ │ │ ┌►└─────────┘
|
||||
┌──────┐ │ ┌───────┐ ┌──┼───────┼──┘ ▼
|
||||
│Client├─┼──►│Session├──┘ │ │
|
||||
└──────┘ │ └───────┘ └───────┘
|
||||
│
|
||||
```
|
||||
|
||||
> Note that even if multiple Sessions puppet one Character, there is only ever one instance of that Character.
|
||||
|
||||
Mode `0` is the default and mimics how many legacy codebases work, especially in the DIKU world. The equivalence of higher modes are often 'hacked' into existing servers to allow for players to have multiple characters.
|
||||
|
||||
|
|
|
|||
|
|
@ -250,6 +250,10 @@ div.highlight {
|
|||
border-radius: 5px;
|
||||
}
|
||||
|
||||
div.highlight-shell.notranslate > div.highlight .nb {
|
||||
color: #79ecff !important;
|
||||
}
|
||||
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ to accounts respectively.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.admin.CmdEmit.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['pemit', 'remit']</em><a class="headerlink" href="#evennia.commands.default.admin.CmdEmit.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['remit', 'pemit']</em><a class="headerlink" href="#evennia.commands.default.admin.CmdEmit.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -348,7 +348,7 @@ to accounts respectively.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.admin.CmdEmit.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'pemit remit', 'category': 'admin', 'key': 'emit', 'no_prefix': ' pemit remit', 'tags': '', 'text': '\n admin command for emitting message to multiple objects\n\n Usage:\n emit[/switches] [<obj>, <obj>, ... =] <message>\n remit [<obj>, <obj>, ... =] <message>\n pemit [<obj>, <obj>, ... =] <message>\n\n Switches:\n room - limit emits to rooms only (default)\n accounts - limit emits to accounts only\n contents - send to the contents of matched objects too\n\n Emits a message to the selected objects or to\n your immediate surroundings. If the object is a room,\n send to its contents. remit and pemit are just\n limited forms of emit, for sending to rooms and\n to accounts respectively.\n '}</em><a class="headerlink" href="#evennia.commands.default.admin.CmdEmit.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'remit pemit', 'category': 'admin', 'key': 'emit', 'no_prefix': ' remit pemit', 'tags': '', 'text': '\n admin command for emitting message to multiple objects\n\n Usage:\n emit[/switches] [<obj>, <obj>, ... =] <message>\n remit [<obj>, <obj>, ... =] <message>\n pemit [<obj>, <obj>, ... =] <message>\n\n Switches:\n room - limit emits to rooms only (default)\n accounts - limit emits to accounts only\n contents - send to the contents of matched objects too\n\n Emits a message to the selected objects or to\n your immediate surroundings. If the object is a room,\n send to its contents. remit and pemit are just\n limited forms of emit, for sending to rooms and\n to accounts respectively.\n '}</em><a class="headerlink" href="#evennia.commands.default.admin.CmdEmit.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -1345,7 +1345,7 @@ server settings.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.building.CmdTypeclass.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@parent', '@typeclasses', '@update', '@swap', '@type']</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@update', '@typeclasses', '@type', '@parent', '@swap']</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -1376,7 +1376,7 @@ server settings.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.building.CmdTypeclass.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@parent @typeclasses @update @swap @type', 'category': 'building', 'key': '@typeclass', 'no_prefix': 'typeclass parent typeclasses update swap type', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@update @typeclasses @type @parent @swap', 'category': 'building', 'key': '@typeclass', 'no_prefix': 'typeclass update typeclasses type parent swap', 'tags': '', 'text': "\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] <object> [= typeclass.path]\n typeclass/prototype <object> = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n "}</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ for everyone to use, you need build privileges and the alias command.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdNick.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['nicks', 'nickname']</em><a class="headerlink" href="#evennia.commands.default.general.CmdNick.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['nickname', 'nicks']</em><a class="headerlink" href="#evennia.commands.default.general.CmdNick.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -300,7 +300,7 @@ for everyone to use, you need build privileges and the alias command.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdNick.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'nicks nickname', 'category': 'general', 'key': 'nick', 'no_prefix': ' nicks nickname', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdNick.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'nickname nicks', 'category': 'general', 'key': 'nick', 'no_prefix': ' nickname nicks', 'tags': '', 'text': '\n define a personal alias/nick by defining a string to\n match and replace it with another on the fly\n\n Usage:\n nick[/switches] <string> [= [replacement_string]]\n nick[/switches] <template> = <replacement_template>\n nick/delete <string> or number\n nicks\n\n Switches:\n inputline - replace on the inputline (default)\n object - replace on object-lookup\n account - replace on account-lookup\n list - show all defined aliases (also "nicks" works)\n delete - remove nick by index in /list\n clearall - clear all nicks\n\n Examples:\n nick hi = say Hello, I\'m Sarah!\n nick/object tom = the tall man\n nick build $1 $2 = create/drop $1;$2\n nick tell $1 $2=page $1=$2\n nick tm?$1=page tallman=$1\n nick tm\\=$1=page tallman=$1\n\n A \'nick\' is a personal string replacement. Use $1, $2, ... to catch arguments.\n Put the last $-marker without an ending space to catch all remaining text. You\n can also use unix-glob matching for the left-hand side <string>:\n\n * - matches everything\n ? - matches 0 or 1 single characters\n [abcd] - matches these chars in any order\n [!abcd] - matches everything not among these chars\n \\= - escape literal \'=\' you want in your <string>\n\n Note that no objects are actually renamed or changed by this command - your nicks\n are only available to you. If you want to permanently add keywords to an object\n for everyone to use, you need build privileges and the alias command.\n\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdNick.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -323,7 +323,7 @@ inv</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdInventory.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['inv', 'i']</em><a class="headerlink" href="#evennia.commands.default.general.CmdInventory.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['i', 'inv']</em><a class="headerlink" href="#evennia.commands.default.general.CmdInventory.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -354,7 +354,7 @@ inv</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdInventory.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'no_prefix': ' inv i', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdInventory.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'no_prefix': ' i inv', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdInventory.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -598,7 +598,7 @@ placing it in their inventory.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdSay.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['"', "'"]</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ["'", '"']</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -629,7 +629,7 @@ placing it in their inventory.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdSay.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '" \'', 'category': 'general', 'key': 'say', 'no_prefix': ' " \'', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'no_prefix': ' \' "', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -773,7 +773,7 @@ which permission groups you are a member of.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdAccess.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['hierarchy', 'groups']</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['groups', 'hierarchy']</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -804,7 +804,7 @@ which permission groups you are a member of.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.general.CmdAccess.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hierarchy groups', 'category': 'general', 'key': 'access', 'no_prefix': ' hierarchy groups', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'groups hierarchy', 'category': 'general', 'key': 'access', 'no_prefix': ' groups hierarchy', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -683,7 +683,7 @@ See <a href="#id11"><span class="problematic" id="id12">|</span></a>luhttps://ww
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.system.CmdTasks.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@task', '@delays']</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@delays', '@task']</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -729,7 +729,7 @@ to all the variables defined therein.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.system.CmdTasks.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@task @delays', 'category': 'system', 'key': '@tasks', 'no_prefix': 'tasks task delays', 'tags': '', 'text': "\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n "}</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@delays @task', 'category': 'system', 'key': '@tasks', 'no_prefix': 'tasks delays task', 'tags': '', 'text': "\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n "}</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -902,7 +902,7 @@ main test suite started with</p>
|
|||
<p>Test the batch processor.</p>
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.tests.TestBatchProcess.red_button">
|
||||
<code class="sig-name descname">red_button</code><em class="property"> = <module 'evennia.contrib.tutorials.red_button.red_button' from '/tmp/tmpbbi6me6k/ecf4b5c52451b9773c5003b4d0127961d156e0e6/evennia/contrib/tutorials/red_button/red_button.py'></em><a class="headerlink" href="#evennia.commands.default.tests.TestBatchProcess.red_button" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">red_button</code><em class="property"> = <module 'evennia.contrib.tutorials.red_button.red_button' from '/tmp/tmpw2foz9tg/857984b26cec545b5f780fc0957fef9a31123d87/evennia/contrib/tutorials/red_button/red_button.py'></em><a class="headerlink" href="#evennia.commands.default.tests.TestBatchProcess.red_button" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ create “account name” “pass word”</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedCreate.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['cre', 'cr']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['cr', 'cre']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -212,7 +212,7 @@ create “account name” “pass word”</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedCreate.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'no_prefix': ' cre cr', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create <accountname> <password>\n create "account name" "pass word"\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -236,7 +236,7 @@ version is a bit more complicated.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedQuit.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['qu', 'q']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedQuit.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['q', 'qu']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedQuit.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -262,7 +262,7 @@ version is a bit more complicated.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedQuit.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'no_prefix': ' qu q', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedQuit.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'no_prefix': ' q qu', 'tags': '', 'text': '\n quit when in unlogged-in state\n\n Usage:\n quit\n\n We maintain a different version of the quit command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedQuit.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -286,7 +286,7 @@ All it does is display the connect screen.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedLook.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['l', 'look']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['look', 'l']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -312,7 +312,7 @@ All it does is display the connect screen.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedLook.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ there is no object yet before the account has logged in)</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['cre', 'cr']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['cr', 'cre']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -227,7 +227,7 @@ name enclosed in quotes:</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'no_prefix': ' cre cr', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create "accountname" <email> <password>\n\n This creates a new account account.\n\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -246,7 +246,7 @@ version is a bit more complicated.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['qu', 'q']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['q', 'qu']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -272,7 +272,7 @@ version is a bit more complicated.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'qu q', 'category': 'general', 'key': 'quit', 'no_prefix': ' qu q', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'q qu', 'category': 'general', 'key': 'quit', 'no_prefix': ' q qu', 'tags': '', 'text': '\n We maintain a different version of the `quit` command\n here for unconnected accounts for the sake of simplicity. The logged in\n version is a bit more complicated.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedQuit.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -291,7 +291,7 @@ All it does is display the connect screen.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['l', 'look']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['look', 'l']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -317,7 +317,7 @@ All it does is display the connect screen.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.ingame_python.commands.CmdCallback.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@callbacks', '@calls', '@callback']</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@callback', '@callbacks', '@calls']</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -197,7 +197,7 @@ on user permission.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.ingame_python.commands.CmdCallback.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@callbacks @calls @callback', 'category': 'building', 'key': '@call', 'no_prefix': 'call callbacks calls callback', 'tags': '', 'text': '\n Command to edit callbacks.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@callback @callbacks @calls', 'category': 'building', 'key': '@call', 'no_prefix': 'call callback callbacks calls', 'tags': '', 'text': '\n Command to edit callbacks.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ for that channel.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['delaliaschan', 'delchanalias']</em><a class="headerlink" href="#evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['delchanalias', 'delaliaschan']</em><a class="headerlink" href="#evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -248,7 +248,7 @@ for that channel.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'delaliaschan delchanalias', 'category': 'comms', 'key': 'delcom', 'no_prefix': ' delaliaschan delchanalias', 'tags': '', 'text': "\n remove a channel alias and/or unsubscribe from channel\n\n Usage:\n delcom <alias or channel>\n delcom/all <channel>\n\n If the full channel name is given, unsubscribe from the\n channel. If an alias is given, remove the alias but don't\n unsubscribe. If the 'all' switch is used, remove all aliases\n for that channel.\n "}</em><a class="headerlink" href="#evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'delchanalias delaliaschan', 'category': 'comms', 'key': 'delcom', 'no_prefix': ' delchanalias delaliaschan', 'tags': '', 'text': "\n remove a channel alias and/or unsubscribe from channel\n\n Usage:\n delcom <alias or channel>\n delcom/all <channel>\n\n If the full channel name is given, unsubscribe from the\n channel. If an alias is given, remove the alias but don't\n unsubscribe. If the 'all' switch is used, remove all aliases\n for that channel.\n "}</em><a class="headerlink" href="#evennia.contrib.base_systems.mux_comms_cmds.mux_comms_cmds.CmdDelCom.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@ the operation will be general or on the room.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['chicken out', 'abort', 'quit', 'q']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['quit', 'q', 'abort', 'chicken out']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
|
|
@ -235,7 +235,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'chicken out abort quit q', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' chicken out abort quit q', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'quit q abort chicken out', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' quit q abort chicken out', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -371,7 +371,7 @@ shout</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = [';', 'whisper', 'shout']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = [';', 'shout', 'whisper']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -400,7 +400,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '; whisper shout', 'category': 'general', 'key': 'say', 'no_prefix': ' ; whisper shout', 'tags': '', 'text': '\n Perform an communication action.\n\n Usage:\n say <text>\n whisper\n shout\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '; shout whisper', 'category': 'general', 'key': 'say', 'no_prefix': ' ; shout whisper', 'tags': '', 'text': '\n Perform an communication action.\n\n Usage:\n say <text>\n whisper\n shout\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdSpeak.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -490,7 +490,7 @@ looks and what actions is available.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['ex', 'e', 'examine', 'unfocus']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['examine', 'unfocus', 'e', 'ex']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -519,7 +519,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'ex e examine unfocus', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' ex e examine unfocus', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus <obj>\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'examine unfocus e ex', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' examine unfocus e ex', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus <obj>\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -581,7 +581,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdGet.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['inv', 'give', 'i', 'inventory']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGet.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['give', 'inventory', 'inv', 'i']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGet.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
|
|
@ -605,7 +605,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdGet.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'inv give i inventory', 'category': 'evscaperoom', 'key': 'get', 'no_prefix': ' inv give i inventory', 'tags': '', 'text': '\n Use focus / examine instead.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGet.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'give inventory inv i', 'category': 'evscaperoom', 'key': 'get', 'no_prefix': ' give inventory inv i', 'tags': '', 'text': '\n Use focus / examine instead.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGet.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -626,7 +626,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@dig', '@open']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['@open', '@dig']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
|
|
@ -649,7 +649,7 @@ to all the variables defined therein.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@dig @open', 'category': 'general', 'key': 'open', 'no_prefix': ' dig open', 'tags': '', 'text': '\n Interact with an object in focus.\n\n Usage:\n <action> [arg]\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '@open @dig', 'category': 'general', 'key': 'open', 'no_prefix': ' open dig', 'tags': '', 'text': '\n Interact with an object in focus.\n\n Usage:\n <action> [arg]\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdRerouter.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -745,7 +745,7 @@ try to influence the other part in the deal.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.game_systems.barter.barter.CmdStatus.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['offers', 'deal']</em><a class="headerlink" href="#evennia.contrib.game_systems.barter.barter.CmdStatus.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['deal', 'offers']</em><a class="headerlink" href="#evennia.contrib.game_systems.barter.barter.CmdStatus.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -771,7 +771,7 @@ try to influence the other part in the deal.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.game_systems.barter.barter.CmdStatus.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'offers deal', 'category': 'trading', 'key': 'status', 'no_prefix': ' offers deal', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}</em><a class="headerlink" href="#evennia.contrib.game_systems.barter.barter.CmdStatus.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'deal offers', 'category': 'trading', 'key': 'status', 'no_prefix': ' deal offers', 'tags': '', 'text': "\n show a list of the current deal\n\n Usage:\n status\n deal\n offers\n\n Shows the currently suggested offers on each sides of the deal. To\n accept the current deal, use the 'accept' command. Use 'offer' to\n change your deal. You might also want to use 'say', 'emote' etc to\n try to influence the other part in the deal.\n "}</em><a class="headerlink" href="#evennia.contrib.game_systems.barter.barter.CmdStatus.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -622,7 +622,7 @@ inv</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.game_systems.clothing.clothing.CmdInventory.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['inv', 'i']</em><a class="headerlink" href="#evennia.contrib.game_systems.clothing.clothing.CmdInventory.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['i', 'inv']</em><a class="headerlink" href="#evennia.contrib.game_systems.clothing.clothing.CmdInventory.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -653,7 +653,7 @@ inv</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.game_systems.clothing.clothing.CmdInventory.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'no_prefix': ' inv i', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.clothing.clothing.CmdInventory.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'no_prefix': ' i inv', 'tags': '', 'text': '\n view inventory\n\n Usage:\n inventory\n inv\n\n Shows your inventory.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.clothing.clothing.CmdInventory.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -695,7 +695,7 @@ a different language.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['"', "'"]</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ["'", '"']</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -726,7 +726,7 @@ a different language.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '" \'', 'category': 'general', 'key': 'say', 'no_prefix': ' " \'', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '\' "', 'category': 'general', 'key': 'say', 'no_prefix': ' \' "', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say <message>\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.evadventure.commands.CmdInventory.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['inv', 'i']</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.commands.CmdInventory.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['i', 'inv']</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.commands.CmdInventory.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
|
|
@ -280,7 +280,7 @@ set in self.parse())</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.evadventure.commands.CmdInventory.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'inv i', 'category': 'general', 'key': 'inventory', 'no_prefix': ' inv i', 'tags': '', 'text': '\n View your inventory\n\n Usage:\n inventory\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.commands.CmdInventory.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'i inv', 'category': 'general', 'key': 'inventory', 'no_prefix': ' i inv', 'tags': '', 'text': '\n View your inventory\n\n Usage:\n inventory\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.commands.CmdInventory.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -252,7 +252,7 @@ check if the lid is open or closed.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['break lid', 'smash lid', 'smash']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['break lid', 'smash', 'smash lid']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -279,7 +279,7 @@ break.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'break lid smash lid smash', 'category': 'general', 'key': 'smash glass', 'no_prefix': ' break lid smash lid smash', 'tags': '', 'text': '\n Smash the protective glass.\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'break lid smash smash lid', 'category': 'general', 'key': 'smash glass', 'no_prefix': ' break lid smash smash lid', 'tags': '', 'text': '\n Smash the protective glass.\n\n Usage:\n smash glass\n\n Try to smash the glass of the button.\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdSmashGlass.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -506,7 +506,7 @@ be mutually exclusive.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['l', 'listen', 'feel', 'get', 'ex', 'examine']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['get', 'feel', 'listen', 'ex', 'examine', 'l']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -532,7 +532,7 @@ be mutually exclusive.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'l listen feel get ex examine', 'category': 'general', 'key': 'look', 'no_prefix': ' l listen feel get ex examine', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'get feel listen ex examine l', 'category': 'general', 'key': 'look', 'no_prefix': ' get feel listen ex examine l', 'tags': '', 'text': "\n Looking around in darkness\n\n Usage:\n look <obj>\n\n ... not that there's much to see in the dark.\n\n "}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -556,7 +556,7 @@ shift green root up/down</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['pull', 'move', 'push', 'shiftroot']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['pull', 'shiftroot', 'move', 'push']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -592,7 +592,7 @@ yellow/green - horizontal roots</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'pull move push shiftroot', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' pull move push shiftroot', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'pull shiftroot move push', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' pull shiftroot move push', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
@ -779,7 +779,7 @@ parry - forgoes your attack but will make you harder to hit on next</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['kill', 'parry', 'stab', 'slash', 'fight', 'chop', 'bash', 'pierce', 'hit', 'thrust', 'defend']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['defend', 'chop', 'parry', 'pierce', 'slash', 'thrust', 'hit', 'bash', 'fight', 'kill', 'stab']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -805,7 +805,7 @@ parry - forgoes your attack but will make you harder to hit on next</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'kill parry stab slash fight chop bash pierce hit thrust defend', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' kill parry stab slash fight chop bash pierce hit thrust defend', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'defend chop parry pierce slash thrust hit bash fight kill stab', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' defend chop parry pierce slash thrust hit bash fight kill stab', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab <enemy>\n slash <enemy>\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -968,7 +968,7 @@ to find something.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['l', 'fiddle', 'feel', 'feel around', 'search']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['fiddle', 'feel around', 'search', 'feel', 'l']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -996,7 +996,7 @@ random chance of eventually finding a light source.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'l fiddle feel feel around search', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' l fiddle feel feel around search', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'fiddle feel around search feel l', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' fiddle feel around search feel l', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ git evennia pull - Pull the latest evennia code.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.utils.git_integration.git_integration.CmdGitEvennia.directory">
|
||||
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmpbbi6me6k/ecf4b5c52451b9773c5003b4d0127961d156e0e6/evennia'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGitEvennia.directory" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmpw2foz9tg/857984b26cec545b5f780fc0957fef9a31123d87/evennia'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGitEvennia.directory" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -269,7 +269,7 @@ git pull - Pull the latest code from your current branch.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.contrib.utils.git_integration.git_integration.CmdGit.directory">
|
||||
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmpbbi6me6k/ecf4b5c52451b9773c5003b4d0127961d156e0e6/evennia/game_template'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGit.directory" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmpw2foz9tg/857984b26cec545b5f780fc0957fef9a31123d87/evennia/game_template'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGit.directory" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ indentation.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.utils.eveditor.CmdEditorGroup.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = [':y', ':echo', '::', ':w', ':fd', ':s', ':h', ':UU', ':fi', ':p', ':dw', ':q!', ':S', ':=', ':::', ':>', ':u', ':I', ':!', ':<', ':i', ':A', ':dd', ':DD', ':q', ':wq', ':x', ':j', ':f', ':', ':r', ':uu']</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = [':h', ':', ':dd', ':y', ':s', ':w', ':q!', ':uu', ':f', ':::', ':dw', ':I', ':echo', ':r', ':<', ':u', ':UU', ':DD', ':j', ':S', ':x', ':!', ':fd', ':=', ':A', ':>', ':wq', ':q', ':i', '::', ':fi', ':p']</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -364,7 +364,7 @@ efficient presentation.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.utils.eveditor.CmdEditorGroup.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': ':y :echo :: :w :fd :s :h :UU :fi :p :dw :q! :S := ::: :> :u :I :! :< :i :A :dd :DD :q :wq :x :j :f : :r :uu', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :y :echo :: :w :fd :s :h :UU :fi :p :dw :q! :S := ::: :> :u :I :! :< :i :A :dd :DD :q :wq :x :j :f : :r :uu', 'tags': '', 'text': '\n Commands for the editor\n '}</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': ':h : :dd :y :s :w :q! :uu :f ::: :dw :I :echo :r :< :u :UU :DD :j :S :x :! :fd := :A :> :wq :q :i :: :fi :p', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :h : :dd :y :s :w :q! :uu :f ::: :dw :I :echo :r :< :u :UU :DD :j :S :x :! :fd := :A :> :wq :q :i :: :fi :p', 'tags': '', 'text': '\n Commands for the editor\n '}</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -931,7 +931,7 @@ single question.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.utils.evmenu.CmdYesNoQuestion.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['y', '__nomatch_command', 'abort', 'n', 'yes', 'no', 'a']</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['yes', 'no', 'y', 'n', 'abort', 'a', '__nomatch_command']</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -957,7 +957,7 @@ single question.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.utils.evmenu.CmdYesNoQuestion.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'y __nomatch_command abort n yes no a', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' y __nomatch_command abort n yes no a', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'yes no y n abort a __nomatch_command', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' yes no y n abort a __nomatch_command', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ the <strong>caller.msg()</strong> construct every time the page is updated.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.utils.evmore.CmdMore.aliases">
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['quit', 'end', 'abort', 'top', 'n', 't', 'next', 'a', 'previous', 'e', 'p', 'q']</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">aliases</code><em class="property"> = ['end', 'top', 'e', 't', 'p', 'n', 'next', 'previous', 'quit', 'a', 'q', 'abort']</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.aliases" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
|
|
@ -163,7 +163,7 @@ the <strong>caller.msg()</strong> construct every time the page is updated.</p>
|
|||
|
||||
<dl class="py attribute">
|
||||
<dt id="evennia.utils.evmore.CmdMore.search_index_entry">
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'quit end abort top n t next a previous e p q', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' quit end abort top n t next a previous e p q', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'end top e t p n next previous quit a q abort', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' end top e t p n next previous quit a q abort', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.search_index_entry" title="Permalink to this definition">¶</a></dt>
|
||||
<dd></dd></dl>
|
||||
|
||||
</dd></dl>
|
||||
|
|
|
|||
|
|
@ -294,9 +294,10 @@ or the original github wiki. You have been warned.</p>
|
|||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="Components/Components-Overview.html">Core Components</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Components/Components-Overview.html#basic-entites">Basic entites</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Typeclasses.html">Typeclasses</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Components/Components-Overview.html#base-components">Base components</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Portal-And-Server.html">Portal And Server</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Sessions.html">Sessions</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Typeclasses.html">Typeclasses</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Accounts.html">Accounts</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Objects.html">Objects</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Scripts.html">Scripts</a></li>
|
||||
|
|
@ -308,17 +309,14 @@ or the original github wiki. You have been warned.</p>
|
|||
<li class="toctree-l3"><a class="reference internal" href="Components/Prototypes.html">Spawner and Prototypes</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Help-System.html">Help System</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Permissions.html">Permissions</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Portal-And-Server.html">Portal And Server</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Locks.html">Locks</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="Components/Components-Overview.html#commands">Commands</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Commands.html">Commands</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Command-Sets.html">Command Sets</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Default-Commands.html">Default Commands</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Connection-Screen.html">Connection Screen</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Batch-Processors.html">Batch Processors</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Batch-Code-Processor.html">Batch Code Processor</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Batch-Command-Processor.html">Batch Command Processor</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Inputfuncs.html">Inputfuncs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
@ -329,10 +327,9 @@ or the original github wiki. You have been warned.</p>
|
|||
<li class="toctree-l3"><a class="reference internal" href="Components/EvMenu.html">EvMenu</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/EvMore.html">EvMore</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/EvTable.html">EvTable</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/FuncParser.html">The Inline Function Parser</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/FuncParser.html">FuncParser inline text parsing</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/MonitorHandler.html">MonitorHandler</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/TickerHandler.html">TickerHandler</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Locks.html">Locks</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="Components/Signals.html">Signals</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
|||
Binary file not shown.
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue