Updated HTML docs

This commit is contained in:
Griatch 2020-07-14 00:21:00 +02:00
parent a551188691
commit 781788f2e5
2063 changed files with 215958 additions and 250783 deletions

View file

@ -0,0 +1,212 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accounts &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Accounts</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="accounts">
<h1>Accounts<a class="headerlink" href="#accounts" title="Permalink to this headline"></a></h1>
<p>All <em>users</em> (real people) that starts a game <a class="reference internal" href="Sessions.html"><span class="doc">Session</span></a> on Evennia are doing so through an
object called <em>Account</em>. The Account object has no in-game representation, it represents a unique
game account. 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">Object</span></a>
(normally a <a class="reference external" href="Components/Objects.html#Character">Character</a>).</p>
<p>Exactly how many Sessions can interact with an Account and its Puppets at once is determined by
Evennias <a class="reference external" href="Components/Sessions.html#Multisession-mode">MULTISESSION_MODE</a> setting.</p>
<p>Apart from storing login information and other account-specific data, the Account object is what is
chatting on <a class="reference internal" href="Communications.html"><span class="doc">Channels</span></a>. It is also a good place to store <a class="reference internal" href="Locks.html"><span class="doc">Permissions</span></a> to be
consistent between different in-game characters as well as configuration options. The Account
object also has its own <a class="reference internal" href="Command-Sets.html"><span class="doc">CmdSet</span></a>, the <code class="docutils literal notranslate"><span class="pre">AccountCmdSet</span></code>.</p>
<p>Logged into default evennia, you can use the <code class="docutils literal notranslate"><span class="pre">ooc</span></code> command to leave your current
<a class="reference internal" href="Objects.html"><span class="doc">character</span></a> and go into OOC mode. You are quite limited in this mode, basically it works
like a simple chat program. It acts as a staging area for switching between Characters (if your
game supports that) or as a safety mode if your Character gets deleted. Use <code class="docutils literal notranslate"><span class="pre">ic</span></code> to attempt to
(re)puppet a Character.</p>
<p>Note that the Account object can have, and often does have, a different set of
<a class="reference external" href="Components/Locks.html#Permissions">Permissions</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 cant 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>
<div class="section" id="how-to-create-your-own-account-types">
<h2>How to create your own Account types<a class="headerlink" href="#how-to-create-your-own-account-types" title="Permalink to this headline"></a></h2>
<p>You will usually not want more than one Account typeclass for all new accounts (but you could in
principle create a system that changes an accounts typeclass dynamically).</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>Heres an example of modifying the default Account class in code:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># in mygame/typeclasses/accounts.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultAccount</span>
<span class="k">class</span> <span class="nc">Account</span><span class="p">(</span><span class="n">DefaultAccount</span><span class="p">):</span> <span class="c1"># [...]</span>
<span class="n">at_account_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span> <span class="s2">&quot;this is called only once, when account is first created&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">real_name</span> <span class="o">=</span> <span class="bp">None</span> <span class="c1"># this is set later self.db.real_address = None # &quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">config_1</span> <span class="o">=</span> <span class="bp">True</span> <span class="c1"># default config self.db.config_2 = False # &quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">config_3</span> <span class="o">=</span> <span class="mi">1</span> <span class="c1"># &quot;</span>
<span class="c1"># ... whatever else our game needs to know ``` Reload the server with `reload`. </span>
</pre></div>
</td></tr></table></div>
<p>… However, if you use <code class="docutils literal notranslate"><span class="pre">examine</span> <span class="pre">*self</span></code> (the asterisk makes you examine your Account object rather
than your Character), you wont see your new Attributes yet. This is because <code class="docutils literal notranslate"><span class="pre">at_account_creation</span></code>
is only called the very <em>first</em> time the Account is called and your Account object already exists
(any new Accounts that connect will see them though). To update yourself you need to make sure to
re-fire the hook on all the Accounts you have already created. Here is an example of how to do this
using <code class="docutils literal notranslate"><span class="pre">py</span></code>:</p>
<p><code class="docutils literal notranslate"><span class="pre">py</span> <span class="pre">[account.at_account_creation()</span> <span class="pre">for</span> <span class="pre">account</span> <span class="pre">in</span> <span class="pre">evennia.managers.accounts.all()]</span></code></p>
<p>You should now see the Attributes on yourself.</p>
<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>
</div>
<div class="section" id="properties-on-accounts">
<h2>Properties on Accounts<a class="headerlink" href="#properties-on-accounts" title="Permalink to this headline"></a></h2>
<p>Beyond those properties assigned to all typeclassed objects (see <a class="reference internal" href="Typeclasses.html"><span class="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>
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code> - an alias for <code class="docutils literal notranslate"><span class="pre">character</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">name</span></code> - an alias for <code class="docutils literal notranslate"><span class="pre">user.username</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">sessions</span></code> - an instance of
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.objects.objects#objectsessionhandler">ObjectSessionHandler</a>
managing all connected Sessions (physical connections) this object listens to (Note: In older
versions of Evennia, this was a list). The so-called <code class="docutils literal notranslate"><span class="pre">session-id</span></code> (used in many places) is found
as
a property <code class="docutils literal notranslate"><span class="pre">sessid</span></code> on each Session instance.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">is_superuser</span></code> (bool: True/False) - if this account is a superuser.</p></li>
</ul>
<p>Special handlers:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset</span></code> - This holds all the current <a class="reference internal" href="Commands.html"><span class="doc">Commands</span></a> of this Account. By default these are
the commands found in the cmdset defined by <code class="docutils literal notranslate"><span class="pre">settings.CMDSET_ACCOUNT</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">nicks</span></code> - This stores and handles <a class="reference internal" href="Nicks.html"><span class="doc">Nicks</span></a>, in the same way as nicks it works on Objects.
For Accounts, nicks are primarily used to store custom aliases for
<a class="reference external" href="Components/Communications.html#Channels">Channels</a>.</p></li>
</ul>
<p>Selection of special methods (see <code class="docutils literal notranslate"><span class="pre">evennia.DefaultAccount</span></code> for details):</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">get_puppet</span></code> - get a currently puppeted object connected to the Account and a given session id, if
any.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">puppet_object</span></code> - connect a session to a puppetable Object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">unpuppet_object</span></code> - disconnect a session from a puppetable Object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">msg</span></code> - send text to the Account</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">execute_cmd</span></code> - runs a command as if this Account did it.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">search</span></code> - search for Accounts.</p></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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-create-your-own-account-types">How to create your own Account types</a></li>
<li><a class="reference internal" href="#properties-on-accounts">Properties on Accounts</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Accounts.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Accounts.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Accounts</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,541 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Attributes &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Attributes</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="attributes">
<h1>Attributes<a class="headerlink" href="#attributes" title="Permalink to this headline"></a></h1>
<p>When performing actions in Evennia it is often important that you store data for later. If you write
a menu system, you have to keep track of the current location in the menu tree so that the player
can give correct subsequent commands. If you are writing a combat system, you might have a
combattants next roll get easier dependent on if their opponent failed. Your characters will
probably need to store roleplaying-attributes like strength and agility. And so on.</p>
<p><a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclassed</span></a> game entities (<a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a>,
<a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a> and <a class="reference internal" href="Communications.html"><span class="doc">Channels</span></a>) always have <em>Attributes</em> associated with them.
Attributes are used to store any type of data on such entities. This is different from storing
data in properties already defined on entities (such as <code class="docutils literal notranslate"><span class="pre">key</span></code> or <code class="docutils literal notranslate"><span class="pre">location</span></code>) - these have very
specific names and require very specific types of data (for example you couldnt assign a python
<em>list</em> to the <code class="docutils literal notranslate"><span class="pre">key</span></code> property no matter how hard you tried). <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> come into play when you
want to assign arbitrary data to arbitrary names.</p>
<p><strong>Attributes are <em>not</em> secure by default and any player may be able to change them unless you
<a class="reference external" href="Components/Attributes.html#locking-and-checking-attributes">prevent this behavior</a>.</strong></p>
<div class="section" id="the-db-and-ndb-shortcuts">
<h2>The .db and .ndb shortcuts<a class="headerlink" href="#the-db-and-ndb-shortcuts" title="Permalink to this headline"></a></h2>
<p>To save persistent data on a Typeclassed object you normally use the <code class="docutils literal notranslate"><span class="pre">db</span></code> (DataBase) operator. Lets
try to save some data to a <em>Rose</em> (an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a>):</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># saving</span>
<span class="n">rose</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">has_thorns</span> <span class="o">=</span> <span class="bp">True</span>
<span class="c1"># getting it back</span>
<span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">has_thorns</span>
</pre></div>
</td></tr></table></div>
<p>This looks like any normal Python assignment, but that <code class="docutils literal notranslate"><span class="pre">db</span></code> makes sure that an <em>Attribute</em> is
created behind the scenes and is stored in the database. Your rose will continue to have thorns
throughout the life of the server now, until you deliberately remove them.</p>
<p>To be sure to save <strong>non-persistently</strong>, i.e. to make sure NOT to create a database entry, you use
<code class="docutils literal notranslate"><span class="pre">ndb</span></code> (NonDataBase). It works in the same way:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># saving</span>
<span class="n">rose</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">has_thorns</span> <span class="o">=</span> <span class="bp">True</span>
<span class="c1"># getting it back</span>
<span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">has_thorns</span>
</pre></div>
</td></tr></table></div>
<p>Technically, <code class="docutils literal notranslate"><span class="pre">ndb</span></code> has nothing to do with <code class="docutils literal notranslate"><span class="pre">Attributes</span></code>, despite how similar they look. No
<code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object is created behind the scenes when using <code class="docutils literal notranslate"><span class="pre">ndb</span></code>. In fact the database is not
invoked at all since we are not interested in persistence. There is however an important reason to
use <code class="docutils literal notranslate"><span class="pre">ndb</span></code> to store data rather than to just store variables direct on entities - <code class="docutils literal notranslate"><span class="pre">ndb</span></code>-stored data
is tracked by the server and will not be purged in various cache-cleanup operations Evennia may do
while it runs. Data stored on <code class="docutils literal notranslate"><span class="pre">ndb</span></code> (as well as <code class="docutils literal notranslate"><span class="pre">db</span></code>) will also be easily listed by example the
<code class="docutils literal notranslate"><span class="pre">&#64;examine</span></code> command.</p>
<p>You can also <code class="docutils literal notranslate"><span class="pre">del</span></code> properties on <code class="docutils literal notranslate"><span class="pre">db</span></code> and <code class="docutils literal notranslate"><span class="pre">ndb</span></code> as normal. This will for example delete an
<code class="docutils literal notranslate"><span class="pre">Attribute</span></code>:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">del</span> <span class="n">rose</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">has_thorns</span>
</pre></div>
</td></tr></table></div>
<p>Both <code class="docutils literal notranslate"><span class="pre">db</span></code> and <code class="docutils literal notranslate"><span class="pre">ndb</span></code> defaults to offering an <code class="docutils literal notranslate"><span class="pre">all</span></code> property on themselves. This returns all
associated attributes or non-persistent properties.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">list_of_all_rose_attributes</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">all</span>
<span class="n">list_of_all_rose_ndb_attrs</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">all</span>
</pre></div>
</td></tr></table></div>
<p>If you use <code class="docutils literal notranslate"><span class="pre">all</span></code> as the name of an attribute, this will be used instead. Later deleting your custom
<code class="docutils literal notranslate"><span class="pre">all</span></code> will return the default behaviour.</p>
</div>
<div class="section" id="the-attributehandler">
<h2>The AttributeHandler<a class="headerlink" href="#the-attributehandler" title="Permalink to this headline"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">.db</span></code> and <code class="docutils literal notranslate"><span class="pre">.ndb</span></code> properties are very convenient but if you dont know the name of the Attribute
beforehand they cannot be used. Behind the scenes <code class="docutils literal notranslate"><span class="pre">.db</span></code> actually accesses the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code>
which sits on typeclassed entities as the <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> property. <code class="docutils literal notranslate"><span class="pre">.ndb</span></code> does the same for the
<code class="docutils literal notranslate"><span class="pre">.nattributes</span></code> property.</p>
<p>The handlers have normal access methods that allow you to manage and retrieve <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> and
<code class="docutils literal notranslate"><span class="pre">NAttributes</span></code>:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">has('attrname')</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>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">get(...)</span></code> - this retrieves the given Attribute. Normally the <code class="docutils literal notranslate"><span class="pre">value</span></code> property of the Attribute is
returned, but the method takes keywords for returning the Attribute object itself. By supplying an
<code class="docutils literal notranslate"><span class="pre">accessing_object</span></code> to the call one can also make sure to check permissions before modifying
anything.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">add(...)</span></code> - this adds a new Attribute to the object. An optional <a class="reference internal" href="Locks.html"><span class="doc">lockstring</span></a> can be
supplied here to restrict future access and also the call itself may be checked against locks.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">remove(...)</span></code> - Remove the given Attribute. This can optionally be made to check for permission
before performing the deletion. - <code class="docutils literal notranslate"><span class="pre">clear(...)</span></code> - removes all Attributes from object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">all(...)</span></code> - returns all Attributes (of the given category) attached to this object.</p></li>
</ul>
<p>See <a class="reference external" href="Components/Attributes.html#locking-and-checking-attributes">this section</a> for more about locking down Attribute
access and editing. The <code class="docutils literal notranslate"><span class="pre">Nattribute</span></code> offers no concept of access control.</p>
<p>Some examples:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="kn">import</span> <span class="nn">evennia</span>
<span class="n">obj</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;MyObject&quot;</span><span class="p">)</span>
<span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;test&quot;</span><span class="p">,</span> <span class="s2">&quot;testvalue&quot;</span><span class="p">)</span>
<span class="k">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test</span><span class="p">)</span> <span class="c1"># prints &quot;testvalue&quot;</span>
<span class="k">print</span><span class="p">(</span><span class="n">obj</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">&quot;test&quot;</span><span class="p">))</span> <span class="c1"># &quot;</span>
<span class="k">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">all</span><span class="p">())</span> <span class="c1"># prints [&lt;AttributeObject&gt;]</span>
<span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">&quot;test&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="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 Attribute 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 external" href="Components/Attributes.html#What_types_of_data_can_I_save_in_an_Attribute">this section</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">Nicks</span></a> is an example of using
Attributes
in this way). To modify this property you need to use the <a class="reference external" href="Components/Attributes.html#The_Attribute_Handler">Attribute
Handler</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">Nicks</span></a> use it). It is only
accessible via the <a class="reference external" href="Components/Attributes.html#The_Attribute_Handler">Attribute Handler</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">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 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>
</div>
<div class="section" id="persistent-vs-non-persistent">
<h2>Persistent vs non-persistent<a class="headerlink" href="#persistent-vs-non-persistent" title="Permalink to this headline"></a></h2>
<p>So <em>persistent</em> data means that your data will survive a server reboot, whereas with
<em>non-persistent</em> data it will not …</p>
<p>… So why would you ever want to use non-persistent data? The answer is, you dont have to. Most of
the time you really want to save as much as you possibly can. Non-persistent data is potentially
useful in a few situations though.</p>
<ul class="simple">
<li><p>You are worried about database performance. Since Evennia caches Attributes very aggressively,
this is not an issue unless you are reading <em>and</em> writing to your Attribute very often (like many
times per second). Reading from an already cached Attribute is as fast as reading any Python
property. But even then this is not likely something to worry about: Apart from Evennias own
caching, modern database systems themselves also cache data very efficiently for speed. Our
default
database even runs completely in RAM if possible, alleviating much of the need to write to disk
during heavy loads.</p></li>
<li><p>A more valid reason for using non-persistent data is if you <em>want</em> to lose your state when logging
off. Maybe you are storing throw-away data that are re-initialized at server startup. Maybe you
are implementing some caching of your own. Or maybe you are testing a buggy <a class="reference internal" href="Scripts.html"><span class="doc">Script</span></a> that
does potentially harmful stuff to your character object. With non-persistent storage you can be
sure
that whatever is messed up, its nothing a server reboot cant clear up.</p></li>
<li><p>NAttributes have no restrictions at all on what they can store (see next section), since they
dont need to worry about being saved to the database - they work very well for temporary storage.</p></li>
<li><p>You want to implement a fully or partly <em>non-persistent world</em>. Who are we to argue with your
grand vision!</p></li>
</ul>
</div>
<div class="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>
<blockquote>
<div><p>None of the following affects NAttributes, which does not invoke the database at all. There are no
restrictions to what can be stored in a NAttribute.</p>
</div></blockquote>
<p>The database doesnt know anything about Python objects, so Evennia must <em>serialize</em> Attribute
values into a string representation in order to store it to the database. This is done using the
<code class="docutils literal notranslate"><span class="pre">pickle</span></code> module of Python (the only exception is if you use the <code class="docutils literal notranslate"><span class="pre">strattr</span></code> keyword of the
AttributeHandler to save to the <code class="docutils literal notranslate"><span class="pre">strvalue</span></code> field of the Attribute. In that case you can only save
<em>strings</em> which will not be pickled).</p>
<p>Its important to note that when you access the data in an Attribute you are <em>always</em> de-serializing
it from the database representation every time. This is because we allow for storing
database-entities in Attributes too. If we cached it as its Python form, we might end up with
situations where the database entity was deleted since we last accessed the Attribute.
De-serializing data with a database-entity in it means querying the database for that object and
making sure it still exists (otherwise it will be set to <code class="docutils literal notranslate"><span class="pre">None</span></code>). Performance-wise this is usually
not a big deal. But if you are accessing the Attribute as part of some big loop or doing a large
amount of reads/writes you should first extract it to a temporary variable, operate on <em>that</em> and
then save the result back to the Attribute. If you are storing a more complex structure like a
<code class="docutils literal notranslate"><span class="pre">dict</span></code> or a <code class="docutils literal notranslate"><span class="pre">list</span></code> you should make sure to “disconnect” it from the database before looping over it,
as mentioned in the <a class="reference external" href="Components/Attributes.html#retrieving-mutable-objects">Retrieving Mutable Objects</a> section
below.</p>
<div class="section" id="storing-single-objects">
<h3>Storing single objects<a class="headerlink" href="#storing-single-objects" title="Permalink to this headline"></a></h3>
<p>With a single object, we mean anything that is <em>not iterable</em>, like numbers, strings or custom class
instances without the <code class="docutils literal notranslate"><span class="pre">__iter__</span></code> method.</p>
<ul class="simple">
<li><p>You can generally store any non-iterable Python entity that can be
<a class="reference external" href="http://docs.python.org/library/pickle.html">pickled</a>.</p></li>
<li><p>Single database objects/typeclasses can be stored as any other in the Attribute. These can
normally <em>not</em> be pickled, but Evennia will behind the scenes convert them to an internal
representation using their classname, database-id and creation-date with a microsecond precision,
guaranteeing you get the same object back when you access the Attribute later.</p></li>
<li><p>If you <em>hide</em> a database object inside a non-iterable custom class (like stored as a variable
inside it), Evennia will not know its there and wont convert it safely. Storing classes with
such hidden database objects is <em>not</em> supported and will lead to errors!</p></li>
</ul>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># Examples of valid single-value attribute data:</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test1</span> <span class="o">=</span> <span class="mi">23</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test1</span> <span class="o">=</span> <span class="bp">False</span>
<span class="c1"># a database object (will be stored as an internal representation)</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test2</span> <span class="o">=</span> <span class="n">myobj</span>
<span class="c1"># example of an invalid, &quot;hidden&quot; dbobject</span>
<span class="k">class</span> <span class="nc">Invalid</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">dbobj</span><span class="p">):</span>
<span class="c1"># no way for Evennia to know this is a dbobj</span>
<span class="bp">self</span><span class="o">.</span><span class="n">dbobj</span> <span class="o">=</span> <span class="n">dbobj</span>
<span class="n">invalid</span> <span class="o">=</span> <span class="n">Invalid</span><span class="p">(</span><span class="n">myobj</span><span class="p">)</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">invalid</span> <span class="o">=</span> <span class="n">invalid</span> <span class="c1"># will cause error!</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="storing-multiple-objects">
<h3>Storing multiple objects<a class="headerlink" href="#storing-multiple-objects" title="Permalink to this headline"></a></h3>
<p>This means storing objects in a collection of some kind and are examples of <em>iterables</em>, pickle-able
entities you can loop over in a for-loop. Attribute-saving supports the following iterables:</p>
<ul class="simple">
<li><p><a class="reference external" href="https://docs.python.org/2/library/functions.html#tuple">Tuples</a>, like <code class="docutils literal notranslate"><span class="pre">(1,2,&quot;test&quot;,</span> <span class="pre">&lt;dbobj&gt;)</span></code>.</p></li>
<li><p><a class="reference external" href="https://docs.python.org/2/tutorial/datastructures.html#more-on-lists">Lists</a>, like <code class="docutils literal notranslate"><span class="pre">[1,2,&quot;test&quot;,</span> <span class="pre">&lt;dbobj&gt;]</span></code>.</p></li>
<li><p><a class="reference external" href="https://docs.python.org/2/tutorial/datastructures.html#dictionaries">Dicts</a>, like <code class="docutils literal notranslate"><span class="pre">{1:2,</span> <span class="pre">&quot;test&quot;:&lt;dbobj&gt;]</span></code>.</p></li>
<li><p><a class="reference external" href="https://docs.python.org/2/tutorial/datastructures.html#sets">Sets</a>, like <code class="docutils literal notranslate"><span class="pre">{1,2,&quot;test&quot;,&lt;dbobj&gt;}</span></code>.</p></li>
<li></li>
</ul>
<p><a class="reference external" href="https://docs.python.org/2/library/collections.html#collections.OrderedDict">collections.OrderedDict</a>,
like <code class="docutils literal notranslate"><span class="pre">OrderedDict((1,2),</span> <span class="pre">(&quot;test&quot;,</span> <span class="pre">&lt;dbobj&gt;))</span></code>.</p>
<ul class="simple">
<li><p><a class="reference external" href="https://docs.python.org/2/library/collections.html#collections.deque">collections.Deque</a>, like
<code class="docutils literal notranslate"><span class="pre">deque((1,2,&quot;test&quot;,&lt;dbobj&gt;))</span></code>.</p></li>
<li><p><em>Nestings</em> of any combinations of the above, like lists in dicts or an OrderedDict of tuples, each
containing dicts, etc.</p></li>
<li><p>All other iterables (i.e. entities with the <code class="docutils literal notranslate"><span class="pre">__iter__</span></code> method) will be converted to a <em>list</em>.
Since you can use any combination of the above iterables, this is generally not much of a
limitation.</p></li>
</ul>
<p>Any entity listed in the <a class="reference external" href="Components/Attributes.html#Storing-Single-Objects">Single object</a> section above can be
stored in the iterable.</p>
<blockquote>
<div><p>As mentioned in the previous section, database entities (aka typeclasses) are not possible to
pickle. So when storing an iterable, Evennia must recursively traverse the iterable <em>and all its
nested sub-iterables</em> in order to find eventual database objects to convert. This is a very fast
process but for efficiency you may want to avoid too deeply nested structures if you can.</p>
</div></blockquote>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># examples of valid iterables to store</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test3</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj1</span><span class="p">,</span> <span class="mi">45</span><span class="p">,</span> <span class="n">obj2</span><span class="p">,</span> <span class="mi">67</span><span class="p">]</span>
<span class="c1"># a dictionary</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test4</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;str&#39;</span><span class="p">:</span><span class="mi">34</span><span class="p">,</span> <span class="s1">&#39;dex&#39;</span><span class="p">:</span><span class="mi">56</span><span class="p">,</span> <span class="s1">&#39;agi&#39;</span><span class="p">:</span><span class="mi">22</span><span class="p">,</span> <span class="s1">&#39;int&#39;</span><span class="p">:</span><span class="mi">77</span><span class="p">}</span>
<span class="c1"># a mixed dictionary/list</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test5</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;members&#39;</span><span class="p">:</span> <span class="p">[</span><span class="n">obj1</span><span class="p">,</span><span class="n">obj2</span><span class="p">,</span><span class="n">obj3</span><span class="p">],</span> <span class="s1">&#39;enemies&#39;</span><span class="p">:[</span><span class="n">obj4</span><span class="p">,</span><span class="n">obj5</span><span class="p">]}</span>
<span class="c1"># a tuple with a list in it</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test6</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">8</span><span class="p">,</span> <span class="p">[</span><span class="s2">&quot;test&quot;</span><span class="p">,</span> <span class="s2">&quot;test2&quot;</span><span class="p">],</span> <span class="mi">9</span><span class="p">)</span>
<span class="c1"># a set</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test7</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">,</span><span class="mi">5</span><span class="p">])</span>
<span class="c1"># in-situ manipulation</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test8</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,{</span><span class="s2">&quot;test&quot;</span><span class="p">:</span><span class="mi">1</span><span class="p">}]</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test8</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test8</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s2">&quot;test&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span>
<span class="c1"># test8 is now [4,2,{&quot;test&quot;:5}]</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="retrieving-mutable-objects">
<h3>Retrieving Mutable objects<a class="headerlink" href="#retrieving-mutable-objects" title="Permalink to this headline"></a></h3>
<p>A side effect of the way Evennia stores Attributes is that <em>mutable</em> iterables (iterables that can
be modified in-place after they were created, which is everything except tuples) are handled by
custom objects called <code class="docutils literal notranslate"><span class="pre">_SaverList</span></code>, <code class="docutils literal notranslate"><span class="pre">_SaverDict</span></code> etc. These <code class="docutils literal notranslate"><span class="pre">_Saver...</span></code> classes behave just like the
normal variant except that they are aware of the database and saves to it whenever new data gets
assigned to them. This is what allows you to do things like <code class="docutils literal notranslate"><span class="pre">self.db.mylist[7]</span> <span class="pre">=</span> <span class="pre">val</span></code> and be sure
that the new version of list is saved. Without this you would have to load the list into a temporary
variable, change it and then re-assign it to the Attribute in order for it to save.</p>
<p>There is however an important thing to remember. If you retrieve your mutable iterable into another
variable, e.g. <code class="docutils literal notranslate"><span class="pre">mylist2</span> <span class="pre">=</span> <span class="pre">obj.db.mylist</span></code>, your new variable (<code class="docutils literal notranslate"><span class="pre">mylist2</span></code>) will <em>still</em> be a
<code class="docutils literal notranslate"><span class="pre">_SaverList</span></code>. This means it will continue to save itself to the database whenever it is updated!</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
<span class="n">mylist</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span>
<span class="n">mylist</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># this will also update database</span>
<span class="k">print</span><span class="p">(</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># this is now [1,2,3,5]</span>
<span class="k">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># this is also [1,2,3,5]</span>
</pre></div>
</td></tr></table></div>
<p>To “disconnect” your extracted mutable variable from the database you simply need to convert the
<code class="docutils literal notranslate"><span class="pre">_Saver...</span></code> iterable to a normal Python structure. So to convert a <code class="docutils literal notranslate"><span class="pre">_SaverList</span></code>, you use the
<code class="docutils literal notranslate"><span class="pre">list()</span></code> function, for a <code class="docutils literal notranslate"><span class="pre">_SaverDict</span></code> you use <code class="docutils literal notranslate"><span class="pre">dict()</span></code> and so on.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">]</span>
<span class="n">mylist</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># convert to normal list</span>
<span class="n">mylist</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span>
<span class="k">print</span><span class="p">(</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># this is now [1,2,3,5]</span>
<span class="k">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># this is still [1,2,3,4]</span>
</pre></div>
</td></tr></table></div>
<p>A further problem comes with <em>nested mutables</em>, like a dict containing lists of dicts or something
like that. Each of these nested mutables would be <code class="docutils literal notranslate"><span class="pre">_Saver*</span></code> structures connected to the database and
disconnecting the outermost one of them would not disconnect those nested within. To make really
sure you disonnect a nested structure entirely from the database, Evennia provides a special
function <code class="docutils literal notranslate"><span class="pre">evennia.utils.dbserialize.deserialize</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.dbserialize</span> <span class="k">import</span> <span class="n">deserialize</span>
<span class="n">decoupled_mutables</span> <span class="o">=</span> <span class="n">deserialize</span><span class="p">(</span><span class="n">nested_mutables</span><span class="p">)</span>
</pre></div>
</div>
<p>The result of this operation will be a structure only consisting of normal Python mutables (<code class="docutils literal notranslate"><span class="pre">list</span></code>
instead of <code class="docutils literal notranslate"><span class="pre">_SaverList</span></code> and so on).</p>
<p>Remember, this is only valid for <em>mutable</em> iterables.
<a class="reference external" href="http://en.wikipedia.org/wiki/Immutable">Immutable</a> objects (strings, numbers, tuples etc) are
already disconnected from the database from the onset.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mytup</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="mi">2</span><span class="p">,[</span><span class="mi">3</span><span class="p">,</span><span class="mi">4</span><span class="p">])</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mytup</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># this fails since tuples are immutable</span>
<span class="c1"># this works but will NOT update database since outermost is a tuple</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mytup</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span>
<span class="k">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mytup</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">1</span><span class="p">])</span> <span class="c1"># this still returns 4, not 5</span>
<span class="n">mytup1</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mytup</span> <span class="c1"># mytup1 is already disconnected from database since outermost</span>
<span class="c1"># iterable is a tuple, so we can edit the internal list as we want</span>
<span class="c1"># without affecting the database.</span>
</pre></div>
</td></tr></table></div>
<blockquote>
<div><p>Attributes will fetch data fresh from the database whenever you read them, so
if you are performing big operations on a mutable Attribute property (such as looping over a list
or dict) you should make sure to “disconnect” the Attributes value first and operate on this
rather than on the Attribute. You can gain dramatic speed improvements to big loops this
way.</p>
</div></blockquote>
</div>
</div>
<div class="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>
<p>Attributes are normally not locked down by default, but you can easily change that for individual
Attributes (like those that may be game-sensitive in games with user-level building).</p>
<p>First you need to set a <em>lock string</em> on your Attribute. Lock strings are specified <a class="reference internal" href="Locks.html"><span class="doc">Locks</span></a>.
The relevant lock types are</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">attrread</span></code> - limits who may read the value of the Attribute</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attredit</span></code> - limits who may set/change this Attribute</p></li>
</ul>
<p>You cannot use the <code class="docutils literal notranslate"><span class="pre">db</span></code> handler to modify Attribute object (such as setting a lock on them) - The
<code class="docutils literal notranslate"><span class="pre">db</span></code> handler will return the Attributes <em>value</em>, not the Attribute object itself. Instead you use
the AttributeHandler and set it to return the object instead of the value:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">lockstring</span> <span class="o">=</span> <span class="s2">&quot;attread:all();attredit:perm(Admins)&quot;</span>
<span class="n">obj</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">&quot;myattr&quot;</span><span class="p">,</span> <span class="n">return_obj</span><span class="o">=</span><span class="bp">True</span><span class="p">)</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="n">lockstring</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Note the <code class="docutils literal notranslate"><span class="pre">return_obj</span></code> keyword which makes sure to return the <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object so its LockHandler
could be accessed.</p>
<p>A lock is no good if nothing checks it and by default Evennia does not check locks on Attributes.
You have to add a check to your commands/code wherever it fits (such as before setting an
Attribute).</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># in some command code where we want to limit</span>
<span class="c1"># setting of a given attribute name on an object</span>
<span class="n">attr</span> <span class="o">=</span> <span class="n">obj</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="n">attrname</span><span class="p">,</span>
<span class="n">return_obj</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span>
<span class="n">accessing_obj</span><span class="o">=</span><span class="n">caller</span><span class="p">,</span>
<span class="n">default</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
<span class="n">default_access</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You cannot edit that Attribute!&quot;</span><span class="p">)</span>
<span class="k">return</span>
<span class="c1"># edit the Attribute here</span>
</pre></div>
</td></tr></table></div>
<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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#the-db-and-ndb-shortcuts">The .db and .ndb shortcuts</a></li>
<li><a class="reference internal" href="#the-attributehandler">The AttributeHandler</a></li>
<li><a class="reference internal" href="#properties-of-attributes">Properties of Attributes</a></li>
<li><a class="reference internal" href="#persistent-vs-non-persistent">Persistent vs non-persistent</a></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="#locking-and-checking-attributes">Locking and checking Attributes</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Attributes.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Attributes.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Attributes</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,398 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Batch Code Processor &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Code Processor</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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">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>
<div class="section" id="basic-usage">
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline"></a></h2>
<p>The batch-code processor is a superuser-only function, invoked by</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nd">@batchcode</span> <span class="n">path</span><span class="o">.</span><span class="n">to</span><span class="o">.</span><span class="n">batchcodefile</span>
</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 shouldnt 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-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nd">@batchcode</span> <span class="n">batch_code</span>
</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>
</div>
<div class="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">&#64;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>
</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 processors <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>
<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 its 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 cant exchange data between code blocks, so editing a header-
variable in one code block wont 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>
</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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1">#</span>
<span class="c1"># This is an example batch-code build file for Evennia. </span>
<span class="c1">#</span>
<span class="c1">#HEADER</span>
<span class="c1"># This will be included in all other #CODE blocks</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_object</span><span class="p">,</span> <span class="n">search_object</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>
<span class="n">limbo</span> <span class="o">=</span> <span class="n">search_object</span><span class="p">(</span><span class="s1">&#39;Limbo&#39;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="c1">#CODE </span>
<span class="n">red_button</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">red_button</span><span class="o">.</span><span class="n">RedButton</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;Red button&quot;</span><span class="p">,</span>
<span class="n">location</span><span class="o">=</span><span class="n">limbo</span><span class="p">,</span> <span class="n">aliases</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;button&quot;</span><span class="p">])</span>
<span class="c1"># caller points to the one running the script</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;A red button was created.&quot;</span><span class="p">)</span>
<span class="c1"># importing more code from another batch-code file</span>
<span class="c1">#INSERT batch_code_insert</span>
<span class="c1">#CODE</span>
<span class="n">table</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">Object</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;Blue Table&quot;</span><span class="p">,</span> <span class="n">location</span><span class="o">=</span><span class="n">limbo</span><span class="p">)</span>
<span class="n">chair</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">Object</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;Blue Chair&quot;</span><span class="p">,</span> <span class="n">location</span><span class="o">=</span><span class="n">limbo</span><span class="p">)</span>
<span class="n">string</span> <span class="o">=</span> <span class="s2">&quot;A </span><span class="si">%s</span><span class="s2"> and </span><span class="si">%s</span><span class="s2"> were created.&quot;</span>
<span class="k">if</span> <span class="n">DEBUG</span><span class="p">:</span>
<span class="n">table</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="n">chair</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="n">string</span> <span class="o">+=</span> <span class="s2">&quot; Since debug was active, &quot;</span> \
<span class="s2">&quot;they were deleted again.&quot;</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">string</span> <span class="o">%</span> <span class="p">(</span><span class="n">table</span><span class="p">,</span> <span class="n">chair</span><span class="p">))</span>
</pre></div>
</td></tr></table></div>
<p>This uses Evennias Python API to create three objects in sequence.</p>
</div>
<div class="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-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nd">@batchcode</span><span class="o">/</span><span class="n">debug</span> <span class="n">tutorial_examples</span><span class="o">.</span><span class="n">example_batch_code</span>
</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 wont 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>
</div>
<div class="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">&#64;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-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nd">@batchcode</span><span class="o">/</span><span class="n">interactive</span> <span class="n">tutorial_examples</span><span class="o">.</span><span class="n">batch_code</span>
</pre></div>
</div>
<p>You should see the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mi">01</span><span class="o">/</span><span class="mi">02</span><span class="p">:</span> <span class="n">red_button</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">red_button</span><span class="o">.</span><span class="n">RedButton</span><span class="p">,</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span> <span class="p">(</span><span class="n">hh</span> <span class="k">for</span> <span class="n">help</span><span class="p">)</span>
</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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11</pre></div></td><td class="code"><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>
<span class="n">limbo</span> <span class="o">=</span> <span class="n">search</span><span class="o">.</span><span class="n">objects</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s1">&#39;Limbo&#39;</span><span class="p">,</span> <span class="n">global_search</span><span class="o">=</span><span class="bp">True</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">red_button</span> <span class="o">=</span> <span class="n">create</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">red_button</span><span class="o">.</span><span class="n">RedButton</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;Red button&quot;</span><span class="p">,</span>
<span class="n">location</span><span class="o">=</span><span class="n">limbo</span><span class="p">,</span> <span class="n">aliases</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;button&quot;</span><span class="p">])</span>
<span class="c1"># caller points to the one running the script</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;A red button was created.&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></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
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 (dont 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>
</div>
<div class="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>
<div class="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
processor by default. The code-processor runs <strong>without any Evennia security checks</strong> and allows
full access to Python. If an untrusted party could run the code-processor they could execute
arbitrary python code on your machine, which is potentially a very dangerous thing. If you want to
allow other users to access the batch-code processor you should make sure to run Evennia as a
separate and very limited-access user on your machine (i.e. in a jail). By comparison, the batch-
command processor is much safer since the user running it is still inside the game and cant
really do anything outside what the game commands allow them to.</p>
</div>
<div class="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 wont 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>
<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">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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12</pre></div></td><td class="code"><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="bp">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>
<span class="c1">#CODE </span>
<span class="c1"># create and store the castle</span>
<span class="n">castle</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="s2">&quot;rooms.Room&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;Castle&quot;</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="p">[</span><span class="s2">&quot;castle&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">castle</span>
<span class="c1">#CODE </span>
<span class="c1"># in another node we want to access the castle</span>
<span class="n">castle</span> <span class="o">=</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="n">get</span><span class="p">(</span><span class="s2">&quot;castle&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></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> doesnt 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
wed be wiping the dict every block!</p>
</div>
<div class="section" id="don-t-treat-a-batchcode-file-like-any-python-file">
<h3>Dont treat a batchcode file like any Python file<a class="headerlink" href="#don-t-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>
</div>
<div class="section" id="don-t-let-code-rely-on-the-batch-file-s-real-file-path">
<h3>Dont let code rely on the batch-files real file path<a class="headerlink" href="#don-t-let-code-rely-on-the-batch-file-s-real-file-path" title="Permalink to this headline"></a></h3>
<p>When you import things into your batchcode file, dont 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 files “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>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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>
<li><a class="reference internal" href="#limitations-and-caveats">Limitations and Caveats</a><ul>
<li><a class="reference internal" href="#safety">Safety</a></li>
<li><a class="reference internal" href="#no-communication-between-code-blocks">No communication between code blocks</a></li>
<li><a class="reference internal" href="#don-t-treat-a-batchcode-file-like-any-python-file">Dont treat a batchcode file like any Python file</a></li>
<li><a class="reference internal" href="#don-t-let-code-rely-on-the-batch-file-s-real-file-path">Dont let code rely on the batch-files real file path</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Batch-Code-Processor.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Batch-Code-Processor.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Code Processor</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,322 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Batch Command Processor &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Command Processor</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="batch-command-processor">
<h1>Batch Command Processor<a class="headerlink" href="#batch-command-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">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>
<div class="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-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nd">@batchcommand</span> <span class="n">path</span><span class="o">.</span><span class="n">to</span><span class="o">.</span><span class="n">batchcmdfile</span>
</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.
This path is given like a python path relative to a folder you define to hold your batch files, set
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-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nd">@batchcommand</span> <span class="n">batch_cmds</span>
</pre></div>
</div>
<p>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 <em>it will not stop if commands in
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>
</div>
<div class="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. Youll find its 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">&lt;path.batchfile&gt;</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">&#64;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">&#64;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">&#64;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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1">#</span>
<span class="c1"># This is an example batch build file for Evennia. </span>
<span class="c1">#</span>
<span class="c1"># This creates a red button</span>
@create button:tutorial_examples.red_button.RedButton
<span class="c1"># (This comment ends input for @create)</span>
<span class="c1"># Next command. Let&#39;s create something. </span>
@set button/desc <span class="o">=</span>
This is a large red button. Now and <span class="k">then</span>
it flashes in an evil, yet strangely tantalizing way.
A big sign sits next to it. It says:
-----------
Press me!
-----------
... It really begs to be pressed! You
know you want to!
<span class="c1"># This inserts the commands from another batch-cmd file named</span>
<span class="c1"># batch_insert_file.ev.</span>
<span class="c1">#INSERT examples.batch_insert_file</span>
<span class="c1"># (This ends the @set command). Note that single line breaks </span>
<span class="c1"># and extra whitespace in the argument are ignored. Empty lines </span>
<span class="c1"># translate into line breaks in the output.</span>
<span class="c1"># Now let&#39;s place the button where it belongs (let&#39;s say limbo #2 is </span>
<span class="c1"># the evil lair in our example)</span>
@teleport <span class="c1">#2</span>
<span class="c1"># (This comments ends the @teleport command.) </span>
<span class="c1"># Now we drop it so others can see it. </span>
<span class="c1"># The very last command in the file needs not be ended with #.</span>
drop button
</pre></div>
</td></tr></table></div>
<p>To test this, run <code class="docutils literal notranslate"><span class="pre">&#64;batchcommand</span></code> on the file:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@batchcommand</span> <span class="n">contrib</span><span class="o">.</span><span class="n">tutorial_examples</span><span class="o">.</span><span class="n">batch_cmds</span>
</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>
<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></blockquote>
</div>
<div class="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">&#64;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">&#64;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-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nd">@batchcommand</span><span class="o">/</span><span class="n">interactive</span> <span class="n">tutorial_examples</span><span class="o">.</span><span class="n">batch_cmds</span>
</pre></div>
</div>
<p>You will see this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="mi">01</span><span class="o">/</span><span class="mi">04</span><span class="p">:</span> <span class="nd">@create</span> <span class="n">button</span><span class="p">:</span><span class="n">tutorial_examples</span><span class="o">.</span><span class="n">red_button</span><span class="o">.</span><span class="n">RedButton</span> <span class="p">(</span><span class="n">hh</span> <span class="k">for</span> <span class="n">help</span><span class="p">)</span>
</pre></div>
</div>
<p>This shows that you are on the <code class="docutils literal notranslate"><span class="pre">&#64;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">&#64;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">&#64;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">&#64;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>
</div>
<div class="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 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>
<ul class="simple">
<li><p><em>Rooms that change your <a class="reference internal" href="Command-Sets.html"><span class="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
youve 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 its always set to <em>off</em> upon
creation. Its all doable, one just needs to keep it in mind.</p>
</div>
<div class="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">Batch Code
Processor</span></a>)</p>
<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">&lt;tab&gt;</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="http://www.vim.org/">VIM</a> users can use amfls <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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Batch-Command-Processor.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Batch-Command-Processor.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Command Processor</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,176 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Batch Processors &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Processors</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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
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
Evennias <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>Its 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 wont 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 doesnt 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 Evennias 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">Batch Command Processor</span></a></p></li>
<li><p>The <a class="reference internal" href="Batch-Code-Processor.html"><span class="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>
<div class="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="http://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="http://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
its practially impossible to determine which encoding was used to save a file just by looking at it
(its just a bunch of bytes!). You have to <em>know</em>.</p>
<p>With this little introduction it should be clear that Evennia cant 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 editors encoding to Evennias <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">Text Encodings</span></a> and also in the
Wikipedia article <a class="reference external" href="http://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, doesnt 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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Batch Processors</a><ul>
<li><a class="reference internal" href="#a-note-on-file-encodings">A note on File Encodings</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Batch-Processors.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Batch-Processors.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Processors</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,210 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Bootstrap Components and Utilities &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Bootstrap Components and Utilities</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="bootstrap-components-and-utilities">
<h1>Bootstrap Components and Utilities<a class="headerlink" href="#bootstrap-components-and-utilities" title="Permalink to this headline"></a></h1>
<p>Bootstrap provides many utilities and components you can use when customizing Evennias web
presence. Well go over a few examples here that you might find useful.</p>
<blockquote>
<div><p>Please take a look at either <a class="reference internal" href="../Howto/Starting/Part5/Add-a-simple-new-web-page.html"><span class="doc">the basic web tutorial</span></a> or
<a class="reference internal" href="../Howto/Web-Character-View-Tutorial.html"><span class="doc">the web character view tutorial</span></a>
to get a feel for how to add pages to Evennias website to test these examples.</p>
</div></blockquote>
<div class="section" id="general-styling">
<h2>General Styling<a class="headerlink" href="#general-styling" title="Permalink to this headline"></a></h2>
<p>Bootstrap provides base styles for your site. These can be customized through CSS, but the default
styles are intended to provide a consistent, clean look for sites.</p>
<div class="section" id="color">
<h3>Color<a class="headerlink" href="#color" title="Permalink to this headline"></a></h3>
<p>Most elements can be styled with default colors. <a class="reference external" href="https://getbootstrap.com/docs/4.0/utilities/colors/">Take a look at the documentation</a> to learn more about these colors</p>
<ul class="simple">
<li><p>suffice to say, adding a class of text-* or bg-*, for instance, text-primary, sets the text color
or background color.</p></li>
</ul>
</div>
<div class="section" id="borders">
<h3>Borders<a class="headerlink" href="#borders" title="Permalink to this headline"></a></h3>
<p>Simply adding a class of border to an element adds a border to the element. For more in-depth
info, please <a class="reference external" href="https://getbootstrap.com/docs/4.0/utilities/borders/">read the documentation on borders.</a>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">span</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;border border-dark&quot;</span><span class="o">&gt;&lt;/</span><span class="n">span</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>You can also easily round corners just by adding a class.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">img</span> <span class="n">src</span><span class="o">=</span><span class="s2">&quot;...&quot;</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;rounded&quot;</span> <span class="o">/&gt;</span>
</pre></div>
</div>
</div>
<div class="section" id="spacing">
<h3>Spacing<a class="headerlink" href="#spacing" title="Permalink to this headline"></a></h3>
<p>Bootstrap provides classes to easily add responsive margin and padding. Most of the time, you might
like to add margins or padding through CSS itself - however these classes are used in the default
Evennia site. <a class="reference external" href="https://getbootstrap.com/docs/4.0/utilities/spacing/">Take a look at the docs</a> to
learn more.</p>
</div>
</div>
<hr class="docutils" />
<div class="section" id="components">
<h2>Components<a class="headerlink" href="#components" title="Permalink to this headline"></a></h2>
<div class="section" id="buttons">
<h3>Buttons<a class="headerlink" href="#buttons" title="Permalink to this headline"></a></h3>
<p><a class="reference external" href="https://getbootstrap.com/docs/4.0/components/buttons/">Buttons</a> in Bootstrap are very easy to use -
button styling can be added to <code class="docutils literal notranslate"><span class="pre">&lt;button&gt;</span></code>, <code class="docutils literal notranslate"><span class="pre">&lt;a&gt;</span></code>, and <code class="docutils literal notranslate"><span class="pre">&lt;input&gt;</span></code> elements.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&lt;a class=&quot;btn btn-primary&quot; href=&quot;#&quot; role=&quot;button&quot;&gt;I&#39;m a Button&lt;/a&gt;
&lt;button class=&quot;btn btn-primary&quot; type=&quot;submit&quot;&gt;Me too!&lt;/button&gt;
&lt;input class=&quot;btn btn-primary&quot; type=&quot;button&quot; value=&quot;Button&quot;&gt;
&lt;input class=&quot;btn btn-primary&quot; type=&quot;submit&quot; value=&quot;Also a Button&quot;&gt;
&lt;input class=&quot;btn btn-primary&quot; type=&quot;reset&quot; value=&quot;Button as Well&quot;&gt;
</pre></div>
</div>
</div>
<div class="section" id="cards">
<h3>Cards<a class="headerlink" href="#cards" title="Permalink to this headline"></a></h3>
<p><a class="reference external" href="https://getbootstrap.com/docs/4.0/components/card/">Cards</a> provide a container for other elements
that stands out from the rest of the page. The “Accounts”, “Recently Connected”, and “Database
Stats” on the default webpage are all in cards. Cards provide quite a bit of formatting options -
the following is a simple example, but read the documentation or look at the sites source for more.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;card&quot;</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;card-body&quot;</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">h4</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;card-title&quot;</span><span class="o">&gt;</span><span class="n">Card</span> <span class="n">title</span><span class="o">&lt;/</span><span class="n">h4</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">h6</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;card-subtitle mb-2 text-muted&quot;</span><span class="o">&gt;</span><span class="n">Card</span> <span class="n">subtitle</span><span class="o">&lt;/</span><span class="n">h6</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">p</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;card-text&quot;</span><span class="o">&gt;</span><span class="n">Fancy</span><span class="p">,</span> <span class="n">isn</span><span class="s1">&#39;t it?&lt;/p&gt;</span>
<span class="o">&lt;</span><span class="n">a</span> <span class="n">href</span><span class="o">=</span><span class="s2">&quot;#&quot;</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;card-link&quot;</span><span class="o">&gt;</span><span class="n">Card</span> <span class="n">link</span><span class="o">&lt;/</span><span class="n">a</span><span class="o">&gt;</span>
<span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span>
<span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span>
</pre></div>
</div>
</div>
<div class="section" id="jumbotron">
<h3>Jumbotron<a class="headerlink" href="#jumbotron" title="Permalink to this headline"></a></h3>
<p><a class="reference external" href="https://getbootstrap.com/docs/4.0/components/jumbotron/">Jumbotrons</a> are useful for featuring an
image or tagline for your game. They can flow with the rest of your content or take up the full
width of the page - Evennias base site uses the former.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;jumbotron jumbotron-fluid&quot;</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;container&quot;</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">h1</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;display-3&quot;</span><span class="o">&gt;</span><span class="n">Full</span> <span class="n">Width</span> <span class="n">Jumbotron</span><span class="o">&lt;/</span><span class="n">h1</span><span class="o">&gt;</span>
<span class="o">&lt;</span><span class="n">p</span> <span class="n">class</span><span class="o">=</span><span class="s2">&quot;lead&quot;</span><span class="o">&gt;</span><span class="n">Look</span> <span class="n">at</span> <span class="n">the</span> <span class="n">source</span> <span class="n">of</span> <span class="n">the</span> <span class="n">default</span> <span class="n">Evennia</span> <span class="n">page</span> <span class="k">for</span> <span class="n">a</span> <span class="n">regular</span> <span class="n">Jumbotron</span><span class="o">&lt;/</span><span class="n">p</span><span class="o">&gt;</span>
<span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span>
<span class="o">&lt;/</span><span class="n">div</span><span class="o">&gt;</span>
</pre></div>
</div>
</div>
<div class="section" id="forms">
<h3>Forms<a class="headerlink" href="#forms" title="Permalink to this headline"></a></h3>
<p><a class="reference external" href="https://getbootstrap.com/docs/4.0/components/forms/">Forms</a> are highly customizable with Bootstrap.
For a more in-depth look at how to use forms and their styles in your own Evennia site, please read
over <a class="reference internal" href="../Howto/Web-Character-Generation.html"><span class="doc">the web character gen tutorial.</span></a></p>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Bootstrap Components and Utilities</a><ul>
<li><a class="reference internal" href="#general-styling">General Styling</a><ul>
<li><a class="reference internal" href="#color">Color</a></li>
<li><a class="reference internal" href="#borders">Borders</a></li>
<li><a class="reference internal" href="#spacing">Spacing</a></li>
</ul>
</li>
<li><a class="reference internal" href="#components">Components</a><ul>
<li><a class="reference internal" href="#buttons">Buttons</a></li>
<li><a class="reference internal" href="#cards">Cards</a></li>
<li><a class="reference internal" href="#jumbotron">Jumbotron</a></li>
<li><a class="reference internal" href="#forms">Forms</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Bootstrap-Components-and-Utilities.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Bootstrap-Components-and-Utilities.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Bootstrap Components and Utilities</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Channels &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Channels</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="channels">
<h1>Channels<a class="headerlink" href="#channels" title="Permalink to this headline"></a></h1>
<p>TODO: Channels are covered in <a class="reference internal" href="Communications.html"><span class="doc">Communications</span></a> right now.</p>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Channels.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Channels.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Channels</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,467 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Coding Utils &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Coding Utils</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="coding-utils">
<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>
<div class="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 its easiest to use the <code class="docutils literal notranslate"><span class="pre">search</span></code> method defined
on all objects. This will search for objects in the same location and inside the self object:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><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>
</td></tr></table></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 callers (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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><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>
<span class="n">obj</span> <span class="o">=</span> <span class="n">search_object</span><span class="p">(</span><span class="n">objname</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<ul class="simple">
<li><p><a class="reference external" href="wiki/evennia.accounts.manager#accountdbmanagersearch_account">evennia.search_account</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.objects.manager#objectdbmanagersearch_object">evennia.search_object</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.utils.search#search_object_by_tag">evennia.search_object_by_tag</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.scripts.manager#scriptdbmanagersearch_script">evennia.search_script</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.comms.managers#channeldbmanagersearch_channel">evennia.search_channel</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.comms.managers#msgmanagersearch_message">evennia.search_message</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.help.manager#helpentrymanagersearch_help">evennia.search_help</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>
</div>
<div class="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">&#64;create</span></code> etc), you can also build all of Evennias game
entities directly in code (for example when defining new create commands).</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><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">&quot;game.gamesrc.objects.myobj.MyObj&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;MyObj&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<ul class="simple">
<li><p><a class="reference external" href="wiki/evennia.utils.create#create_account">evennia.create_account</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.utils.create#create_object">evennia.create_object</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.utils.create#create_script">evennia.create_script</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.utils.create#create_channel">evennia.create_channel</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.utils.create#create_help_entry">evennia.create_help_entry</a></p></li>
<li><p><a class="reference external" href="wiki/evennia.utils.create#create_message">evennia.create_message</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>
</div>
<div class="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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><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">&quot;This is an Error!&quot;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_warn</span><span class="p">(</span><span class="s2">&quot;This is a Warning!&quot;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_info</span><span class="p">(</span><span class="s2">&quot;This is normal information&quot;</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_dep</span><span class="p">(</span><span class="s2">&quot;This feature is deprecated&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></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
kill the server.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">try</span><span class="p">:</span>
<span class="c1"># [some code that may fail...]</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="s2">&quot;This text will show beneath the traceback itself.&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><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">&quot;mylog.log&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></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>
</div>
<div class="section" id="time-utilities">
<h2>Time Utilities<a class="headerlink" href="#time-utilities" title="Permalink to this headline"></a></h2>
<div class="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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21</pre></div></td><td class="code"><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>
<span class="c1"># total running time of the server</span>
<span class="n">runtime</span> <span class="o">=</span> <span class="n">gametime</span><span class="o">.</span><span class="n">runtime</span><span class="p">()</span>
<span class="c1"># time since latest hard reboot (not including reloads)</span>
<span class="n">uptime</span> <span class="o">=</span> <span class="n">gametime</span><span class="o">.</span><span class="n">uptime</span><span class="p">()</span>
<span class="c1"># server epoch (its start time)</span>
<span class="n">server_epoch</span> <span class="o">=</span> <span class="n">gametime</span><span class="o">.</span><span class="n">server_epoch</span><span class="p">()</span>
<span class="c1"># in-game epoch (this can be set by `settings.TIME_GAME_EPOCH`.</span>
<span class="c1"># If not, the server epoch is used.</span>
<span class="n">game_epoch</span> <span class="o">=</span> <span class="n">gametime</span><span class="o">.</span><span class="n">game_epoch</span><span class="p">()</span>
<span class="c1"># in-game time passed since time started running</span>
<span class="n">gametime</span> <span class="o">=</span> <span class="n">gametime</span><span class="o">.</span><span class="n">gametime</span><span class="p">()</span>
<span class="c1"># in-game time plus game epoch (i.e. the current in-game</span>
<span class="c1"># time stamp)</span>
<span class="n">gametime</span> <span class="o">=</span> <span class="n">gametime</span><span class="o">.</span><span class="n">gametime</span><span class="p">(</span><span class="n">absolute</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="c1"># reset the game time (back to game epoch)</span>
<span class="n">gametime</span><span class="o">.</span><span class="n">reset_gametime</span><span class="p">()</span>
</pre></div>
</td></tr></table></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">&#64;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 external" href="https://github.com/evennia/evennia/blob/master/evennia.utils.gametime#schedule">gametime.schedule</a> function:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><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>
<span class="n">limbo</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">&quot;Limbo&quot;</span><span class="p">)</span>
<span class="n">limbo</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="s2">&quot;The church clock chimes two.&quot;</span><span class="p">)</span>
<span class="n">gametime</span><span class="o">.</span><span class="n">schedule</span><span class="p">(</span><span class="n">church_clock</span><span class="p">,</span> <span class="n">hour</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="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. Its 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>
<li><p>style 2 - <code class="docutils literal notranslate"><span class="pre">5</span> <span class="pre">days,</span> <span class="pre">45</span> <span class="pre">minutes</span></code> (full format, ignores seconds)</p></li>
<li><p>style 3 - <code class="docutils literal notranslate"><span class="pre">5</span> <span class="pre">days,</span> <span class="pre">45</span> <span class="pre">minutes,</span> <span class="pre">12</span> <span class="pre">seconds</span></code> (full format, with seconds)</p></li>
</ul>
</div>
<div class="section" id="utils-delay">
<h3>utils.delay()<a class="headerlink" href="#utils-delay" title="Permalink to this headline"></a></h3>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><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 &quot;Echo!&quot; 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">&quot;Echo!&quot;</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
<span class="c1"># code here will run immediately, not waiting for the delay to fire!</span>
</pre></div>
</td></tr></table></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">&#64;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">&#64;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">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">TickerHandler</span></a> and <a class="reference internal" href="Scripts.html"><span class="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
its needed, but checking the current time and calculating on the fly what value it should have.</p>
</div></blockquote>
</div>
</div>
<div class="section" id="object-classes">
<h2>Object Classes<a class="headerlink" href="#object-classes" title="Permalink to this headline"></a></h2>
<div class="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 Pythons 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="http://en.wikipedia.org/wiki/Duck_typing">duck
typing</a>. But in Evennias 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">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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><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">&quot;typeclasses.objects.animals.Animal&quot;</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">&quot;The bouncer stops you in the door. He says: &#39;No talking animals allowed.&#39;&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
</div>
</div>
<div class="section" id="text-utilities">
<h2>Text utilities<a class="headerlink" href="#text-utilities" title="Permalink to this headline"></a></h2>
<p>In a text game, you are naturally doing a lot of work shuffling text back and forth. Here is a <em>non-
complete</em> selection of text utilities found in <code class="docutils literal notranslate"><span class="pre">evennia/utils/utils.py</span></code> (shortcut <code class="docutils literal notranslate"><span class="pre">evennia.utils</span></code>).
If nothing else it can be good to look here before starting to develop a solution of your own.</p>
<div class="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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><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>
</td></tr></table></div>
</div>
<div class="section" id="utils-crop">
<h3>utils.crop()<a class="headerlink" href="#utils-crop" title="Permalink to this headline"></a></h3>
<p>This function will crop a very long line, adding a suffix to show the line actually continues. This
can be useful in listings when showing multiple lines would mess up things.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">intxt</span> <span class="o">=</span> <span class="s2">&quot;This is a long text that we want to crop.&quot;</span>
<span class="n">outtxt</span> <span class="o">=</span> <span class="n">crop</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">19</span><span class="p">,</span> <span class="n">suffix</span><span class="o">=</span><span class="s2">&quot;[...]&quot;</span><span class="p">)</span>
<span class="c1"># outtxt is now &quot;This is a long text[...]&quot;</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="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 dont want to shift the string to the left edge.</p></li>
</ul>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><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">&quot;&quot;&quot;</span>
<span class="s2"> This is an example text that will end</span>
<span class="s2"> up with a lot of whitespace on the left.</span>
<span class="s2"> It also has indentations of</span>
<span class="s2"> its own.&quot;&quot;&quot;</span>
<span class="n">outtxt</span> <span class="o">=</span> <span class="n">dedent</span><span class="p">(</span><span class="n">intxt</span><span class="p">)</span>
<span class="c1"># outtxt will now retain all internal indentation</span>
<span class="c1"># but be shifted all the way to the left.</span>
</pre></div>
</td></tr></table></div>
<p>Normally you do the dedent in the display code (this is for example how the help system homogenizes
help entries).</p>
</div>
<div class="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 youll need.</p>
<p>The difference from Pythons 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">here</span></a> for more info.</p>
</div>
<div class="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 external" href="../api/evennia.utils.ansi.html">evennia.ansi</a></p></li>
</ul>
</div>
</div>
<div class="section" id="display-utilities">
<h2>Display utilities<a class="headerlink" href="#display-utilities" title="Permalink to this headline"></a></h2>
<div class="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 external" href="https://github.com/evennia/evennia/blob/master/evennia.utils.evtable#evtable">EvTable</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 external" href="https://github.com/evennia/evennia/blob/master/evennia.utils.evform#evform">EvForm</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>
</div>
<div class="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 external" href="https://github.com/evennia/evennia/blob/master/evennia.utils.evmenu#evmenu">evennia.EvMenu</a></p></li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Coding Utils</a><ul>
<li><a class="reference internal" href="#searching">Searching</a></li>
<li><a class="reference internal" href="#create">Create</a></li>
<li><a class="reference internal" href="#logging">Logging</a></li>
<li><a class="reference internal" href="#time-utilities">Time Utilities</a><ul>
<li><a class="reference internal" href="#game-time">Game time</a></li>
<li><a class="reference internal" href="#utils-time-format">utils.time_format()</a></li>
<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="#utils-inherits-from">utils.inherits_from()</a></li>
</ul>
</li>
<li><a class="reference internal" href="#text-utilities">Text utilities</a><ul>
<li><a class="reference internal" href="#utils-fill">utils.fill()</a></li>
<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>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Coding-Utils.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Coding-Utils.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Coding Utils</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,512 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Command Sets &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command Sets</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="command-sets">
<h1>Command Sets<a class="headerlink" href="#command-sets" title="Permalink to this headline"></a></h1>
<p>Command Sets are intimately linked with <a class="reference internal" href="Commands.html"><span class="doc">Commands</span></a> and you should be familiar with
Commands before reading this page. The two pages were split for ease of reading.</p>
<p>A <em>Command Set</em> (often referred to as a CmdSet or cmdset) is the basic unit for storing one or more
<em>Commands</em>. A given Command can go into any number of different command sets. Storing Command
classes in a command set is the way to make commands available to use in your game.</p>
<p>When storing a CmdSet on an object, you will make the commands in that command set available to the
object. An example is the default command set stored on new Characters. This command set contains
all the useful commands, from <code class="docutils literal notranslate"><span class="pre">look</span></code> and <code class="docutils literal notranslate"><span class="pre">inventory</span></code> to <code class="docutils literal notranslate"><span class="pre">&#64;dig</span></code> and <code class="docutils literal notranslate"><span class="pre">&#64;reload</span></code>
(<a class="reference external" href="Components/Locks.html#Permissions">permissions</a> then limit which players may use them, but thats a separate
topic).</p>
<p>When an account enters a command, cmdsets from the Account, Character, its location, and elsewhere
are pulled together into a <em>merge stack</em>. This stack is merged together in a specific order to
create a single “merged” cmdset, representing the pool of commands available at that very moment.</p>
<p>An example would be a <code class="docutils literal notranslate"><span class="pre">Window</span></code> object that has a cmdset with two commands in it: <code class="docutils literal notranslate"><span class="pre">look</span> <span class="pre">through</span> <span class="pre">window</span></code> and <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">window</span></code>. The command set would be visible to players in the room with the window,
allowing them to use those commands only there. You could imagine all sorts of clever uses of this,
like a <code class="docutils literal notranslate"><span class="pre">Television</span></code> object which had multiple commands for looking at it, switching channels and so
on. The tutorial world included with Evennia showcases a dark room that replaces certain critical
commands with its own versions because the Character cannot see.</p>
<p>If you want a quick start into defining your first commands and using them with command sets, you
can head over to the <a class="reference internal" href="../Howto/Starting/Part1/Adding-Commands.html"><span class="doc">Adding Command Tutorial</span></a> which steps through things
without the explanations.</p>
<div class="section" id="defining-command-sets">
<h2>Defining Command Sets<a class="headerlink" href="#defining-command-sets" title="Permalink to this headline"></a></h2>
<p>A CmdSet is, as most things in Evennia, defined as a Python class inheriting from the correct parent
(<code class="docutils literal notranslate"><span class="pre">evennia.CmdSet</span></code>, which is a shortcut to <code class="docutils literal notranslate"><span class="pre">evennia.commands.cmdset.CmdSet</span></code>). The CmdSet class only
needs to define one method, called <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation()</span></code>. All other class parameters are optional,
but are used for more advanced set manipulation and coding (see the [merge rules](Command-
Sets#merge-rules) section).</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># file mygame/commands/mycmdset.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">CmdSet</span>
<span class="c1"># this is a theoretical custom module with commands we </span>
<span class="c1"># created previously: mygame/commands/mycommands.py</span>
<span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">mycommands</span>
<span class="k">class</span> <span class="nc">MyCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The only thing this method should need</span>
<span class="sd"> to do is to add commands to the set.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCommand1</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCommand2</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCommand3</span><span class="p">())</span>
</pre></div>
</td></tr></table></div>
<p>The CmdSets <code class="docutils literal notranslate"><span class="pre">add()</span></code> method can also take another CmdSet as input. In this case all the commands
from that CmdSet will be appended to this one as if you added them line by line:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">():</span>
<span class="o">...</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">AdditionalCmdSet</span><span class="p">)</span> <span class="c1"># adds all command from this set</span>
<span class="o">...</span>
</pre></div>
</td></tr></table></div>
<p>If you added your command to an existing cmdset (like to the default cmdset), that set is already
loaded into memory. You need to make the server aware of the code changes:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@reload</span>
</pre></div>
</div>
<p>You should now be able to use the command.</p>
<p>If you created a new, fresh cmdset, this must be added to an object in order to make the commands
within available. A simple way to temporarily test a cmdset on yourself is use the <code class="docutils literal notranslate"><span class="pre">&#64;py</span></code> command to
execute a python snippet:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="nd">@py</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">&#39;commands.mycmdset.MyCmdSet&#39;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>This will stay with you until you <code class="docutils literal notranslate"><span class="pre">&#64;reset</span></code> or <code class="docutils literal notranslate"><span class="pre">&#64;shutdown</span></code> the server, or you run</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="nd">@py</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="s1">&#39;commands.mycmdset.MyCmdSet&#39;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>In the example above, a specific Cmdset class is removed. Calling <code class="docutils literal notranslate"><span class="pre">delete</span></code> without arguments will
remove the latest added cmdset.</p>
<blockquote>
<div><p>Note: Command sets added using <code class="docutils literal notranslate"><span class="pre">cmdset.add</span></code> are, by default, <em>not</em> persistent in the database.</p>
</div></blockquote>
<p>If you want the cmdset to survive a reload, you can do:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@py</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">mycmdset</span><span class="o">.</span><span class="n">MyCmdSet</span><span class="p">,</span> <span class="n">permanent</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>Or you could add the cmdset as the <em>default</em> cmdset:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@py</span> <span class="bp">self</span><span class="o">.</span><span class="n">cmdset</span><span class="o">.</span><span class="n">add_default</span><span class="p">(</span><span class="n">commands</span><span class="o">.</span><span class="n">mycmdset</span><span class="o">.</span><span class="n">MyCmdSet</span><span class="p">)</span>
</pre></div>
</div>
<p>An object can only have one “default” cmdset (but can also have none). This is meant as a safe fall-
back even if all other cmdsets fail or are removed. It is always persistent and will not be affected
by <code class="docutils literal notranslate"><span class="pre">cmdset.delete()</span></code>. To remove a default cmdset you must explicitly call <code class="docutils literal notranslate"><span class="pre">cmdset.remove_default()</span></code>.</p>
<p>Command sets are often added to an object in its <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> method. For more examples of
adding commands, read the <a class="reference internal" href="../Howto/Starting/Part1/Adding-Commands.html"><span class="doc">Step by step tutorial</span></a>. Generally you can
customize which command sets are added to your objects by using <code class="docutils literal notranslate"><span class="pre">self.cmdset.add()</span></code> or
<code class="docutils literal notranslate"><span class="pre">self.cmdset.add_default()</span></code>.</p>
<blockquote>
<div><p>Important: Commands are identified uniquely by key <em>or</em> alias (see <a class="reference internal" href="Commands.html"><span class="doc">Commands</span></a>). If any
overlap exists, two commands are considered identical. Adding a Command to a command set that
already has an identical command will <em>replace</em> the previous command. This is very important. You
must take this behavior into account when attempting to overload any default Evennia commands with
your own. Otherwise, you may accidentally “hide” your own command in your command set when adding a
new one that has a matching alias.</p>
</div></blockquote>
<div class="section" id="properties-on-command-sets">
<h3>Properties on Command Sets<a class="headerlink" href="#properties-on-command-sets" title="Permalink to this headline"></a></h3>
<p>There are several extra flags that you can set on CmdSets in order to modify how they work. All are
optional and will be set to defaults otherwise. Since many of these relate to <em>merging</em> cmdsets,
you might want to read the [Adding and Merging Command Sets](./Command-Sets#adding-and-merging-
command-sets) section for some of these to make sense.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (string) - an identifier for the cmdset. This is optional, but should be unique. It is used
for display in lists, but also to identify special merging behaviours using the <code class="docutils literal notranslate"><span class="pre">key_mergetype</span></code>
dictionary below.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">mergetype</span></code> (string) - allows for one of the following string values: “<em>Union</em>”, “<em>Intersect</em>”,
<em>Replace</em>”, or “<em>Remove</em>”.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">priority</span></code> (int) - This defines the merge order of the merge stack - cmdsets will merge in rising
order of priority with the highest priority set merging last. During a merger, the commands from the
set with the higher priority will have precedence (just what happens depends on the <a class="reference external" href="Components/Command-Sets.html#adding-and-merging-command-sets">merge
type</a>). If priority is identical, the order in the
merge stack determines preference. The priority value must be greater or equal to <code class="docutils literal notranslate"><span class="pre">-100</span></code>. Most in-
game sets should usually have priorities between <code class="docutils literal notranslate"><span class="pre">0</span></code> and <code class="docutils literal notranslate"><span class="pre">100</span></code>. Evennia default sets have priorities
as follows (these can be changed if you want a different distribution):</p>
<ul>
<li><p>EmptySet: <code class="docutils literal notranslate"><span class="pre">-101</span></code> (should be lower than all other sets)</p></li>
<li><p>SessionCmdSet: <code class="docutils literal notranslate"><span class="pre">-20</span></code></p></li>
<li><p>AccountCmdSet: <code class="docutils literal notranslate"><span class="pre">-10</span></code></p></li>
<li><p>CharacterCmdSet: <code class="docutils literal notranslate"><span class="pre">0</span></code></p></li>
<li><p>ExitCmdSet: <code class="docutils literal notranslate"> <span class="pre">101</span></code> (generally should always be available)</p></li>
<li><p>ChannelCmdSet: <code class="docutils literal notranslate"><span class="pre">101</span></code> (should usually always be available) - since exits never accept
arguments, there is no collision between exits named the same as a channel even though the commands
“collide”.</p></li>
</ul>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">key_mergetype</span></code> (dict) - a dict of <code class="docutils literal notranslate"><span class="pre">key:mergetype</span></code> pairs. This allows this cmdset to merge
differently with certain named cmdsets. If the cmdset to merge with has a <code class="docutils literal notranslate"><span class="pre">key</span></code> matching an entry in
<code class="docutils literal notranslate"><span class="pre">key_mergetype</span></code>, it will not be merged according to the setting in <code class="docutils literal notranslate"><span class="pre">mergetype</span></code> but according to the
mode in this dict. Please note that this is more complex than it may seem due to the <a class="reference external" href="Components/Command-Sets.html#adding-and-merging-command-sets">merge
order</a> of command sets. Please review that section
before using <code class="docutils literal notranslate"><span class="pre">key_mergetype</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">duplicates</span></code> (bool/None default <code class="docutils literal notranslate"><span class="pre">None</span></code>) - this determines what happens when merging same-priority
cmdsets containing same-key commands together. The<code class="docutils literal notranslate"><span class="pre">dupicate</span></code> option will <em>only</em> apply when merging
the cmdset with this option onto one other cmdset with the same priority. The resulting cmdset will
<em>not</em> retain this <code class="docutils literal notranslate"><span class="pre">duplicate</span></code> setting.</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">None</span></code> (default): No duplicates are allowed and the cmdset being merged “onto” the old one
will take precedence. The result will be unique commands. <em>However</em>, the system will assume this
value to be <code class="docutils literal notranslate"><span class="pre">True</span></code> for cmdsets on Objects, to avoid dangerous clashes. This is usually the safe bet.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">False</span></code>: Like <code class="docutils literal notranslate"><span class="pre">None</span></code> except the system will not auto-assume any value for cmdsets defined on
Objects.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">True</span></code>: Same-named, same-prio commands will merge into the same cmdset. This will lead to a
multimatch error (the user will get a list of possibilities in order to specify which command they
meant). This is is useful e.g. for on-object cmdsets (example: There is a <code class="docutils literal notranslate"><span class="pre">red</span> <span class="pre">button</span></code> and a <code class="docutils literal notranslate"><span class="pre">green</span> <span class="pre">button</span></code> in the room. Both have a <code class="docutils literal notranslate"><span class="pre">press</span> <span class="pre">button</span></code> command, in cmdsets with the same priority. This
flag makes sure that just writing <code class="docutils literal notranslate"><span class="pre">press</span> <span class="pre">button</span></code> will force the Player to define just which objects
command was intended).</p></li>
</ul>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">no_objs</span></code> this is a flag for the cmdhandler that builds the set of commands available at every
moment. It tells the handler not to include cmdsets from objects around the account (nor from rooms
or inventory) when building the merged set. Exit commands will still be included. This option can
have three values:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">None</span></code> (default): Passthrough of any value set explicitly earlier in the merge stack. If never
set explicitly, this acts as <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">True</span></code>/<code class="docutils literal notranslate"><span class="pre">False</span></code>: Explicitly turn on/off. If two sets with explicit <code class="docutils literal notranslate"><span class="pre">no_objs</span></code> are merged,
priority determines what is used.</p></li>
</ul>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">no_exits</span></code> - this is a flag for the cmdhandler that builds the set of commands available at every
moment. It tells the handler not to include cmdsets from exits. This flag can have three values:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">None</span></code> (default): Passthrough of any value set explicitly earlier in the merge stack. If
never set explicitly, this acts as <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">True</span></code>/<code class="docutils literal notranslate"><span class="pre">False</span></code>: Explicitly turn on/off. If two sets with explicit <code class="docutils literal notranslate"><span class="pre">no_exits</span></code> are merged,
priority determines what is used.</p></li>
</ul>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">no_channels</span></code> (bool) - this is a flag for the cmdhandler that builds the set of commands available
at every moment. It tells the handler not to include cmdsets from available in-game channels. This
flag can have three values:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">None</span></code> (default): Passthrough of any value set explicitly earlier in the merge stack. If
never set explicitly, this acts as <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">True</span></code>/<code class="docutils literal notranslate"><span class="pre">False</span></code>: Explicitly turn on/off. If two sets with explicit <code class="docutils literal notranslate"><span class="pre">no_channels</span></code> are merged,
priority determines what is used.</p></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="section" id="command-sets-searched">
<h2>Command Sets Searched<a class="headerlink" href="#command-sets-searched" title="Permalink to this headline"></a></h2>
<p>When a user issues a command, it is matched against the [merged](./Command-Sets#adding-and-merging-
command-sets) command sets available to the player at the moment. Which those are may change at any
time (such as when the player walks into the room with the <code class="docutils literal notranslate"><span class="pre">Window</span></code> object described earlier).</p>
<p>The currently valid command sets are collected from the following sources:</p>
<ul class="simple">
<li><p>The cmdsets stored on the currently active <a class="reference internal" href="Sessions.html"><span class="doc">Session</span></a>. Default is the empty
<code class="docutils literal notranslate"><span class="pre">SessionCmdSet</span></code> with merge priority <code class="docutils literal notranslate"><span class="pre">-20</span></code>.</p></li>
<li><p>The cmdsets defined on the <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a>. Default is the AccountCmdSet with merge priority
<code class="docutils literal notranslate"><span class="pre">-10</span></code>.</p></li>
<li><p>All cmdsets on the Character/Object (assuming the Account is currently puppeting such a
Character/Object). Merge priority <code class="docutils literal notranslate"><span class="pre">0</span></code>.</p></li>
<li><p>The cmdsets of all objects carried by the puppeted Character (checks the <code class="docutils literal notranslate"><span class="pre">call</span></code> lock). Will not be
included if <code class="docutils literal notranslate"><span class="pre">no_objs</span></code> option is active in the merge stack.</p></li>
<li><p>The cmdsets of the Characters current location (checks the <code class="docutils literal notranslate"><span class="pre">call</span></code> lock). Will not be included if
<code class="docutils literal notranslate"><span class="pre">no_objs</span></code> option is active in the merge stack.</p></li>
<li><p>The cmdsets of objects in the current location (checks the <code class="docutils literal notranslate"><span class="pre">call</span></code> lock). Will not be included if
<code class="docutils literal notranslate"><span class="pre">no_objs</span></code> option is active in the merge stack.</p></li>
<li><p>The cmdsets of Exits in the location. Merge priority <code class="docutils literal notranslate"><span class="pre">+101</span></code>. Will not be included if <code class="docutils literal notranslate"><span class="pre">no_exits</span></code>
<em>or</em> <code class="docutils literal notranslate"><span class="pre">no_objs</span></code> option is active in the merge stack.</p></li>
<li><p>The <a class="reference internal" href="Communications.html"><span class="doc">channel</span></a> cmdset containing commands for posting to all channels the account
or character is currently connected to. Merge priority <code class="docutils literal notranslate"><span class="pre">+101</span></code>. Will not be included if <code class="docutils literal notranslate"><span class="pre">no_channels</span></code>
option is active in the merge stack.</p></li>
</ul>
<p>Note that an object does not <em>have</em> to share its commands with its surroundings. A Characters
cmdsets should not be shared for example, or all other Characters would get multi-match errors just
by being in the same room. The ability of an object to share its cmdsets is managed by its <code class="docutils literal notranslate"><span class="pre">call</span></code>
<a class="reference internal" href="Locks.html"><span class="doc">lock</span></a>. For example, <a class="reference internal" href="Objects.html"><span class="doc">Character objects</span></a> defaults to <code class="docutils literal notranslate"><span class="pre">call:false()</span></code> so that any
cmdsets on them can only be accessed by themselves, not by other objects around them. Another
example might be to lock an object with <code class="docutils literal notranslate"><span class="pre">call:inside()</span></code> to only make their commands available to
objects inside them, or <code class="docutils literal notranslate"><span class="pre">cmd:holds()</span></code> to make their commands available only if they are held.</p>
</div>
<div class="section" id="adding-and-merging-command-sets">
<h2>Adding and Merging Command Sets<a class="headerlink" href="#adding-and-merging-command-sets" title="Permalink to this headline"></a></h2>
<p><em>Note: This is an advanced topic. Its very useful to know about, but you might want to skip it if
this is your first time learning about commands.</em></p>
<p>CmdSets have the special ability that they can be <em>merged</em> together into new sets. Which of the
ingoing commands end up in the merged set is defined by the <em>merge rule</em> and the relative
<em>priorities</em> of the two sets. Removing the latest added set will restore things back to the way it
was before the addition.</p>
<p>CmdSets are non-destructively stored in a stack inside the cmdset handler on the object. This stack
is parsed to create the “combined” cmdset active at the moment. CmdSets from other sources are also
included in the merger such as those on objects in the same room (like buttons to press) or those
introduced by state changes (such as when entering a menu). The cmdsets are all ordered after
priority and then merged together in <em>reverse order</em>. That is, the higher priority will be merged
“onto” lower-prio ones. By defining a cmdset with a merge-priority between that of two other sets,
you will make sure it will be merged in between them.
The very first cmdset in this stack is called the <em>Default cmdset</em> and is protected from accidental
deletion. Running <code class="docutils literal notranslate"><span class="pre">obj.cmdset.delete()</span></code> will never delete the default set. Instead one should add
new cmdsets on top of the default to “hide” it, as described below. Use the special
<code class="docutils literal notranslate"><span class="pre">obj.cmdset.delete_default()</span></code> only if you really know what you are doing.</p>
<p>CmdSet merging is an advanced feature useful for implementing powerful game effects. Imagine for
example a player entering a dark room. You dont want the player to be able to find everything in
the room at a glance - maybe you even want them to have a hard time to find stuff in their backpack!
You can then define a different CmdSet with commands that override the normal ones. While they are
in the dark room, maybe the <code class="docutils literal notranslate"><span class="pre">look</span></code> and <code class="docutils literal notranslate"><span class="pre">inv</span></code> commands now just tell the player they cannot see
anything! Another example would be to offer special combat commands only when the player is in
combat. Or when being on a boat. Or when having taken the super power-up. All this can be done on
the fly by merging command sets.</p>
<div class="section" id="merge-rules">
<h3>Merge Rules<a class="headerlink" href="#merge-rules" title="Permalink to this headline"></a></h3>
<p>Basic rule is that command sets are merged in <em>reverse priority order</em>. That is, lower-prio sets are
merged first and higher prio sets are merged “on top” of them. Think of it like a layered cake with
the highest priority on top.</p>
<p>To further understand how sets merge, we need to define some examples. Lets call the first command
set <strong>A</strong> and the second <strong>B</strong>. We assume <strong>B</strong> is the command set already active on our object and
we will merge <strong>A</strong> onto <strong>B</strong>. In code terms this would be done by <code class="docutils literal notranslate"><span class="pre">object.cdmset.add(A)</span></code>.
Remember, B is already active on <code class="docutils literal notranslate"><span class="pre">object</span></code> from before.</p>
<p>We let the <strong>A</strong> set have higher priority than <strong>B</strong>. A priority is simply an integer number. As
seen in the list above, Evennias default cmdsets have priorities in the range <code class="docutils literal notranslate"><span class="pre">-101</span></code> to <code class="docutils literal notranslate"><span class="pre">120</span></code>. You
are usually safe to use a priority of <code class="docutils literal notranslate"><span class="pre">0</span></code> or <code class="docutils literal notranslate"><span class="pre">1</span></code> for most game effects.</p>
<p>In our examples, both sets contain a number of commands which well identify by numbers, like <code class="docutils literal notranslate"><span class="pre">A1,</span> <span class="pre">A2</span></code> for set <strong>A</strong> and <code class="docutils literal notranslate"><span class="pre">B1,</span> <span class="pre">B2,</span> <span class="pre">B3,</span> <span class="pre">B4</span></code> for <strong>B</strong>. So for that example both sets contain commands
with the same keys (or aliases) “1” and “2” (this could for example be “look” and “get” in the real
game), whereas commands 3 and 4 are unique to <strong>B</strong>. To describe a merge between these sets, we
would write <code class="docutils literal notranslate"><span class="pre">A1,A2</span> <span class="pre">+</span> <span class="pre">B1,B2,B3,B4</span> <span class="pre">=</span> <span class="pre">?</span></code> where <code class="docutils literal notranslate"><span class="pre">?</span></code> is a list of commands that depend on which merge
type <strong>A</strong> has, and which relative priorities the two sets have. By convention, we read this
statement as “New command set <strong>A</strong> is merged onto the old command set <strong>B</strong> to form <strong>?</strong>”.</p>
<p>Below are the available merge types and how they work. Names are partly borrowed from <a class="reference external" href="http://en.wikipedia.org/wiki/Set_theory">Set
theory</a>.</p>
<ul>
<li><p><strong>Union</strong> (default) - The two cmdsets are merged so that as many commands as possible from each
cmdset ends up in the merged cmdset. Same-key commands are merged by priority.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="c1"># Union</span>
<span class="n">A1</span><span class="p">,</span><span class="n">A2</span> <span class="o">+</span> <span class="n">B1</span><span class="p">,</span><span class="n">B2</span><span class="p">,</span><span class="n">B3</span><span class="p">,</span><span class="n">B4</span> <span class="o">=</span> <span class="n">A1</span><span class="p">,</span><span class="n">A2</span><span class="p">,</span><span class="n">B3</span><span class="p">,</span><span class="n">B4</span>
</pre></div>
</div>
</li>
<li><p><strong>Intersect</strong> - Only commands found in <em>both</em> cmdsets (i.e. which have the same keys) end up in
the merged cmdset, with the higher-priority cmdset replacing the lower ones commands.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="c1"># Intersect </span>
<span class="n">A1</span><span class="p">,</span><span class="n">A3</span><span class="p">,</span><span class="n">A5</span> <span class="o">+</span> <span class="n">B1</span><span class="p">,</span><span class="n">B2</span><span class="p">,</span><span class="n">B4</span><span class="p">,</span><span class="n">B5</span> <span class="o">=</span> <span class="n">A1</span><span class="p">,</span><span class="n">A5</span>
</pre></div>
</div>
</li>
<li><p><strong>Replace</strong> - The commands of the higher-prio cmdset completely replaces the lower-priority
cmdsets commands, regardless of if same-key commands exist or not.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="c1"># Replace</span>
<span class="n">A1</span><span class="p">,</span><span class="n">A3</span> <span class="o">+</span> <span class="n">B1</span><span class="p">,</span><span class="n">B2</span><span class="p">,</span><span class="n">B4</span><span class="p">,</span><span class="n">B5</span> <span class="o">=</span> <span class="n">A1</span><span class="p">,</span><span class="n">A3</span>
</pre></div>
</div>
</li>
<li><p><strong>Remove</strong> - The high-priority command sets removes same-key commands from the lower-priority
cmdset. They are not replaced with anything, so this is a sort of filter that prunes the low-prio
set using the high-prio one as a template.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="c1"># Remove</span>
<span class="n">A1</span><span class="p">,</span><span class="n">A3</span> <span class="o">+</span> <span class="n">B1</span><span class="p">,</span><span class="n">B2</span><span class="p">,</span><span class="n">B3</span><span class="p">,</span><span class="n">B4</span><span class="p">,</span><span class="n">B5</span> <span class="o">=</span> <span class="n">B2</span><span class="p">,</span><span class="n">B4</span><span class="p">,</span><span class="n">B5</span>
</pre></div>
</div>
</li>
</ul>
<p>Besides <code class="docutils literal notranslate"><span class="pre">priority</span></code> and <code class="docutils literal notranslate"><span class="pre">mergetype</span></code>, a command-set also takes a few other variables to control how
they merge:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">duplicates</span></code> (bool) - determines what happens when two sets of equal priority merge. Default is
that the new set in the merger (i.e. <strong>A</strong> above) automatically takes precedence. But if
<em>duplicates</em> is true, the result will be a merger with more than one of each name match. This will
usually lead to the player receiving a multiple-match error higher up the road, but can be good for
things like cmdsets on non-player objects in a room, to allow the system to warn that more than one
ball in the room has the same kick command defined on it and offer a chance to select which
ball to kick … Allowing duplicates only makes sense for <em>Union</em> and <em>Intersect</em>, the setting is
ignored for the other mergetypes.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">key_mergetypes</span></code> (dict) - allows the cmdset to define a unique mergetype for particular cmdsets,
identified by their cmdset <code class="docutils literal notranslate"><span class="pre">key</span></code>. Format is <code class="docutils literal notranslate"><span class="pre">{CmdSetkey:mergetype}</span></code>. Example:
<code class="docutils literal notranslate"><span class="pre">{'Myevilcmdset','Replace'}</span></code> which would make sure for this set to always use Replace on the
cmdset with the key <code class="docutils literal notranslate"><span class="pre">Myevilcmdset</span></code> only, no matter what the main <code class="docutils literal notranslate"><span class="pre">mergetype</span></code> is set to.</p></li>
</ul>
<blockquote>
<div><p>Warning: The <code class="docutils literal notranslate"><span class="pre">key_mergetypes</span></code> dictionary <em>can only work on the cmdset we merge onto</em>. When using
<code class="docutils literal notranslate"><span class="pre">key_mergetypes</span></code> it is thus important to consider the merge priorities - you must make sure that you
pick a priority <em>between</em> the cmdset you want to detect and the next higher one, if any. That is, if
we define a cmdset with a high priority and set it to affect a cmdset that is far down in the merge
stack, we would not “see” that set when its time for us to merge. Example: Merge stack is
<code class="docutils literal notranslate"><span class="pre">A(prio=-10),</span> <span class="pre">B(prio=-5),</span> <span class="pre">C(prio=0),</span> <span class="pre">D(prio=5)</span></code>. We now merge a cmdset <code class="docutils literal notranslate"><span class="pre">E(prio=10)</span></code> onto this stack,
with a <code class="docutils literal notranslate"><span class="pre">key_mergetype={&quot;B&quot;:&quot;Replace&quot;}</span></code>. But priorities dictate that we wont be merged onto B, we
will be merged onto E (which is a merger of the lower-prio sets at this point). Since we are merging
onto E and not B, our <code class="docutils literal notranslate"><span class="pre">key_mergetype</span></code> directive wont trigger. To make sure it works we must make
sure we merge onto B. Setting Es priority to, say, -4 will make sure to merge it onto B and affect
it appropriately.</p>
</div></blockquote>
<p>More advanced cmdset example:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">commands</span> <span class="kn">import</span> <span class="n">mycommands</span>
<span class="k">class</span> <span class="nc">MyCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;MyCmdSet&quot;</span>
<span class="n">priority</span> <span class="o">=</span> <span class="mi">4</span>
<span class="n">mergetype</span> <span class="o">=</span> <span class="s2">&quot;Replace&quot;</span>
<span class="n">key_mergetypes</span> <span class="o">=</span> <span class="p">{</span><span class="s1">&#39;MyOtherCmdSet&#39;</span><span class="p">:</span><span class="s1">&#39;Union&#39;</span><span class="p">}</span>
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> The only thing this method should need</span>
<span class="sd"> to do is to add commands to the set.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCommand1</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCommand2</span><span class="p">())</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">mycommands</span><span class="o">.</span><span class="n">MyCommand3</span><span class="p">())</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="assorted-notes">
<h3>Assorted Notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline"></a></h3>
<p>It is very important to remember that two commands are compared <em>both</em> by their <code class="docutils literal notranslate"><span class="pre">key</span></code> properties
<em>and</em> by their <code class="docutils literal notranslate"><span class="pre">aliases</span></code> properties. If either keys or one of their aliases match, the two commands
are considered the <em>same</em>. So consider these two Commands:</p>
<ul class="simple">
<li><p>A Command with key “kick” and alias “fight”</p></li>
<li><p>A Command with key “punch” also with an alias “fight”</p></li>
</ul>
<p>During the cmdset merging (which happens all the time since also things like channel commands and
exits are merged in), these two commands will be considered <em>identical</em> since they share alias. It
means only one of them will remain after the merger. Each will also be compared with all other
commands having any combination of the keys and/or aliases “kick”, “punch” or “fight”.</p>
<p>… So avoid duplicate aliases, it will only cause confusion.</p>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Command Sets</a><ul>
<li><a class="reference internal" href="#defining-command-sets">Defining Command Sets</a><ul>
<li><a class="reference internal" href="#properties-on-command-sets">Properties on Command Sets</a></li>
</ul>
</li>
<li><a class="reference internal" href="#command-sets-searched">Command Sets Searched</a></li>
<li><a class="reference internal" href="#adding-and-merging-command-sets">Adding and Merging Command Sets</a><ul>
<li><a class="reference internal" href="#merge-rules">Merge Rules</a></li>
<li><a class="reference internal" href="#assorted-notes">Assorted Notes</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Command-Sets.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Command-Sets.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command Sets</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,108 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Command System &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command System</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="command-system">
<h1>Command System<a class="headerlink" href="#command-system" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><p><a class="reference internal" href="Commands.html"><span class="doc">Commands</span></a></p></li>
<li><p><a class="reference internal" href="Command-Sets.html"><span class="doc">Command Sets</span></a></p></li>
<li><p><a class="reference external" href="Components/Help-System.html#command-auto-help-system">Command Auto-help</a></p></li>
</ul>
<p>See also:</p>
<ul class="simple">
<li><p><a class="reference external" href="../api/evennia.commands.default.html#modules">Default Command Help</a></p></li>
<li><p><a class="reference internal" href="../Howto/Starting/Part1/Adding-Commands.html"><span class="doc">Adding Command Tutorial</span></a></p></li>
</ul>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Command-System.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Command-System.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command System</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,885 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Commands &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Commands</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="commands">
<h1>Commands<a class="headerlink" href="#commands" title="Permalink to this headline"></a></h1>
<p>Commands are intimately linked to <a class="reference internal" href="Command-Sets.html"><span class="doc">Command Sets</span></a> and you need to read that page too to
be familiar with how the command system works. The two pages were split for easy reading.</p>
<p>The basic way for users to communicate with the game is through <em>Commands</em>. These can be commands
directly related to the game world such as <em>look</em>, <em>get</em>, <em>drop</em> and so on, or administrative
commands such as <em>examine</em> or <em>&#64;dig</em>.</p>
<p>The <a class="reference external" href="../api/evennia.commands.default.html#modules">default commands</a> coming with Evennia are MUX-like in that they use &#64;
for admin commands, support things like switches, syntax with the = symbol etc, but there is
nothing that prevents you from implementing a completely different command scheme for your game. You
can find the default commands in <code class="docutils literal notranslate"><span class="pre">evennia/commands/default</span></code>. You should not edit these directly -
they will be updated by the Evennia team as new features are added. Rather you should look to them
for inspiration and inherit your own designs from them.</p>
<p>There are two components to having a command running - the <em>Command</em> class and the
<a class="reference internal" href="Command-Sets.html"><span class="doc">Command Set</span></a> (command sets were split into a separate wiki page for ease of reading).</p>
<ol class="simple">
<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">Command Sets</span></a>. There is also a step-by-step
<a class="reference internal" href="../Howto/Starting/Part1/Adding-Commands.html"><span class="doc">Adding Command Tutorial</span></a> that will get you started quickly without the
extra explanations.</p>
<div class="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>
(<code class="docutils literal notranslate"><span class="pre">evennia.Command</span></code>). You will find that this base class is very “bare”. The default commands of
Evennia actually inherit from a child of <code class="docutils literal notranslate"><span class="pre">Command</span></code> called <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> - this is the class that
knows all the mux-like syntax like <code class="docutils literal notranslate"><span class="pre">/switches</span></code>, splitting by “=” etc. Below well avoid mux-
specifics and use the base <code class="docutils literal notranslate"><span class="pre">Command</span></code> class directly.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># basic Command definition</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">MyCmd</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This is the help-text for the command</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;mycommand&quot;</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># parsing the command line here</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="c1"># executing the command here</span>
</pre></div>
</td></tr></table></div>
<p>Here is a minimalistic command with no custom parsing:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8</pre></div></td><td class="code"><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">CmdEcho</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">&quot;echo&quot;</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="c1"># echo the caller&#39;s input back to the caller</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="s2">&quot;Echo: {}&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>You define a new command by assigning a few class-global properties on your inherited class and
overloading one or two hook functions. The full gritty mechanic behind how commands work are found
towards the end of this page; for now you only need to know that the command handler creates an
instance of this class and uses that instance whenever you use this command - it also dynamically
assigns the new command instance a few useful properties that you can assume to always be available.</p>
<div class="section" id="who-is-calling-the-command">
<h3>Who is calling the command?<a class="headerlink" href="#who-is-calling-the-command" title="Permalink to this headline"></a></h3>
<p>In Evennia there are three types of objects that may call the command. It is important to be aware
of this since this will also assign appropriate <code class="docutils literal notranslate"><span class="pre">caller</span></code>, <code class="docutils literal notranslate"><span class="pre">session</span></code>, <code class="docutils literal notranslate"><span class="pre">sessid</span></code> and <code class="docutils literal notranslate"><span class="pre">account</span></code>
properties on the command body at runtime. Most often the calling type is <code class="docutils literal notranslate"><span class="pre">Session</span></code>.</p>
<ul class="simple">
<li><p>A <a class="reference internal" href="Sessions.html"><span class="doc">Session</span></a>. This is by far the most common case when a user is entering a command in
their client.</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> - this is set to the puppeted <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> if such an object exists. If no
puppet is found, <code class="docutils literal notranslate"><span class="pre">caller</span></code> is set equal to <code class="docutils literal notranslate"><span class="pre">account</span></code>. Only if an Account is not found either (such as
before being logged in) will this be set to the Session object itself.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">session</span></code> - a reference to the <a class="reference internal" href="Sessions.html"><span class="doc">Session</span></a> object itself.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">sessid</span></code> - <code class="docutils literal notranslate"><span class="pre">sessid.id</span></code>, a unique integer identifier of the 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">Account</span></a> object connected to this Session. None if not logged in.</p></li>
</ul>
</li>
<li><p>An <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a>. This only happens if <code class="docutils literal notranslate"><span class="pre">account.execute_cmd()</span></code> was used. No Session
information can be obtained in this case.</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> - this is set to the puppeted Object if such an object can be determined (without
Session info this can only be determined in <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE=0</span></code> or <code class="docutils literal notranslate"><span class="pre">1</span></code>). If no puppet is found,
this is equal to <code class="docutils literal notranslate"><span class="pre">account</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">session</span></code> - <code class="docutils literal notranslate"><span class="pre">None*</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">sessid</span></code> - <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> - Set to the Account object.</p></li>
</ul>
</li>
<li><p>An <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a>. This only happens if <code class="docutils literal notranslate"><span class="pre">object.execute_cmd()</span></code> was used (for example by an
NPC).</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> - This is set to the calling Object in question.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">session</span></code> - <code class="docutils literal notranslate"><span class="pre">None*</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">sessid</span></code> - <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> - <code class="docutils literal notranslate"><span class="pre">None</span></code></p></li>
</ul>
</li>
</ul>
<blockquote>
<div><p><code class="docutils literal notranslate"><span class="pre">*)</span></code>: There is a way to make the Session available also inside tests run directly on Accounts and
Objects, and that is to pass it to <code class="docutils literal notranslate"><span class="pre">execute_cmd</span></code> like so: <code class="docutils literal notranslate"><span class="pre">account.execute_cmd(&quot;...&quot;,</span> <span class="pre">session=&lt;Session&gt;)</span></code>. Doing so <em>will</em> make the <code class="docutils literal notranslate"><span class="pre">.session</span></code> and <code class="docutils literal notranslate"><span class="pre">.sessid</span></code> properties available in the
command.</p>
</div></blockquote>
</div>
<div class="section" id="properties-assigned-to-the-command-instance-at-run-time">
<h3>Properties assigned to the command instance at run-time<a class="headerlink" href="#properties-assigned-to-the-command-instance-at-run-time" title="Permalink to this headline"></a></h3>
<p>Lets say account <em>Bob</em> with a character <em>BigGuy</em> enters the command <em>look at sword</em>. After the
system having successfully identified this as the “look” command and determined that BigGuy really
has access to a command named <code class="docutils literal notranslate"><span class="pre">look</span></code>, it chugs the <code class="docutils literal notranslate"><span class="pre">look</span></code> command class out of storage and either
loads an existing Command instance from cache or creates one. After some more checks it then assigns
it the following properties:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> - The character BigGuy, in this example. This is a reference to the object executing the
command. The value of this depends on what type of object is calling the command; see the previous
section.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">session</span></code> - the <a class="reference internal" href="Sessions.html"><span class="doc">Session</span></a> Bob uses to connect to the game and control BigGuy (see also
previous section).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">sessid</span></code> - the unique id of <code class="docutils literal notranslate"><span class="pre">self.session</span></code>, for quick lookup.</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">Account</span></a> Bob (see previous section).</p></li>
<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">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.</p></li>
<li><p><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, its main use is for the [auto-help system](Help-
System#command-auto-help-system) (<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>
<div class="section" id="other-useful-utility-methods">
<h4>Other useful utility methods:<a class="headerlink" href="#other-useful-utility-methods" title="Permalink to this headline"></a></h4>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">.get_help(caller,</span> <span class="pre">cmdset)</span></code> - Get the help entry for this command. By default the arguments are
not
used, but they could be used to implement alternate help-display systems.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.client_width()</span></code> - Shortcut for getting the clients screen-width. Note that not all clients will
truthfully report this value - that case the <code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_SCREEN_WIDTH</span></code> will be returned.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.styled_table(*args,</span> <span class="pre">**kwargs)</span></code> - This returns an [EvTable](api:evennia.utils#module-
evennia.utils.evtable) styled based on the
session calling this command. The args/kwargs are the same as for EvTable, except styling defaults
are set.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.styled_header</span></code>, <code class="docutils literal notranslate"><span class="pre">_footer</span></code>, <code class="docutils literal notranslate"><span class="pre">separator</span></code> - These will produce styled decorations for
display to the user. They are useful for creating listings and forms with colors adjustable per-
user.</p></li>
</ul>
</div>
</div>
<div class="section" id="defining-your-own-command-classes">
<h3>Defining your own command classes<a class="headerlink" href="#defining-your-own-command-classes" title="Permalink to this headline"></a></h3>
<p>Beyond the properties Evennia always assigns to the command at run-time (listed above), your job is
to define the following class properties:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (string) - the identifier for the command, like <code class="docutils literal notranslate"><span class="pre">look</span></code>. This should (ideally) be unique. A
key can consist of more than one word, like “press button” or “pull left lever”. Note that <em>both</em>
<code class="docutils literal notranslate"><span class="pre">key</span></code> and <code class="docutils literal notranslate"><span class="pre">aliases</span></code> below determine the identity of a command. So two commands are considered if
either matches. This is important for merging cmdsets described below.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">aliases</span></code> (optional list) - a list of alternate names for the command (<code class="docutils literal notranslate"><span class="pre">[&quot;glance&quot;,</span> <span class="pre">&quot;see&quot;,</span> <span class="pre">&quot;l&quot;]</span></code>).
Same name rules as for <code class="docutils literal notranslate"><span class="pre">key</span></code> applies.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> (string) - a <a class="reference internal" href="Locks.html"><span class="doc">lock definition</span></a>, usually on the form <code class="docutils literal notranslate"><span class="pre">cmd:&lt;lockfuncs&gt;</span></code>. Locks is a
rather big topic, so until you learn more about locks, stick to giving the lockstring <code class="docutils literal notranslate"><span class="pre">&quot;cmd:all()&quot;</span></code>
to make the command available to everyone (if you dont provide a lock string, this will be assigned
for you).</p></li>
<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 external" href="Components/Commands.html#on-arg_regex">See the arg_regex section</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 external" href="Components/Help-System.html#command-auto-help-system">auto-help system</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">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 servers <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code>.</p></li>
</ul>
<p>You should also implement at least two methods, <code class="docutils literal notranslate"><span class="pre">parse()</span></code> and <code class="docutils literal notranslate"><span class="pre">func()</span></code> (You could also implement
<code class="docutils literal notranslate"><span class="pre">perm()</span></code>, but thats not needed unless you want to fundamentally change how access checks work).</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">at_pre_cmd()</span></code> is called very first on the command. If this function returns anything that
evaluates to <code class="docutils literal notranslate"><span class="pre">True</span></code> the command execution is aborted at this point.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">parse()</span></code> is intended to parse the arguments (<code class="docutils literal notranslate"><span class="pre">self.args</span></code>) of the function. You can do this in any
way you like, then store the result(s) in variable(s) on the command object itself (i.e. on <code class="docutils literal notranslate"><span class="pre">self</span></code>).
To take an example, the default mux-like system uses this method to detect “command switches” and
store them as a list in <code class="docutils literal notranslate"><span class="pre">self.switches</span></code>. Since the parsing is usually quite similar inside a command
scheme you should make <code class="docutils literal notranslate"><span class="pre">parse()</span></code> as generic as possible and then inherit from it rather than re-
implementing it over and over. In this way, the default <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> class implements a <code class="docutils literal notranslate"><span class="pre">parse()</span></code>
for all child commands to use.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">func()</span></code> is called right after <code class="docutils literal notranslate"><span class="pre">parse()</span></code> and should make use of the pre-parsed input to actually
do whatever the command is supposed to do. This is the main body of the command. The return value
from this method will be returned from the execution as a Twisted Deferred.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_post_cmd()</span></code> is called after <code class="docutils literal notranslate"><span class="pre">func()</span></code> to handle eventual cleanup.</p></li>
</ul>
<p>Finally, you should always make an informative <a class="reference external" href="http://www.python.org/dev/peps/pep-0257/#what-is-a-docstring">doc
string</a> (<code class="docutils literal notranslate"><span class="pre">__doc__</span></code>) at the top of your
class. This string is dynamically read by the <a class="reference internal" href="Help-System.html"><span class="doc">Help System</span></a> to create the help entry
for this command. You should decide on a way to format your help and stick to that.</p>
<p>Below is how you define a simple alternative “<code class="docutils literal notranslate"><span class="pre">smile</span></code>” command:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40</pre></div></td><td class="code"><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">CmdSmile</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A smile command</span>
<span class="sd"> Usage:</span>
<span class="sd"> smile [at] [&lt;someone&gt;]</span>
<span class="sd"> grin [at] [&lt;someone&gt;]</span>
<span class="sd"> Smiles to someone in your vicinity or to the room</span>
<span class="sd"> in general.</span>
<span class="sd"> (This initial string (the __doc__ string)</span>
<span class="sd"> is also used to auto-generate the help</span>
<span class="sd"> for this command)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;smile&quot;</span>
<span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;smile at&quot;</span><span class="p">,</span> <span class="s2">&quot;grin&quot;</span><span class="p">,</span> <span class="s2">&quot;grin at&quot;</span><span class="p">]</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:all()&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;General&quot;</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;Very trivial parser&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">strip</span><span class="p">()</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="s2">&quot;This actually does things&quot;</span>
<span class="n">caller</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="ow">or</span> <span class="bp">self</span><span class="o">.</span><span class="n">target</span> <span class="o">==</span> <span class="s2">&quot;here&quot;</span><span class="p">:</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">f</span><span class="s2">&quot;{caller.key} smiles&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">target</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">target</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">target</span><span class="p">:</span>
<span class="k">return</span>
<span class="n">string</span> <span class="o">=</span> <span class="n">f</span><span class="s2">&quot;{caller.key} smiles at {target.key}&quot;</span>
<span class="n">caller</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>The power of having commands as classes and to separate <code class="docutils literal notranslate"><span class="pre">parse()</span></code> and <code class="docutils literal notranslate"><span class="pre">func()</span></code>
lies in the ability to inherit functionality without having to parse every
command individually. For example, as mentioned the default commands all
inherit from <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code>. <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> implements its own version of <code class="docutils literal notranslate"><span class="pre">parse()</span></code>
that understands all the specifics of MUX-like commands. Almost none of the
default commands thus need to implement <code class="docutils literal notranslate"><span class="pre">parse()</span></code> at all, but can assume the
incoming string is already split up and parsed in suitable ways by its parent.</p>
<p>Before you can actually use the command in your game, you must now store it
within a <em>command set</em>. See the <a class="reference internal" href="Command-Sets.html"><span class="doc">Command Sets</span></a> page.</p>
</div>
<div class="section" id="on-arg-regex">
<h3>On arg_regex<a class="headerlink" href="#on-arg-regex" title="Permalink to this headline"></a></h3>
<p>The command parser is very general and does not require a space to end your command name. This means
that the alias <code class="docutils literal notranslate"><span class="pre">:</span></code> to <code class="docutils literal notranslate"><span class="pre">emote</span></code> can be used like <code class="docutils literal notranslate"><span class="pre">:smiles</span></code> without modification. It also means
<code class="docutils literal notranslate"><span class="pre">getstone</span></code> will get you the stone (unless there is a command specifically named <code class="docutils literal notranslate"><span class="pre">getstone</span></code>, then
that will be used). If you want to tell the parser to require a certain separator between the
command name and its arguments (so that <code class="docutils literal notranslate"><span class="pre">get</span> <span class="pre">stone</span></code> works but <code class="docutils literal notranslate"><span class="pre">getstone</span></code> gives you a command not
found error) you can do so with the <code class="docutils literal notranslate"><span class="pre">arg_regex</span></code> property.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">arg_regex</span></code> is a <a class="reference external" href="http://docs.python.org/library/re.html">raw regular expression string</a>. The
regex will be compiled by the system at runtime. This allows you to customize how the part
<em>immediately following</em> the command name (or alias) must look in order for the parser to match for
this command. Some examples:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">commandname</span> <span class="pre">argument</span></code> (<code class="docutils literal notranslate"><span class="pre">arg_regex</span> <span class="pre">=</span> <span class="pre">r&quot;\s.+&quot;</span></code>): This forces the parser to require the command name
to be followed by one or more spaces. Whatever is entered after the space will be treated as an
argument. However, if youd forget the space (like a command having no arguments), this would <em>not</em>
match <code class="docutils literal notranslate"><span class="pre">commandname</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">commandname</span></code> or <code class="docutils literal notranslate"><span class="pre">commandname</span> <span class="pre">argument</span></code> (<code class="docutils literal notranslate"><span class="pre">arg_regex</span> <span class="pre">=</span> <span class="pre">r&quot;\s.+|$&quot;</span></code>): This makes both <code class="docutils literal notranslate"><span class="pre">look</span></code> and
<code class="docutils literal notranslate"><span class="pre">look</span> <span class="pre">me</span></code> work but <code class="docutils literal notranslate"><span class="pre">lookme</span></code> will not.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">commandname/switches</span> <span class="pre">arguments</span></code> (<code class="docutils literal notranslate"><span class="pre">arg_regex</span> <span class="pre">=</span> <span class="pre">r&quot;(?:^(?:\s+|\/).*$)|^$&quot;</span></code>. If you are using
Evennias <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> Command parent, you may wish to use this since it will allow <code class="docutils literal notranslate"><span class="pre">/switche</span></code>s to
work as well as having or not having a space.</p></li>
</ul>
<p>The <code class="docutils literal notranslate"><span class="pre">arg_regex</span></code> allows you to customize the behavior of your commands. You can put it in the parent
class of your command to customize all children of your Commands. However, you can also change the
base default behavior for all Commands by modifying <code class="docutils literal notranslate"><span class="pre">settings.COMMAND_DEFAULT_ARG_REGEX</span></code>.</p>
</div>
</div>
<div class="section" id="exiting-a-command">
<h2>Exiting a command<a class="headerlink" href="#exiting-a-command" title="Permalink to this headline"></a></h2>
<p>Normally you just use <code class="docutils literal notranslate"><span class="pre">return</span></code> in one of your Command class hook methods to exit that method. That
will however still fire the other hook methods of the Command in sequence. Thats usually what you
want but sometimes it may be useful to just abort the command, for example if you find some
unacceptable input in your parse method. To exit the command this way you can raise
<code class="docutils literal notranslate"><span class="pre">evennia.InterruptCommand</span></code>:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">InterruptCommand</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="c1"># ...</span>
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="c1"># ...</span>
<span class="c1"># if this fires, `func()` and `at_post_cmd` will not</span>
<span class="c1"># be called at all</span>
<span class="k">raise</span> <span class="n">InterruptCommand</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="pauses-in-commands">
<h2>Pauses in commands<a class="headerlink" href="#pauses-in-commands" title="Permalink to this headline"></a></h2>
<p>Sometimes you want to pause the execution of your command for a little while before continuing -
maybe you want to simulate a heavy swing taking some time to finish, maybe you want the echo of your
voice to return to you with an ever-longer delay. Since Evennia is running asynchronously, you
cannot use <code class="docutils literal notranslate"><span class="pre">time.sleep()</span></code> in your commands (or anywhere, really). If you do, the <em>entire game</em> will
be frozen for everyone! So dont do that. Fortunately, Evennia offers a really quick syntax for
making pauses in commands.</p>
<p>In your <code class="docutils literal notranslate"><span class="pre">func()</span></code> method, you can use the <code class="docutils literal notranslate"><span class="pre">yield</span></code> keyword. This is a Python keyword that will freeze
the current execution of your command and wait for more before processing.</p>
<blockquote>
<div><p>Note that you <em>cannot</em> just drop <code class="docutils literal notranslate"><span class="pre">yield</span></code> into any code and expect it to pause. Evennia will only
pause for you if you <code class="docutils literal notranslate"><span class="pre">yield</span></code> inside the Commands <code class="docutils literal notranslate"><span class="pre">func()</span></code> method. Dont expect it to work anywhere
else.</p>
</div></blockquote>
<p>Heres an example of a command using a small pause of five seconds between messages:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22</pre></div></td><td class="code"><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">CmdWait</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A dummy command to show how to wait</span>
<span class="sd"> Usage:</span>
<span class="sd"> wait</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;wait&quot;</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:all()&quot;</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;General&quot;</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="sd">&quot;&quot;&quot;Command execution.&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Starting to wait ...&quot;</span><span class="p">)</span>
<span class="k">yield</span> <span class="mi">5</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;... This shows after 5 seconds. Waiting ...&quot;</span><span class="p">)</span>
<span class="k">yield</span> <span class="mi">2</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;... And now another 2 seconds have passed.&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>The important line is the <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">5</span></code> and <code class="docutils literal notranslate"><span class="pre">yield</span> <span class="pre">2</span></code> lines. It will tell Evennia to pause execution
here and not continue until the number of seconds given has passed.</p>
<p>There are two things to remember when using <code class="docutils literal notranslate"><span class="pre">yield</span></code> in your Commands <code class="docutils literal notranslate"><span class="pre">func</span></code> method:</p>
<ol class="simple">
<li><p>The paused state produced by the <code class="docutils literal notranslate"><span class="pre">yield</span></code> is not saved anywhere. So if the server reloads in the
middle of your command pausing, it will <em>not</em> resume when the server comes back up - the remainder
of the command will never fire. So be careful that you are not freezing the character or account in
a way that will not be cleared on reload.</p></li>
<li><p>If you use <code class="docutils literal notranslate"><span class="pre">yield</span></code> you may not also use <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre">&lt;values&gt;</span></code> in your <code class="docutils literal notranslate"><span class="pre">func</span></code> method. Youll get an
error explaining this. This is due to how Python generators work. You can however use a “naked”
<code class="docutils literal notranslate"><span class="pre">return</span></code> just fine. Usually there is no need for <code class="docutils literal notranslate"><span class="pre">func</span></code> to return a value, but if you ever do need
to mix <code class="docutils literal notranslate"><span class="pre">yield</span></code> with a final return value in the same <code class="docutils literal notranslate"><span class="pre">func</span></code>, look at
<a class="reference external" href="https://twistedmatrix.com/documents/current/api/twisted.internet.defer.html#returnValue">twisted.internet.defer.returnValue</a>.</p></li>
</ol>
</div>
<div class="section" id="asking-for-user-input">
<h2>Asking for user input<a class="headerlink" href="#asking-for-user-input" title="Permalink to this headline"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">yield</span></code> keyword can also be used to ask for user input. Again you cant
use Pythons <code class="docutils literal notranslate"><span class="pre">input</span></code> in your command, for it would freeze Evennia for
everyone while waiting for that user to input their text. Inside a Commands
<code class="docutils literal notranslate"><span class="pre">func</span></code> method, the following syntax can also be used:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">answer</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">&quot;Your question&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Heres a very simple example:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CmdConfirm</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A dummy command to show confirmation.</span>
<span class="sd"> Usage:</span>
<span class="sd"> confirm</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;confirm&quot;</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">answer</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">&quot;Are you sure you want to go on?&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">answer</span><span class="o">.</span><span class="n">strip</span><span class="p">()</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">&quot;yes&quot;</span><span class="p">,</span> <span class="s2">&quot;y&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Yes!&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;No!&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>This time, when the user enters the confirm command, she will be asked if she wants to go on.
Entering yes or “y” (regardless of case) will give the first reply, otherwise the second reply
will show.</p>
<blockquote>
<div><p>Note again that the <code class="docutils literal notranslate"><span class="pre">yield</span></code> keyword does not store state. If the game reloads while waiting for
the user to answer, the user will have to start over. It is not a good idea to use <code class="docutils literal notranslate"><span class="pre">yield</span></code> for
important or complex choices, a persistent <a class="reference internal" href="EvMenu.html"><span class="doc">EvMenu</span></a> might be more appropriate in this case.</p>
</div></blockquote>
</div>
<div class="section" id="system-commands">
<h2>System commands<a class="headerlink" href="#system-commands" title="Permalink to this headline"></a></h2>
<p><em>Note: This is an advanced topic. Skip it if this is your first time learning about commands.</em></p>
<p>There are several command-situations that are exceptional in the eyes of the server. What happens if
the account enters an empty string? What if the command given is infact the name of a channel the
user wants to send a message to? Or if there are multiple command possibilities?</p>
<p>Such special cases are handled by whats called <em>system commands</em>. A system command is defined
in the same way as other commands, except that their name (key) must be set to one reserved by the
engine (the names are defined at the top of <code class="docutils literal notranslate"><span class="pre">evennia/commands/cmdhandler.py</span></code>). You can find (unused)
implementations of the system commands in <code class="docutils literal notranslate"><span class="pre">evennia/commands/default/system_commands.py</span></code>. Since these
are not (by default) included in any <code class="docutils literal notranslate"><span class="pre">CmdSet</span></code> they are not actually used, they are just there for
show. When the special situation occurs, Evennia will look through all valid <code class="docutils literal notranslate"><span class="pre">CmdSet</span></code>s for your
custom system command. Only after that will it resort to its own, hard-coded implementation.</p>
<p>Here are the exceptional situations that triggers system commands. You can find the command keys
they use as properties on <code class="docutils literal notranslate"><span class="pre">evennia.syscmdkeys</span></code>:</p>
<ul class="simple">
<li><p>No input (<code class="docutils literal notranslate"><span class="pre">syscmdkeys.CMD_NOINPUT</span></code>) - the account just pressed return without any input. Default
is to do nothing, but it can be useful to do something here for certain implementations such as line
editors that interpret non-commands as text input (an empty line in the editing buffer).</p></li>
<li><p>Command not found (<code class="docutils literal notranslate"><span class="pre">syscmdkeys.CMD_NOMATCH</span></code>) - No matching command was found. Default is to
display the “Huh?” error message.</p></li>
<li><p>Several matching commands where found (<code class="docutils literal notranslate"><span class="pre">syscmdkeys.CMD_MULTIMATCH</span></code>) - Default is to show a list of
matches.</p></li>
<li><p>User is not allowed to execute the command (<code class="docutils literal notranslate"><span class="pre">syscmdkeys.CMD_NOPERM</span></code>) - Default is to display the
“Huh?” error message.</p></li>
<li><p>Channel (<code class="docutils literal notranslate"><span class="pre">syscmdkeys.CMD_CHANNEL</span></code>) - This is a <a class="reference internal" href="Communications.html"><span class="doc">Channel</span></a> name of a channel you are
subscribing to - Default is to relay the commands argument to that channel. Such commands are
created by the Comm system on the fly depending on your subscriptions.</p></li>
<li><p>New session connection (<code class="docutils literal notranslate"><span class="pre">syscmdkeys.CMD_LOGINSTART</span></code>). This command name should be put in the
<code class="docutils literal notranslate"><span class="pre">settings.CMDSET_UNLOGGEDIN</span></code>. Whenever a new connection is established, this command is always
called on the server (default is to show the login screen).</p></li>
</ul>
<p>Below is an example of redefining what happens when the account doesnt provide any input (e.g. just
presses return). Of course the new system command must be added to a cmdset as well before it will
work.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">syscmdkeys</span><span class="p">,</span> <span class="n">Command</span>
<span class="k">class</span> <span class="nc">MyNoInputCommand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="s2">&quot;Usage: Just press return, I dare you&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="n">syscmdkeys</span><span class="o">.</span><span class="n">CMD_NOINPUT</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="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="s2">&quot;Don&#39;t just press return like that, talk to me!&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="dynamic-commands">
<h2>Dynamic Commands<a class="headerlink" href="#dynamic-commands" title="Permalink to this headline"></a></h2>
<p><em>Note: This is an advanced topic.</em></p>
<p>Normally Commands are created as fixed classes and used without modification. There are however
situations when the exact key, alias or other properties is not possible (or impractical) to pre-
code (<a class="reference external" href="Components/Commands.html#Exits">Exits</a> is an example of this).</p>
<p>To create a command with a dynamic call signature, first define the command body normally in a class
(set your <code class="docutils literal notranslate"><span class="pre">key</span></code>, <code class="docutils literal notranslate"><span class="pre">aliases</span></code> to default values), then use the following call (assuming the command
class you created is named <code class="docutils literal notranslate"><span class="pre">MyCommand</span></code>):</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">cmd</span> <span class="o">=</span> <span class="n">MyCommand</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">&quot;newname&quot;</span><span class="p">,</span>
<span class="n">aliases</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;test&quot;</span><span class="p">,</span> <span class="s2">&quot;test2&quot;</span><span class="p">],</span>
<span class="n">locks</span><span class="o">=</span><span class="s2">&quot;cmd:all()&quot;</span><span class="p">,</span>
<span class="o">...</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p><em>All</em> keyword arguments you give to the Command constructor will be stored as a property on the
command object. This will overload existing properties defined on the parent class.</p>
<p>Normally you would define your class and only overload things like <code class="docutils literal notranslate"><span class="pre">key</span></code> and <code class="docutils literal notranslate"><span class="pre">aliases</span></code> at run-time.
But you could in principle also send method objects (like <code class="docutils literal notranslate"><span class="pre">func</span></code>) as keyword arguments in order to
make your command completely customized at run-time.</p>
</div>
<div class="section" id="exits">
<h2>Exits<a class="headerlink" href="#exits" title="Permalink to this headline"></a></h2>
<p><em>Note: This is an advanced topic.</em></p>
<p>Exits are examples of the use of a <a class="reference external" href="Components/Commands.html#Dynamic_Commands">Dynamic Command</a>.</p>
<p>The functionality of <a class="reference internal" href="Objects.html"><span class="doc">Exit</span></a> objects in Evennia is not hard-coded in the engine. Instead
Exits are normal <a class="reference internal" href="Typeclasses.html"><span class="doc">typeclassed</span></a> objects that auto-create a <a class="reference external" href="Components/Commands.html#CmdSets">CmdSet</a> on
themselves when they load. This cmdset has a single dynamically created Command with the same
properties (key, aliases and locks) as the Exit object itself. When entering the name of the exit,
this dynamic exit-command is triggered and (after access checks) moves the Character to the exits
destination.
Whereas you could customize the Exit object and its command to achieve completely different
behaviour, you will usually be fine just using the appropriate <code class="docutils literal notranslate"><span class="pre">traverse_*</span></code> hooks on the Exit
object. But if you are interested in really changing how things work under the hood, check out
<code class="docutils literal notranslate"><span class="pre">evennia/objects/objects.py</span></code> for how the <code class="docutils literal notranslate"><span class="pre">Exit</span></code> typeclass is set up.</p>
</div>
<div class="section" id="command-instances-are-re-used">
<h2>Command instances are re-used<a class="headerlink" href="#command-instances-are-re-used" title="Permalink to this headline"></a></h2>
<p><em>Note: This is an advanced topic that can be skipped when first learning about Commands.</em></p>
<p>A Command class sitting on an object is instantiated once and then re-used. So if you run a command
from object1 over and over you are in fact running the same command instance over and over (if you
run the same command but sitting on object2 however, it will be a different instance). This is
usually not something youll notice, since every time the Command-instance is used, all the relevant
properties on it will be overwritten. But armed with this knowledge you can implement some of the
more exotic command mechanism out there, like the command having a memory of what you last entered
so that you can back-reference the previous arguments etc.</p>
<blockquote>
<div><p>Note: On a server reload, all Commands are rebuilt and memory is flushed.</p>
</div></blockquote>
<p>To show this in practice, consider this command:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">CmdTestID</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">&quot;testid&quot;</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="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="s2">&quot;xval&quot;</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">xval</span> <span class="o">=</span> <span class="mi">0</span>
<span class="bp">self</span><span class="o">.</span><span class="n">xval</span> <span class="o">+=</span> <span class="mi">1</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="s2">&quot;Command memory ID: {} (xval={})&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="nb">id</span><span class="p">(</span><span class="bp">self</span><span class="p">),</span> <span class="bp">self</span><span class="o">.</span><span class="n">xval</span><span class="p">))</span>
</pre></div>
</td></tr></table></div>
<p>Adding this to the default character cmdset gives a result like this in-game:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">testid</span>
<span class="n">Command</span> <span class="n">memory</span> <span class="n">ID</span><span class="p">:</span> <span class="mi">140313967648552</span> <span class="p">(</span><span class="n">xval</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span>
<span class="o">&gt;</span> <span class="n">testid</span>
<span class="n">Command</span> <span class="n">memory</span> <span class="n">ID</span><span class="p">:</span> <span class="mi">140313967648552</span> <span class="p">(</span><span class="n">xval</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="o">&gt;</span> <span class="n">testid</span>
<span class="n">Command</span> <span class="n">memory</span> <span class="n">ID</span><span class="p">:</span> <span class="mi">140313967648552</span> <span class="p">(</span><span class="n">xval</span><span class="o">=</span><span class="mi">3</span><span class="p">)</span>
</pre></div>
</div>
<p>Note how the in-memory address of the <code class="docutils literal notranslate"><span class="pre">testid</span></code> command never changes, but <code class="docutils literal notranslate"><span class="pre">xval</span></code> keeps ticking up.</p>
</div>
<div class="section" id="dynamically-created-commands">
<h2>Dynamically created commands<a class="headerlink" href="#dynamically-created-commands" title="Permalink to this headline"></a></h2>
<p><em>This is also an advanced topic.</em></p>
<p>Commands can also be created and added to a cmdset on the fly. Creating a class instance with a
keyword argument, will assign that keyword argument as a property on this paricular command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">at_cmdset_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">MyCommand</span><span class="p">(</span><span class="n">myvar</span><span class="o">=</span><span class="mi">1</span><span class="p">,</span> <span class="n">foo</span><span class="o">=</span><span class="s2">&quot;test&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>This will start the <code class="docutils literal notranslate"><span class="pre">MyCommand</span></code> with <code class="docutils literal notranslate"><span class="pre">myvar</span></code> and <code class="docutils literal notranslate"><span class="pre">foo</span></code> set as properties (accessable as <code class="docutils literal notranslate"><span class="pre">self.myvar</span></code>
and <code class="docutils literal notranslate"><span class="pre">self.foo</span></code>). How they are used is up to the Command. Remember however the discussion from the
previous section - since the Command instance is re-used, those properties will <em>remain</em> on the
command as long as this cmdset and the object it sits is in memory (i.e. until the next reload).
Unless <code class="docutils literal notranslate"><span class="pre">myvar</span></code> and <code class="docutils literal notranslate"><span class="pre">foo</span></code> are somehow reset when the command runs, they can be modified and that
change will be remembered for subsequent uses of the command.</p>
</div>
<div class="section" id="how-commands-actually-work">
<h2>How commands actually work<a class="headerlink" href="#how-commands-actually-work" title="Permalink to this headline"></a></h2>
<p><em>Note: This is an advanced topic mainly of interest to server developers.</em></p>
<p>Any time the user sends text to Evennia, the server tries to figure out if the text entered
corresponds to a known command. This is how the command handler sequence looks for a logged-in user:</p>
<ol class="simple">
<li><p>A user enters a string of text and presses enter.</p></li>
<li><p>The users Session determines the text is not some protocol-specific control sequence or OOB
command, but sends it on to the command handler.</p></li>
<li><p>Evennias <em>command handler</em> analyzes the Session and grabs eventual references to Account and
eventual puppeted Characters (these will be stored on the command object later). The <em>caller</em>
property is set appropriately.</p></li>
<li><p>If input is an empty string, resend command as <code class="docutils literal notranslate"><span class="pre">CMD_NOINPUT</span></code>. If no such command is found in
cmdset, ignore.</p></li>
<li><p>If command.key matches <code class="docutils literal notranslate"><span class="pre">settings.IDLE_COMMAND</span></code>, update timers but dont do anything more.</p></li>
<li><p>The command handler gathers the CmdSets available to <em>caller</em> at this time:</p>
<ul class="simple">
<li><p>The callers own currently active CmdSet.</p></li>
<li><p>CmdSets defined on the current account, if caller is a puppeted object.</p></li>
<li><p>CmdSets defined on the Session itself.</p></li>
<li><p>The active CmdSets of eventual objects in the same location (if any). This includes commands
on <a class="reference external" href="Components/Objects.html#Exits">Exits</a>.</p></li>
<li><p>Sets of dynamically created <em>System commands</em> representing available
<a class="reference external" href="Components/Communications.html#Channels">Communications</a>.</p></li>
</ul>
</li>
<li><p>All CmdSets <em>of the same priority</em> are merged together in groups. Grouping avoids order-
dependent issues of merging multiple same-prio sets onto lower ones.</p></li>
<li><p>All the grouped CmdSets are <em>merged</em> in reverse priority into one combined CmdSet according to
each sets merge rules.</p></li>
<li><p>Evennias <em>command parser</em> takes the merged cmdset and matches each of its commands (using its
key and aliases) against the beginning of the string entered by <em>caller</em>. This produces a set of
candidates.</p></li>
<li><p>The <em>cmd parser</em> next rates the matches by how many characters they have and how many percent
matches the respective known command. Only if candidates cannot be separated will it return multiple
matches.</p>
<ul class="simple">
<li><p>If multiple matches were returned, resend as <code class="docutils literal notranslate"><span class="pre">CMD_MULTIMATCH</span></code>. If no such command is found in
cmdset, return hard-coded list of matches.</p></li>
<li><p>If no match was found, resend as <code class="docutils literal notranslate"><span class="pre">CMD_NOMATCH</span></code>. If no such command is found in cmdset, give
hard-coded error message.</p></li>
</ul>
</li>
<li><p>If a single command was found by the parser, the correct command object is plucked out of
storage. This usually doesnt mean a re-initialization.</p></li>
<li><p>It is checked that the caller actually has access to the command by validating the <em>lockstring</em>
of the command. If not, it is not considered as a suitable match and <code class="docutils literal notranslate"><span class="pre">CMD_NOMATCH</span></code> is triggered.</p></li>
<li><p>If the new command is tagged as a channel-command, resend as <code class="docutils literal notranslate"><span class="pre">CMD_CHANNEL</span></code>. If no such command
is found in cmdset, use hard-coded implementation.</p></li>
<li><p>Assign several useful variables to the command instance (see previous sections).</p></li>
<li><p>Call <code class="docutils literal notranslate"><span class="pre">at_pre_command()</span></code> on the command instance.</p></li>
<li><p>Call <code class="docutils literal notranslate"><span class="pre">parse()</span></code> on the command instance. This is fed the remainder of the string, after the name
of the command. Its intended to pre-parse the string into a form useful for the <code class="docutils literal notranslate"><span class="pre">func()</span></code> method.</p></li>
<li><p>Call <code class="docutils literal notranslate"><span class="pre">func()</span></code> on the command instance. This is the functional body of the command, actually
doing useful things.</p></li>
<li><p>Call <code class="docutils literal notranslate"><span class="pre">at_post_command()</span></code> on the command instance.</p></li>
</ol>
</div>
<div class="section" id="assorted-notes">
<h2>Assorted notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline"></a></h2>
<p>The return value of <code class="docutils literal notranslate"><span class="pre">Command.func()</span></code> is a Twisted
<a class="reference external" href="http://twistedmatrix.com/documents/current/core/howto/defer.html">deferred</a>.
Evennia does not use this return value at all by default. If you do, you must
thus do so asynchronously, using callbacks.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># in command class func()</span>
<span class="k">def</span> <span class="nf">callback</span><span class="p">(</span><span class="n">ret</span><span class="p">,</span> <span class="n">caller</span><span class="p">):</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Returned is </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="n">ret</span><span class="p">)</span>
<span class="n">deferred</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">execute_command</span><span class="p">(</span><span class="s2">&quot;longrunning&quot;</span><span class="p">)</span>
<span class="n">deferred</span><span class="o">.</span><span class="n">addCallback</span><span class="p">(</span><span class="n">callback</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>This is probably not relevant to any but the most advanced/exotic designs (one might use it to
create a “nested” command structure for example).</p>
<p>The <code class="docutils literal notranslate"><span class="pre">save_for_next</span></code> class variable can be used to implement state-persistent commands. For example
it can make a command operate on “it”, where it is determined by what the previous command operated
on.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Commands</a><ul>
<li><a class="reference internal" href="#defining-commands">Defining Commands</a><ul>
<li><a class="reference internal" href="#who-is-calling-the-command">Who is calling the command?</a></li>
<li><a class="reference internal" href="#properties-assigned-to-the-command-instance-at-run-time">Properties assigned to the command instance at run-time</a><ul>
<li><a class="reference internal" href="#other-useful-utility-methods">Other useful utility methods:</a></li>
</ul>
</li>
<li><a class="reference internal" href="#defining-your-own-command-classes">Defining your own command classes</a></li>
<li><a class="reference internal" href="#on-arg-regex">On arg_regex</a></li>
</ul>
</li>
<li><a class="reference internal" href="#exiting-a-command">Exiting a command</a></li>
<li><a class="reference internal" href="#pauses-in-commands">Pauses in commands</a></li>
<li><a class="reference internal" href="#asking-for-user-input">Asking for user input</a></li>
<li><a class="reference internal" href="#system-commands">System commands</a></li>
<li><a class="reference internal" href="#dynamic-commands">Dynamic Commands</a></li>
<li><a class="reference internal" href="#exits">Exits</a></li>
<li><a class="reference internal" href="#command-instances-are-re-used">Command instances are re-used</a></li>
<li><a class="reference internal" href="#dynamically-created-commands">Dynamically created commands</a></li>
<li><a class="reference internal" href="#how-commands-actually-work">How commands actually work</a></li>
<li><a class="reference internal" href="#assorted-notes">Assorted notes</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Commands.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Commands</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,223 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Communications &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Communications</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="communications">
<h1>Communications<a class="headerlink" href="#communications" title="Permalink to this headline"></a></h1>
<p>Apart from moving around in the game world and talking, players might need other forms of
communication. This is offered by Evennias <code class="docutils literal notranslate"><span class="pre">Comm</span></code> system. Stock evennia implements a MUX-like
system of channels, but there is nothing stopping you from changing things to better suit your
taste.</p>
<p>Comms rely on two main database objects - <code class="docutils literal notranslate"><span class="pre">Msg</span></code> and <code class="docutils literal notranslate"><span class="pre">Channel</span></code>. There is also the <code class="docutils literal notranslate"><span class="pre">TempMsg</span></code> which
mimics the API of a <code class="docutils literal notranslate"><span class="pre">Msg</span></code> but has no connection to the database.</p>
<div class="section" id="msg">
<h2>Msg<a class="headerlink" href="#msg" title="Permalink to this headline"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">Msg</span></code> object is the basic unit of communication in Evennia. A message works a little like an
e-mail; it always has a sender (a <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a>) and one or more recipients. The recipients
may be either other Accounts, or a <em>Channel</em> (see below). You can mix recipients to send the message
to both Channels and Accounts if you like.</p>
<p>Once created, a <code class="docutils literal notranslate"><span class="pre">Msg</span></code> is normally not changed. It is peristently saved in the database. This allows
for comprehensive logging of communications. This could be useful for allowing senders/receivers to
have mailboxes with the messages they want to keep.</p>
<div class="section" id="properties-defined-on-msg">
<h3>Properties defined on <code class="docutils literal notranslate"><span class="pre">Msg</span></code><a class="headerlink" href="#properties-defined-on-msg" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">senders</span></code> - this is a reference to one or many <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a> or <a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a> (normally
<em>Characters</em>) sending the message. This could also be an <em>External Connection</em> such as a message
coming in over IRC/IMC2 (see below). There is usually only one sender, but the types can also be
mixed in any combination.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">receivers</span></code> - a list of target <a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a> (usually <em>Characters</em>) or
<em>Channels</em> to send the message to. The types of receivers can be mixed in any combination.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">header</span></code> - this is a text field for storing a title or header for the message.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">message</span></code> - the actual text being sent.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">date_sent</span></code> - when message was sent (auto-created).</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">lock definition</span></a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">hide_from</span></code> - this can optionally hold a list of objects, accounts or channels to hide this <code class="docutils literal notranslate"><span class="pre">Msg</span></code>
from. This relationship is stored in the database primarily for optimization reasons, allowing for
quickly post-filter out messages not intended for a given target. There is no in-game methods for
setting this, its intended to be done in code.</p></li>
</ul>
<p>You create new messages in code using <code class="docutils literal notranslate"><span class="pre">evennia.create_message</span></code> (or
<code class="docutils literal notranslate"><span class="pre">evennia.utils.create.create_message.</span></code>)</p>
</div>
</div>
<div class="section" id="tempmsg">
<h2>TempMsg<a class="headerlink" href="#tempmsg" title="Permalink to this headline"></a></h2>
<p><code class="docutils literal notranslate"><span class="pre">evennia.comms.models</span></code> also has <code class="docutils literal notranslate"><span class="pre">TempMsg</span></code> which mimics the API of <code class="docutils literal notranslate"><span class="pre">Msg</span></code> but is not connected to the
database. TempMsgs are used by Evennia for channel messages by default. They can be used for any
system expecting a <code class="docutils literal notranslate"><span class="pre">Msg</span></code> but when you dont actually want to save anything.</p>
</div>
<div class="section" id="channels">
<h2>Channels<a class="headerlink" href="#channels" title="Permalink to this headline"></a></h2>
<p>Channels are <a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclassed</span></a> entities, which mean they can be easily extended and their
functionality modified. To change which channel typeclass Evennia uses, change
settings.BASE_CHANNEL_TYPECLASS.</p>
<p>Channels act as generic distributors of messages. Think of them as “switch boards” redistributing
<code class="docutils literal notranslate"><span class="pre">Msg</span></code> or <code class="docutils literal notranslate"><span class="pre">TempMsg</span></code> objects. Internally they hold a list of “listening” objects and any <code class="docutils literal notranslate"><span class="pre">Msg</span></code> (or
<code class="docutils literal notranslate"><span class="pre">TempMsg</span></code>) sent to the channel will be distributed out to all channel listeners. Channels have
<a class="reference internal" href="Locks.html"><span class="doc">Locks</span></a> to limit who may listen and/or send messages through them.</p>
<p>The <em>sending</em> of text to a channel is handled by a dynamically created <a class="reference internal" href="Commands.html"><span class="doc">Command</span></a> that
always have the same name as the channel. This is created for each channel by the global
<code class="docutils literal notranslate"><span class="pre">ChannelHandler</span></code>. The Channel command is added to the Accounts cmdset and normal command locks are
used to determine which channels are possible to write to. When subscribing to a channel, you can
then just write the channel name and the text to send.</p>
<p>The default ChannelCommand (which can be customized by pointing <code class="docutils literal notranslate"><span class="pre">settings.CHANNEL_COMMAND_CLASS</span></code> to
your own command), implements a few convenient features:</p>
<ul>
<li><p>It only sends <code class="docutils literal notranslate"><span class="pre">TempMsg</span></code> objects. Instead of storing individual entries in the database it instead
dumps channel output a file log in <code class="docutils literal notranslate"><span class="pre">server/logs/channel_&lt;channelname&gt;.log</span></code>. This is mainly for
practical reasons - we find one rarely need to query individual Msg objects at a later date. Just
stupidly dumping the log to a file also means a lot less database overhead.</p></li>
<li><p>It adds a <code class="docutils literal notranslate"><span class="pre">/history</span></code> switch to view the 20 last messages in the channel. These are read from the
end of the log file. One can also supply a line number to start further back in the file (but always
20 entries at a time). Its used like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="n">public</span><span class="o">/</span><span class="n">history</span>
<span class="o">&gt;</span> <span class="n">public</span><span class="o">/</span><span class="n">history</span> <span class="mi">35</span>
</pre></div>
</div>
</li>
</ul>
<p>There are two default channels created in stock Evennia - <code class="docutils literal notranslate"><span class="pre">MudInfo</span></code> and <code class="docutils literal notranslate"><span class="pre">Public</span></code>. <code class="docutils literal notranslate"><span class="pre">MudInfo</span></code>
receives server-related messages meant for Admins whereas <code class="docutils literal notranslate"><span class="pre">Public</span></code> is open to everyone to chat on
(all new accounts are automatically joined to it when logging in, it is useful for asking
questions). The default channels are defined by the <code class="docutils literal notranslate"><span class="pre">DEFAULT_CHANNELS</span></code> list (see
<code class="docutils literal notranslate"><span class="pre">evennia/settings_default.py</span></code> for more details).</p>
<p>You create new channels with <code class="docutils literal notranslate"><span class="pre">evennia.create_channel</span></code> (or <code class="docutils literal notranslate"><span class="pre">evennia.utils.create.create_channel</span></code>).</p>
<p>In code, messages are sent to a channel using the <code class="docutils literal notranslate"><span class="pre">msg</span></code> or <code class="docutils literal notranslate"><span class="pre">tempmsg</span></code> methods of channels:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">channel</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">msgobj</span><span class="p">,</span> <span class="n">header</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">senders</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>The argument <code class="docutils literal notranslate"><span class="pre">msgobj</span></code> can be either a string, a previously constructed <code class="docutils literal notranslate"><span class="pre">Msg</span></code> or a <code class="docutils literal notranslate"><span class="pre">TempMsg</span></code> - in the
latter cases all the following keywords are ignored since the message objects already contains all
this information. If <code class="docutils literal notranslate"><span class="pre">msgobj</span></code> is a string, the other keywords are used for creating a new <code class="docutils literal notranslate"><span class="pre">Msg</span></code> or
<code class="docutils literal notranslate"><span class="pre">TempMsg</span></code> on the fly, depending on if <code class="docutils literal notranslate"><span class="pre">persistent</span></code> is set or not. By default, a <code class="docutils literal notranslate"><span class="pre">TempMsg</span></code> is emitted
for channel communication (since the default ChannelCommand instead logs to a file).</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># assume we have a &#39;sender&#39; object and a channel named &#39;mychan&#39;</span>
<span class="c1"># manually sending a message to a channel</span>
<span class="n">mychan</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Hello!&quot;</span><span class="p">,</span> <span class="n">senders</span><span class="o">=</span><span class="p">[</span><span class="n">sender</span><span class="p">])</span>
</pre></div>
</td></tr></table></div>
<div class="section" id="properties-defined-on-channel">
<h3>Properties defined on <code class="docutils literal notranslate"><span class="pre">Channel</span></code><a class="headerlink" href="#properties-defined-on-channel" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - main name for channel</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">aliases</span></code> - alternative native names for channels</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">desc</span></code> - optional description of channel (seen in listings)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">keep_log</span></code> (bool) - if the channel should store messages (default)</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">lock definition</span></a>. Channels normally use the access_types <code class="docutils literal notranslate"><span class="pre">send,</span> <span class="pre">control</span></code> and
<code class="docutils literal notranslate"><span class="pre">listen</span></code>.</p></li>
</ul>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Communications</a><ul>
<li><a class="reference internal" href="#msg">Msg</a><ul>
<li><a class="reference internal" href="#properties-defined-on-msg">Properties defined on <code class="docutils literal notranslate"><span class="pre">Msg</span></code></a></li>
</ul>
</li>
<li><a class="reference internal" href="#tempmsg">TempMsg</a></li>
<li><a class="reference internal" href="#channels">Channels</a><ul>
<li><a class="reference internal" href="#properties-defined-on-channel">Properties defined on <code class="docutils literal notranslate"><span class="pre">Channel</span></code></a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Communications.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Communications.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Communications</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,189 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Core Components &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Core Components</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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">API</span></a>.</p>
<div class="section" id="database-entites">
<h2>Database entites<a class="headerlink" href="#database-entites" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p><a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclasses</span></a></p>
<ul>
<li><p><a class="reference internal" href="Sessions.html"><span class="doc">Sessions</span></a></p></li>
<li><p><a class="reference internal" href="Accounts.html"><span class="doc">Acccounts</span></a></p>
<ul>
<li><p><a class="reference internal" href="../Concepts/Guest-Logins.html"><span class="doc">Guests</span></a></p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a></p></li>
<li><p><a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a></p></li>
<li><p><a class="reference internal" href="Communications.html"><span class="doc">Channels and Messages</span></a></p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a></p></li>
<li><p><a class="reference internal" href="Nicks.html"><span class="doc">Nicks</span></a></p></li>
<li><p><a class="reference internal" href="Tags.html"><span class="doc">Tags</span></a></p></li>
<li><p><a class="reference internal" href="Spawner-and-Prototypes.html"><span class="doc">Spawner and prototypes</span></a></p></li>
<li><p><a class="reference internal" href="Help-System.html"><span class="doc">Help entries</span></a></p></li>
</ul>
</div>
<div class="section" id="commands">
<h2>Commands<a class="headerlink" href="#commands" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p><a class="reference internal" href="Command-System.html"><span class="doc">Command system</span></a></p>
<ul>
<li><p><a class="reference internal" href="Commands.html"><span class="doc">Commands</span></a></p></li>
<li><p><a class="reference internal" href="Command-Sets.html"><span class="doc">Command-Sets</span></a></p></li>
<li><p><a class="reference internal" href="Connection-Screen.html"><span class="doc">The Connection Screen</span></a></p></li>
<li><p><a class="reference external" href="../api/evennia.commands.default.html#modules">Available default Commands</a></p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Batch-Processors.html"><span class="doc">Batch-Processors</span></a></p>
<ul>
<li><p><a class="reference internal" href="Batch-Code-Processor.html"><span class="doc">Batch-Code-Processor</span></a></p></li>
<li><p><a class="reference internal" href="Batch-Command-Processor.html"><span class="doc">Batch-Command-Processor</span></a></p></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="utils-and-tools">
<h2>Utils and tools<a class="headerlink" href="#utils-and-tools" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p><a class="reference internal" href="Coding-Utils.html"><span class="doc">Misc Utils</span></a></p></li>
<li><p><a class="reference internal" href="EvEditor.html"><span class="doc">EvEditor</span></a></p></li>
<li><p><a class="reference internal" href="EvMenu.html"><span class="doc">EvMenu</span></a></p></li>
<li><p><a class="reference internal" href="EvMore.html"><span class="doc">EvMore</span></a></p></li>
<li><p><a class="reference internal" href="MonitorHandler.html"><span class="doc">MonitorHandler</span></a></p></li>
<li><p><a class="reference internal" href="TickerHandler.html"><span class="doc">TickerHandler</span></a></p></li>
<li><p><a class="reference internal" href="Locks.html"><span class="doc">Lock system</span></a></p></li>
</ul>
</div>
<div class="section" id="server-and-network">
<h2>Server and network<a class="headerlink" href="#server-and-network" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p><a class="reference internal" href="Portal-And-Server.html"><span class="doc">Portal</span></a></p>
<ul>
<li><p><a class="reference internal" href="Inputfuncs.html"><span class="doc">Inputfuncs</span></a></p></li>
<li><p><a class="reference internal" href="Outputfuncs.html"><span class="doc">Outputfuncs</span></a></p></li>
<li><p><a class="reference internal" href="../Concepts/Custom-Protocols.html"><span class="doc">Protocols</span></a></p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Server.html"><span class="doc">Server</span></a></p>
<ul>
<li><p><a class="reference internal" href="Server-Conf.html"><span class="doc">Server conf object</span></a></p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Webserver.html"><span class="doc">Webserver</span></a></p>
<ul>
<li><p><a class="reference internal" href="Webclient.html"><span class="doc">Webclient</span></a></p></li>
<li><p><a class="reference internal" href="Bootstrap-Components-and-Utilities.html"><span class="doc">Bootstrap</span></a></p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Signals.html"><span class="doc">Signals</span></a></p></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#database-entites">Database entites</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="#server-and-network">Server and network</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Components-Overview.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Components-Overview.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Core Components</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,138 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Connection Screen &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Connection Screen</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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 Evennias default connection screen.</p>
<div class="highlight-default 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 &lt;username&gt; &lt;password&gt;
If you need to create an account, type (without the &lt;&gt;&#39;s):
create &lt;username&gt; &lt;password&gt;
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/Start-Stop-Reload.html"><span class="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>
<div class="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">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">Commands</span></a> and the
tutorial section on how to add new commands to a default command set.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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>
<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>Versions</h3>
<ul>
<li><a href="Connection-Screen.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Connection Screen</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,346 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EvEditor &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvEditor</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="eveditor">
<h1>EvEditor<a class="headerlink" href="#eveditor" title="Permalink to this headline"></a></h1>
<p>Evennia offers a powerful in-game line editor in <code class="docutils literal notranslate"><span class="pre">evennia.utils.eveditor.EvEditor</span></code>. This editor,
mimicking the well-known VI line editor. It offers line-by-line editing, undo/redo, line deletes,
search/replace, fill, dedent and more.</p>
<div class="section" id="launching-the-editor">
<h2>Launching the editor<a class="headerlink" href="#launching-the-editor" title="Permalink to this headline"></a></h2>
<p>The editor is created as follows:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.eveditor</span> <span class="kn">import</span> <span class="n">EvEditor</span>
<span class="n">EvEditor</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span>
<span class="n">loadfunc</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">savefunc</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">quitfunc</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">caller</span></code> (Object or Account): The user of the editor.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">loadfunc</span></code> (callable, optional): This is a function called when the editor is first started. It
is called with <code class="docutils literal notranslate"><span class="pre">caller</span></code> as its only argument. The return value from this function is used as the
starting text in the editor buffer.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">savefunc</span></code> (callable, optional): This is called when the user saves their buffer in the editor is
called with two arguments, <code class="docutils literal notranslate"><span class="pre">caller</span></code> and <code class="docutils literal notranslate"><span class="pre">buffer</span></code>, where <code class="docutils literal notranslate"><span class="pre">buffer</span></code> is the current buffer.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">quitfunc</span></code> (callable, optional): This is called when the user quits the editor. If given, all
cleanup and exit messages to the user must be handled by this function.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (str, optional): This text will be displayed as an identifier and reminder while editing.
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>
</div>
<div class="section" id="example-of-usage">
<h2>Example of usage<a class="headerlink" href="#example-of-usage" 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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29</pre></div></td><td class="code"><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>
<span class="k">class</span> <span class="nc">CmdSetTestAttr</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Set the &quot;test&quot; Attribute using </span>
<span class="sd"> the line editor.</span>
<span class="sd"> Usage:</span>
<span class="sd"> settestattr</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;settestattr&quot;</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="s2">&quot;Set up the callbacks and launch the editor&quot;</span>
<span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
<span class="s2">&quot;get the current value&quot;</span>
<span class="k">return</span> <span class="n">caller</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">&quot;test&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="nb">buffer</span><span class="p">):</span>
<span class="s2">&quot;save the buffer&quot;</span>
<span class="n">caller</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;test&quot;</span><span class="p">,</span> <span class="nb">buffer</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">quit</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
<span class="s2">&quot;Since we define it, we must handle messages&quot;</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Editor exited&quot;</span><span class="p">)</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">/test&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span>
<span class="c1"># launch the editor</span>
<span class="n">eveditor</span><span class="o">.</span><span class="n">EvEditor</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span>
<span class="n">loadfunc</span><span class="o">=</span><span class="n">load</span><span class="p">,</span> <span class="n">savefunc</span><span class="o">=</span><span class="n">save</span><span class="p">,</span> <span class="n">quitfunc</span><span class="o">=</span><span class="n">quit</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="n">key</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="persistent-editor">
<h2>Persistent editor<a class="headerlink" href="#persistent-editor" title="Permalink to this headline"></a></h2>
<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
functions will be stored, Python will need to find them.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32</pre></div></td><td class="code"><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>
<span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
<span class="s2">&quot;get the current value&quot;</span>
<span class="k">return</span> <span class="n">caller</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">&quot;test&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="nb">buffer</span><span class="p">):</span>
<span class="s2">&quot;save the buffer&quot;</span>
<span class="n">caller</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">set</span><span class="p">(</span><span class="s2">&quot;test&quot;</span><span class="p">,</span> <span class="nb">buffer</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">quit</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
<span class="s2">&quot;Since we define it, we must handle messages&quot;</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Editor exited&quot;</span><span class="p">)</span>
<span class="k">class</span> <span class="nc">CmdSetTestAttr</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Set the &quot;test&quot; Attribute using </span>
<span class="sd"> the line editor.</span>
<span class="sd"> Usage:</span>
<span class="sd"> settestattr</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;settestattr&quot;</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="s2">&quot;Set up the callbacks and launch the editor&quot;</span>
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;</span><span class="si">%s</span><span class="s2">/test&quot;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span>
<span class="c1"># launch the editor</span>
<span class="n">eveditor</span><span class="o">.</span><span class="n">EvEditor</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span>
<span class="n">loadfunc</span><span class="o">=</span><span class="n">load</span><span class="p">,</span> <span class="n">savefunc</span><span class="o">=</span><span class="n">save</span><span class="p">,</span> <span class="n">quitfunc</span><span class="o">=</span><span class="n">quit</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="n">key</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="line-editor-usage">
<h2>Line editor usage<a class="headerlink" href="#line-editor-usage" title="Permalink to this headline"></a></h2>
<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> &lt;txt&gt; - any non-command is appended to the end of the buffer.
: &lt;l&gt; - view buffer or only line &lt;l&gt;
:: &lt;l&gt; - view buffer without line numbers or other parsing
::: - print a &#39;:&#39; as the only character on the line...
:h - this help.
:w - save the buffer (don&#39;t quit)
:wq - save buffer and quit
:q - quit (will be asked to save if buffer was changed)
:q! - quit without saving, no questions asked
:u - (undo) step backwards in undo history
:uu - (redo) step forward in undo history
:UU - reset all changes back to initial state
:dd &lt;l&gt; - delete line &lt;n&gt;
:dw &lt;l&gt; &lt;w&gt; - delete word or regex &lt;w&gt; in entire buffer or on line &lt;l&gt;
:DD - clear buffer
:y &lt;l&gt; - yank (copy) line &lt;l&gt; to the copy buffer
:x &lt;l&gt; - cut line &lt;l&gt; and store it in the copy buffer
:p &lt;l&gt; - put (paste) previously copied line directly after &lt;l&gt;
:i &lt;l&gt; &lt;txt&gt; - insert new text &lt;txt&gt; at line &lt;l&gt;. Old line will move down
:r &lt;l&gt; &lt;txt&gt; - replace line &lt;l&gt; with text &lt;txt&gt;
:I &lt;l&gt; &lt;txt&gt; - insert text at the beginning of line &lt;l&gt;
:A &lt;l&gt; &lt;txt&gt; - append text after the end of line &lt;l&gt;
:s &lt;l&gt; &lt;w&gt; &lt;txt&gt; - search/replace word or regex &lt;w&gt; in buffer or on line &lt;l&gt;
:f &lt;l&gt; - flood-fill entire buffer or line &lt;l&gt;
:fi &lt;l&gt; - indent entire buffer or line &lt;l&gt;
:fd &lt;l&gt; - de-indent entire buffer or line &lt;l&gt;
:echo - turn echoing of the input on/off (helpful for some clients)
Legend:
&lt;l&gt; - line numbers, or range lstart:lend, e.g. &#39;3:7&#39;.
&lt;w&gt; - one word or several enclosed in quotes.
&lt;txt&gt; - longer string, usually not needed to be enclosed in quotes.
</pre></div>
</div>
</div>
<div class="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">&#64;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 isnt 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">:&lt;</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><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">&#64;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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<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="#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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/EvEditor.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="EvEditor.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvEditor</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,139 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EvMore &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvMore</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="evmore">
<h1>EvMore<a class="headerlink" href="#evmore" title="Permalink to this headline"></a></h1>
<p>When sending a very long text to a user client, it might scroll beyond of the height of the client
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>
<div class="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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><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>
<span class="n">evmore</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">receiver</span><span class="p">,</span> <span class="n">long_text</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Where receiver is an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> or a <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a>. If the text is longer than the
clients screen height (as determined by the NAWS handshake or by <code class="docutils literal notranslate"><span class="pre">settings.CLIENT_DEFAULT_HEIGHT</span></code>)
the pager will show up, something like this:</p>
<blockquote>
<div><p>[…]
aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur
sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.</p>
</div></blockquote>
<blockquote>
<div><p>(<strong>more</strong> [1/6] retur<strong>n</strong>|<strong>b</strong>ack|<strong>t</strong>op|<strong>e</strong>nd|<strong>a</strong>bort)</p>
</div></blockquote>
<p>where the user will be able to hit the return key to move to the next page, or use the suggested
commands to jump to previous pages, to the top or bottom of the document as well as abort the
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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/EvMore.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="EvMore.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvMore</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,238 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Help System &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Help System</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="help-system">
<h1>Help System<a class="headerlink" href="#help-system" title="Permalink to this headline"></a></h1>
<p>An important part of Evennia is the online help system. This allows the players and staff alike to
learn how to use the games commands as well as other information pertinent to the game. The help
system has many different aspects, from the normal editing of help entries from inside the game, to
auto-generated help entries during code development using the <em>auto-help system</em>.</p>
<div class="section" id="viewing-the-help-database">
<h2>Viewing the help database<a class="headerlink" href="#viewing-the-help-database" title="Permalink to this headline"></a></h2>
<p>The main command is <code class="docutils literal notranslate"><span class="pre">help</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">help</span> <span class="p">[</span><span class="n">searchstring</span><span class="p">]</span>
</pre></div>
</div>
<p>This will show a list of help entries, ordered after categories. You will find two sections,
<em>Command help entries</em> and <em>Other help entries</em> (initially you will only have the first one). You
can use help to get more info about an entry; you can also give partial matches to get suggestions.
If you give category names you will only be shown the topics in that category.</p>
</div>
<div class="section" id="command-auto-help-system">
<h2>Command Auto-help system<a class="headerlink" href="#command-auto-help-system" title="Permalink to this headline"></a></h2>
<p>A common item that requires help entries are in-game commands. Keeping these entries up-to-date with
the actual source code functionality can be a chore. Evennias commands are therefore auto-
documenting straight from the sources through its <em>auto-help system</em>. Only commands that you and
your character can actually currently use are picked up by the auto-help system. That means an admin
will see a considerably larger amount of help topics than a normal player when using the default
<code class="docutils literal notranslate"><span class="pre">help</span></code> command.</p>
<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">&#64;reload</span></code> away. There is no need to manually
create and maintain help database entries for commands; as long as you keep the docstrings updated
your help will be dynamically updated for you as well.</p>
<p>Example (from a module with command definitions):</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20</pre></div></td><td class="code"><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">&quot;&quot;&quot;</span>
<span class="sd"> mycmd - my very own command</span>
<span class="sd"> </span>
<span class="sd"> Usage: </span>
<span class="sd"> mycmd[/switches] &lt;args&gt;</span>
<span class="sd"> </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"> </span>
<span class="sd"> This is my own command that does this and that.</span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># [...]</span>
<span class="n">help_category</span> <span class="o">=</span> <span class="s2">&quot;General&quot;</span> <span class="c1"># default</span>
<span class="n">auto_help</span> <span class="o">=</span> <span class="bp">True</span> <span class="c1"># default</span>
<span class="c1"># [...]</span>
</pre></div>
</td></tr></table></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 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 dont specify the category, “General” is assumed.</p>
<p>If you dont 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">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 commands <code class="docutils literal notranslate"><span class="pre">get_help()</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>
</div>
<div class="section" id="database-help-entries">
<h2>Database help entries<a class="headerlink" href="#database-help-entries" title="Permalink to this headline"></a></h2>
<p>These are all help entries not involving commands (this is handled automatically by the <a class="reference external" href="Components/Help-System.html#command-auto-help-system">Command
Auto-help system</a>). Non-automatic help entries describe how
your particular game is played - its rules, world descriptions and so on.</p>
<p>A help entry consists of four parts:</p>
<ul class="simple">
<li><p>The <em>topic</em>. This is the name of the help entry. This is what players search for when they are
looking for help. The topic can contain spaces and also partial matches will be found.</p></li>
<li><p>The <em>help category</em>. Examples are <em>Administration</em>, <em>Building</em>, <em>Comms</em> or <em>General</em>. This is an
overall grouping of similar help topics, used by the engine to give a better overview.</p></li>
<li><p>The <em>text</em> - the help text itself, of any length.</p></li>
<li><p>locks - a <a class="reference internal" href="Locks.html"><span class="doc">lock definition</span></a>. This can be used to limit access to this help entry, maybe
because its staff-only or otherwise meant to be restricted. Help commands check for <code class="docutils literal notranslate"><span class="pre">access_type</span></code>s
<code class="docutils literal notranslate"><span class="pre">view</span></code> and <code class="docutils literal notranslate"><span class="pre">edit</span></code>. An example of a lock string would be <code class="docutils literal notranslate"><span class="pre">view:perm(Builders)</span></code>.</p></li>
</ul>
<p>You can create new help entries in code by using <code class="docutils literal notranslate"><span class="pre">evennia.create_help_entry()</span></code>.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><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">&quot;emote&quot;</span><span class="p">,</span>
<span class="s2">&quot;Emoting is important because ...&quot;</span><span class="p">,</span>
<span class="n">category</span><span class="o">=</span><span class="s2">&quot;Roleplaying&quot;</span><span class="p">,</span> <span class="n">locks</span><span class="o">=</span><span class="s2">&quot;view:all()&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>From inside the game those with the right permissions can use the <code class="docutils literal notranslate"><span class="pre">&#64;sethelp</span></code> command to add and
modify help entries.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@sethelp</span><span class="o">/</span><span class="n">add</span> <span class="n">emote</span> <span class="o">=</span> <span class="n">The</span> <span class="n">emote</span> <span class="n">command</span> <span class="ow">is</span> <span class="o">...</span>
</pre></div>
</div>
<p>Using <code class="docutils literal notranslate"><span class="pre">&#64;sethelp</span></code> you can add, delete and append text to existing entries. By default new entries
will go in the <em>General</em> help category. You can change this using a different form of the <code class="docutils literal notranslate"><span class="pre">&#64;sethelp</span></code>
command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@sethelp</span><span class="o">/</span><span class="n">add</span> <span class="n">emote</span><span class="p">,</span> <span class="n">Roleplaying</span> <span class="o">=</span> <span class="n">Emoting</span> <span class="ow">is</span> <span class="n">important</span> <span class="n">because</span> <span class="o">...</span>
</pre></div>
</div>
<p>If the category <em>Roleplaying</em> did not already exist, it is created and will appear in the help
index.</p>
<p>You can, finally, define a lock for the help entry by following the category with a <a class="reference internal" href="Locks.html"><span class="doc">lock
definition</span></a>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@sethelp</span><span class="o">/</span><span class="n">add</span> <span class="n">emote</span><span class="p">,</span> <span class="n">Roleplaying</span><span class="p">,</span> <span class="n">view</span><span class="p">:</span><span class="nb">all</span><span class="p">()</span> <span class="o">=</span> <span class="n">Emoting</span> <span class="ow">is</span> <span class="o">...</span>
</pre></div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#viewing-the-help-database">Viewing the help database</a></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>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Help-System.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Help-System.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Help System</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,299 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Inputfuncs &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Inputfuncs</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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">inputcommand</span></a>) from
the client. The inputfunc is the last destination for the inputcommand along the <a class="reference external" href="Components/Messagepath#the-ingoing-message-path">ingoing message
path</a>. 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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><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>
</td></tr></table></div>
<p>Or, if no match was found, it will call an inputfunc named “default” on this form</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><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>
</td></tr></table></div>
<div class="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. Thats 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>
</div>
<div class="section" id="default-inputfuncs">
<h2>Default inputfuncs<a class="headerlink" href="#default-inputfuncs" title="Permalink to this headline"></a></h2>
<p>Evennia defines a few default inputfuncs to handle the common cases. These are defined in
<code class="docutils literal notranslate"><span class="pre">evennia/server/inputfuncs.py</span></code>.</p>
<div class="section" id="text">
<h3>text<a class="headerlink" href="#text" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;text&quot;,</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">Command</span></a>, this inputfunc will do things like nick-replacement
and then pass on the input to the central Commandhandler.</p>
</div>
<div class="section" id="echo">
<h3>echo<a class="headerlink" href="#echo" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;echo&quot;,</span> <span class="pre">(args),</span> <span class="pre">{})</span></code></p></li>
<li><p>Output: <code class="docutils literal notranslate"><span class="pre">(&quot;text&quot;,</span> <span class="pre">(&quot;Echo</span> <span class="pre">returns:</span> <span class="pre">%s&quot;</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>
</div>
<div class="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>
</div>
<div class="section" id="client-options">
<h3>client_options<a class="headerlink" href="#client-options" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;client_options,</span> <span class="pre">(),</span> <span class="pre">{key:value,</span> <span class="pre">...})</span></code></p></li>
<li><p>Output:</p></li>
<li><p>normal: None</p></li>
<li><p>get: <code class="docutils literal notranslate"><span class="pre">(&quot;client_options&quot;,</span> <span class="pre">(),</span> <span class="pre">{key:value,</span> <span class="pre">...})</span></code></p></li>
</ul>
<p>This is a direct command for setting protocol options. These are settable with the <code class="docutils literal notranslate"><span class="pre">&#64;option</span></code>
command, but this offers a client-side way to set them. Not all connection protocols makes use of
all flags, but here are the possible keywords:</p>
<ul class="simple">
<li><p>get (bool): If this is true, ignore all other kwargs and immediately return the current settings
as an outputcommand <code class="docutils literal notranslate"><span class="pre">(&quot;client_options&quot;,</span> <span class="pre">(),</span> <span class="pre">{key=value,</span> <span class="pre">...})</span></code>-</p></li>
<li><p>client (str): A client identifier, like “mushclient”.</p></li>
<li><p>version (str): A client version</p></li>
<li><p>ansi (bool): Supports ansi colors</p></li>
<li><p>xterm256 (bool): Supports xterm256 colors or not</p></li>
<li><p>mxp (bool): Supports MXP or not</p></li>
<li><p>utf-8 (bool): Supports UTF-8 or not</p></li>
<li><p>screenreader (bool): Screen-reader mode on/off</p></li>
<li><p>mccp (bool): MCCP compression on/off</p></li>
<li><p>screenheight (int): Screen height in lines</p></li>
<li><p>screenwidth (int): Screen width in characters</p></li>
<li><p>inputdebug (bool): Debug input functions</p></li>
<li><p>nomarkup (bool): Strip all text tags</p></li>
<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></blockquote>
</div>
<div class="section" id="get-client-options">
<h3>get_client_options<a class="headerlink" href="#get-client-options" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;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">(&quot;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>
</div>
<div class="section" id="get-inputfuncs">
<h3>get_inputfuncs<a class="headerlink" href="#get-inputfuncs" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;get_inputfuncs&quot;,</span> <span class="pre">(),</span> <span class="pre">{})</span></code></p></li>
<li><p>Output: <code class="docutils literal notranslate"><span class="pre">(&quot;get_inputfuncs&quot;,</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">(&quot;get_inputfuncs&quot;,</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>
</div>
<div class="section" id="login">
<h3>login<a class="headerlink" href="#login" title="Permalink to this headline"></a></h3>
<blockquote>
<div><p>Note: this is currently experimental and not very well tested.</p>
</div></blockquote>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;login&quot;,</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>
</div>
<div class="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">(&quot;get_value&quot;,</span> <span class="pre">(name,</span> <span class="pre">),</span> <span class="pre">{})</span></code>
Output: <code class="docutils literal notranslate"><span class="pre">(&quot;get_value&quot;,</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, youll 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>
<li><p>“servername”: Name of the Evennia server connected to.</p></li>
</ul>
</div>
<div class="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">(&quot;repeat&quot;,</span> <span class="pre">(),</span> <span class="pre">{&quot;callback&quot;:funcname,</span>&#160; <span class="pre">&quot;interval&quot;:</span> <span class="pre">secs,</span> <span class="pre">&quot;stop&quot;:</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">(&quot;text&quot;,</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">Ticker</span></a>. Only previously acceptable functions are possible to
repeat-call in this way, youll 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">&quot;stop&quot;:</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>
</div>
<div class="section" id="unrepeat">
<h3>unrepeat<a class="headerlink" href="#unrepeat" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;unrepeat&quot;,</span> <span class="pre">(),</span> <span class="pre">(&quot;callback&quot;:funcname,</span>&#160; <span class="pre">&quot;interval&quot;:</span> <span class="pre">secs)</span></code></p></li>
<li><p>Output: None</p></li>
</ul>
<p>This is a convenience wrapper for sending “stop” to the <code class="docutils literal notranslate"><span class="pre">repeat</span></code> inputfunc.</p>
</div>
<div class="section" id="monitor">
<h3>monitor<a class="headerlink" href="#monitor" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;monitor&quot;,</span> <span class="pre">(),</span> <span class="pre">(&quot;name&quot;: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">(&quot;monitor&quot;,</span> <span class="pre">(),</span> <span class="pre">{&quot;name&quot;:name,</span> <span class="pre">&quot;value&quot;: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">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>
</div>
</div>
<div class="section" id="unmonitor">
<h2>unmonitor<a class="headerlink" href="#unmonitor" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p>Input: <code class="docutils literal notranslate"><span class="pre">(&quot;unmonitor&quot;,</span> <span class="pre">(),</span> <span class="pre">{&quot;name&quot;: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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Inputfuncs</a><ul>
<li><a class="reference internal" href="#adding-your-own-inputfuncs">Adding your own inputfuncs</a></li>
<li><a class="reference internal" href="#default-inputfuncs">Default inputfuncs</a><ul>
<li><a class="reference internal" href="#text">text</a></li>
<li><a class="reference internal" href="#echo">echo</a></li>
<li><a class="reference internal" href="#default">default</a></li>
<li><a class="reference internal" href="#client-options">client_options</a></li>
<li><a class="reference internal" href="#get-client-options">get_client_options</a></li>
<li><a class="reference internal" href="#get-inputfuncs">get_inputfuncs</a></li>
<li><a class="reference internal" href="#login">login</a></li>
<li><a class="reference internal" href="#get-value">get_value</a></li>
<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>
</ul>
</li>
<li><a class="reference internal" href="#unmonitor">unmonitor</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Inputfuncs.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Inputfuncs.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Inputfuncs</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,649 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Locks &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Locks</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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">Commands</span></a>,
<a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a>, <a class="reference internal" href="Help-System.html"><span class="doc">Help System</span></a>,
<a class="reference external" href="Components/Communications.html#Msg">messages</a> and <a class="reference external" href="Components/Communications.html#Channels">channels</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>
<p>Lets 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 players 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>
<div class="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>
<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-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="n">lock</span> <span class="n">obj</span> <span class="o">=</span> <span class="o">&lt;</span><span class="n">lockstring</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">&lt;lockstring&gt;</span></code> is a string of a certain form that defines the behaviour of the lock. We will go
into more detail on how <code class="docutils literal notranslate"><span class="pre">&lt;lockstring&gt;</span></code> should look in the next section.</p>
<p>Code-wise, Evennia handles locks through what is usually called <code class="docutils literal notranslate"><span class="pre">locks</span></code> on all relevant entities.
This is a handler that allows you to add, delete and check locks.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">myobj</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="o">&lt;</span><span class="n">lockstring</span><span class="o">&gt;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>One can call <code class="docutils literal notranslate"><span class="pre">locks.check()</span></code> to perform a lock check, but to hide the underlying implementation all
objects also have a convenience function called <code class="docutils literal notranslate"><span class="pre">access</span></code>. This should preferably be used. In the
example below, <code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> is the object requesting the delete access whereas <code class="docutils literal notranslate"><span class="pre">obj</span></code> is the
object that might get deleted. This is how it would look (and does look) from inside the <code class="docutils literal notranslate"><span class="pre">delete</span></code>
command:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="s1">&#39;delete&#39;</span><span class="p">):</span>
<span class="n">accessing_obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Sorry, you may not delete that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="defining-locks">
<h2>Defining locks<a class="headerlink" href="#defining-locks" title="Permalink to this headline"></a></h2>
<p>Defining a lock (i.e. an access restriction) in Evennia is done by adding simple strings of lock
definitions to the objects <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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">delete</span><span class="p">:</span><span class="nb">id</span><span class="p">(</span><span class="mi">34</span><span class="p">)</span> <span class="c1"># only allow obj #34 to delete</span>
<span class="n">edit</span><span class="p">:</span><span class="nb">all</span><span class="p">()</span> <span class="c1"># let everyone edit </span>
<span class="c1"># only those who are not &quot;very_weak&quot; or are Admins may pick this up</span>
<span class="n">get</span><span class="p">:</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">(</span><span class="n">very_weak</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Admin</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Formally, a lockstring has the following syntax:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">access_type</span><span class="p">:</span> <span class="p">[</span><span class="n">NOT</span><span class="p">]</span> <span class="n">lockfunc1</span><span class="p">([</span><span class="n">arg1</span><span class="p">,</span><span class="o">..</span><span class="p">])</span> <span class="p">[</span><span class="n">AND</span><span class="o">|</span><span class="n">OR</span><span class="p">]</span> <span class="p">[</span><span class="n">NOT</span><span class="p">]</span> <span class="n">lockfunc2</span><span class="p">([</span><span class="n">arg1</span><span class="p">,</span><span class="o">...</span><span class="p">])</span> <span class="p">[</span><span class="o">...</span><span class="p">]</span>
</pre></div>
</td></tr></table></div>
<p>where <code class="docutils literal notranslate"><span class="pre">[]</span></code> marks optional parts. <code class="docutils literal notranslate"><span class="pre">AND</span></code>, <code class="docutils literal notranslate"><span class="pre">OR</span></code> and <code class="docutils literal notranslate"><span class="pre">NOT</span></code> are not case sensitive and excess spaces are
ignored. <code class="docutils literal notranslate"><span class="pre">lockfunc1,</span> <span class="pre">lockfunc2</span></code> etc are special <em>lock functions</em> available to the lock system.</p>
<p>So, a lockstring consists of the type of restriction (the <code class="docutils literal notranslate"><span class="pre">access_type</span></code>), a colon (<code class="docutils literal notranslate"><span class="pre">:</span></code>) and then an
expression involving function calls that determine what is needed to pass the lock. Each function
returns either <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>. <code class="docutils literal notranslate"><span class="pre">AND</span></code>, <code class="docutils literal notranslate"><span class="pre">OR</span></code> and <code class="docutils literal notranslate"><span class="pre">NOT</span></code> work as they do normally in Python. If the
total result is <code class="docutils literal notranslate"><span class="pre">True</span></code>, the lock is passed.</p>
<p>You can create several lock types one after the other by separating them with a semicolon (<code class="docutils literal notranslate"><span class="pre">;</span></code>) in
the lockstring. The string below yields the same result as the previous example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">delete</span><span class="p">:</span><span class="nb">id</span><span class="p">(</span><span class="mi">34</span><span class="p">);</span><span class="n">edit</span><span class="p">:</span><span class="nb">all</span><span class="p">();</span><span class="n">get</span><span class="p">:</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">(</span><span class="n">very_weak</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Admin</span><span class="p">)</span>
</pre></div>
</div>
<div class="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,
such as “delete” or “edit”. You may in principle name your <code class="docutils literal notranslate"><span class="pre">access_type</span></code> anything as long as it is
unique for the particular object. The name of the access types is not case-sensitive.</p>
<p>If you want to make sure the lock is used however, you should pick <code class="docutils literal notranslate"><span class="pre">access_type</span></code> names that you (or
the default command set) actually checks for, as in the example of <code class="docutils literal notranslate"><span class="pre">delete</span></code> above that uses the
delete <code class="docutils literal notranslate"><span class="pre">access_type</span></code>.</p>
<p>Below are the access_types checked by the default commandset.</p>
<ul class="simple">
<li><p><a class="reference internal" href="Commands.html"><span class="doc">Commands</span></a></p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">cmd</span></code> - this defines who may call this command at all.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Objects.html"><span class="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 dont 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 objects 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>
<li><p><code class="docutils literal notranslate"><span class="pre">view</span></code> - if the <code class="docutils literal notranslate"><span class="pre">look</span></code> command will display/list this object</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">get</span></code>- who may pick up the object and carry it around.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">puppet</span></code> - who may “become” this object and control it as their “character”.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attrcreate</span></code> - who may create new attributes on the object (default True)</p></li>
</ul>
</li>
<li><p><a class="reference external" href="Components/Objects.html#Characters">Characters</a>:</p>
<ul>
<li><p>Same as for Objects</p></li>
</ul>
</li>
<li><p><a class="reference external" href="Components/Objects.html#Exits">Exits</a>:</p>
<ul>
<li><p>Same as for Objects</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">traverse</span></code> - who may pass the exit.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">examine</span></code> - who may examine the accounts properties.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">delete</span></code> - who may delete the account.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">edit</span></code> - who may edit the accounts attributes and properties.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">msg</span></code> - who may send messages to the account.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">boot</span></code> - who may boot the account.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a>: (only checked by <code class="docutils literal notranslate"><span class="pre">obj.secure_attr</span></code>)</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">attrread</span></code> - see/access attribute</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attredit</span></code> - change/delete attribute</p></li>
</ul>
</li>
<li><p><a class="reference external" href="Components/Communications.html#Channels">Channels</a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">control</span></code> - who is administrating the channel. This means the ability to delete the channel,
boot listeners etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">send</span></code> - who may send to the channel.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">listen</span></code> - who may subscribe and listen to the channel.</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Help-System.html"><span class="doc">HelpEntry</span></a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">examine</span></code> - who may view this help entry (usually everyone)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">edit</span></code> - who may edit this help entry.</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">&lt;lock</span> <span class="pre">functions&gt;</span></code>.</p>
</div>
<div class="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>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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><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">&quot;read:perm(Player);post:perm(Admin)&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>This will create a read access type for Characters having the <code class="docutils literal notranslate"><span class="pre">Player</span></code> permission or above and a
post access type for those with <code class="docutils literal notranslate"><span class="pre">Admin</span></code> permissions or above (see below how the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lock
function works). When it comes time to test these permissions, simply check like this (in this
example, the <code class="docutils literal notranslate"><span class="pre">obj</span></code> may be a board on the bulletin board system and <code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> is the player
trying to read the board):</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="s1">&#39;read&#39;</span><span class="p">):</span>
<span class="n">accessing_obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Sorry, you may not read that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="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
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>.
You can append the setting to add more module paths. To replace a default lock function, just add
your own with the same name.</p>
<p>A lock function must always accept at least two arguments - the <em>accessing object</em> (this is the
object wanting to get access) and the <em>accessed object</em> (this is the object with the lock). Those
two are fed automatically as the first two arguments to the function when the lock is checked. Any
arguments explicitly given in the lock definition will appear as extra arguments.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># A simple example lock function. Called with e.g. `id(34)`. This is</span>
<span class="c1"># defined in, say mygame/server/conf/lockfuncs.py</span>
<span class="k">def</span> <span class="nf">id</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="n">accessed_obj</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="k">if</span> <span class="n">args</span><span class="p">:</span>
<span class="n">wanted_id</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
<span class="k">return</span> <span class="n">accessing_obj</span><span class="o">.</span><span class="n">id</span> <span class="o">==</span> <span class="n">wanted_id</span>
<span class="k">return</span> <span class="bp">False</span>
</pre></div>
</td></tr></table></div>
<p>The above could for example be used in a lock function like this:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># we have `obj` and `owner_object` from before</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">&quot;edit: id(</span><span class="si">%i</span><span class="s2">)&quot;</span> <span class="o">%</span> <span class="n">owner_object</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>We could check if the “edit” lock is passed with something like this:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># as part of a Command&#39;s func() method, for example</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s2">&quot;edit&quot;</span><span class="p">):</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You don&#39;t have access to edit this!&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
<p>In this example, everyone except the <code class="docutils literal notranslate"><span class="pre">caller</span></code> with the right <code class="docutils literal notranslate"><span class="pre">id</span></code> will get the error.</p>
<blockquote>
<div><p>(Using the <code class="docutils literal notranslate"><span class="pre">*</span></code> and <code class="docutils literal notranslate"><span class="pre">**</span></code> syntax causes Python to magically put all extra arguments into a list
<code class="docutils literal notranslate"><span class="pre">args</span></code> and all keyword arguments into a dictionary <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> respectively. If you are unfamiliar with
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, see the Python manuals).</p>
</div></blockquote>
<p>Some useful default lockfuncs (see <code class="docutils literal notranslate"><span class="pre">src/locks/lockfuncs.py</span></code> for more):</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">true()/all()</span></code> - give access to everyone</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">false()/none()/superuser()</span></code> - give access to none. Superusers bypass the check entirely and are
thus the only ones who will pass this check.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">perm(perm)</span></code> - this tries to match a given <code class="docutils literal notranslate"><span class="pre">permission</span></code> property, on an Account firsthand, on a
Character second. See <a class="reference external" href="Components/Locks.html#permissions">below</a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">perm_above(perm)</span></code> - like <code class="docutils literal notranslate"><span class="pre">perm</span></code> but requires a “higher” permission level than the one given.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">id(num)/dbref(num)</span></code> - checks so the access_object has a certain dbref/id.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr(attrname)</span></code> - checks if a certain <a class="reference internal" href="Attributes.html"><span class="doc">Attribute</span></a> exists on accessing_object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr(attrname,</span> <span class="pre">value)</span></code> - checks so an attribute exists on accessing_object <em>and</em> has the given
value.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr_gt(attrname,</span> <span class="pre">value)</span></code> - checks so accessing_object has a value larger (<code class="docutils literal notranslate"><span class="pre">&gt;</span></code>) than the given
value.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attr_ge,</span> <span class="pre">attr_lt,</span> <span class="pre">attr_le,</span> <span class="pre">attr_ne</span></code> - corresponding for <code class="docutils literal notranslate"><span class="pre">&gt;=</span></code>, <code class="docutils literal notranslate"><span class="pre">&lt;</span></code>, <code class="docutils literal notranslate"><span class="pre">&lt;=</span></code> and <code class="docutils literal notranslate"><span class="pre">!=</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">holds(objid)</span></code> - checks so the accessing objects contains an object of given name or dbref.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">inside()</span></code> - checks so the accessing object is inside the accessed object (the inverse of
<code class="docutils literal notranslate"><span class="pre">holds()</span></code>).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pperm(perm)</span></code>, <code class="docutils literal notranslate"><span class="pre">pid(num)/pdbref(num)</span></code> - same as <code class="docutils literal notranslate"><span class="pre">perm</span></code>, <code class="docutils literal notranslate"><span class="pre">id/dbref</span></code> but always looks for
permissions and dbrefs of <em>Accounts</em>, not on Characters.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">serversetting(settingname,</span> <span class="pre">value)</span></code> - Only returns True if Evennia has a given setting or a
setting set to a given value.</p></li>
</ul>
</div>
</div>
<div class="section" id="checking-simple-strings">
<h2>Checking simple strings<a class="headerlink" href="#checking-simple-strings" title="Permalink to this headline"></a></h2>
<p>Sometimes you dont 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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># inside command definition</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">check_lockstring</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">,</span> <span class="s2">&quot;dummy:perm(Admin)&quot;</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="s2">&quot;You must be an Admin or higher to do this!&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></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>
</div>
<div class="section" id="default-locks">
<h2>Default locks<a class="headerlink" href="#default-locks" title="Permalink to this headline"></a></h2>
<p>Evennia sets up a few basic locks on all new objects and accounts (if we didnt, 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">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 dont want to
edit unless you want to change how basic stuff like rooms and exits store their internal variables).
This is called once, before <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>, so just put them in the latter method on your
child object to change the default. Also creation commands like <code class="docutils literal notranslate"><span class="pre">create</span></code> changes the locks of
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>
</div>
</div>
<div class="section" id="permissions">
<h1>Permissions<a class="headerlink" href="#permissions" title="Permalink to this headline"></a></h1>
<blockquote>
<div><p>This section covers the underlying code use of permissions. If you just want to learn how to
practically assign permissions in-game, refer to the <a class="reference internal" href="../Concepts/Building-Permissions.html"><span class="doc">Building Permissions</span></a>
page, which details how you use the <code class="docutils literal notranslate"><span class="pre">perm</span></code> command.</p>
</div></blockquote>
<p>A <em>permission</em> is simply a list of text strings stored in the handler <code class="docutils literal notranslate"><span class="pre">permissions</span></code> on <code class="docutils literal notranslate"><span class="pre">Objects</span></code>
and <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>. Permissions can be used as a convenient way to structure access levels and
hierarchies. It is set by the <code class="docutils literal notranslate"><span class="pre">perm</span></code> command. Permissions are especially handled by the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> and
<code class="docutils literal notranslate"><span class="pre">pperm()</span></code> lock functions listed above.</p>
<p>Lets say we have a <code class="docutils literal notranslate"><span class="pre">red_key</span></code> object. We also have red chests that we want to unlock with this key.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">perm</span> <span class="n">red_key</span> <span class="o">=</span> <span class="n">unlocks_red_chests</span>
</pre></div>
</div>
<p>This gives the <code class="docutils literal notranslate"><span class="pre">red_key</span></code> object the permission “unlocks_red_chests”. Next we lock our red chests:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">lock</span> <span class="n">red</span> <span class="n">chest</span> <span class="o">=</span> <span class="n">unlock</span><span class="p">:</span><span class="n">perm</span><span class="p">(</span><span class="n">unlocks_red_chests</span><span class="p">)</span>
</pre></div>
</div>
<p>What this lock will expect is to the fed the actual key object. The <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lock function will
check the permissions set on the key and only return true if the permission is the one given.</p>
<p>Finally we need to actually check this lock somehow. Lets say the chest has an command <code class="docutils literal notranslate"><span class="pre">open</span> <span class="pre">&lt;key&gt;</span></code>
sitting on itself. Somewhere in its code the command needs to figure out which key you are using and
test if this key has the correct permission:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># self.obj is the chest </span>
<span class="c1"># and used_key is the key we used as argument to</span>
<span class="c1"># the command. The self.caller is the one trying</span>
<span class="c1"># to unlock the chest</span>
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">used_key</span><span class="p">,</span> <span class="s2">&quot;unlock&quot;</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="s2">&quot;The key does not fit!&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
<p>All new accounts are given a default set of permissions defined by
<code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_ACCOUNT_DEFAULT</span></code>.</p>
<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>. Evennias default permission hierarchy is as follows:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">Developer</span> <span class="c1"># like superuser but affected by locks</span>
<span class="n">Admin</span> <span class="c1"># can administrate accounts</span>
<span class="n">Builder</span> <span class="c1"># can edit the world</span>
<span class="n">Helper</span> <span class="c1"># can edit help files</span>
<span class="n">Player</span> <span class="c1"># can chat and send tells (default level)</span>
</pre></div>
</div>
<p>(Also the plural form works, so you could use <code class="docutils literal notranslate"><span class="pre">Developers</span></code> etc too).</p>
<blockquote>
<div><p>There is also a <code class="docutils literal notranslate"><span class="pre">Guest</span></code> level below <code class="docutils literal notranslate"><span class="pre">Player</span></code> that is only active if <code class="docutils literal notranslate"><span class="pre">settings.GUEST_ENABLED</span></code> is
set. This is never part of <code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_HIERARCHY</span></code>.</p>
</div></blockquote>
<p>The main use of this is that if you use the lock function <code class="docutils literal notranslate"><span class="pre">perm()</span></code> mentioned above, a lock check for
a particular permission in the hierarchy will <em>also</em> grant access to those with <em>higher</em> hierarchy
access. So if you have the permission “Admin” you will also pass a lock defined as <code class="docutils literal notranslate"><span class="pre">perm(Builder)</span></code>
or any of those levels below “Admin”.</p>
<p>When doing an access check from an <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> or Character, the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lock function 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.</p>
<p>Here is how you use <code class="docutils literal notranslate"><span class="pre">perm</span></code> to give an account more permissions:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">perm</span><span class="o">/</span><span class="n">account</span> <span class="n">Tommy</span> <span class="o">=</span> <span class="n">Builders</span>
<span class="n">perm</span><span class="o">/</span><span class="n">account</span><span class="o">/</span><span class="k">del</span> <span class="n">Tommy</span> <span class="o">=</span> <span class="n">Builders</span> <span class="c1"># remove it again</span>
</pre></div>
</div>
<p>Note the use of the <code class="docutils literal notranslate"><span class="pre">/account</span></code> switch. It means you assign the permission to the
<a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a> Tommy instead of any <a class="reference internal" href="Objects.html"><span class="doc">Character</span></a> that also happens to be named
“Tommy”.</p>
<p>Putting permissions on the <em>Account</em> guarantees that they are kept, <em>regardless</em> of which Character
they are currently puppeting. This is especially important to remember when assigning permissions
from the <em>hierarchy tree</em> - as mentioned above, an Accounts permissions will overrule that of its
character. So to be sure to avoid confusion you should generally put hierarchy permissions on the
Account, not on their Characters (but see also <a class="reference external" href="Components/Locks.html#Quelling">quelling</a>).</p>
<p>Below is an example of an object without any connected account</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">obj1</span><span class="o">.</span><span class="n">permissions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;Builders&quot;</span><span class="p">,</span> <span class="s2">&quot;cool_guy&quot;</span><span class="p">]</span>
<span class="n">obj2</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">&quot;enter:perm_above(Accounts) and perm(cool_guy)&quot;</span><span class="p">)</span>
<span class="n">obj2</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">obj1</span><span class="p">,</span> <span class="s2">&quot;enter&quot;</span><span class="p">)</span> <span class="c1"># this returns True!</span>
</pre></div>
</td></tr></table></div>
<p>And one example of a puppet with a connected account:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">account</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Accounts&quot;</span><span class="p">)</span>
<span class="n">puppet</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Builders&quot;</span><span class="p">,</span> <span class="s2">&quot;cool_guy&quot;</span><span class="p">)</span>
<span class="n">obj2</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">&quot;enter:perm_above(Accounts) and perm(cool_guy)&quot;</span><span class="p">)</span>
<span class="n">obj2</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">puppet</span><span class="p">,</span> <span class="s2">&quot;enter&quot;</span><span class="p">)</span> <span class="c1"># this returns False!</span>
</pre></div>
</td></tr></table></div>
<div class="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 so no checks are even run. This allows for the
superuser to always have access to everything in an emergency. But it also hides 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 so your locks get tested correctly.</p>
</div>
<div class="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 permissions on the
Account and instead use the permissions on the Character only. This can be used e.g. by staff to
test out things with a lower permission level. Return to the normal operation with <code class="docutils literal notranslate"><span class="pre">unquell</span></code>. Note
that quelling will use the smallest of any hierarchical permission on the Account or Character, so
one cannot escalate ones Account permission by quelling to a high-permission Character. Also the
superuser can quell their powers this way, making them affectable by locks.</p>
</div>
<div class="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-default notranslate"><div class="highlight"><pre><span></span><span class="n">examine</span><span class="p">:</span> <span class="n">attr</span><span class="p">(</span><span class="n">eyesight</span><span class="p">,</span> <span class="n">excellent</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Builders</span><span class="p">)</span>
</pre></div>
</div>
<p>You are only allowed to do <em>examine</em> on this object if you have excellent eyesight (that is, has
an Attribute <code class="docutils literal notranslate"><span class="pre">eyesight</span></code> with the value <code class="docutils literal notranslate"><span class="pre">excellent</span></code> defined on yourself) or if you have the
“Builders” permission string assigned to you.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nb">open</span><span class="p">:</span> <span class="n">holds</span><span class="p">(</span><span class="s1">&#39;the green key&#39;</span><span class="p">)</span> <span class="ow">or</span> <span class="n">perm</span><span class="p">(</span><span class="n">Builder</span><span class="p">)</span>
</pre></div>
</div>
<p>This could be called by the <code class="docutils literal notranslate"><span class="pre">open</span></code> command on a “door” object. The check is passed if you are a
Builder or has the right key in your inventory.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cmd</span><span class="p">:</span> <span class="n">perm</span><span class="p">(</span><span class="n">Builders</span><span class="p">)</span>
</pre></div>
</div>
<p>Evennias command handler looks for a lock of type <code class="docutils literal notranslate"><span class="pre">cmd</span></code> to determine if a user is allowed to even
call upon a particular command or not. When you define a command, this is the kind of lock you must
set. See the default command set for lots of examples. If a character/account dont pass the <code class="docutils literal notranslate"><span class="pre">cmd</span></code>
lock type the command will not even appear in their <code class="docutils literal notranslate"><span class="pre">help</span></code> list.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">cmd</span><span class="p">:</span> <span class="ow">not</span> <span class="n">perm</span><span class="p">(</span><span class="n">no_tell</span><span class="p">)</span>
</pre></div>
</div>
<p>“Permissions” can also be used to block users or implement highly specific bans. The above example
would be be added as a lock string to the <code class="docutils literal notranslate"><span class="pre">tell</span></code> command. This will allow everyone <em>not</em> having the
“permission” <code class="docutils literal notranslate"><span class="pre">no_tell</span></code> to use the <code class="docutils literal notranslate"><span class="pre">tell</span></code> command. You could easily give an account the “permission”
<code class="docutils literal notranslate"><span class="pre">no_tell</span></code> to disable their use of this particular command henceforth.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">dbref</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">id</span>
<span class="n">lockstring</span> <span class="o">=</span> <span class="s2">&quot;control:id(</span><span class="si">%s</span><span class="s2">);examine:perm(Builders);delete:id(</span><span class="si">%s</span><span class="s2">) or perm(Admin);get:all()&quot;</span> <span class="o">%</span>
<span class="p">(</span><span class="n">dbref</span><span class="p">,</span> <span class="n">dbref</span><span class="p">)</span>
<span class="n">new_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="n">lockstring</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<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>
</div>
<div class="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>
<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">Object</span></a>
called <code class="docutils literal notranslate"><span class="pre">box</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="n">create</span><span class="o">/</span><span class="n">drop</span> <span class="n">box</span>
<span class="o">&gt;</span> <span class="n">desc</span> <span class="n">box</span> <span class="o">=</span> <span class="s2">&quot;This is a very big and heavy box.&quot;</span>
</pre></div>
</div>
<p>We want to limit which objects can pick up this heavy box. Lets say that to do that we require the
would-be lifter to to have an attribute <em>strength</em> on themselves, with a value greater than 50. We
assign it to ourselves to begin with.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nb">set</span> <span class="bp">self</span><span class="o">/</span><span class="n">strength</span> <span class="o">=</span> <span class="mi">45</span>
</pre></div>
</div>
<p>Ok, so for testing we made ourselves strong, but not strong enough. Now we need to look at what
happens when someone tries to pick up the the box - they use the <code class="docutils literal notranslate"><span class="pre">get</span></code> command (in the default set).
This is defined in <code class="docutils literal notranslate"><span class="pre">evennia/commands/default/general.py</span></code>. In its code we find this snippet:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="s1">&#39;get&#39;</span><span class="p">):</span>
<span class="k">if</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">get_err_msg</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">get_err_msg</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You can&#39;t get that.&quot;</span><span class="p">)</span>
<span class="k">return</span>
</pre></div>
</td></tr></table></div>
<p>So the <code class="docutils literal notranslate"><span class="pre">get</span></code> command looks for a lock with the type <em>get</em> (not so surprising). It also looks for an
<a class="reference internal" href="Attributes.html"><span class="doc">Attribute</span></a> on the checked object called <em>get_err_msg</em> in order to return a customized
error message. Sounds good! Lets start by setting that on the box:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="o">&gt;</span> <span class="nb">set</span> <span class="n">box</span><span class="o">/</span><span class="n">get_err_msg</span> <span class="o">=</span> <span class="n">You</span> <span class="n">are</span> <span class="ow">not</span> <span class="n">strong</span> <span class="n">enough</span> <span class="n">to</span> <span class="n">lift</span> <span class="n">this</span> <span class="n">box</span><span class="o">.</span>
</pre></div>
</div>
<p>Next we need to craft a Lock of type <em>get</em> on our box. We want it to only be passed if the accessing
object has the attribute <em>strength</em> of the right value. For this we would need to create a lock
function that checks if attributes have a value greater than a given value. Luckily there is already
such a one included in evennia (see <code class="docutils literal notranslate"><span class="pre">evennia/locks/lockfuncs.py</span></code>), called <code class="docutils literal notranslate"><span class="pre">attr_gt</span></code>.</p>
<p>So the lock string will look like this: <code class="docutils literal notranslate"><span class="pre">get:attr_gt(strength,</span> <span class="pre">50)</span></code>. We put this on the box now:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">lock</span> <span class="n">box</span> <span class="o">=</span> <span class="n">get</span><span class="p">:</span><span class="n">attr_gt</span><span class="p">(</span><span class="n">strength</span><span class="p">,</span> <span class="mi">50</span><span class="p">)</span>
</pre></div>
</div>
<p>Try to <code class="docutils literal notranslate"><span class="pre">get</span></code> the object and you should get the message that we are not strong enough. Increase your
strength above 50 however and youll pick it up no problem. Done! A very heavy box!</p>
<p>If you wanted to set this up in python code, it would look something like this:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre></div></td><td class="code"><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="c1"># create, then set the lock</span>
<span class="n">box</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;box&quot;</span><span class="p">)</span>
<span class="n">box</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">&quot;get:attr_gt(strength, 50)&quot;</span><span class="p">)</span>
<span class="c1"># or we can assign locks in one go right away</span>
<span class="n">box</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="bp">None</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;box&quot;</span><span class="p">,</span> <span class="n">locks</span><span class="o">=</span><span class="s2">&quot;get:attr_gt(strength, 50)&quot;</span><span class="p">)</span>
<span class="c1"># set the attributes</span>
<span class="n">box</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">&quot;This is a very big and heavy box.&quot;</span>
<span class="n">box</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">get_err_msg</span> <span class="o">=</span> <span class="s2">&quot;You are not strong enough to lift this box.&quot;</span>
<span class="c1"># one heavy box, ready to withstand all but the strongest...</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="on-django-s-permission-system">
<h2>On Djangos permission system<a class="headerlink" href="#on-django-s-permission-system" title="Permalink to this headline"></a></h2>
<p>Django also implements a comprehensive permission/security system of its own. The reason we dont
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 Evennias 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. Its stand-alone from the permissions described above.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#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>
</ul>
</li>
<li><a class="reference internal" href="#permissions">Permissions</a><ul>
<li><a class="reference internal" href="#superusers">Superusers</a></li>
<li><a class="reference internal" href="#quelling">Quelling</a></li>
<li><a class="reference internal" href="#more-lock-definition-examples">More Lock definition examples</a></li>
<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>
<li><a class="reference internal" href="#on-django-s-permission-system">On Djangos permission system</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Locks.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Locks.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Locks</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,196 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MonitorHandler &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">MonitorHandler</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="monitorhandler">
<h1>MonitorHandler<a class="headerlink" href="#monitorhandler" title="Permalink to this headline"></a></h1>
<p>The <em>MonitorHandler</em> is a system for watching changes in properties or Attributes on objects. A
monitor can be thought of as a sort of trigger that responds to change.</p>
<p>The main use for the MonitorHandler is to report changes to the client; for example the client
Session may ask Evennia to monitor the value of the Characers <code class="docutils literal notranslate"><span class="pre">health</span></code> attribute and report
whenever it changes. This way the client could for example update its health bar graphic as needed.</p>
<div class="section" id="using-the-monitorhandler">
<h2>Using the MonitorHandler<a class="headerlink" href="#using-the-monitorhandler" title="Permalink to this headline"></a></h2>
<p>The MontorHandler is accessed from the singleton <code class="docutils literal notranslate"><span class="pre">evennia.MONITOR_HANDLER</span></code>. The code for the handler
is in <code class="docutils literal notranslate"><span class="pre">evennia.scripts.monitorhandler</span></code>.</p>
<p>Heres how to add a new monitor:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">MONITOR_HANDLER</span>
<span class="n">MONITOR_HANDLER</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">fieldname</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span>
<span class="n">idstring</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code> (<a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclassed</span></a> entity) - the object to monitor. Since this must be
typeclassed, it means you cant monitor changes on <a class="reference internal" href="Sessions.html"><span class="doc">Sessions</span></a> with the monitorhandler, for
example.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">fieldname</span></code> (str) - the name of a field or <a class="reference internal" href="Attributes.html"><span class="doc">Attribute</span></a> on <code class="docutils literal notranslate"><span class="pre">obj</span></code>. If you want to
monitor a database field you must specify its full name, including the starting <code class="docutils literal notranslate"><span class="pre">db_</span></code> (like
<code class="docutils literal notranslate"><span class="pre">db_key</span></code>, <code class="docutils literal notranslate"><span class="pre">db_location</span></code> etc). Any names not starting with <code class="docutils literal notranslate"><span class="pre">db_</span></code> are instead assumed to be the names
of Attributes. This difference matters, since the MonitorHandler will automatically know to watch
the <code class="docutils literal notranslate"><span class="pre">db_value</span></code> field of the Attribute.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">callback</span></code>(callable) - This will be called as <code class="docutils literal notranslate"><span class="pre">callback(fieldname=fieldname,</span> <span class="pre">obj=obj,</span> <span class="pre">**kwargs)</span></code>
when the field updates.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">idstring</span></code> (str) - this is used to separate multiple monitors on the same object and fieldname.
This is required in order to properly identify and remove the monitor later. Its also used for
saving it.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code> (bool) - if True, the monitor will survive a server reboot.</p></li>
</ul>
<p>Example:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">MONITOR_HANDLER</span> <span class="k">as</span> <span class="n">monitorhandler</span>
<span class="k">def</span> <span class="nf">_monitor_callback</span><span class="p">(</span><span class="n">fieldname</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># reporting callback that works both</span>
<span class="c1"># for db-fields and Attributes</span>
<span class="k">if</span> <span class="n">fieldname</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;db_&quot;</span><span class="p">):</span>
<span class="n">new_value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="n">fieldname</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span> <span class="c1"># an attribute </span>
<span class="n">new_value</span> <span class="o">=</span> <span class="n">obj</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="n">fieldname</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">&quot;</span><span class="si">%s</span><span class="s2">.</span><span class="si">%s</span><span class="s2"> changed to &#39;</span><span class="si">%s</span><span class="s2">&#39;.&quot;</span> <span class="o">%</span> \
<span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">fieldname</span><span class="p">,</span> <span class="n">new_value</span><span class="p">))</span>
<span class="c1"># (we could add _some_other_monitor_callback here too)</span>
<span class="c1"># monitor Attribute (assume we have obj from before)</span>
<span class="n">monitorhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;desc&quot;</span><span class="p">,</span> <span class="n">_monitor_callback</span><span class="p">)</span>
<span class="c1"># monitor same db-field with two different callbacks (must separate by id_string)</span>
<span class="n">monitorhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;db_key&quot;</span><span class="p">,</span> <span class="n">_monitor_callback</span><span class="p">,</span> <span class="n">id_string</span><span class="o">=</span><span class="s2">&quot;foo&quot;</span><span class="p">)</span>
<span class="n">monitorhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;db_key&quot;</span><span class="p">,</span> <span class="n">_some_other_monitor_callback</span><span class="p">,</span> <span class="n">id_string</span><span class="o">=</span><span class="s2">&quot;bar&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>A monitor is uniquely identified by the combination of the <em>object instance</em> it is monitoring, the
<em>name</em> of the field/attribute to monitor on that object and its <code class="docutils literal notranslate"><span class="pre">idstring</span></code> (<code class="docutils literal notranslate"><span class="pre">obj</span></code> + <code class="docutils literal notranslate"><span class="pre">fieldname</span></code> +
<code class="docutils literal notranslate"><span class="pre">idstring</span></code>). The <code class="docutils literal notranslate"><span class="pre">idstring</span></code> will be the empty string unless given explicitly.</p>
<p>So to “un-monitor” the above you need to supply enough information for the system to uniquely find
the monitor to remove:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">monitorhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;desc&quot;</span><span class="p">)</span>
<span class="n">monitorhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;db_key&quot;</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="s2">&quot;foo&quot;</span><span class="p">)</span>
<span class="n">monitorhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&quot;db_key&quot;</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="s2">&quot;bar&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">MonitorHandler</a><ul>
<li><a class="reference internal" href="#using-the-monitorhandler">Using the MonitorHandler</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/MonitorHandler.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="MonitorHandler.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">MonitorHandler</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,235 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nicks &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Nicks</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="nicks">
<h1>Nicks<a class="headerlink" href="#nicks" title="Permalink to this headline"></a></h1>
<p><em>Nicks</em>, short for <em>Nicknames</em> is a system allowing an object (usually a <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a>) to
assign custom replacement names for other game entities.</p>
<p>Nicks are not to be confused with <em>Aliases</em>. Setting an Alias on a game entity actually changes an
inherent attribute on that entity, and everyone in the game will be able to use that alias to
address the entity thereafter. A <em>Nick</em> on the other hand, is used to map a different way <em>you
alone</em> can refer to that entity. Nicks are also commonly used to replace your input text which means
you can create your own aliases to default commands.</p>
<p>Default Evennia use Nicks in three flavours that determine when Evennia actually tries to do the
substitution.</p>
<ul class="simple">
<li><p>inputline - replacement is attempted whenever you write anything on the command line. This is the
default.</p></li>
<li><p>objects - replacement is only attempted when referring to an object</p></li>
<li><p>accounts - replacement is only attempted when referring an account</p></li>
</ul>
<p>Heres how to use it in the default command set (using the <code class="docutils literal notranslate"><span class="pre">nick</span></code> command):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">nick</span> <span class="n">ls</span> <span class="o">=</span> <span class="n">look</span>
</pre></div>
</div>
<p>This is a good one for unix/linux users who are accustomed to using the <code class="docutils literal notranslate"><span class="pre">ls</span></code> command in their daily
life. It is equivalent to <code class="docutils literal notranslate"><span class="pre">nick/inputline</span> <span class="pre">ls</span> <span class="pre">=</span> <span class="pre">look</span></code>.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">nick</span><span class="o">/</span><span class="nb">object</span> <span class="n">mycar2</span> <span class="o">=</span> <span class="n">The</span> <span class="n">red</span> <span class="n">sports</span> <span class="n">car</span>
</pre></div>
</div>
<p>With this example, substitutions will only be done specifically for commands expecting an object
reference, such as</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">look</span> <span class="n">mycar2</span>
</pre></div>
</div>
<p>becomes equivalent to “<code class="docutils literal notranslate"><span class="pre">look</span> <span class="pre">The</span> <span class="pre">red</span> <span class="pre">sports</span> <span class="pre">car</span></code>”.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">nick</span><span class="o">/</span><span class="n">accounts</span> <span class="n">tom</span> <span class="o">=</span> <span class="n">Thomas</span> <span class="n">Johnsson</span>
</pre></div>
</div>
<p>This is useful for commands searching for accounts explicitly:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nd">@find</span> <span class="o">*</span><span class="n">tom</span>
</pre></div>
</div>
<p>One can use nicks to speed up input. Below we add ourselves a quicker way to build red buttons. In
the future just writing <em>rb</em> will be enough to execute that whole long string.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">nick</span> <span class="n">rb</span> <span class="o">=</span> <span class="nd">@create</span> <span class="n">button</span><span class="p">:</span><span class="n">examples</span><span class="o">.</span><span class="n">red_button</span><span class="o">.</span><span class="n">RedButton</span>
</pre></div>
</div>
<p>Nicks could also be used as the start for building a “recog” system suitable for an RP mud.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">nick</span><span class="o">/</span><span class="n">account</span> <span class="n">Arnold</span> <span class="o">=</span> <span class="n">The</span> <span class="n">mysterious</span> <span class="n">hooded</span> <span class="n">man</span>
</pre></div>
</div>
<p>The nick replacer also supports unix-style <em>templating</em>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> nick build $1 $2 = @create/drop $1;$2
</pre></div>
</div>
<p>This will catch space separated arguments and store them in the the tags <code class="docutils literal notranslate"><span class="pre">$1</span></code> and <code class="docutils literal notranslate"><span class="pre">$2</span></code>, to be
inserted in the replacement string. This example allows you to do <code class="docutils literal notranslate"><span class="pre">build</span> <span class="pre">box</span> <span class="pre">crate</span></code> and have Evennia
see <code class="docutils literal notranslate"><span class="pre">&#64;create/drop</span> <span class="pre">box;crate</span></code>. You may use any <code class="docutils literal notranslate"><span class="pre">$</span></code> numbers between 1 and 99, but the markers must
match between the nick pattern and the replacement.</p>
<blockquote>
<div><p>If you want to catch “the rest” of a command argument, make sure to put a <code class="docutils literal notranslate"><span class="pre">$</span></code> tag <em>with no spaces
to the right of it</em> - it will then receive everything up until the end of the line.</p>
</div></blockquote>
<p>You can also use <a class="reference external" href="http://www.linfo.org/wildcard.html">shell-type wildcards</a>:</p>
<ul class="simple">
<li><p>* - matches everything.</p></li>
<li><p>? - matches a single character.</p></li>
<li><p>[seq] - matches everything in the sequence, e.g. [xyz] will match both x, y and z</p></li>
<li><p>[!seq] - matches everything <em>not</em> in the sequence. e.g. [!xyz] will match all but x,y z.</p></li>
</ul>
<div class="section" id="coding-with-nicks">
<h2>Coding with nicks<a class="headerlink" href="#coding-with-nicks" title="Permalink to this headline"></a></h2>
<p>Nicks are stored as the <code class="docutils literal notranslate"><span class="pre">Nick</span></code> database model and are referred from the normal Evennia
<a class="reference internal" href="Objects.html"><span class="doc">object</span></a> through the <code class="docutils literal notranslate"><span class="pre">nicks</span></code> property - this is known as the <em>NickHandler</em>. The NickHandler
offers effective error checking, searches and conversion.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># A command/channel nick:</span>
<span class="n">obj</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;greetjack&quot;</span><span class="p">,</span> <span class="s2">&quot;tell Jack = Hello pal!&quot;</span><span class="p">)</span>
<span class="c1"># An object nick: </span>
<span class="n">obj</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;rose&quot;</span><span class="p">,</span> <span class="s2">&quot;The red flower&quot;</span><span class="p">,</span> <span class="n">nick_type</span><span class="o">=</span><span class="s2">&quot;object&quot;</span><span class="p">)</span>
<span class="c1"># An account nick:</span>
<span class="n">obj</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;tom&quot;</span><span class="p">,</span> <span class="s2">&quot;Tommy Hill&quot;</span><span class="p">,</span> <span class="n">nick_type</span><span class="o">=</span><span class="s2">&quot;account&quot;</span><span class="p">)</span>
<span class="c1"># My own custom nick type (handled by my own game code somehow):</span>
<span class="n">obj</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;hood&quot;</span><span class="p">,</span> <span class="s2">&quot;The hooded man&quot;</span><span class="p">,</span> <span class="n">nick_type</span><span class="o">=</span><span class="s2">&quot;my_identsystem&quot;</span><span class="p">)</span>
<span class="c1"># get back the translated nick:</span>
<span class="n">full_name</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;rose&quot;</span><span class="p">,</span> <span class="n">nick_type</span><span class="o">=</span><span class="s2">&quot;object&quot;</span><span class="p">)</span>
<span class="c1"># delete a previous set nick</span>
<span class="nb">object</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">&quot;rose&quot;</span><span class="p">,</span> <span class="n">nick_type</span><span class="o">=</span><span class="s2">&quot;object&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>In a command definition you can reach the nick handler through <code class="docutils literal notranslate"><span class="pre">self.caller.nicks</span></code>. See the <code class="docutils literal notranslate"><span class="pre">nick</span></code>
command in <code class="docutils literal notranslate"><span class="pre">evennia/commands/default/general.py</span></code> for more examples.</p>
<p>As a last note, The Evennia <a class="reference internal" href="Communications.html"><span class="doc">channel</span></a> alias systems are using nicks with the
<code class="docutils literal notranslate"><span class="pre">nick_type=&quot;channel&quot;</span></code> in order to allow users to create their own custom aliases to channels.</p>
</div>
</div>
<div class="section" id="advanced-note">
<h1>Advanced note<a class="headerlink" href="#advanced-note" title="Permalink to this headline"></a></h1>
<p>Internally, nicks are <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a> saved with the <code class="docutils literal notranslate"><span class="pre">db_attrype</span></code> set to “nick” (normal
Attributes has this set to <code class="docutils literal notranslate"><span class="pre">None</span></code>).</p>
<p>The nick stores the replacement data in the Attribute.db_value field as a tuple with four fields
<code class="docutils literal notranslate"><span class="pre">(regex_nick,</span> <span class="pre">template_string,</span> <span class="pre">raw_nick,</span> <span class="pre">raw_template)</span></code>. Here <code class="docutils literal notranslate"><span class="pre">regex_nick</span></code> is the converted regex
representation of the <code class="docutils literal notranslate"><span class="pre">raw_nick</span></code> and the <code class="docutils literal notranslate"><span class="pre">template-string</span></code> is a version of the <code class="docutils literal notranslate"><span class="pre">raw_template</span></code>
prepared for efficient replacement of any <code class="docutils literal notranslate"><span class="pre">$</span></code>- type markers. The <code class="docutils literal notranslate"><span class="pre">raw_nick</span></code> and <code class="docutils literal notranslate"><span class="pre">raw_template</span></code> are
basically the unchanged strings you enter to the <code class="docutils literal notranslate"><span class="pre">nick</span></code> command (with unparsed <code class="docutils literal notranslate"><span class="pre">$</span></code> etc).</p>
<p>If you need to access the tuple for some reason, heres how:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="nb">tuple</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;nickname&quot;</span><span class="p">,</span> <span class="n">return_tuple</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span>
<span class="c1"># or, alternatively</span>
<span class="nb">tuple</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">nicks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;nickname&quot;</span><span class="p">,</span> <span class="n">return_obj</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span><span class="o">.</span><span class="n">value</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Nicks</a><ul>
<li><a class="reference internal" href="#coding-with-nicks">Coding with nicks</a></li>
</ul>
</li>
<li><a class="reference internal" href="#advanced-note">Advanced note</a></li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Nicks.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Nicks.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Nicks</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,304 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Objects &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Objects</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="objects">
<h1>Objects<a class="headerlink" href="#objects" title="Permalink to this headline"></a></h1>
<p>All in-game objects in Evennia, be it characters, chairs, monsters, rooms or hand grenades are
represented by an Evennia <em>Object</em>. Objects form the core of Evennia and is probably what youll
spend most time working with. Objects are <a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclassed</span></a> entities.</p>
<div class="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>
<p>An Evennia Object is, per definition, a Python class that includes <code class="docutils literal notranslate"><span class="pre">evennia.DefaultObject</span></code> among its
parents. In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects.py</span></code> there is already a class <code class="docutils literal notranslate"><span class="pre">Object</span></code> that inherits from
<code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> and that you can inherit from. You can put your new typeclass directly in that
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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># mygame/typeclasses/flowers.py</span>
<span class="kn">from</span> <span class="nn">typeclasses.objects</span> <span class="kn">import</span> <span class="n">Object</span>
<span class="k">class</span> <span class="nc">Rose</span><span class="p">(</span><span class="n">Object</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This creates a simple rose object </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">at_object_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="s2">&quot;this is called only once, when object is first created&quot;</span>
<span class="c1"># add a persistent attribute &#39;desc&#39; </span>
<span class="c1"># to object (silly example).</span>
<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">&quot;This is a pretty rose with thorns.&quot;</span>
</pre></div>
</td></tr></table></div>
<p>You could save this in the <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/objects.py</span></code> (then youd not need to import <code class="docutils literal notranslate"><span class="pre">Object</span></code>)
or you can put it in a new module. Lets say we do the latter, making a module
<code class="docutils literal notranslate"><span class="pre">typeclasses/flowers.py</span></code>. Now you just need to point to the class <em>Rose</em> with the <code class="docutils literal notranslate"><span class="pre">&#64;create</span></code> command
to make a new rose:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nd">@create</span><span class="o">/</span><span class="n">drop</span> <span class="n">MyRose</span><span class="p">:</span><span class="n">flowers</span><span class="o">.</span><span class="n">Rose</span>
</pre></div>
</div>
<p>What the <code class="docutils literal notranslate"><span class="pre">&#64;create</span></code> command actually <em>does</em> is to use <code class="docutils literal notranslate"><span class="pre">evennia.create_object</span></code>. You can do the same
thing yourself in code:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><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">&quot;typeclasses.flowers.Rose&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;MyRose&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>(The <code class="docutils literal notranslate"><span class="pre">&#64;create</span></code> command will auto-append the most likely path to your typeclass, if you enter the
call manually you have to give the full path to the class. The <code class="docutils literal notranslate"><span class="pre">create.create_object</span></code> function is
powerful and should be used for all coded object creating (so this is what you use when defining
your own building commands). Check out the <code class="docutils literal notranslate"><span class="pre">ev.create_*</span></code> functions for how to build other entities
like <a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a>).</p>
<p>This particular Rose class doesnt 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">&#64;desc</span></code> command or using the
<a class="reference internal" href="Spawner-and-Prototypes.html"><span class="doc">Spawner</span></a>). The <code class="docutils literal notranslate"><span class="pre">Object</span></code> typeclass offers many more hooks that is available
to use though - see next section.</p>
</div>
<div class="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>
<p>Beyond the properties assigned to all <a class="reference internal" href="Typeclasses.html"><span class="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">
<li><p><code class="docutils literal notranslate"><span class="pre">aliases</span></code> - a handler that allows you to add and remove aliases from this object. Use
<code class="docutils literal notranslate"><span class="pre">aliases.add()</span></code> to add a new alias and <code class="docutils literal notranslate"><span class="pre">aliases.remove()</span></code> to remove one.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">location</span></code> - a reference to the object currently containing this object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">home</span></code> is a backup location. The main motivation is to have a safe place to move the object to if
its <code class="docutils literal notranslate"><span class="pre">location</span></code> is destroyed. All objects should usually have a home location for safety.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">destination</span></code> - this holds a reference to another object this object links to in some way. Its
main use is for <a class="reference external" href="Components/Objects.html#Exits">Exits</a>, its otherwise usually unset.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">nicks</span></code> - as opposed to aliases, a <a class="reference internal" href="Nicks.html"><span class="doc">Nick</span></a> holds a convenient nickname replacement for a
real name, word or sequence, only valid for this object. This mainly makes sense if the Object is
used as a game character - it can then store briefer shorts, example so as to quickly reference game
commands or other characters. Use nicks.add(alias, realname) to add a new one.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">account</span></code> - this holds a reference to a connected <a class="reference internal" href="Accounts.html"><span class="doc">Account</span></a> controlling this object (if
any). Note that this is set also if the controlling account is <em>not</em> currently online - to test if
an account is online, use the <code class="docutils literal notranslate"><span class="pre">has_account</span></code> property instead.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">sessions</span></code> - if <code class="docutils literal notranslate"><span class="pre">account</span></code> field is set <em>and the account is online</em>, this is a list of all active
sessions (server connections) to contact them through (it may be more than one if multiple
connections are allowed in settings).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">has_account</span></code> - a shorthand for checking if an <em>online</em> account is currently connected to this
object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">contents</span></code> - this returns a list referencing all objects inside this object (i,e. which has this
object set as their <code class="docutils literal notranslate"><span class="pre">location</span></code>).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">exits</span></code> - this returns all objects inside this object that are <em>Exits</em>, that is, has the
<code class="docutils literal notranslate"><span class="pre">destination</span></code> property set.</p></li>
</ul>
<p>The last two properties are special:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">cmdset</span></code> - this is a handler that stores all <a class="reference external" href="Components/Commands.html#Command_Sets">command sets</a> defined on the
object (if any).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">scripts</span></code> - this is a handler that manages <a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a> attached to the object (if any).</p></li>
</ul>
<p>The Object also has a host of useful utility functions. See the function headers in
<code class="docutils literal notranslate"><span class="pre">src/objects/objects.py</span></code> for their arguments and more details.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">msg()</span></code> - this function is used to send messages from the server to an account connected to this
object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">msg_contents()</span></code> - calls <code class="docutils literal notranslate"><span class="pre">msg</span></code> on all objects inside this object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">search()</span></code> - this is a convenient shorthand to search for a specific object, at a given location
or globally. Its mainly useful when defining commands (in which case the object executing the
command is named <code class="docutils literal notranslate"><span class="pre">caller</span></code> and one can do <code class="docutils literal notranslate"><span class="pre">caller.search()</span></code> to find objects in the room to operate
on).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">execute_cmd()</span></code> - Lets the object execute the given string as if it was given on the command line.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">move_to</span></code> - perform a full move of this object to a new location. This is the main move method
and will call all relevant hooks, do all checks etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">clear_exits()</span></code> - will delete all <a class="reference external" href="Components/Objects.html#Exits">Exits</a> to <em>and</em> from this object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">clear_contents()</span></code> - this will not delete anything, but rather move all contents (except Exits) to
their designated <code class="docutils literal notranslate"><span class="pre">Home</span></code> locations.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">delete()</span></code> - deletes this object, first calling <code class="docutils literal notranslate"><span class="pre">clear_exits()</span></code> and
<code class="docutils literal notranslate"><span class="pre">clear_contents()</span></code>.</p></li>
</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 external" href="../api/evennia.objects.objects.html#defaultobject">API for DefaultObject
here</a>.</p>
</div>
<div class="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>
<div class="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">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 external" href="Components/Commands.html#Command_Sets">Default Commandset</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>
</div>
<div class="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">&#64;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>
</div>
<div class="section" id="exits">
<h3>Exits<a class="headerlink" href="#exits" title="Permalink to this headline"></a></h3>
<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">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 Exitss <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 (its not recommended though, unless you really know what you are
doing). Exits are <a class="reference internal" href="Locks.html"><span class="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 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">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>
<li><p>The Exit command checks the <code class="docutils literal notranslate"><span class="pre">traverse</span></code> lock on the Exit object</p></li>
<li><p>The Exit command triggers <code class="docutils literal notranslate"><span class="pre">at_traverse(obj,</span> <span class="pre">destination)</span></code> on the Exit object.</p></li>
<li><p>In <code class="docutils literal notranslate"><span class="pre">at_traverse</span></code>, <code class="docutils literal notranslate"><span class="pre">object.move_to(destination)</span></code> is triggered. This triggers the following hooks,
in order:</p>
<ol class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">obj.at_before_move(destination)</span></code> - if this returns False, move is aborted.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">origin.at_before_leave(obj,</span> <span class="pre">destination)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">obj.announce_move_from(destination)</span></code></p></li>
<li><p>Move is performed by changing <code class="docutils literal notranslate"><span class="pre">obj.location</span></code> from source location to <code class="docutils literal notranslate"><span class="pre">destination</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">obj.announce_move_to(source)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">destination.at_object_receive(obj,</span> <span class="pre">source)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">obj.at_after_move(source)</span></code></p></li>
</ol>
</li>
<li><p>On the Exit object, <code class="docutils literal notranslate"><span class="pre">at_after_traverse(obj,</span> <span class="pre">source)</span></code> is triggered.</p></li>
</ol>
<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>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#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>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Objects.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Objects.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Objects</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Outputfuncs &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Outputfuncs</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="outputfuncs">
<h1>Outputfuncs<a class="headerlink" href="#outputfuncs" title="Permalink to this headline"></a></h1>
<p>TODO. For now info about outputfuncs are found in <a class="reference internal" href="../Concepts/OOB.html"><span class="doc">OOB</span></a>.</p>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Outputfuncs.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Outputfuncs.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Outputfuncs</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Portal And Server &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Portal And Server</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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/Start-Stop-Reload.html"><span class="doc">here</span></a>.</p>
<p>If you are new to the concept, the main purpose of separating the two is to have accounts connect to
the Portal but keep the MUD running on the Server. This way one can restart/reload the game (the
Server part) without Accounts getting disconnected.</p>
<p>![portal and server layout](https://474a3b9f-a-62cb3a1a-s-
sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia_server_portal.png)</p>
<p>The Server and Portal are glued together via an AMP (Asynchronous Messaging Protocol) connection.
This allows the two programs to communicate seamlessly.</p>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Portal-And-Server.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Portal-And-Server.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Portal And Server</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,537 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Scripts &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Scripts</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="scripts">
<h1>Scripts<a class="headerlink" href="#scripts" title="Permalink to this headline"></a></h1>
<p><em>Scripts</em> are the out-of-character siblings to the in-character
<a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a>. Scripts are so flexible that the “Script” is a bit limiting</p>
<ul class="simple">
<li><p>we had to pick something to name them after all. Other possible names
(depending on what youd 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></li>
</ul>
<p>Scripts can be used for many different things in Evennia:</p>
<ul class="simple">
<li><p>They can attach to Objects to influence them in various ways - or exist
independently of any one in-game entity (so-called <em>Global Scripts</em>).</p></li>
<li><p>They can work as timers and tickers - anything that may change with Time. But
they can also have no time dependence at all. Note though that if all you want
is just to have an object method called repeatedly, you should consider using
the <a class="reference internal" href="TickerHandler.html"><span class="doc">TickerHandler</span></a> which is more limited but is specialized on
just this task.</p></li>
<li><p>They can describe State changes. A Script is an excellent platform for
hosting a persistent, but unique system handler. For example, a Script could be
used as the base to track the state of a turn-based combat system. Since
Scripts can also operate on a timer they can also update themselves regularly
to perform various actions.</p></li>
<li><p>They can act as data stores for storing game data persistently in the database
(thanks to its ability to have <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a>).</p></li>
<li><p>They can be used as OOC stores for sharing data between groups of objects, for
example for tracking the turns in a turn-based combat system or barter exchange.</p></li>
</ul>
<p>Scripts are <a class="reference internal" href="Typeclasses.html"><span class="doc">Typeclassed</span></a> entities and are manipulated in a similar
way to how it works for other such Evennia entities:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># create a new script </span>
<span class="n">new_script</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">&quot;myscript&quot;</span><span class="p">,</span> <span class="n">typeclass</span><span class="o">=...</span><span class="p">)</span>
<span class="c1"># search (this is always a list, also if there is only one match)</span>
<span class="n">list_of_myscript</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_script</span><span class="p">(</span><span class="s2">&quot;myscript&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<div class="section" id="defining-new-scripts">
<h2>Defining new Scripts<a class="headerlink" href="#defining-new-scripts" title="Permalink to this headline"></a></h2>
<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">typeclassed</span></a> entities. The class has several properties
to control the timer-component of the scripts. These are all <em>optional</em> -
leaving them out will just create a Script with no timer components (useful to act as
a database store or to hold a persistent game system, for example).</p>
<p>This you can do for example in the module
<code class="docutils literal notranslate"><span class="pre">evennia/typeclasses/scripts.py</span></code>. Below is an example Script
Typeclass.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
<span class="k">class</span> <span class="nc">MyScript</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;myscript&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">60</span> <span class="c1"># 1 min repeat</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="c1"># do stuff every minute </span>
</pre></div>
</td></tr></table></div>
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/scripts.py</span></code> is the <code class="docutils literal notranslate"><span class="pre">Script</span></code> class which inherits from <code class="docutils literal notranslate"><span class="pre">DefaultScript</span></code>
already. This is provided as your own base class to do with what you like: You can tweak <code class="docutils literal notranslate"><span class="pre">Script</span></code> if
you want to change the default behavior and it is usually convenient to inherit from this instead.
Heres an example:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># for example in mygame/typeclasses/scripts.py </span>
<span class="c1"># Script class is defined at the top of this module</span>
<span class="kn">import</span> <span class="nn">random</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="sd">&quot;&quot;&quot;</span>
<span class="sd"> A timer script that displays weather info. Meant to </span>
<span class="sd"> be attached to a room. </span>
<span class="sd"> </span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;weather_script&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">&quot;Gives random weather messages.&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">5</span> <span class="c1"># every 5 minutes</span>
<span class="bp">self</span><span class="o">.</span><span class="n">persistent</span> <span class="o">=</span> <span class="bp">True</span> <span class="c1"># will survive reload</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="s2">&quot;called every self.interval seconds.&quot;</span>
<span class="n">rand</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span>
<span class="k">if</span> <span class="n">rand</span> <span class="o">&lt;</span> <span class="mf">0.5</span><span class="p">:</span>
<span class="n">weather</span> <span class="o">=</span> <span class="s2">&quot;A faint breeze is felt.&quot;</span>
<span class="k">elif</span> <span class="n">rand</span> <span class="o">&lt;</span> <span class="mf">0.7</span><span class="p">:</span>
<span class="n">weather</span> <span class="o">=</span> <span class="s2">&quot;Clouds sweep across the sky.&quot;</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">weather</span> <span class="o">=</span> <span class="s2">&quot;There is a light drizzle of rain.&quot;</span>
<span class="c1"># send this message to everyone inside the object this</span>
<span class="c1"># script is attached to (likely a room)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="n">weather</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>If we put this script on a room, it will randomly report some weather
to everyone in the room every 5 minutes.</p>
<p>To activate it, just add it to the script handler (<code class="docutils literal notranslate"><span class="pre">scripts</span></code>) on an
<a class="reference internal" href="Objects.html"><span class="doc">Room</span></a>. That object becomes <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> in the example above. Here we
put it on a room called <code class="docutils literal notranslate"><span class="pre">myroom</span></code>:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">myroom</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">scripts</span><span class="o">.</span><span class="n">Weather</span><span class="p">)</span>
</pre></div>
</div>
<blockquote>
<div><p>Note that <code class="docutils literal notranslate"><span class="pre">typeclasses</span></code> in your game dir is added to the setting <code class="docutils literal notranslate"><span class="pre">TYPECLASS_PATHS</span></code>.
Therefore we dont need to give the full path (<code class="docutils literal notranslate"><span class="pre">typeclasses.scripts.Weather</span></code>
but only <code class="docutils literal notranslate"><span class="pre">scripts.Weather</span></code> above.</p>
</div></blockquote>
<p>You can also create scripts using the <code class="docutils literal notranslate"><span class="pre">evennia.create_script</span></code> function:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><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_script</span>
<span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.weather.Weather&#39;</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">myroom</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Note that if you were to give a keyword argument to <code class="docutils literal notranslate"><span class="pre">create_script</span></code>, that would
override the default value in your Typeclass. So for example, here is an instance
of the weather script that runs every 10 minutes instead (and also not survive
a server reload):</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.weather.Weather&#39;</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">myroom</span><span class="p">,</span>
<span class="n">persistent</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">interval</span><span class="o">=</span><span class="mi">10</span><span class="o">*</span><span class="mi">60</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>From in-game you can use the <code class="docutils literal notranslate"><span class="pre">&#64;script</span></code> command to launch the Script on things:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nd">@script</span> <span class="n">here</span> <span class="o">=</span> <span class="n">typeclasses</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">Weather</span>
</pre></div>
</div>
<p>You can conveniently view and kill running Scripts by using the <code class="docutils literal notranslate"><span class="pre">&#64;scripts</span></code>
command in-game.</p>
</div>
<div class="section" id="properties-and-functions-defined-on-scripts">
<h2>Properties and functions defined on Scripts<a class="headerlink" href="#properties-and-functions-defined-on-scripts" title="Permalink to this headline"></a></h2>
<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">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 Scripts 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">desc</span></code> - an optional description of the scripts function. Seen in script listings.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">interval</span></code> - how often the script should run. If <code class="docutils literal notranslate"><span class="pre">interval</span> <span class="pre">==</span> <span class="pre">0</span></code> (default), this script has no
timing component, will not repeat and will exist forever. This is useful for Scripts used for
storage or acting as bases for various non-time dependent game systems.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">start_delay</span></code> - (bool), if we should wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds before firing for the first time or
not.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">repeats</span></code> - How many times we should repeat, assuming <code class="docutils literal notranslate"><span class="pre">interval</span> <span class="pre">&gt;</span> <span class="pre">0</span></code>. If repeats is set to <code class="docutils literal notranslate"><span class="pre">&lt;=</span> <span class="pre">0</span></code>,
the script will repeat indefinitely. Note that <em>each</em> firing of the script (including the first one)
counts towards this value. So a <code class="docutils literal notranslate"><span class="pre">Script</span></code> with <code class="docutils literal notranslate"><span class="pre">start_delay=False</span></code> and <code class="docutils literal notranslate"><span class="pre">repeats=1</span></code> will start,
immediately fire and shut down right away.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code>- if this script should survive a server <em>reset</em> or server <em>shutdown</em>. (You dont need
to set this for it to survive a normal reload - the script will be paused and seamlessly restart
after the reload is complete).</p></li>
</ul>
<p>There is one special property:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">obj</span></code> - the <a class="reference internal" href="Objects.html"><span class="doc">Object</span></a> this script is attached to (if any). You should not need to set
this manually. If you add the script to the Object with <code class="docutils literal notranslate"><span class="pre">myobj.scripts.add(myscriptpath)</span></code> or give
<code class="docutils literal notranslate"><span class="pre">myobj</span></code> as an argument to the <code class="docutils literal notranslate"><span class="pre">utils.create.create_script</span></code> function, the <code class="docutils literal notranslate"><span class="pre">obj</span></code> property will be set
to <code class="docutils literal notranslate"><span class="pre">myobj</span></code> for you.</p></li>
</ul>
<p>Its also imperative to know the hook functions. Normally, overriding
these are all the customization youll need to do in Scripts. You can
find longer descriptions of these in <code class="docutils literal notranslate"><span class="pre">src/scripts/scripts.py</span></code>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">at_script_creation()</span></code> - this is usually where the script class sets things like <code class="docutils literal notranslate"><span class="pre">interval</span></code> and
<code class="docutils literal notranslate"><span class="pre">repeats</span></code>; things that control how the script runs. It is only called once - when the script is
first created.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">is_valid()</span></code> - determines if the script should still be running or not. This is called when
running <code class="docutils literal notranslate"><span class="pre">obj.scripts.validate()</span></code>, which you can run manually, but which is also called by Evennia
during certain situations such as reloads. This is also useful for using scripts as state managers.
If the method returns <code class="docutils literal notranslate"><span class="pre">False</span></code>, the script is stopped and cleanly removed.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_start()</span></code> - this is called when the script starts or is unpaused. For persistent scripts this
is at least once ever server startup. Note that this will <em>always</em> be called right away, also if
<code class="docutils literal notranslate"><span class="pre">start_delay</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code> - this is called every <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds, or not at all. It is called right away at
startup, unless <code class="docutils literal notranslate"><span class="pre">start_delay</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code>, in which case the system will wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds
before calling.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_stop()</span></code> - this is called when the script stops for whatever reason. Its a good place to do
custom cleanup.</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">&#64;reload</span></code> command). Its 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>
</ul>
<p>Running methods (usually called automatically by the engine, but possible to also invoke manually)</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">start()</span></code> - this will start the script. This is called automatically whenever you add a new script
to a handler. <code class="docutils literal notranslate"><span class="pre">at_start()</span></code> will be called.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">stop()</span></code> - this will stop the script and delete it. Removing a script from a handler will stop it
automatically. <code class="docutils literal notranslate"><span class="pre">at_stop()</span></code> will be called.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pause()</span></code> - this pauses a running script, rendering it inactive, but not deleting it. All
properties are saved and timers can be resumed. This is called automatically when the server reloads
and will <em>not</em> lead to the <em>at_stop()</em> hook being called. This is a suspension of the script, not a
change of state.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">unpause()</span></code> - resumes a previously paused script. The <code class="docutils literal notranslate"><span class="pre">at_start()</span></code> hook <em>will</em> be called to allow
it to reclaim its internal state. Timers etc are restored to what they were before pause. The server
automatically unpauses all paused scripts after a server reload.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">force_repeat()</span></code> - this will forcibly step the script, regardless of when it would otherwise have
fired. The timer will reset and the <code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code> hook is called as normal. This also counts towards
the total number of repeats, if limited.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">time_until_next_repeat()</span></code> - for timed scripts, this returns the time in seconds until it next
fires. Returns <code class="docutils literal notranslate"><span class="pre">None</span></code> if <code class="docutils literal notranslate"><span class="pre">interval==0</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">remaining_repeats()</span></code> - if the Script should run a limited amount of times, this tells us how many
are currently left.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">reset_callcount(value=0)</span></code> - this allows you to reset the number of times the Script has fired. It
only makes sense if <code class="docutils literal notranslate"><span class="pre">repeats</span> <span class="pre">&gt;</span> <span class="pre">0</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">restart(interval=None,</span> <span class="pre">repeats=None,</span> <span class="pre">start_delay=None)</span></code> - this method allows you to restart the
Script in-place with different run settings. If you do, the <code class="docutils literal notranslate"><span class="pre">at_stop</span></code> hook will be called and the
Script brought to a halt, then the <code class="docutils literal notranslate"><span class="pre">at_start</span></code> hook will be called as the Script starts up with your
(possibly changed) settings. Any keyword left at <code class="docutils literal notranslate"><span class="pre">None</span></code> means to not change the original setting.</p></li>
</ul>
</div>
<div class="section" id="global-scripts">
<h2>Global Scripts<a class="headerlink" href="#global-scripts" title="Permalink to this headline"></a></h2>
<p>A script does not have to be connected to an in-game object. If not it is
called a <em>Global script</em>. You can create global scripts by simply not supplying an object to store
it on:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># adding a global script</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_script</span>
<span class="n">create_script</span><span class="p">(</span><span class="s2">&quot;typeclasses.globals.MyGlobalEconomy&quot;</span><span class="p">,</span>
<span class="n">key</span><span class="o">=</span><span class="s2">&quot;economy&quot;</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Henceforth you can then get it back by searching for its key or other identifier with
<code class="docutils literal notranslate"><span class="pre">evennia.search_script</span></code>. In-game, the <code class="docutils literal notranslate"><span class="pre">scripts</span></code> command will show all scripts.</p>
<p>Evennia supplies a convenient “container” called <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> that can offer an easy
way to access global scripts. If you know the name (key) of the script you can get it like so:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><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>
<span class="n">my_script</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">my_script</span>
<span class="c1"># needed if there are spaces in name or name determined on the fly</span>
<span class="n">another_script</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;another script&quot;</span><span class="p">)</span>
<span class="c1"># get all global scripts (this returns a Queryset)</span>
<span class="n">all_scripts</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
<span class="c1"># you can operate directly on the script</span>
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">weather</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">current_weather</span> <span class="o">=</span> <span class="s2">&quot;Cloudy&quot;</span>
</pre></div>
</td></tr></table></div>
<blockquote>
<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_script</span></code> to get exactly the script you want.</p>
</div></blockquote>
<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>. The first is
to manually create a new global script with <code class="docutils literal notranslate"><span class="pre">create_script</span></code> as mentioned above. Often you want this
to happen automatically when the server starts though. For this you can use the setting
<code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">GLOBAL_SCRIPTS</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;my_script&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;typeclass&quot;</span><span class="p">:</span> <span class="s2">&quot;scripts.Weather&quot;</span><span class="p">,</span>
<span class="s2">&quot;repeats&quot;</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
<span class="s2">&quot;interval&quot;</span><span class="p">:</span> <span class="mi">50</span><span class="p">,</span>
<span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Weather script&quot;</span>
<span class="s2">&quot;persistent&quot;</span><span class="p">:</span> <span class="bp">True</span>
<span class="p">},</span>
<span class="s2">&quot;storagescript&quot;</span><span class="p">:</span> <span class="p">{</span>
<span class="s2">&quot;typeclass&quot;</span><span class="p">:</span> <span class="s2">&quot;scripts.Storage&quot;</span><span class="p">,</span>
<span class="s2">&quot;persistent&quot;</span><span class="p">:</span> <span class="bp">True</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></div>
<p>Here the key (<code class="docutils literal notranslate"><span class="pre">myscript</span></code> and <code class="docutils literal notranslate"><span class="pre">storagescript</span></code> above) is required, all other fields are optional. If
<code class="docutils literal notranslate"><span class="pre">typeclass</span></code> is not given, a script of type <code class="docutils literal notranslate"><span class="pre">settings.BASE_SCRIPT_TYPECLASS</span></code> is assumed. The keys
related to timing and intervals are only needed if the script is timed.</p>
<p>Evennia will use the information in <code class="docutils literal notranslate"><span class="pre">settings.GLOBAL_SCRIPTS</span></code> to automatically create and start
these
scripts when the server starts (unless they already exist, based on their <code class="docutils literal notranslate"><span class="pre">key</span></code>). You need to reload
the server before the setting is read and new scripts become available. You can then find the <code class="docutils literal notranslate"><span class="pre">key</span></code>
you gave as properties on <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS</span></code>
(such as <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS.storagescript</span></code>).</p>
<blockquote>
<div><p>Note: Make sure that your Script typeclass does not have any critical errors. If so, youll 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></blockquote>
<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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><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>
<span class="c1"># first stop the script </span>
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">storagescript</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
<span class="c1"># running the `scripts` command now will show no storagescript</span>
<span class="c1"># but below now it&#39;s recreated again! </span>
<span class="n">storage</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">storagescript</span>
</pre></div>
</td></tr></table></div>
<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>, it will use the
information
in settings to recreate it for you.</p>
<blockquote>
<div><p>Note that if your goal with the Script is to store persistent data, you should set it as
<code class="docutils literal notranslate"><span class="pre">persistent=True</span></code>, either in <code class="docutils literal notranslate"><span class="pre">settings.GLOBAL_SCRIPTS</span></code> or in the Scripts typeclass. Otherwise any
data you wanted to store on it will be gone (since a new script of the same name is restarted
instead).</p>
</div></blockquote>
</div>
<div class="section" id="dealing-with-errors">
<h2>Dealing with Errors<a class="headerlink" href="#dealing-with-errors" title="Permalink to this headline"></a></h2>
<p>Errors inside an 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 Evennias native logger and wrap your
functions in a try/catch block. Evennias logger can show you where the
traceback occurred in your script.</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15</pre></div></td><td class="code"><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">DefaultScript</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"># [...] code as above</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="c1"># logs the error </span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
</div>
<div class="section" id="example-of-a-timed-script">
<h2>Example of a timed script<a class="headerlink" href="#example-of-a-timed-script" title="Permalink to this headline"></a></h2>
<p>In-game you can try out scripts using the <code class="docutils literal notranslate"><span class="pre">&#64;script</span></code> command. In the
<code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples/bodyfunctions.py</span></code> is a little example script
that makes you do little sounds at random intervals. Try the following to apply an
example time-based script to your character.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@script</span> <span class="bp">self</span> <span class="o">=</span> <span class="n">bodyfunctions</span><span class="o">.</span><span class="n">BodyFunctions</span>
</pre></div>
</div>
<blockquote>
<div><p>Note: Since <code class="docutils literal notranslate"><span class="pre">evennia/contrib/tutorial_examples</span></code> is in the default setting
<code class="docutils literal notranslate"><span class="pre">TYPECLASS_PATHS</span></code>, we only need to specify the final part of the path,
that is, <code class="docutils literal notranslate"><span class="pre">bodyfunctions.BodyFunctions</span></code>.</p>
</div></blockquote>
<p>If you want to inflict your flatulence script on another person, place or
thing, try something like the following:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@py</span> <span class="bp">self</span><span class="o">.</span><span class="n">location</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s1">&#39;matt&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s1">&#39;bodyfunctions.BodyFunctions&#39;</span><span class="p">)</span>
</pre></div>
</div>
<p>Heres how you stop it on yourself.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nd">@script</span><span class="o">/</span><span class="n">stop</span> <span class="bp">self</span> <span class="o">=</span> <span class="n">bodyfunctions</span><span class="o">.</span><span class="n">BodyFunctions</span>
</pre></div>
</div>
<p>This will kill the script again. You can use the <code class="docutils literal notranslate"><span class="pre">&#64;scripts</span></code> command to list all
active scripts in the game, if any (there are none by default).</p>
<p>For another example of a Script in use, check out the <a class="reference external" href="https://github.com/evennia/evennia/wiki/Turn%20based%20Combat%20System">Turn Based Combat System
tutorial</a>.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#defining-new-scripts">Defining new Scripts</a></li>
<li><a class="reference internal" href="#properties-and-functions-defined-on-scripts">Properties and functions defined on Scripts</a></li>
<li><a class="reference internal" href="#global-scripts">Global Scripts</a></li>
<li><a class="reference internal" href="#dealing-with-errors">Dealing with Errors</a></li>
<li><a class="reference internal" href="#example-of-a-timed-script">Example of a timed script</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Scripts.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Scripts.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Scripts</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,209 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Server Conf &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Server Conf</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="server-conf">
<h1>Server Conf<a class="headerlink" href="#server-conf" title="Permalink to this headline"></a></h1>
<p>Evennia runs out of the box without any changes to its settings. But there are several important
ways to customize the server and expand it with your own plugins.</p>
<div class="section" id="settings-file">
<h2>Settings file<a class="headerlink" href="#settings-file" title="Permalink to this headline"></a></h2>
<p>The “Settings” file referenced throughout the documentation is the file
<code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>. This is automatically created on the first run of <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">--init</span></code>
(see the <a class="reference internal" href="../Setup/Setup-Quickstart.html"><span class="doc">Setup Quickstart</span></a> page).</p>
<p>Your new <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> is relatively bare out of the box. Evennias core settings file is actually
<a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia/settings_default.py">evennia/settings_default.py</a>
and is considerably more extensive (it is also heavily documented so you should refer to this file
directly for the available settings).</p>
<p>Since <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> is a normal Python module, it simply imports
<code class="docutils literal notranslate"><span class="pre">evennia/settings_default.py</span></code> into itself at the top.</p>
<p>This means that if any setting you want to change were to depend on some <em>other</em> default setting,
you might need to copy &amp; paste both in order to change them and get the effect you want (for most
commonly changed settings, this is not something you need to worry about).</p>
<p>You should never edit <code class="docutils literal notranslate"><span class="pre">evennia/settings_default.py</span></code>. Rather you should copy&amp;paste the select
variables you want to change into your <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> and edit them there. This will overload the
previously imported defaults.</p>
<blockquote>
<div><p>Warning: It may be tempting to copy everything from <code class="docutils literal notranslate"><span class="pre">settings_default.py</span></code> into your own settings
file. There is a reason we dont do this out of the box though: it makes it directly clear what
changes you did. Also, if you limit your copying to the things you really need you will directly be
able to take advantage of upstream changes and additions to Evennia for anything you didnt
customize.</p>
</div></blockquote>
<p>In code, the settings is accessed through</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="c1"># or (shorter):</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="c1"># example:</span>
<span class="n">servername</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">SERVER_NAME</span>
</pre></div>
</td></tr></table></div>
<p>Each setting appears as a property on the imported <code class="docutils literal notranslate"><span class="pre">settings</span></code> object. You can also explore all
possible options with <code class="docutils literal notranslate"><span class="pre">evennia.settings_full</span></code> (this also includes advanced Django defaults that are
not touched in default Evennia).</p>
<blockquote>
<div><p>It should be pointed out that when importing <code class="docutils literal notranslate"><span class="pre">settings</span></code> into your code like this, it will be <em>read
only</em>. You <em>cannot</em> edit your settings from your code! The only way to change an Evennia setting is
to edit <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> directly. You also generally need to restart the server
(possibly also the Portal) before a changed setting becomes available.</p>
</div></blockquote>
</div>
<div class="section" id="other-files-in-the-server-conf-directory">
<h2>Other files in the <code class="docutils literal notranslate"><span class="pre">server/conf</span></code> directory<a class="headerlink" href="#other-files-in-the-server-conf-directory" title="Permalink to this headline"></a></h2>
<p>Apart from the main <code class="docutils literal notranslate"><span class="pre">settings.py</span></code> file,</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">at_initial_setup.py</span></code> - this allows you to add a custom startup method to be called (only) the
very first time Evennia starts (at the same time as user #1 and Limbo is created). It can be made to
start your own global scripts or set up other system/world-related things your game needs to have
running from the start.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_startstop.py</span></code> - this module contains two functions that Evennia will call every time
the Server starts and stops respectively - this includes stopping due to reloading and resetting as
well as shutting down completely. Its a useful place to put custom startup code for handlers and
other things that must run in your game but which has no database persistence.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">connection_screens.py</span></code> - all global string variables in this module are interpreted by Evennia as
a greeting screen to show when an Account first connects. If more than one string variable is
present in the module a random one will be picked.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">inlinefuncs.py</span></code> - this is where you can define custom <a class="reference external" href="Concepts/TextTags.html#inlinefuncs">Inline functions</a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">inputfuncs.py</span></code> - this is where you define custom <a class="reference internal" href="Inputfuncs.html"><span class="doc">Input functions</span></a> to handle data
from the client.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">lockfuncs.py</span></code> - this is one of many possible modules to hold your own “safe” <em>lock functions</em> to
make available to Evennias <a class="reference internal" href="Locks.html"><span class="doc">Locks</span></a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">mssp.py</span></code> - this holds meta information about your game. It is used by MUD search engines (which
you often have to register with) in order to display what kind of game you are running along with
statistics such as number of online accounts and online status.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">oobfuncs.py</span></code> - in here you can define custom <a class="reference internal" href="../Concepts/OOB.html"><span class="doc">OOB functions</span></a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">portal_services_plugin.py</span></code> - this allows for adding your own custom services/protocols to the
Portal. It must define one particular function that will be called by Evennia at startup. There can
be any number of service plugin modules, all will be imported and used if defined. More info can be
found <a class="reference external" href="http://code.google.com/p/evennia/wiki/SessionProtocols#Adding_custom_Protocols">here</a>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">server_services_plugin.py</span></code> - this is equivalent to the previous one, but used for adding new
services to the Server instead. More info can be found
<a class="reference external" href="http://code.google.com/p/evennia/wiki/SessionProtocols#Adding_custom_Protocols">here</a>.</p></li>
</ul>
<p>Some other Evennia systems can be customized by plugin modules but has no explicit template in
<code class="docutils literal notranslate"><span class="pre">conf/</span></code>:</p>
<ul class="simple">
<li><p><em>cmdparser.py</em> - a custom module can be used to totally replace Evennias default command parser.
All this does is to split the incoming string into “command name” and “the rest”. It also handles
things like error messages for no-matches and multiple-matches among other things that makes this
more complex than it sounds. The default parser is <em>very</em> generic, so you are most often best served
by modifying things further down the line (on the command parse level) than here.</p></li>
<li><p><em>at_search.py</em> - this allows for replacing the way Evennia handles search results. It allows to
change how errors are echoed and how multi-matches are resolved and reported (like how the default
understands that “2-ball” should match the second “ball” object if there are two of them in the
room).</p></li>
</ul>
</div>
<div class="section" id="serverconf">
<h2>ServerConf<a class="headerlink" href="#serverconf" title="Permalink to this headline"></a></h2>
<p>There is a special database model called <code class="docutils literal notranslate"><span class="pre">ServerConf</span></code> that stores server internal data and settings
such as current account count (for interfacing with the webserver), startup status and many other
things. Its rarely of use outside the server core itself but may be good to
know about if you are an Evennia developer.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Server Conf</a><ul>
<li><a class="reference internal" href="#settings-file">Settings file</a></li>
<li><a class="reference internal" href="#other-files-in-the-server-conf-directory">Other files in the <code class="docutils literal notranslate"><span class="pre">server/conf</span></code> directory</a></li>
<li><a class="reference internal" href="#serverconf">ServerConf</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Server-Conf.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Server-Conf.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Server Conf</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Server component &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Server component</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="server-component">
<h1>Server component<a class="headerlink" href="#server-component" title="Permalink to this headline"></a></h1>
<p>TODO: This is currently in <a class="reference internal" href="Portal-And-Server.html"><span class="doc">Portal-and-Server</span></a>.</p>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Server.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Server.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Server component</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,289 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sessions &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Sessions</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="sessions">
<h1>Sessions<a class="headerlink" href="#sessions" title="Permalink to this headline"></a></h1>
<p>An Evennia <em>Session</em> represents one single established connection to the server. Depending on the
Evennia session, it is possible for a person to connect multiple times, for example using different
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">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">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>
<blockquote>
<div><p>Warning: A Session is not <em>persistent</em> - it is not a <a class="reference internal" href="Typeclasses.html"><span class="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 dont 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 dont store any data on Sessions that you cant afford to
lose in a reload. You have been warned.</p>
</div></blockquote>
<div class="section" id="properties-on-sessions">
<h2>Properties on Sessions<a class="headerlink" href="#properties-on-sessions" title="Permalink to this headline"></a></h2>
<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 clients 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">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">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">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 dont 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 Sessions <a class="reference internal" href="Command-Sets.html"><span class="doc">CmdSetHandler</span></a></p></li>
</ul>
<p>Session statistics are mainly used internally by Evennia.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">conn_time</span></code> - How long this Session has been connected</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">cmd_last</span></code> - Last active time stamp. This will be reset by sending <code class="docutils literal notranslate"><span class="pre">idle</span></code> keepalives.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">cmd_last_visible</span></code> - last active time stamp. This ignores <code class="docutils literal notranslate"><span class="pre">idle</span></code> keepalives and representes the
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>
</div>
<div class="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 class="simple">
<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. In default Evennia,
this mode also changes how the <code class="docutils literal notranslate"><span class="pre">create</span> <span class="pre">account</span></code> Command works - it will automatically create a
Character with the <em>same name</em> as the Account. When logging in, the login command is also modified
to have the player automatically puppet that Character. This makes the distinction between Account
and Character minimal from the players perspective.</p></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. This mode will have the
Session(s) auto-create and puppet a Character in the same way as mode 0.</p></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 players perspective, this will mean that they can open separate game clients
and play a different Character in each using one game account.
This mode will <em>not</em> auto-create a Character and <em>not</em> auto-puppet on login like in modes 0 and 1.
Instead it changes how the account-cmdsetss <code class="docutils literal notranslate"><span class="pre">OOCLook</span></code> command works so as to show a simple
character select menu.</p></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 users perspective it means one can open
multiple client windows, some for controlling different Characters and some that share a Characters
input/output like in mode 1. This mode otherwise works the same as mode 2.</p></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>
</div>
<div class="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>
<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(&quot;hello&quot;)</span></code> there is no way for evennia to know which session it
should send the greeting to. In this case it will send it to all sessions. If you want a specific
session you need to supply its session to the <code class="docutils literal notranslate"><span class="pre">msg</span></code> call (<code class="docutils literal notranslate"><span class="pre">account.msg(&quot;hello&quot;,</span> <span class="pre">session=mysession)</span></code>).</p>
<p>On the other hand, if you call the <code class="docutils literal notranslate"><span class="pre">msg()</span></code> message on a puppeted object, like
<code class="docutils literal notranslate"><span class="pre">character.msg(&quot;hello&quot;)</span></code>, the character already knows the session that controls it - it will
cleverly auto-add this for you (you can specify a different session if you specifically want to send
stuff to another session).</p>
<p>Finally, there is a wrapper for <code class="docutils literal notranslate"><span class="pre">msg()</span></code> on all command classes: <code class="docutils literal notranslate"><span class="pre">command.msg()</span></code>. This will
transparently detect which session was triggering the command (if any) and redirects to that session
(this is most often what you want). If you are having trouble redirecting to a given session,
<code class="docutils literal notranslate"><span class="pre">command.msg()</span></code> is often the safest bet.</p>
<p>You can get the <code class="docutils literal notranslate"><span class="pre">session</span></code> in two main ways:</p>
<ul class="simple">
<li><p><a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a> and <a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a> (including Characters) have a <code class="docutils literal notranslate"><span class="pre">sessions</span></code> property.
This is a <em>handler</em> that tracks all Sessions attached to or puppeting them. Use e.g.
<code class="docutils literal notranslate"><span class="pre">accounts.sessions.get()</span></code> to get a list of Sessions attached to that entity.</p></li>
<li><p>A Command instance has a <code class="docutils literal notranslate"><span class="pre">session</span></code> property that always points back to the Session that triggered
it (its always a single one). It will be <code class="docutils literal notranslate"><span class="pre">None</span></code> if no session is involved, like when a mob or
script triggers the Command.</p></li>
</ul>
</div>
<div class="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
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>
</div>
<div class="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 dont 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">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>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>
<p>During certain situations, the portal- and server-side sessions are
“synced” with each other:</p>
<ul class="simple">
<li><p>The Player closes their client, killing the Portal Session. The Portal syncs with the Server to
make sure the corresponding Server Session is also deleted.</p></li>
<li><p>The Player quits from inside the game, killing the Server Session. The Server then syncs with the
Portal to make sure to close the Portal connection cleanly.</p></li>
<li><p>The Server is rebooted/reset/shutdown - The Server Sessions are copied over (“saved”) to the
Portal side. When the Server comes back up, this data is returned by the Portal so the two are again
in sync. This way an Accounts 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>
</div>
<div class="section" id="sessionhandlers">
<h2>Sessionhandlers<a class="headerlink" href="#sessionhandlers" title="Permalink to this headline"></a></h2>
<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/Custom-Protocols.html"><span class="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="k">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></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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#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>
<li><a class="reference internal" href="#sessionhandlers">Sessionhandlers</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Sessions.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Sessions.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Sessions</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,222 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Signals &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Signals</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="signals">
<h1>Signals<a class="headerlink" href="#signals" title="Permalink to this headline"></a></h1>
<p><em>This is feature available from evennia 0.9 and onward</em>.</p>
<p>There are multiple ways for you to plug in your own functionality into Evennia.
The most common way to do so is through <em>hooks</em> - methods on typeclasses that
gets called at particular events. Hooks are great when you want a game entity
to behave a certain way when something happens to it. <em>Signals</em> complements
hooks for cases when you want to easily attach new functionality without
overriding things on the typeclass.</p>
<p>When certain events happen in Evennia, a <em>Signal</em> is fired. The idea is that
you can “attach” any number of event-handlers to these signals. You can attach
any number of handlers and theyll 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>
<div class="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>
<p>First you create your handler</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><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>
<span class="c1"># do stuff</span>
</pre></div>
</td></tr></table></div>
<p>The <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> is mandatory. Then you attach it to the signal of your choice:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.server</span> <span class="kn">import</span> <span class="n">signals</span>
<span class="n">signals</span><span class="o">.</span><span class="n">SIGNAL_OBJECT_POST_CREATE</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">myhandler</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>This particular signal fires after (post) an Account has connected to the game.
When that happens, <code class="docutils literal notranslate"><span class="pre">myhandler</span></code> will fire with the <code class="docutils literal notranslate"><span class="pre">sender</span></code> being the Account that just connected.</p>
<p>If you want to respond only to the effects of a specific entity you can do so
like this:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><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_account</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">signals</span>
<span class="n">account</span> <span class="o">=</span> <span class="n">search_account</span><span class="p">(</span><span class="s2">&quot;foo&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<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>
</td></tr></table></div>
</div>
<div class="section" id="available-signals">
<h2>Available signals<a class="headerlink" href="#available-signals" title="Permalink to this headline"></a></h2>
<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>
returns
<code class="docutils literal notranslate"><span class="pre">Account</span></code> instances as senders, <code class="docutils literal notranslate"><span class="pre">SIGNAL_OBJECT_*</span></code> returns <code class="docutils literal notranslate"><span class="pre">Object</span></code>s etc. Extra keywords (kwargs)
should
be extracted from the <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> dict in the signal handler.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_CREATE</span></code> - this is triggered at the very end of <code class="docutils literal notranslate"><span class="pre">Account.create()</span></code>. Note that
calling <code class="docutils literal notranslate"><span class="pre">evennia.create.create_account</span></code> (which is called internally by <code class="docutils literal notranslate"><span class="pre">Account.create</span></code>) will
<em>not</em>
trigger this signal. This is because using <code class="docutils literal notranslate"><span class="pre">Account.create()</span></code> is expected to be the most commonly
used way for users to themselves create accounts during login. It passes and extra kwarg <code class="docutils literal notranslate"><span class="pre">ip</span></code> with
the client IP of the connecting account.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_LOGIN</span></code> - this will always fire when the account has authenticated. Sends
extra kwarg <code class="docutils literal notranslate"><span class="pre">session</span></code> with the new <a class="reference internal" href="Sessions.html"><span class="doc">Session</span></a> object involved.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCCOUNT_POST_FIRST_LOGIN</span></code> - this fires just before <code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_LOGIN</span></code> but only
if
this is the <em>first</em> connection done (that is, if there are no previous sessions connected). Also
passes the <code class="docutils literal notranslate"><span class="pre">session</span></code> along as a kwarg.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_LOGIN_FAIL</span></code> - sent when someone tried to log into an account by failed.
Passes
the <code class="docutils literal notranslate"><span class="pre">session</span></code> as an extra kwarg.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_LOGOUT</span></code> - always fires when an account logs off, no matter if other sessions
remain or not. Passes the disconnecting <code class="docutils literal notranslate"><span class="pre">session</span></code> along as a kwarg.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_LAST_LOGOUT</span></code> - fires before <code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_LOGOUT</span></code>, but only if this is
the <em>last</em> Session to disconnect for that account. Passes the <code class="docutils literal notranslate"><span class="pre">session</span></code> as a kwarg.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_OBJECT_POST_PUPPET</span></code> - fires when an account puppets this object. Extra kwargs <code class="docutils literal notranslate"><span class="pre">session</span></code>
and <code class="docutils literal notranslate"><span class="pre">account</span></code> represent the puppeting entities.
<code class="docutils literal notranslate"><span class="pre">SIGNAL_OBJECT_POST_UNPUPPET</span></code> - fires when the sending object is unpuppeted. Extra kwargs are
<code class="docutils literal notranslate"><span class="pre">session</span></code> and <code class="docutils literal notranslate"><span class="pre">account</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_ACCOUNT_POST_RENAME</span></code> - triggered by the setting of <code class="docutils literal notranslate"><span class="pre">Account.username</span></code>. Passes extra
kwargs <code class="docutils literal notranslate"><span class="pre">old_name</span></code>, <code class="docutils literal notranslate"><span class="pre">new_name</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_TYPED_OBJECT_POST_RENAME</span></code> - triggered when any Typeclassed entitys <code class="docutils literal notranslate"><span class="pre">key</span></code> is changed.
Extra
kwargs passed are <code class="docutils literal notranslate"><span class="pre">old_key</span></code> and <code class="docutils literal notranslate"><span class="pre">new_key</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_SCRIPT_POST_CREATE</span></code> - fires when a script is first created, after any hooks.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_CHANNEL_POST_CREATE</span></code> - fires when a Channel is first created, after any hooks.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">SIGNAL_HELPENTRY_POST_CREATE</span></code> - fires when a help entry is first created.</p></li>
</ul>
<p>The <code class="docutils literal notranslate"><span class="pre">evennia.signals</span></code> module also gives you conveneient access to the default Django signals (these
use a
different naming convention).</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">pre_save</span></code> - fired when any database entitiys <code class="docutils literal notranslate"><span class="pre">.save</span></code> method fires, before any saving has
happened.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">post_save</span></code> - fires after saving a database entity.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pre_delete</span></code> - fires just before a database entity is deleted.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">post_delete</span></code> - fires after a database entity was deleted.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pre_init</span></code> - fires before a typeclass <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method (which in turn
happens before the <code class="docutils literal notranslate"><span class="pre">at_init</span></code> hook fires).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">post_init</span></code> - triggers at the end of <code class="docutils literal notranslate"><span class="pre">__init__</span></code> (still before the <code class="docutils literal notranslate"><span class="pre">at_init</span></code> hook).</p></li>
</ul>
<p>These are highly specialized Django signals that are unlikely to be useful to most users. But
they are included here for completeness.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">m2m_changed</span></code> - fires after a Many-to-Many field (like <code class="docutils literal notranslate"><span class="pre">db_attributes</span></code>) changes.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pre_migrate</span></code> - fires before database migration starts with <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">migrate</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">post_migrate</span></code> - fires after database migration finished.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">request_started</span></code> - sent when HTTP request begins.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">request_finished</span></code> - sent when HTTP request ends.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">settings_changed</span></code> - sent when changing settings due to <code class="docutils literal notranslate"><span class="pre">&#64;override_settings</span></code>
decorator (only relevant for unit testing)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">template_rendered</span></code> - sent when test system renders http template (only useful for unit tests).</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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#available-signals">Available signals</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Signals.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Signals.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Signals</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,436 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Spawner and Prototypes &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Spawner and Prototypes</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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">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">Typeclass</span></a>. If you
havent 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 its 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>
<div class="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">&#64;spawn/olc</span></code> to enter the prototype wizard. This is a menu system for
creating, loading, saving and manipulating prototypes. Its 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>
</div>
<div class="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">&#64;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">&#64;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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="p">{</span>
<span class="s2">&quot;prototype_key&quot;</span><span class="p">:</span> <span class="s2">&quot;house&quot;</span>
<span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;Large house&quot;</span>
<span class="s2">&quot;typeclass&quot;</span><span class="p">:</span> <span class="s2">&quot;typeclasses.rooms.house.House&quot;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table></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-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@spawn</span> <span class="p">{</span><span class="s2">&quot;prototype_key=&quot;</span><span class="n">house</span><span class="s2">&quot;, &quot;</span><span class="n">key</span><span class="s2">&quot;: &quot;</span><span class="n">Large</span> <span class="n">house</span><span class="s2">&quot;, ...}</span>
</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></blockquote>
<div class="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>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> - the name of the prototype. While this can sometimes be skipped (such as when
defining a prototype in a module or feeding a prototype-dict manually to the spawner function),
its good
practice to try to include this. It is used for book-keeping and storing of the prototype so you
can find it later.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> - If given, this should be the <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> of another prototype stored in
the system or available in a module. This makes this prototype <em>inherit</em> the keys from the
parent and only override what is needed. Give a tuple <code class="docutils literal notranslate"><span class="pre">(parent1,</span> <span class="pre">parent2,</span> <span class="pre">...)</span></code> for multiple
left-right inheritance. If this is not given, a <code class="docutils literal notranslate"><span class="pre">typeclass</span></code> should usually be defined (below).</p></li>
<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
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">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">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">[&quot;Accounts&quot;,</span> <span class="pre">&quot;may_use_red_door&quot;]</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">lock-string</span></a> like <code class="docutils literal notranslate"><span class="pre">&quot;edit:all();control:perm(Builder)&quot;</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">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">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">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>
<p>Deprecated as of Evennia 0.8:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">ndb_&lt;name&gt;</span></code> - sets the value of a non-persistent attribute (<code class="docutils literal notranslate"><span class="pre">&quot;ndb_&quot;</span></code> is stripped from the name).
This is simply not useful in a prototype and is deprecated.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">exec</span></code> - This accepts a code snippet or a list of code snippets to run. This should not be used -
use callables or <a class="reference external" href="Components/Spawner-and-Prototypes.html#protfuncs">$protfuncs</a> instead (see below).</p></li>
</ul>
</div>
<div class="section" id="prototype-values">
<h3>Prototype values<a class="headerlink" href="#prototype-values" title="Permalink to this headline"></a></h3>
<p>The prototype supports values of several different types.</p>
<p>It can be a hard-coded value:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="p">{</span><span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;An ugly goblin&quot;</span><span class="p">,</span> <span class="o">...</span><span class="p">}</span>
</pre></div>
</td></tr></table></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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="p">{</span><span class="s2">&quot;key&quot;</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>
</td></tr></table></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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="p">{</span><span class="s2">&quot;key&quot;</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">&quot;Urfgar&quot;</span><span class="p">,</span> <span class="s2">&quot;Rick the smelly&quot;</span><span class="p">,</span> <span class="s2">&quot;Blargh the foul&quot;</span><span class="p">,</span> <span class="o">...</span><span class="p">)),</span> <span class="o">...</span><span class="p">}</span>
</pre></div>
</td></tr></table></div>
<div class="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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="p">{</span><span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;$choice(Urfgar, Rick the smelly, Blargh the foul)&quot;</span><span class="p">,</span>
<span class="s2">&quot;attrs&quot;</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;This is a large $red(and very red) demon. &quot;</span>
<span class="s2">&quot;He has $randint(2,5) skulls in a chain around his neck.&quot;</span><span class="p">}</span>
</pre></div>
</td></tr></table></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 works in much the same way as an
<a class="reference external" href="Concepts/TextTags.html#inline-functions">InlineFunc</a> - they are actually
parsed using the same parser - except protfuncs are run every time the prototype is used to spawn a
new object (whereas an inlinefunc is called when a text is returned to the user).</p>
<p>Here is how a protfunc is defined (same as an inlinefunc).</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><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">&quot;&quot;&quot;</span>
<span class="sd"> Usage: $red(&lt;text&gt;)</span>
<span class="sd"> Returns the same text you entered, but red.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">args</span> <span class="ow">or</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">&quot;Must have one argument, the text to color red!&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="s2">&quot;|r{}|n&quot;</span><span class="o">.</span><span class="n">format</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span>
</pre></div>
</td></tr></table></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></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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><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">&quot;world.myprotfuncs&quot;</span><span class="p">]</span>
</pre></div>
</td></tr></table></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>| Protfunc | Description |</p>
<p>| <code class="docutils literal notranslate"><span class="pre">$random()</span></code> | Returns random value in range [0, 1) |
| <code class="docutils literal notranslate"><span class="pre">$randint(start,</span> <span class="pre">end)</span></code> | Returns random value in range [start, end] |
| <code class="docutils literal notranslate"><span class="pre">$left_justify(&lt;text&gt;)</span></code> | Left-justify text |
| <code class="docutils literal notranslate"><span class="pre">$right_justify(&lt;text&gt;)</span></code> | Right-justify text to screen width |
| <code class="docutils literal notranslate"><span class="pre">$center_justify(&lt;text&gt;)</span></code> | Center-justify text to screen width |
| <code class="docutils literal notranslate"><span class="pre">$full_justify(&lt;text&gt;)</span></code> | Spread text across screen width by adding spaces |
| <code class="docutils literal notranslate"><span class="pre">$protkey(&lt;name&gt;)</span></code> | Returns value of another key in this prototype (self-reference) |
| <code class="docutils literal notranslate"><span class="pre">$add(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code> | Returns value1 + value2. Can also be lists, dicts etc |
| <code class="docutils literal notranslate"><span class="pre">$sub(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code> | Returns value1 - value2 |
| <code class="docutils literal notranslate"><span class="pre">$mult(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code> | Returns value1 * value2 |
| <code class="docutils literal notranslate"><span class="pre">$div(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code> | Returns value2 / value1 |
| <code class="docutils literal notranslate"><span class="pre">$toint(&lt;value&gt;)</span></code> | Returns value converted to integer (or value if not possible) |
| <code class="docutils literal notranslate"><span class="pre">$eval(&lt;code&gt;)</span></code> | Returns result of <a class="reference external" href="https://docs.python.org/2/library/ast.html#ast.literal_eval">literal-
eval</a> of code string. Only simple
python expressions. |
| <code class="docutils literal notranslate"><span class="pre">$obj(&lt;query&gt;)</span></code> | Returns object #dbref searched globally by key, tag or #dbref. Error if more
than one found.” |
| <code class="docutils literal notranslate"><span class="pre">$objlist(&lt;query&gt;)</span></code> | Like <code class="docutils literal notranslate"><span class="pre">$obj</span></code>, except always returns a list of zero, one or more results. |
| <code class="docutils literal notranslate"><span class="pre">$dbref(dbref)</span></code> | Returns argument if it is formed as a #dbref (e.g. #1234), otherwise error.</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>
</div>
</div>
</div>
<div class="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>
<div class="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">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>
</div>
<div class="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>
<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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># in mygame/server/conf.py</span>
<span class="n">PROTOTYPE_MODULES</span> <span class="o">=</span> <span class="o">+=</span> <span class="p">[</span><span class="s2">&quot;world.myownprototypes&quot;</span><span class="p">,</span> <span class="s2">&quot;combat.prototypes&quot;</span><span class="p">]</span>
</pre></div>
</td></tr></table></div>
<p>Here is an example of a prototype defined in a module:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>```python
# in a module Evennia looks at for prototypes,
# (like mygame/world/prototypes.py)
ORC_SHAMAN = {&quot;key&quot;:&quot;Orc shaman&quot;,
&quot;typeclass&quot;: &quot;typeclasses.monsters.Orc&quot;,
&quot;weapon&quot;: &quot;wooden staff&quot;,
&quot;health&quot;: 20}
```
</pre></div>
</div>
<blockquote>
<div><p>Note that in the example above, <code class="docutils literal notranslate"><span class="pre">&quot;ORC_SHAMAN&quot;</span></code> will become the <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> of this prototype.
Its the only case when <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> can be skipped in a prototype. However, if <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code>
was given explicitly, that would take precedence. This is a legacy behavior and its recommended
that you always add <code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> to be consistent.</p>
</div></blockquote>
</div>
</div>
<div class="section" id="using-spawn">
<h2>Using &#64;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">&#64;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-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@spawn</span> <span class="n">goblin</span>
</pre></div>
</div>
<p>You can also specify the prototype directly as a valid Python dictionary:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@spawn</span> <span class="p">{</span><span class="s2">&quot;prototype_key&quot;</span><span class="p">:</span> <span class="s2">&quot;shaman&quot;</span><span class="p">,</span> \
<span class="s2">&quot;key&quot;</span><span class="p">:</span><span class="s2">&quot;Orc shaman&quot;</span><span class="p">,</span> \
<span class="s2">&quot;prototype_parent&quot;</span><span class="p">:</span> <span class="s2">&quot;goblin&quot;</span><span class="p">,</span> \
<span class="s2">&quot;weapon&quot;</span><span class="p">:</span> <span class="s2">&quot;wooden staff&quot;</span><span class="p">,</span> \
<span class="s2">&quot;health&quot;</span><span class="p">:</span> <span class="mi">20</span><span class="p">}</span>
</pre></div>
</div>
<blockquote>
<div><p>Note: The <code class="docutils literal notranslate"><span class="pre">&#64;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></blockquote>
</div>
<div class="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>
<p>In code you access the spawner mechanism directly via the call</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><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>
</td></tr></table></div>
<p>All arguments are prototype dictionaries. The function will return a
matching list of created objects. Example:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">obj1</span><span class="p">,</span> <span class="n">obj2</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="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;Obj1&quot;</span><span class="p">,</span> <span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;A test&quot;</span><span class="p">},</span>
<span class="p">{</span><span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;Obj2&quot;</span><span class="p">,</span> <span class="s2">&quot;desc&quot;</span><span class="p">:</span> <span class="s2">&quot;Another test&quot;</span><span class="p">})</span>
</pre></div>
</td></tr></table></div>
<blockquote>
<div><p>Hint: Same as when using <code class="docutils literal notranslate"><span class="pre">&#64;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>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#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="#prototype-keys">Prototype keys</a></li>
<li><a class="reference internal" href="#prototype-values">Prototype values</a><ul>
<li><a class="reference internal" href="#protfuncs">Protfuncs</a></li>
</ul>
</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>
</ul>
</li>
<li><a class="reference internal" href="#using-spawn">Using &#64;spawn</a></li>
<li><a class="reference internal" href="#using-evennia-prototypes-spawner">Using evennia.prototypes.spawner()</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Spawner-and-Prototypes.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Spawner-and-Prototypes.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Spawner and Prototypes</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,302 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Tags &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Tags</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="tags">
<h1>Tags<a class="headerlink" href="#tags" title="Permalink to this headline"></a></h1>
<p>A common task of a game designer is to organize and find groups of objects and do operations on
them. A classic example is to have a weather script affect all “outside” rooms. Another would be for
a player casting a magic spell that affects every location “in the dungeon”, but not those
“outside”. Another would be to quickly find everyone joined with a particular guild or everyone
currently dead.</p>
<p><em>Tags</em> are short text labels that you attach to objects so as to easily be able to retrieve and
group them. An Evennia entity can be tagged with any number of Tags. On the database side, Tag
entities are <em>shared</em> between all objects with that tag. This makes them very efficient but also
fundamentally different from <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a>, each of which always belongs to one <em>single</em>
object.</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">Locks</span></a> to check for).</p>
<div class="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>
<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
unique key + category combination.</p>
</div></blockquote>
<p>When Tags are assigned to game entities, these entities are actually sharing the same Tag. This
means that Tags are not suitable for storing information about a single object - use an
<a class="reference internal" href="Attributes.html"><span class="doc">Attribute</span></a> for this instead. Tags are a lot more limited than Attributes but this also
makes them very quick to lookup in the database - this is the whole point.</p>
<p>Tags have the following properties, stored in the database:</p>
<ul class="simple">
<li><p><strong>key</strong> - the name of the Tag. This is the main property to search for when looking up a Tag.</p></li>
<li><p><strong>category</strong> - this category allows for retrieving only specific subsets of tags used for
different purposes. You could have one category of tags for “zones”, another for “outdoor
locations”, for example. If not given, the category will be <code class="docutils literal notranslate"><span class="pre">None</span></code>, which is also considered a
separate, default, category.</p></li>
<li><p><strong>data</strong> - this is an optional text field with information about the tag. Remember that Tags are
shared between entities, so this field cannot hold any object-specific information. Usually it would
be used to hold info about the group of entities the Tag is tagging - possibly used for contextual
help like a tool tip. It is not used by default.</p></li>
</ul>
<p>There are also two special properties. These should usually not need to be changed or set, it is
used internally by Evennia to implement various other uses it makes of the <code class="docutils literal notranslate"><span class="pre">Tag</span></code> object:</p>
<ul class="simple">
<li><p><strong>model</strong> - this holds a <em>natural-key</em> description of the model object that this tag deals with,
on the form <em>application.modelclass</em>, for example <code class="docutils literal notranslate"><span class="pre">objects.objectdb</span></code>. It used by the TagHandler of
each entity type for correctly storing the data behind the scenes.</p></li>
<li><p><strong>tagtype</strong> - this is a “top-level category” of sorts for the inbuilt children of Tags, namely
<em>Aliases</em> and <em>Permissions</em>. The Taghandlers using this special field are especially intended to
free up the <em>category</em> property for any use you desire.</p></li>
</ul>
</div>
<div class="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">Objects</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a>,
<a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a> and <a class="reference internal" href="Communications.html"><span class="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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><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">&quot;furniture&quot;</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">&quot;furniture&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;luxurious&quot;</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">&quot;dungeon#01&quot;</span><span class="p">)</span>
<span class="n">myscript</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">&quot;weather&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;climate&quot;</span><span class="p">)</span>
<span class="n">myaccount</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">&quot;guestaccount&quot;</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">all</span><span class="p">()</span> <span class="c1"># returns a list of Tags</span>
<span class="n">mychair</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">&quot;furniture&quot;</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">clear</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
<p>Adding a new tag will either create a new Tag or re-use an already existing one. Note that there are
<em>two</em> “furniture” tags, one with a <code class="docutils literal notranslate"><span class="pre">None</span></code> category, and one with the “luxurious” category.</p>
<p>When using <code class="docutils literal notranslate"><span class="pre">remove</span></code>, the <code class="docutils literal notranslate"><span class="pre">Tag</span></code> is not deleted but are just disconnected from the tagged object. This
makes for very quick operations. The <code class="docutils literal notranslate"><span class="pre">clear</span></code> method removes (disconnects) all Tags from the object.
You can also use the default <code class="docutils literal notranslate"><span class="pre">&#64;tag</span></code> command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nd">@tag</span> <span class="n">mychair</span> <span class="o">=</span> <span class="n">furniture</span>
</pre></div>
</div>
<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>
</div>
<div class="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>
<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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="kn">import</span> <span class="nn">evennia</span>
<span class="c1"># all methods return Querysets</span>
<span class="c1"># search for objects </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="s2">&quot;furniture&quot;</span><span class="p">)</span>
<span class="n">objs2</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">&quot;furniture&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;luxurious&quot;</span><span class="p">)</span>
<span class="n">dungeon</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">&quot;dungeon#01&quot;</span><span class="p">)</span>
<span class="n">forest_rooms</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">&quot;forest&quot;</span><span class="p">)</span>
<span class="n">forest_meadows</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">&quot;meadow&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;forest&quot;</span><span class="p">)</span>
<span class="n">magic_meadows</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">&quot;meadow&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;magical&quot;</span><span class="p">)</span>
<span class="c1"># search for scripts</span>
<span class="n">weather</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_tag_script</span><span class="p">(</span><span class="s2">&quot;weather&quot;</span><span class="p">)</span>
<span class="n">climates</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_tag_script</span><span class="p">(</span><span class="n">category</span><span class="o">=</span><span class="s2">&quot;climate&quot;</span><span class="p">)</span>
<span class="c1"># search for accounts</span>
<span class="n">accounts</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_tag_account</span><span class="p">(</span><span class="s2">&quot;guestaccount&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></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></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>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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
2
3
4
5
6
7
8
9
10
11
12</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">evennia</span>
<span class="n">myobj1</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">&quot;foo&quot;</span><span class="p">)</span> <span class="c1"># implies category=None</span>
<span class="n">myobj2</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">&quot;foo&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;bar&quot;</span><span class="p">)</span>
<span class="c1"># this returns a queryset with *only* myobj1 </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="s2">&quot;foo&quot;</span><span class="p">)</span>
<span class="c1"># these return a queryset with *only* myobj2</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="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;bar&quot;</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">&quot;bar&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></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">Object-</span></a>) tags:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="nd">@tag</span><span class="o">/</span><span class="n">search</span> <span class="n">furniture</span>
</pre></div>
</div>
</div>
<div class="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>
<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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">boy</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;rascal&quot;</span><span class="p">)</span>
<span class="n">boy</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;Builders&quot;</span><span class="p">)</span>
<span class="n">boy</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">&quot;Builders&quot;</span><span class="p">)</span>
<span class="n">all_aliases</span> <span class="o">=</span> <span class="n">boy</span><span class="o">.</span><span class="n">aliases</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
<p>and so on. Similarly to how <code class="docutils literal notranslate"><span class="pre">&#64;tag</span></code> works in-game, there is also the <code class="docutils literal notranslate"><span class="pre">&#64;perm</span></code> command for assigning
permissions and <code class="docutils literal notranslate"><span class="pre">&#64;alias</span></code> command for aliases.</p>
</div>
<div class="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">Zone tutorial</span></a>.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><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="#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>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Tags.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Tags.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Tags</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,229 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TickerHandler &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">TickerHandler</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="tickerhandler">
<h1>TickerHandler<a class="headerlink" href="#tickerhandler" title="Permalink to this headline"></a></h1>
<p>One way to implement a dynamic MUD is by using “tickers”, also known as “heartbeats”. A ticker is a
timer that fires (“ticks”) at a given interval. The tick triggers updates in various game systems.</p>
<div class="section" id="about-tickers">
<h2>About Tickers<a class="headerlink" href="#about-tickers" title="Permalink to this headline"></a></h2>
<p>Tickers are very common or even unavoidable in other mud code bases. Certain code bases are even
hard-coded to rely on the concept of the global tick. Evennia has no such notion - the decision to
use tickers is very much up to the need of your game and which requirements you have. The “ticker
recipe” is just one way of cranking the wheels.</p>
<p>The most fine-grained way to manage the flow of time is of course to use <a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a>. Many
types of operations (weather being the classic example) are however done on multiple objects in the
same way at regular intervals, and for this, storing separate Scripts on each object is inefficient.
The way to do this is to use a ticker with a “subscription model” - let objects sign up to be
triggered at the same interval, unsubscribing when the updating is no longer desired.</p>
<p>Evennia offers an optimized implementation of the subscription model - the <em>TickerHandler</em>. This is
a singleton global handler reachable from <code class="docutils literal notranslate"><span class="pre">evennia.TICKER_HANDLER</span></code>. You can assign any <em>callable</em> (a
function or, more commonly, a method on a database object) to this handler. The TickerHandler will
then call this callable at an interval you specify, and with the arguments you supply when adding
it. This continues until the callable un-subscribes from the ticker. The handler survives a reboot
and is highly optimized in resource usage.</p>
<p>Here is an example of importing <code class="docutils literal notranslate"><span class="pre">TICKER_HANDLER</span></code> and using it:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="c1"># we assume that obj has a hook &quot;at_tick&quot; defined on itself</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">TICKER_HANDLER</span> <span class="k">as</span> <span class="n">tickerhandler</span>
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">at_tick</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Thats it - from now on, <code class="docutils literal notranslate"><span class="pre">obj.at_tick()</span></code> will be called every 20 seconds.</p>
<p>You can also import function and tick that:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">TICKER_HANDLER</span> <span class="k">as</span> <span class="n">tickerhandler</span>
<span class="kn">from</span> <span class="nn">mymodule</span> <span class="kn">import</span> <span class="n">myfunc</span>
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">myfunc</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Removing (stopping) the ticker works as expected:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">at_tick</span><span class="p">)</span>
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">myfunc</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>Note that you have to also supply <code class="docutils literal notranslate"><span class="pre">interval</span></code> to identify which subscription to remove. This is
because the TickerHandler maintains a pool of tickers and a given callable can subscribe to be
ticked at any number of different intervals.</p>
<p>The full definition of the <code class="docutils literal notranslate"><span class="pre">tickerhandler.add</span></code> method is</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">interval</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span>
<span class="n">idstring</span><span class="o">=</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="bp">True</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>
</td></tr></table></div>
<p>Here <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> will be passed to <code class="docutils literal notranslate"><span class="pre">callback</span></code> every <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds. If <code class="docutils literal notranslate"><span class="pre">persistent</span></code>
is <code class="docutils literal notranslate"><span class="pre">False</span></code>, this subscription will not survive a server reload.</p>
<p>Tickers are identified and stored by making a key of the callable itself, the ticker-interval, the
<code class="docutils literal notranslate"><span class="pre">persistent</span></code> flag and the <code class="docutils literal notranslate"><span class="pre">idstring</span></code> (the latter being an empty string when not given explicitly).</p>
<p>Since the arguments are not included in the tickers identification, the <code class="docutils literal notranslate"><span class="pre">idstring</span></code> must be used to
have a specific callback triggered multiple times on the same interval but with different arguments:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="s2">&quot;ticker1&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="s2">&quot;ticker2&quot;</span><span class="p">,</span> <span class="bp">True</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<blockquote>
<div><p>Note that, when we want to send arguments to our callback within a ticker handler, we need to
specify <code class="docutils literal notranslate"><span class="pre">idstring</span></code> and <code class="docutils literal notranslate"><span class="pre">persistent</span></code> before, unless we call our arguments as keywords, which would
often be more readable:</p>
</div></blockquote>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="n">caller</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">118</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>If you add a ticker with exactly the same combination of callback, interval and idstring, it will
overload the existing ticker. This identification is also crucial for later removing (stopping) the
subscription:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="s2">&quot;ticker1&quot;</span><span class="p">)</span>
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="s2">&quot;ticker2&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>The <code class="docutils literal notranslate"><span class="pre">callable</span></code> can be on any form as long as it accepts the arguments you give to send to it in
<code class="docutils literal notranslate"><span class="pre">TickerHandler.add</span></code>.</p>
<blockquote>
<div><p>Note that everything you supply to the TickerHandler will need to be pickled at some point to be
saved into the database. Most of the time the handler will correctly store things like database
objects, but the same restrictions as for <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a> apply to what the TickerHandler
may store.</p>
</div></blockquote>
<p>When testing, you can stop all tickers in the entire game with <code class="docutils literal notranslate"><span class="pre">tickerhandler.clear()</span></code>. You can also
view the currently subscribed objects with <code class="docutils literal notranslate"><span class="pre">tickerhandler.all()</span></code>.</p>
<p>See the <a class="reference internal" href="../Howto/Weather-Tutorial.html"><span class="doc">Weather Tutorial</span></a> for an example of using the TickerHandler.</p>
<div class="section" id="when-not-to-use-tickerhandler">
<h3>When <em>not</em> to use TickerHandler<a class="headerlink" href="#when-not-to-use-tickerhandler" title="Permalink to this headline"></a></h3>
<p>Using the TickerHandler may sound very useful but it is important to consider when not to use it.
Even if you are used to habitually relying on tickers for everything in other code bases, stop and
think about what you really need it for. This is the main point:</p>
<blockquote>
<div><p>You should <em>never</em> use a ticker to catch <em>changes</em>.</p>
</div></blockquote>
<p>Think about it - you might have to run the ticker every second to react to the change fast enough.
Most likely nothing will have changed at a given moment. So you are doing pointless calls (since
skipping the call gives the same result as doing it). Making sure nothings changed might even be
computationally expensive depending on the complexity of your system. Not to mention that you might
need to run the check <em>on every object in the database</em>. Every second. Just to maintain status quo
</p>
<p>Rather than checking over and over on the off-chance that something changed, consider a more
proactive approach. Could you implement your rarely changing system to <em>itself</em> report when its
status changes? Its almost always much cheaper/efficient if you can do things “on demand”. Evennia
itself uses hook methods for this very reason.</p>
<p>So, if you consider a ticker that will fire very often but which you expect to have no effect 99% of
the time, consider handling things things some other way. A self-reporting on-demand solution is
usually cheaper also for fast-updating properties. Also remember that some things may not need to be
updated until someone actually is examining or using them - any interim changes happening up to that
moment are pointless waste of computing time.</p>
<p>The main reason for needing a ticker is when you want things to happen to multiple objects at the
same time without input from something else.</p>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">TickerHandler</a><ul>
<li><a class="reference internal" href="#about-tickers">About Tickers</a><ul>
<li><a class="reference internal" href="#when-not-to-use-tickerhandler">When <em>not</em> to use TickerHandler</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/TickerHandler.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="TickerHandler.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">TickerHandler</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,454 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Typeclasses &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Typeclasses</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" 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 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">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a>,
<a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a> and <a class="reference external" href="Components/Communications.html#Channels">Channels</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>
</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 Evennias 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 its 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>
<div class="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 dont 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 external" href="Components/Typeclasses.html#about-typeclass-properties">below</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>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><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>
</pre></div>
</td></tr></table></div>
</li>
<li><p>A typeclass <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method should normally not be overloaded. This has mostly to do with the
fact that the <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method is not called in a predictable way. Instead Evennia suggest you use
the <code class="docutils literal notranslate"><span class="pre">at_*_creation</span></code> hooks (like <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> for Objects) for setting things the very first
time the typeclass is saved to the database or the <code class="docutils literal notranslate"><span class="pre">at_init</span></code> hook which is called every time the
object is cached to memory. If you know what you are doing and want to use <code class="docutils literal notranslate"><span class="pre">__init__</span></code>, it <em>must</em>
both accept arbitrary keyword arguments and use <code class="docutils literal notranslate"><span class="pre">super</span></code> to call its parent::</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># my content</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
<span class="c1"># my content</span>
</pre></div>
</td></tr></table></div>
</li>
</ol>
<p>Apart from this, a typeclass works like any normal Python class and you can
treat it as such.</p>
</div>
<div class="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>
<p>Its 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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6</pre></div></td><td class="code"><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">class</span> <span class="nc">Furniture</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="c1"># this defines what &#39;furniture&#39; is, like</span>
<span class="c1"># storing who sits on it or something.</span>
<span class="k">pass</span>
</pre></div>
</td></tr></table></div>
<p>You can now create a new <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> object in two ways. First (and usually not the most
convenient) way is to create an instance of the class and then save it manually to the database:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">chair</span> <span class="o">=</span> <span class="n">Furniture</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">&quot;Chair&quot;</span><span class="p">)</span>
<span class="n">chair</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
<p>To use this you must give the database field names as keywords to the call. Which are available
depends on the entity you are creating, but all start with <code class="docutils literal notranslate"><span class="pre">db_*</span></code> in Evennia. This is a method you
may be familiar with if you know Django from before.</p>
<p>It is recommended that you instead use the <code class="docutils literal notranslate"><span class="pre">create_*</span></code> functions to create typeclassed entities:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><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">chair</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">Furniture</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;Chair&quot;</span><span class="p">)</span>
<span class="c1"># or (if your typeclass is in a module furniture.py)</span>
<span class="n">chair</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="s2">&quot;furniture.Furniture&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;Chair&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>The <code class="docutils literal notranslate"><span class="pre">create_object</span></code> (<code class="docutils literal notranslate"><span class="pre">create_account</span></code>, <code class="docutils literal notranslate"><span class="pre">create_script</span></code> etc) takes the typeclass as its first
argument; this can both be the actual class or the python path to the typeclass as found under your
game directory. So if your <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> typeclass sits in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/furniture.py</span></code>, you
could point to it as <code class="docutils literal notranslate"><span class="pre">typeclasses.furniture.Furniture</span></code>. Since Evennia will itself look in
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses</span></code>, you can shorten this even further to just <code class="docutils literal notranslate"><span class="pre">furniture.Furniture</span></code>. The create-
functions take a lot of extra keywords allowing you to set things like <a class="reference internal" href="Attributes.html"><span class="doc">Attributes</span></a> and
<a class="reference internal" href="Tags.html"><span class="doc">Tags</span></a> all in one go. These keywords dont 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 dont need to call <code class="docutils literal notranslate"><span class="pre">save()</span></code> explicitly.</p>
<div class="section" id="about-typeclass-properties">
<h3>About typeclass properties<a class="headerlink" href="#about-typeclass-properties" title="Permalink to this headline"></a></h3>
<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"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5</pre></div></td><td class="code"><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">&quot;Table&quot;</span>
<span class="n">chair</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="k">print</span><span class="p">(</span><span class="n">chair</span><span class="o">.</span><span class="n">db_key</span><span class="p">)</span>
<span class="o">&lt;&lt;&lt;</span> <span class="n">Table</span>
</pre></div>
</td></tr></table></div>
<p>That is, we change the chair object to have the <code class="docutils literal notranslate"><span class="pre">db_key</span></code> “Table”, then save this to the database.
However, you almost never do things this way; Evennia defines property wrappers for all the database
fields. These are named the same as the field, but without the <code class="docutils literal notranslate"><span class="pre">db_</span></code> part:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">chair</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;Table&quot;</span>
<span class="k">print</span><span class="p">(</span><span class="n">chair</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
<span class="o">&lt;&lt;&lt;</span> <span class="n">Table</span>
</pre></div>
</td></tr></table></div>
<p>The <code class="docutils literal notranslate"><span class="pre">key</span></code> wrapper is not only shorter to write, it will make sure to save the field for you, and
does so more efficiently by levering sql update mechanics under the hood. So whereas it is good to
be aware that the field is named <code class="docutils literal notranslate"><span class="pre">db_key</span></code> you should use <code class="docutils literal notranslate"><span class="pre">key</span></code> as much as you can.</p>
<p>Each typeclass entity has some unique fields relevant to that type. But all also share the
following fields (the wrapper name without <code class="docutils literal notranslate"><span class="pre">db_</span></code> is given):</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (str): The main identifier for the entity, like “Rose”, “myscript” or “Paul”. <code class="docutils literal notranslate"><span class="pre">name</span></code> is an
alias.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">date_created</span></code> (datetime): Time stamp when this object was created.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">typeclass_path</span></code> (str): A python path pointing to the location of this (type)class</p></li>
</ul>
<p>There is one special field that doesnt use the <code class="docutils literal notranslate"><span class="pre">db_</span></code> prefix (its defined by Django):</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">id</span></code> (int): the database id (database ref) of the object. This is an ever-increasing, unique
integer. It can also be accessed as <code class="docutils literal notranslate"><span class="pre">dbid</span></code> (database ID) or <code class="docutils literal notranslate"><span class="pre">pk</span></code> (primary key). The <code class="docutils literal notranslate"><span class="pre">dbref</span></code> property
returns the string form “#id”.</p></li>
</ul>
<p>The typeclassed entity has several common handlers:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">tags</span></code> - the <a class="reference internal" href="Tags.html"><span class="doc">TagHandler</span></a> that handles tagging. Use <code class="docutils literal notranslate"><span class="pre">tags.add()</span></code> , <code class="docutils literal notranslate"><span class="pre">tags.get()</span></code> etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> - the <a class="reference internal" href="Locks.html"><span class="doc">LockHandler</span></a> that manages access restrictions. Use <code class="docutils literal notranslate"><span class="pre">locks.add()</span></code>,
<code class="docutils literal notranslate"><span class="pre">locks.get()</span></code> etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attributes</span></code> - the <a class="reference internal" href="Attributes.html"><span class="doc">AttributeHandler</span></a> that manages Attributes on the object. Use
<code class="docutils literal notranslate"><span class="pre">attributes.add()</span></code>
etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">db</span></code> (DataBase) - a shortcut property to the AttributeHandler; allowing <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">nattributes</span></code> - the <a class="reference internal" href="Attributes.html"><span class="doc">Non-persistent AttributeHandler</span></a> for attributes not saved in the
database.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">ndb</span></code> (NotDataBase) - a shortcut property to the Non-peristent AttributeHandler. Allows
<code class="docutils literal notranslate"><span class="pre">obj.ndb.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code></p></li>
</ul>
<p>Each of the typeclassed entities then extend this list with their own properties. Go to the
respective pages for <a class="reference internal" href="Objects.html"><span class="doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc">Scripts</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc">Accounts</span></a> and
<a class="reference internal" href="Communications.html"><span class="doc">Channels</span></a> for more info. Its also recommended that you explore the available
entities using <a class="reference internal" href="../Evennia-API.html"><span class="doc">Evennias flat API</span></a> to explore which properties and methods they have
available.</p>
</div>
<div class="section" id="overloading-hooks">
<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>
</div>
<div class="section" id="querying-for-typeclasses">
<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">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/">Djangos query
language</a>. This makes use of a <em>database
manager</em> that sits on all typeclasses, named <code class="docutils literal notranslate"><span class="pre">objects</span></code>. This manager holds methods that allow
database searches against that particular type of object (this is the way Django normally works
too). When using Django queries, you need to use the full field names (like <code class="docutils literal notranslate"><span class="pre">db_key</span></code>) to search:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">matches</span> <span class="o">=</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">&quot;Chair&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>It is important that this will <em>only</em> find objects inheriting directly from <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> in your
database. If there was a subclass of <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> named <code class="docutils literal notranslate"><span class="pre">Sitables</span></code> you would not find any chairs
derived from <code class="docutils literal notranslate"><span class="pre">Sitables</span></code> with this query (this is not a Django feature but special to Evennia). To
find objects from subclasses Evennia instead makes the <code class="docutils literal notranslate"><span class="pre">get_family</span></code> and <code class="docutils literal notranslate"><span class="pre">filter_family</span></code> query
methods available:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># search for all furnitures and subclasses of furnitures</span>
<span class="c1"># whose names starts with &quot;Chair&quot;</span>
<span class="n">matches</span> <span class="o">=</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter_family</span><span class="p">(</span><span class="n">db_key__startswith</span><span class="o">=</span><span class="s2">&quot;Chair&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>To make sure to search, say, all <code class="docutils literal notranslate"><span class="pre">Scripts</span></code> <em>regardless</em> of typeclass, you need to query from the
database model itself. So for Objects, this would be <code class="docutils literal notranslate"><span class="pre">ObjectDB</span></code> in the diagram above. Heres an
example for Scripts:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">ScriptDB</span>
<span class="n">matches</span> <span class="o">=</span> <span class="n">ScriptDB</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">db_key__contains</span><span class="o">=</span><span class="s2">&quot;Combat&quot;</span><span class="p">)</span>
</pre></div>
</td></tr></table></div>
<p>When querying from the database model parent you dont need to use <code class="docutils literal notranslate"><span class="pre">filter_family</span></code> or <code class="docutils literal notranslate"><span class="pre">get_family</span></code> -
you will always query all children on the database model.</p>
</div>
</div>
<div class="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>
<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">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc">Tags</span></a> etc, are
not themselves embedded into the class and will <em>not</em> be updated automatically. This you need to
manage yourself, by searching for all relevant objects and updating or adding the data:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># add a worth Attribute to all existing Furniture</span>
<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="c1"># this will loop over all Furniture instances</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">worth</span> <span class="o">=</span> <span class="mi">100</span>
</pre></div>
</td></tr></table></div>
<p>A common use case is putting all Attributes in the <code class="docutils literal notranslate"><span class="pre">at_*_creation</span></code> hook of the entity, such as
<code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> for <code class="docutils literal notranslate"><span class="pre">Objects</span></code>. This is called every time an object is created - and only then.
This is usually what you want but it does mean already existing objects wont get updated if you
change the contents of <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> later. You can fix this in a similar way as above
(manually setting each Attribute) or with something like this:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="c1"># Re-run at_object_creation only on those objects not having the new Attribute</span>
<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">worth</span><span class="p">:</span>
<span class="n">obj</span><span class="o">.</span><span class="n">at_object_creation</span><span class="p">()</span>
</pre></div>
</td></tr></table></div>
<p>The above examples can be run in the command prompt created by <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">shell</span></code>. You could also run
it all in-game using <code class="docutils literal notranslate"><span class="pre">&#64;py</span></code>. That however requires you to put the code (including imports) as one
single line using <code class="docutils literal notranslate"><span class="pre">;</span></code> and <a class="reference external" href="http://www.secnetix.de/olli/Python/list_comprehensions.hawk">list
comprehensions</a>, like this (ignore the
line break, thats only for readability in the wiki):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@py</span> <span class="kn">from</span> <span class="nn">typeclasses.furniture</span> <span class="k">import</span> <span class="n">Furniture</span><span class="p">;</span>
<span class="p">[</span><span class="n">obj</span><span class="o">.</span><span class="n">at_object_creation</span><span class="p">()</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">worth</span><span class="p">]</span>
</pre></div>
</div>
<p>It is recommended that you plan your game properly before starting to build, to avoid having to
retroactively update objects more than necessary.</p>
</div>
<div class="section" id="swap-typeclass">
<h2>Swap typeclass<a class="headerlink" href="#swap-typeclass" title="Permalink to this headline"></a></h2>
<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">&#64;typeclass</span></code> command:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@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>
</div>
<p>There are two important switches to this command:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">/reset</span></code> - This will purge all existing Attributes on the object and re-run the creation hook
(like <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> for Objects). This assures you get an object which is purely of this new
class.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">/force</span></code> - This is required if you are changing the class to be <em>the same</em> class the object
already has - its a safety check to avoid user errors. This is usually used together with <code class="docutils literal notranslate"><span class="pre">/reset</span></code>
to re-run the creation hook on an existing class.</p></li>
</ul>
<p>In code you instead use the <code class="docutils literal notranslate"><span class="pre">swap_typeclass</span></code> method which you can find on all typeclassed entities:</p>
<div class="highlight-python notranslate"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2</pre></div></td><td class="code"><div class="highlight"><pre><span></span><span class="n">obj_to_change</span><span class="o">.</span><span class="n">swap_typeclass</span><span class="p">(</span><span class="n">new_typeclass_path</span><span class="p">,</span> <span class="n">clean_attributes</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span>
<span class="n">run_start_hooks</span><span class="o">=</span><span class="s2">&quot;all&quot;</span><span class="p">,</span> <span class="n">no_default</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">clean_cmdsets</span><span class="o">=</span><span class="bp">False</span><span class="p">)</span>
</pre></div>
</td></tr></table></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>
</div>
<div class="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">Attributes</span></a> and <a class="reference internal" href="Tags.html"><span class="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 Djangos proxy model in various ways to allow them to work without any boiler plate
(for example you dont 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>
<div class="section" id="caveats">
<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
youll 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 Evennias 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>
</div>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<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="#creating-a-new-typeclass">Creating a new typeclass</a><ul>
<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>
</ul>
</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><ul>
<li><a class="reference internal" href="#caveats">Caveats</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Typeclasses.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Typeclasses.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Typeclasses</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,444 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webclient &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webclient</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="webclient">
<h1>Webclient<a class="headerlink" href="#webclient" title="Permalink to this headline"></a></h1>
</div>
<div class="section" id="web-client">
<h1><strong>Web client</strong><a class="headerlink" href="#web-client" title="Permalink to this headline"></a></h1>
<p>Evennia comes with a MUD client accessible from a normal web browser. During development you can try
it at <code class="docutils literal notranslate"><span class="pre">http://localhost:4001/webclient</span></code>. The client consists of several parts, all under
<code class="docutils literal notranslate"><span class="pre">evennia/web/webclient/</span></code>:</p>
<p><code class="docutils literal notranslate"><span class="pre">templates/webclient/webclient.html</span></code> and <code class="docutils literal notranslate"><span class="pre">templates/webclient/base.html</span></code> are the very simplistic
django html templates describing the webclient layout.</p>
<p><code class="docutils literal notranslate"><span class="pre">static/webclient/js/evennia.js</span></code> is the main evennia javascript library. This handles all
communication between Evennia and the client over websockets and via AJAX/COMET if the browser cant
handle websockets. It will make the Evennia object available to the javascript namespace, which
offers methods for sending and receiving data to/from the server transparently. This is intended to
be used also if swapping out the gui front end.</p>
<p><code class="docutils literal notranslate"><span class="pre">static/webclient/js/webclient_gui.js</span></code> is the default plugin manager. It adds the <code class="docutils literal notranslate"><span class="pre">plugins</span></code> and
<code class="docutils literal notranslate"><span class="pre">plugin_manager</span></code> objects to the javascript namespace, coordinates the GUI operations between the
various plugins, and uses the Evennia object library for all in/out.</p>
<p><code class="docutils literal notranslate"><span class="pre">static/webclient/js/plugins</span></code> provides a default set of plugins that implement a “telnet-like”
interface.</p>
<p><code class="docutils literal notranslate"><span class="pre">static/webclient/css/webclient.css</span></code> is the CSS file for the client; it also defines things like how
to display ANSI/Xterm256 colors etc.</p>
<p>The server-side webclient protocols are found in <code class="docutils literal notranslate"><span class="pre">evennia/server/portal/webclient.py</span></code> and
<code class="docutils literal notranslate"><span class="pre">webclient_ajax.py</span></code> for the two types of connections. You cant (and should not need to) modify
these.</p>
<div class="section" id="customizing-the-web-client">
<h2>Customizing the web client<a class="headerlink" href="#customizing-the-web-client" title="Permalink to this headline"></a></h2>
<p>Like was the case for the website, you override the webclient from your game directory. You need to
add/modify a file in the matching directory location within one of the _overrides directories.
These _override directories are NOT directly used by the web server when the game is running, the
server copies everything web related in the Evennia folder over to <code class="docutils literal notranslate"><span class="pre">mygame/web/static/</span></code> and then
copies in all of your _overrides. This can cause some cases were you edit a file, but it doesnt
seem to make any difference in the servers behavior. <strong>Before doing anything else, try shutting
down the game and running <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">collectstatic</span></code> from the command line then start it back up, clear
your browser cache, and see if your edit shows up.</strong></p>
<p>Example: To change the utilized plugin list, you need to override base.html by copying
<code class="docutils literal notranslate"><span class="pre">evennia/web/webclient/templates/webclient/base.html</span></code> to
<code class="docutils literal notranslate"><span class="pre">mygame/web/template_overrides/webclient/base.html</span></code> and editing it to add your new plugin.</p>
</div>
</div>
<div class="section" id="evennia-web-client-api-from-evennia-js">
<h1>Evennia Web Client API (from evennia.js)<a class="headerlink" href="#evennia-web-client-api-from-evennia-js" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">Evennia.init(</span> <span class="pre">opts</span> <span class="pre">)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Evennia.connect()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Evennia.isConnected()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Evennia.msg(</span> <span class="pre">cmdname,</span> <span class="pre">args,</span> <span class="pre">kwargs,</span> <span class="pre">callback</span> <span class="pre">)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Evennia.emit(</span> <span class="pre">cmdname,</span> <span class="pre">args,</span> <span class="pre">kwargs</span> <span class="pre">)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">log()</span></code></p></li>
</ul>
</div>
<div class="section" id="plugin-manager-api-from-webclient-gui-js">
<h1>Plugin Manager API (from webclient_gui.js)<a class="headerlink" href="#plugin-manager-api-from-webclient-gui-js" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">options</span></code> Object, Stores key/value state that can be used by plugins to coordinate behavior.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">plugins</span></code> Object, key/value list of the all the loaded plugins.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">plugin_handler</span></code> Object</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">plugin_handler.add(&quot;name&quot;,</span> <span class="pre">plugin)</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">plugin_handler.onSend(string)</span></code></p></li>
</ul>
</li>
</ul>
</div>
<div class="section" id="plugin-callbacks-api">
<h1>Plugin callbacks API<a class="headerlink" href="#plugin-callbacks-api" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">init()</span></code> The only required callback</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">boolean</span> <span class="pre">onKeydown(event)</span></code> This plugin listens for Keydown events</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">onBeforeUnload()</span></code> This plugin does something special just before the webclient page/tab is
closed.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">onLoggedIn(args,</span> <span class="pre">kwargs)</span></code> This plugin does something when the webclient first logs in.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">onGotOptions(args,</span> <span class="pre">kwargs)</span></code> This plugin does something with options sent from the server.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">boolean</span> <span class="pre">onText(args,</span> <span class="pre">kwargs)</span></code> This plugin does something with messages sent from the server.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">boolean</span> <span class="pre">onPrompt(args,</span> <span class="pre">kwargs)</span></code> This plugin does something when the server sends a prompt.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">boolean</span> <span class="pre">onUnknownCmd(cmdname,</span> <span class="pre">args,</span> <span class="pre">kwargs)</span></code> This plugin does something with “unknown commands”.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">onConnectionClose(args,</span> <span class="pre">kwargs)</span></code> This plugin does something when the webclient disconnects from
the server.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">newstring</span> <span class="pre">onSend(string)</span></code> This plugin examines/alters text that other plugins generate. <strong>Use
with caution</strong></p></li>
</ul>
<p>The order of the plugins defined in <code class="docutils literal notranslate"><span class="pre">base.html</span></code> is important. All the callbacks for each plugin
will be executed in that order. Functions marked “boolean” above must return true/false. Returning
true will short-circuit the execution, so no other plugins lower in the base.html list will have
their callback for this event called. This enables things like the up/down arrow keys for the
history.js plugin to always occur before the default_in.js plugin adds that key to the current input
buffer.</p>
</div>
<div class="section" id="example-default-plugins-plugins-js">
<h1>Example/Default Plugins (plugins/*.js)<a class="headerlink" href="#example-default-plugins-plugins-js" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">clienthelp.js</span></code> Defines onOptionsUI from the options2 plugin. This is a mostly empty plugin to
add some “How To” information for your game.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">default_in.js</span></code> Defines onKeydown. <enter> key or mouse clicking the arrow will send the currently
typed text.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">default_out.js</span></code> Defines onText, onPrompt, and onUnknownCmd. Generates HTML output for the user.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">default_unload.js</span></code> Defines onBeforeUnload. Prompts the user to confirm that they meant to
leave/close the game.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">font.js</span></code> Defines onOptionsUI. The plugin adds the ability to select your font and font size.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">goldenlayout_default_config.js</span></code> Not actually a plugin, defines a global variable that
goldenlayout uses to determine its window layout, known tag routing, etc.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">goldenlayout.js</span></code> Defines onKeydown, onText and custom functions. A very powerful “tabbed” window
manager for drag-n-drop windows, text routing and more.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">history.js</span></code> Defines onKeydown and onSend. Creates a history of past sent commands, and uses arrow
keys to peruse.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">hotbuttons.js</span></code> Defines onGotOptions. A Disabled-by-default plugin that defines a button bar with
user-assignable commands.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">iframe.js</span></code> Defines onOptionsUI. A goldenlayout-only plugin to create a restricted browsing sub-
window for a side-by-side web/text interface, mostly an example of how to build new HTML
“components” for goldenlayout.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">message_routing.js</span></code> Defines onOptionsUI, onText, onKeydown. This goldenlayout-only plugin
implements regex matching to allow users to “tag” arbitrary text that matches, so that it gets
routed to proper windows. Similar to “Spawn” functions for other clients.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">multimedia.js</span></code> An basic plugin to allow the client to handle “image” “audio” and “video” messages
from the server and display them as inline HTML.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">notifications.js</span></code> Defines onText. Generates browser notification events for each new message
while the tab is hidden.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">oob.js</span></code> Defines onSend. Allows the user to test/send Out Of Band json messages to the server.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">options.js</span></code> Defines most callbacks. Provides a popup-based UI to coordinate options settings with
the server.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">options2.js</span></code> Defines most callbacks. Provides a goldenlayout-based version of the
options/settings tab. Integrates with other plugins via the custom onOptionsUI callback.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">popups.js</span></code> Provides default popups/Dialog UI for other plugins to use.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">splithandler.js</span></code> Defines onText. Provides an older, less-flexible alternative to goldenlayout for
multi-window UI to automatically separate out screen real-estate by type of message.</p></li>
</ul>
</div>
<div class="section" id="writing-your-own-plugins">
<h1>Writing your own Plugins<a class="headerlink" href="#writing-your-own-plugins" title="Permalink to this headline"></a></h1>
<p>So, you love the functionality of the webclient, but your game has specific types of text that need
to be separated out into their own space, visually. There are two plugins to help with this. The
Goldenlayout plugin framework, and the older Splithandler framework.</p>
<div class="section" id="goldenlayout">
<h2>GoldenLayout<a class="headerlink" href="#goldenlayout" title="Permalink to this headline"></a></h2>
<p>GoldenLayout is a web framework that allows web developers and their users to create their own
tabbed/windowed layouts. Windows/tabs can be click-and-dragged from location to location by
clicking on their titlebar and dragging until the “frame lines” appear. Dragging a window onto
another windows titlebar will create a tabbed “Stack”. The Evennia goldenlayout plugin defines 3
basic types of window: The Main window, input windows and non-main text output windows. The Main
window and the first input window are unique in that they cant be “closed”.</p>
<p>The most basic customization is to provide your users with a default layout other than just one Main
output and the one starting input window. This is done by modifying your servers
goldenlayout_default_config.js.</p>
<p>Start by creating a new
<code class="docutils literal notranslate"><span class="pre">mygame/web/static_overrides/webclient/js/plugins/goldenlayout_default_config.js</span></code> file, and adding
the following JSON variable:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">var</span> <span class="n">goldenlayout_config</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">content</span><span class="p">:</span> <span class="p">[{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;column&#39;</span><span class="p">,</span>
<span class="n">content</span><span class="p">:</span> <span class="p">[{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;row&#39;</span><span class="p">,</span>
<span class="n">content</span><span class="p">:</span> <span class="p">[{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;column&#39;</span><span class="p">,</span>
<span class="n">content</span><span class="p">:</span> <span class="p">[{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;component&#39;</span><span class="p">,</span>
<span class="n">componentName</span><span class="p">:</span> <span class="s1">&#39;Main&#39;</span><span class="p">,</span>
<span class="n">isClosable</span><span class="p">:</span> <span class="n">false</span><span class="p">,</span>
<span class="n">tooltip</span><span class="p">:</span> <span class="s1">&#39;Main - drag to desired position.&#39;</span><span class="p">,</span>
<span class="n">componentState</span><span class="p">:</span> <span class="p">{</span>
<span class="n">cssClass</span><span class="p">:</span> <span class="s1">&#39;content&#39;</span><span class="p">,</span>
<span class="n">types</span><span class="p">:</span> <span class="s1">&#39;untagged&#39;</span><span class="p">,</span>
<span class="n">updateMethod</span><span class="p">:</span> <span class="s1">&#39;newlines&#39;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">},</span> <span class="p">{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;component&#39;</span><span class="p">,</span>
<span class="n">componentName</span><span class="p">:</span> <span class="s1">&#39;input&#39;</span><span class="p">,</span>
<span class="nb">id</span><span class="p">:</span> <span class="s1">&#39;inputComponent&#39;</span><span class="p">,</span>
<span class="n">height</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
<span class="n">tooltip</span><span class="p">:</span> <span class="s1">&#39;Input - The last input in the layout is always the default.&#39;</span><span class="p">,</span>
<span class="p">},</span> <span class="p">{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;component&#39;</span><span class="p">,</span>
<span class="n">componentName</span><span class="p">:</span> <span class="s1">&#39;input&#39;</span><span class="p">,</span>
<span class="nb">id</span><span class="p">:</span> <span class="s1">&#39;inputComponent&#39;</span><span class="p">,</span>
<span class="n">height</span><span class="p">:</span> <span class="mi">10</span><span class="p">,</span>
<span class="n">isClosable</span><span class="p">:</span> <span class="n">false</span><span class="p">,</span>
<span class="n">tooltip</span><span class="p">:</span> <span class="s1">&#39;Input - The last input in the layout is always the default.&#39;</span><span class="p">,</span>
<span class="p">}]</span>
<span class="p">},{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;column&#39;</span><span class="p">,</span>
<span class="n">content</span><span class="p">:</span> <span class="p">[{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;component&#39;</span><span class="p">,</span>
<span class="n">componentName</span><span class="p">:</span> <span class="s1">&#39;evennia&#39;</span><span class="p">,</span>
<span class="n">componentId</span><span class="p">:</span> <span class="s1">&#39;evennia&#39;</span><span class="p">,</span>
<span class="n">title</span><span class="p">:</span> <span class="s1">&#39;example&#39;</span><span class="p">,</span>
<span class="n">height</span><span class="p">:</span> <span class="mi">60</span><span class="p">,</span>
<span class="n">isClosable</span><span class="p">:</span> <span class="n">false</span><span class="p">,</span>
<span class="n">componentState</span><span class="p">:</span> <span class="p">{</span>
<span class="n">types</span><span class="p">:</span> <span class="s1">&#39;some-tag-here&#39;</span><span class="p">,</span>
<span class="n">updateMethod</span><span class="p">:</span> <span class="s1">&#39;newlines&#39;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">},</span> <span class="p">{</span>
<span class="nb">type</span><span class="p">:</span> <span class="s1">&#39;component&#39;</span><span class="p">,</span>
<span class="n">componentName</span><span class="p">:</span> <span class="s1">&#39;evennia&#39;</span><span class="p">,</span>
<span class="n">componentId</span><span class="p">:</span> <span class="s1">&#39;evennia&#39;</span><span class="p">,</span>
<span class="n">title</span><span class="p">:</span> <span class="s1">&#39;sheet&#39;</span><span class="p">,</span>
<span class="n">isClosable</span><span class="p">:</span> <span class="n">false</span><span class="p">,</span>
<span class="n">componentState</span><span class="p">:</span> <span class="p">{</span>
<span class="n">types</span><span class="p">:</span> <span class="s1">&#39;sheet&#39;</span><span class="p">,</span>
<span class="n">updateMethod</span><span class="p">:</span> <span class="s1">&#39;replace&#39;</span><span class="p">,</span>
<span class="p">},</span>
<span class="p">}],</span>
<span class="p">}],</span>
<span class="p">}]</span>
<span class="p">}]</span>
<span class="p">};</span>
</pre></div>
</div>
<p>This is a bit ugly, but hopefully, from the indentation, you can see that it creates a side-by-side
(2-column) interface with 3 windows down the left side (The Main and 2 inputs) and a pair of windows
on the right side for extra outputs. Any text tagged with “some-tag-here” will flow to the bottom
of the “example” window, and any text tagged “sheet” will replace the text already in the “sheet”
window.</p>
<p>Note: GoldenLayout gets VERY confused and will break if you create two windows with the “Main”
componentName.</p>
<p>Now, lets say you want to display text on each window using different CSS. This is where new
goldenlayout “components” come in. Each component is like a blueprint that gets stamped out when
you create a new instance of that component, once it is defined, it wont be easily altered. You
will need to define a new component, preferably in a new plugin file, and then add that into your
page (either dynamically to the DOM via javascript, or by including the new plugin file into the
base.html).</p>
<p>First up, follow the directions in Customizing the Web Client section above to override the
base.html.</p>
<p>Next, add the new plugin to your copy of base.html:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">script</span> <span class="n">src</span><span class="o">=</span><span class="p">{</span><span class="o">%</span> <span class="n">static</span> <span class="s2">&quot;webclient/js/plugins/myplugin.js&quot;</span> <span class="o">%</span><span class="p">}</span> <span class="n">language</span><span class="o">=</span><span class="s2">&quot;javascript&quot;</span>
<span class="nb">type</span><span class="o">=</span><span class="s2">&quot;text/javascript&quot;</span><span class="o">&gt;&lt;/</span><span class="n">script</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>Remember, plugins are load-order dependent, so make sure the new <code class="docutils literal notranslate"><span class="pre">&lt;script&gt;</span></code> tag comes before the
goldenlayout.js</p>
<p>Next, create a new plugin file <code class="docutils literal notranslate"><span class="pre">mygame/web/static_overrides/webclient/js/plugins/myplugin.js</span></code> and
edit it.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>let myplugin = (function () {
//
//
var postInit = function() {
var myLayout = window.plugins[&#39;goldenlayout&#39;].getGL();
// register our component and replace the default messagewindow
myLayout.registerComponent( &#39;mycomponent&#39;, function (container, componentState) {
let mycssdiv = $(&#39;&lt;div&gt;&#39;).addClass(&#39;myCSS&#39;);
mycssdiv.attr(&#39;types&#39;, &#39;mytag&#39;);
mycssdiv.attr(&#39;update_method&#39;, &#39;newlines&#39;);
mycssdiv.appendTo( container.getElement() );
});
console.log(&quot;MyPlugin Initialized.&quot;);
}
return {
init: function () {},
postInit: postInit,
}
})();
window.plugin_handler.add(&quot;myplugin&quot;, myplugin);
</pre></div>
</div>
<p>You can then add “mycomponent” to an items componentName in your goldenlayout_default_config.js.</p>
<p>Make sure to stop your server, evennia collectstatic, and restart your server. Then make sure to
clear your browser cache before loading the webclient page.</p>
</div>
<div class="section" id="older-splithandler">
<h2>Older Splithandler<a class="headerlink" href="#older-splithandler" title="Permalink to this headline"></a></h2>
<p>The splithandler.js plugin provides a means to do this, but you dont want to have to force every
player to set up their own layout every time they use the client.</p>
<p>Lets create a <code class="docutils literal notranslate"><span class="pre">mygame/web/static_overrides/webclient/js/plugins/layout.js</span></code> plugin!</p>
<p>First up, follow the directions in Customizing the Web Client section above to override the
base.html.</p>
<p>Next, add the new plugin to your copy of base.html:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&lt;</span><span class="n">script</span> <span class="n">src</span><span class="o">=</span><span class="p">{</span><span class="o">%</span> <span class="n">static</span> <span class="s2">&quot;webclient/js/plugins/layout.js&quot;</span> <span class="o">%</span><span class="p">}</span> <span class="n">language</span><span class="o">=</span><span class="s2">&quot;javascript&quot;</span>
<span class="nb">type</span><span class="o">=</span><span class="s2">&quot;text/javascript&quot;</span><span class="o">&gt;&lt;/</span><span class="n">script</span><span class="o">&gt;</span>
</pre></div>
</div>
<p>Remember, plugins are load-order dependent, so make sure the new <code class="docutils literal notranslate"><span class="pre">&lt;script&gt;</span></code> tag comes after the
splithandler.js</p>
<p>And finally create the layout.js file and add the minimum skeleton of a plugin to it:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">//</span> <span class="n">my</span> <span class="n">new</span> <span class="n">plugin</span>
<span class="n">var</span> <span class="n">my_plugin</span> <span class="o">=</span> <span class="p">(</span><span class="n">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="n">let</span> <span class="n">init</span> <span class="o">=</span> <span class="n">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="n">console</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;myplugin! Hello World!&quot;</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="p">{</span>
<span class="n">init</span><span class="p">:</span> <span class="n">init</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">})();</span>
<span class="n">plugin_handler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;myplugin&quot;</span><span class="p">,</span> <span class="n">my_plugin</span><span class="p">);</span>
</pre></div>
</div>
<p>Now, <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">stop</span></code>, <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">collectstatic</span></code>, and <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">start</span></code> and then load the webclient up in
your browser.
Enable developer options and look in the console, and you should see the message myplugin! Hello
World!</p>
<p>Since our layout.js plugin is going to use the splithandler, lets enhance this by adding a check to
make sure the splithandler.js plugin has been loaded:</p>
<p>change the above init function to:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">let</span> <span class="n">init</span> <span class="o">=</span> <span class="n">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="n">let</span> <span class="n">splithandler</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">[</span><span class="s1">&#39;splithandler&#39;</span><span class="p">];</span>
<span class="k">if</span><span class="p">(</span> <span class="n">splithandler</span> <span class="p">)</span> <span class="p">{</span>
<span class="n">console</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;MyPlugin initialized&quot;</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">alert</span><span class="p">(</span><span class="s1">&#39;MyPlugin requires the splithandler.js plugin. Please contact the game maintainer to</span>
<span class="n">correct</span> <span class="n">this</span><span class="s1">&#39;);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>And finally, the splithandler.js provides provides two functions to cut up the screen real-estate:
<code class="docutils literal notranslate"><span class="pre">dynamic_split(</span> <span class="pre">pane_name_to_cut_apart,</span> <span class="pre">direction_of_split,</span> <span class="pre">new_pane_name1,</span> <span class="pre">new_pane_name2,</span> <span class="pre">text_flow_pane1,</span> <span class="pre">text_flow_pane2,</span> <span class="pre">array_of_split_percentages</span> <span class="pre">)</span></code>
and
<code class="docutils literal notranslate"><span class="pre">set_pane_types(</span> <span class="pre">pane_to_set,</span> <span class="pre">array_of_known_message_types_to_assign)</span></code></p>
<p>In this case, well cut it into 3 panes, 1 bigger, two smaller, and assign help messages to the
top-right pane:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">let</span> <span class="n">init</span> <span class="o">=</span> <span class="n">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="n">let</span> <span class="n">splithandler</span> <span class="o">=</span> <span class="n">plugins</span><span class="p">[</span><span class="s1">&#39;splithandler&#39;</span><span class="p">];</span>
<span class="k">if</span><span class="p">(</span> <span class="n">splithandler</span> <span class="p">)</span> <span class="p">{</span>
<span class="n">splithandler</span><span class="o">.</span><span class="n">dynamic_split</span><span class="p">(</span><span class="s2">&quot;main&quot;</span><span class="p">,</span><span class="s2">&quot;horizontal&quot;</span><span class="p">,</span><span class="s2">&quot;left&quot;</span><span class="p">,</span><span class="s2">&quot;right&quot;</span><span class="p">,</span><span class="s2">&quot;linefeed&quot;</span><span class="p">,</span><span class="s2">&quot;linefeed&quot;</span><span class="p">,[</span><span class="mi">50</span><span class="p">,</span><span class="mi">50</span><span class="p">]);</span>
<span class="n">splithandler</span><span class="o">.</span><span class="n">dynamic_split</span><span class="p">(</span><span class="s2">&quot;right&quot;</span><span class="p">,</span><span class="s2">&quot;vertical&quot;</span><span class="p">,</span><span class="s2">&quot;help&quot;</span><span class="p">,</span><span class="s2">&quot;misc&quot;</span><span class="p">,</span><span class="s2">&quot;replace&quot;</span><span class="p">,</span><span class="s2">&quot;replace&quot;</span><span class="p">,[</span><span class="mi">50</span><span class="p">,</span><span class="mi">50</span><span class="p">]);</span>
<span class="n">splithandler</span><span class="o">.</span><span class="n">set_pane_types</span><span class="p">(</span><span class="s1">&#39;help&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;help&#39;</span><span class="p">]);</span>
<span class="n">console</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">&quot;MyPlugin initialized&quot;</span><span class="p">);</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="n">alert</span><span class="p">(</span><span class="s1">&#39;MyPlugin requires the splithandler.js plugin. Please contact the game maintainer to</span>
<span class="n">correct</span> <span class="n">this</span><span class="s1">&#39;);</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p><code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">stop</span></code>, <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">collectstatic</span></code>, and <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">start</span></code> once more, and force-reload your
browser page to clear any cached version. You should now have a nicely split layout.</p>
</div>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<p><h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Webclient</a></li>
<li><a class="reference internal" href="#web-client"><strong>Web client</strong></a><ul>
<li><a class="reference internal" href="#customizing-the-web-client">Customizing the web client</a></li>
</ul>
</li>
<li><a class="reference internal" href="#evennia-web-client-api-from-evennia-js">Evennia Web Client API (from evennia.js)</a></li>
<li><a class="reference internal" href="#plugin-manager-api-from-webclient-gui-js">Plugin Manager API (from webclient_gui.js)</a></li>
<li><a class="reference internal" href="#plugin-callbacks-api">Plugin callbacks API</a></li>
<li><a class="reference internal" href="#example-default-plugins-plugins-js">Example/Default Plugins (plugins/*.js)</a></li>
<li><a class="reference internal" href="#writing-your-own-plugins">Writing your own Plugins</a><ul>
<li><a class="reference internal" href="#goldenlayout">GoldenLayout</a></li>
<li><a class="reference internal" href="#older-splithandler">Older Splithandler</a></li>
</ul>
</li>
</ul>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Webclient.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Webclient.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webclient</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>

View file

@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Webserver &#8212; 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" />
</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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webserver</a></li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" role="main">
<div class="section" id="webserver">
<h1>Webserver<a class="headerlink" href="#webserver" title="Permalink to this headline"></a></h1>
<p>TODO: There is no central docs for this component yet.</p>
</div>
<div class="clearer"></div>
</div>
</div>
</div>
<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>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Webserver.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div>
<h3>Versions</h3>
<ul>
<li><a href="Webserver.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.1/index.html">0.9.1 (master branch)</a></li>
</ul>
</div>
</div>
<div class="clearer"></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="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webserver</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.1.1.
</div>
</body>
</html>