Revert "Updated HTML docs."

This reverts commit 51d5840b8b.
This commit is contained in:
Griatch 2022-11-14 22:43:45 +01:00
parent 51d5840b8b
commit e34f258a92
2504 changed files with 820160 additions and 0 deletions

View file

@ -0,0 +1,237 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Objects" href="Objects.html" />
<link rel="prev" title="Sessions" href="Sessions.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Objects.html" title="Objects"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Sessions.html" title="Sessions"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Accounts</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Sessions.html"
title="previous chapter">Sessions</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Objects.html"
title="next chapter">Objects</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Accounts.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-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 std std-doc">Object</span></a>
(normally a <a class="reference internal" href="Objects.html#characters"><span class="std std-doc">Character</span></a>).</p>
<p>Exactly how many Sessions can interact with an Account and its Puppets at once is determined by
Evennias <a class="reference internal" href="Sessions.html#multisession-mode"><span class="std std-doc">MULTISESSION_MODE</span></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="Channels.html"><span class="doc std std-doc">Channels</span></a>. It is also a good place to store <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Permissions</span></a> to be
consistent between different in-game characters as well as configuration options. The Account
object also has its own <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">CmdSet</span></a>, the <code class="docutils literal notranslate"><span class="pre">AccountCmdSet</span></code>.</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 std std-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 internal" href="Permissions.html"><span class="doc std std-doc">Permissions</span></a> from the Character they control. Normally you should put your
permissions on the Account level - this will overrule permissions set on the Character level. For
the permissions of the Character to come into play the default <code class="docutils literal notranslate"><span class="pre">quell</span></code> command can be used. This
allows for exploring the game using a different permission set (but you 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>
<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"><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="kc">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="kc">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>
</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>
</section>
<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 std std-doc">Typeclasses</span></a>), the
Account also has the following custom properties:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">user</span></code> - a unique link to a <code class="docutils literal notranslate"><span class="pre">User</span></code> Django object, representing the logged-in user.</p></li>
<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 std std-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 std std-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 internal" href="Channels.html"><span class="doc std std-doc">Channels</span></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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Objects.html" title="Objects"
>next</a> |</li>
<li class="right" >
<a href="Sessions.html" title="Sessions"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Accounts</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,741 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Nicks" href="Nicks.html" />
<link rel="prev" title="Msg" href="Msg.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Nicks.html" title="Nicks"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Msg.html" title="Msg"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Attributes</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Attributes</a><ul>
<li><a class="reference internal" href="#managing-attributes-in-code">Managing Attributes in Code</a><ul>
<li><a class="reference internal" href="#using-db">Using .db</a></li>
<li><a class="reference internal" href="#using-attributes">Using .attributes</a></li>
<li><a class="reference internal" href="#using-attributeproperty">Using AttributeProperty</a></li>
</ul>
</li>
<li><a class="reference internal" href="#managing-attributes-in-game">Managing Attributes in-game</a></li>
<li><a class="reference internal" href="#locking-and-checking-attributes">Locking and checking Attributes</a></li>
<li><a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute">What types of data can I save in an Attribute?</a><ul>
<li><a class="reference internal" href="#storing-single-objects">Storing single objects</a></li>
<li><a class="reference internal" href="#storing-multiple-objects">Storing multiple objects</a></li>
<li><a class="reference internal" href="#retrieving-mutable-objects">Retrieving Mutable objects</a></li>
</ul>
</li>
<li><a class="reference internal" href="#properties-of-attributes">Properties of Attributes</a></li>
<li><a class="reference internal" href="#in-memory-attributes-nattributes">In-memory Attributes (NAttributes)</a><ul>
<li><a class="reference internal" href="#persistent-vs-non-persistent">Persistent vs non-persistent</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Msg.html"
title="previous chapter">Msg</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Nicks.html"
title="next chapter">Nicks</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Attributes.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="attributes">
<h1>Attributes<a class="headerlink" href="#attributes" title="Permalink to this headline"></a></h1>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">In-game</span><a class="headerlink" href="#id1" title="Permalink to this code"></a></div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="nb">set</span> <span class="n">obj</span><span class="o">/</span><span class="n">myattr</span> <span class="o">=</span> <span class="s2">&quot;test&quot;</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">In-code, using the .db wrapper</span><a class="headerlink" href="#id2" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><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">foo</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="s2">&quot;bar&quot;</span><span class="p">]</span>
<span class="n">value</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">foo</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">In-code, using the .attributes handler</span><a class="headerlink" href="#id3" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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;myattr&quot;</span><span class="p">,</span> <span class="mi">1234</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="n">value</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">category</span><span class="o">=</span><span class="s2">&quot;bar&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id4">
<div class="code-block-caption"><span class="caption-text">In-code, using <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> at class level</span><a class="headerlink" href="#id4" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">AttributeProperty</span>
<span class="k">class</span> <span class="nc">MyObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="n">foo</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="n">default</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="s2">&quot;bar&quot;</span><span class="p">])</span>
<span class="n">myattr</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">&#39;bar&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p><em>Attributes</em> allow you to to store arbitrary data on objects and make sure the data survives a server reboot. An Attribute can store pretty much any
Python data structure and data type, like numbers, strings, lists, dicts etc. You can also
store (references to) database objects like characters and rooms.</p>
<ul class="simple">
<li><p><a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute"><span class="std std-doc">What can be stored in an Attribute</span></a> is a must-read to avoid being surprised, also for experienced developers. Attributes can store <em>almost</em> everything
but you need to know the quirks.</p></li>
<li><p><a class="reference internal" href="#in-memory-attributes-nattributes"><span class="std std-doc">NAttributes</span></a> are the in-memory, non-persistent
siblings of Attributes.</p></li>
<li><p><a class="reference internal" href="#managing-attributes-in-game"><span class="std std-doc">Managing Attributes In-game</span></a> for in-game builder commands.</p></li>
</ul>
<section id="managing-attributes-in-code">
<h2>Managing Attributes in Code<a class="headerlink" href="#managing-attributes-in-code" title="Permalink to this headline"></a></h2>
<p>Attributes are usually handled in code. All <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities
(<a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and
<a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>) can (and usually do) have Attributes associated with them. There
are three ways to manage Attributes, all of which can be mixed.</p>
<ul class="simple">
<li><p><a class="reference internal" href="#using-db"><span class="std std-doc">Using the <code class="docutils literal notranslate"><span class="pre">.db</span></code> property shortcut</span></a></p></li>
<li><p><a class="reference internal" href="#using-attributes"><span class="std std-doc">Using the <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> manager (<code class="docutils literal notranslate"><span class="pre">AttributeManager</span></code>)</span></a></p></li>
<li><p><a class="reference internal" href="#using-attributeproperty"><span class="std std-doc">Using <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> for assigning Attributes in a way similar to Django fields</span></a></p></li>
</ul>
<section id="using-db">
<h3>Using .db<a class="headerlink" href="#using-db" title="Permalink to this headline"></a></h3>
<p>The simplest way to get/set Attributes is to use the <code class="docutils literal notranslate"><span class="pre">.db</span></code> shortcut. This allows for setting and getting Attributes that lack a <em>category</em> (having category <code class="docutils literal notranslate"><span class="pre">None</span></code>)</p>
<div class="highlight-python notranslate"><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">create_object</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">&quot;Foo&quot;</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">foo1</span> <span class="o">=</span> <span class="mi">1234</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo2</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">weapon</span> <span class="o">=</span> <span class="s2">&quot;sword&quot;</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">self_reference</span> <span class="o">=</span> <span class="n">obj</span> <span class="c1"># stores a reference to the obj</span>
<span class="c1"># (let&#39;s assume a rose exists in-game)</span>
<span class="n">rose</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;rose&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># returns a list, grab 0th element</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="kc">True</span>
<span class="c1"># retrieving</span>
<span class="n">val1</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">foo1</span>
<span class="n">val2</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">foo2</span>
<span class="n">weap</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">weapon</span>
<span class="n">myself</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">self_reference</span> <span class="c1"># retrieve reference from db, get object 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>
<span class="c1"># this will return None, not AttributeError!</span>
<span class="n">not_found</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">jiwjpowiwwerw</span>
<span class="c1"># returns all Attributes on the object</span>
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">all</span>
<span class="c1"># delete an Attribute</span>
<span class="k">del</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo2</span>
</pre></div>
</div>
<p>Trying to access a non-existing Attribute will never lead to an <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code>. Instead
you will get <code class="docutils literal notranslate"><span class="pre">None</span></code> back. The special <code class="docutils literal notranslate"><span class="pre">.db.all</span></code> will return a list of all Attributes on
the object. You can replace this with your own Attribute <code class="docutils literal notranslate"><span class="pre">all</span></code> if you want, it will replace the
default <code class="docutils literal notranslate"><span class="pre">all</span></code> functionality until you delete it again.</p>
</section>
<section id="using-attributes">
<h3>Using .attributes<a class="headerlink" href="#using-attributes" title="Permalink to this headline"></a></h3>
<p>If you want to group your Attribute in a category, or dont know the name of the Attribute beforehand, you can make use of
the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler" title="evennia.typeclasses.attributes.AttributeHandler"><span class="xref myst py py-class">AttributeHandler</span></a>, available as <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> on all typeclassed entities. With no extra keywords, this is identical to using the <code class="docutils literal notranslate"><span class="pre">.db</span></code> shortcut (<code class="docutils literal notranslate"><span class="pre">.db</span></code> is actually using the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> internally):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</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;has_thorns&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;helmet&quot;</span><span class="p">,</span> <span class="s2">&quot;Knight&#39;s helmet&quot;</span><span class="p">)</span>
<span class="n">helmet</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="s2">&quot;helmet&quot;</span><span class="p">)</span>
<span class="c1"># you can give space-separated Attribute-names (can&#39;t do that with .db)</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;my game log&quot;</span><span class="p">,</span> <span class="s2">&quot;long text about ...&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>By using a category you can separate same-named Attributes on the same object to help organization.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># store (let&#39;s say we have gold_necklace and ringmail_armor from before)</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;neck&quot;</span><span class="p">,</span> <span class="n">gold_necklace</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;clothing&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;neck&quot;</span><span class="p">,</span> <span class="n">ringmail_armor</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;armor&quot;</span><span class="p">)</span>
<span class="c1"># retrieve later - we&#39;ll get back gold_necklace and ringmail_armor</span>
<span class="n">neck_clothing</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="s2">&quot;neck&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;clothing&quot;</span><span class="p">)</span>
<span class="n">neck_armor</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="s2">&quot;neck&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;armor&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>If you dont specify a category, the Attributes <code class="docutils literal notranslate"><span class="pre">category</span></code> will be <code class="docutils literal notranslate"><span class="pre">None</span></code> and can thus also be found via <code class="docutils literal notranslate"><span class="pre">.db</span></code>. <code class="docutils literal notranslate"><span class="pre">None</span></code> is considered a category of its own, so you wont find <code class="docutils literal notranslate"><span class="pre">None</span></code>-category Attributes mixed with Attributes having categories.</p>
<p>Here are the methods of the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code>. See
the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler" title="evennia.typeclasses.attributes.AttributeHandler"><span class="xref myst py py-class">AttributeHandler API</span></a> for more details.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">has(...)</span></code> - this checks if the object has an Attribute with this key. This is equivalent
to doing <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span></code> except you can also check for a specific `category.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">get(...)</span></code> - this retrieves the given Attribute. You can also provide a <code class="docutils literal notranslate"><span class="pre">default</span></code> value to return
if the Attribute is not defined (instead of None). 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. The <code class="docutils literal notranslate"><span class="pre">raise_exception</span></code> kwarg allows you to raise an <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> instead of returning
<code class="docutils literal notranslate"><span class="pre">None</span></code> when you access a non-existing <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>. The <code class="docutils literal notranslate"><span class="pre">strattr</span></code> kwarg tells the system to store
the Attribute as a raw string rather than to pickle it. While an optimization this should usually
not be used unless the Attribute is used for some particular, limited purpose.</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 std std-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(category=None)</span></code> - returns all Attributes (of the given category) attached to this object.</p></li>
</ul>
<p>Examples:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
<span class="c1"># raise error if Attribute foo does not exist</span>
<span class="n">val</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="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="n">raise_exception</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
<span class="c1"># ...</span>
<span class="c1"># return default value if foo2 doesn&#39;t exist</span>
<span class="n">val2</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="s2">&quot;foo2&quot;</span><span class="p">,</span> <span class="n">default</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="s2">&quot;bar&quot;</span><span class="p">])</span>
<span class="c1"># delete foo if it exists (will silently fail if unset, unless</span>
<span class="c1"># raise_exception is set)</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;foo&quot;</span><span class="p">)</span>
<span class="c1"># view all clothes on obj</span>
<span class="n">all_clothes</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">all</span><span class="p">(</span><span class="n">category</span><span class="o">=</span><span class="s2">&quot;clothes&quot;</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="using-attributeproperty">
<h3>Using AttributeProperty<a class="headerlink" href="#using-attributeproperty" title="Permalink to this headline"></a></h3>
<p>The third way to set up an Attribute is to use an <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>. This
is done on the <em>class level</em> of your typeclass and allows you to treat Attributes a bit like Django database Fields. Unlike using <code class="docutils literal notranslate"><span class="pre">.db</span></code> and <code class="docutils literal notranslate"><span class="pre">.attributes</span></code>, an <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> cant be created on the fly, you must assign it in the class code.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/typeclasses/characters.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span>
<span class="kn">from</span> <span class="nn">evennia.typeclasses.attributes</span> <span class="kn">import</span> <span class="n">AttributeProperty</span>
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="n">strength</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">&#39;stat&#39;</span><span class="p">)</span>
<span class="n">constitution</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">&#39;stat&#39;</span><span class="p">)</span>
<span class="n">agility</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">&#39;stat&#39;</span><span class="p">)</span>
<span class="n">magic</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">&#39;stat&#39;</span><span class="p">)</span>
<span class="n">sleepy</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="kc">False</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="n">poisoned</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="kc">False</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</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="c1"># ...</span>
</pre></div>
</div>
<p>When a new instance of the class is created, new <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> will be created with the value and category given.</p>
<p>With <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>s set up like this, one can access the underlying <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> like a regular property on the created object:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">char</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">Character</span><span class="p">)</span>
<span class="n">char</span><span class="o">.</span><span class="n">strength</span> <span class="c1"># returns 10</span>
<span class="n">char</span><span class="o">.</span><span class="n">agility</span> <span class="o">=</span> <span class="mi">15</span> <span class="c1"># assign a new value (category remains &#39;stat&#39;)</span>
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">magic</span> <span class="c1"># returns None (wrong category)</span>
<span class="n">char</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;agility&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;stat&quot;</span><span class="p">)</span> <span class="c1"># returns 15</span>
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># returns None because autocreate=False (see below)</span>
</pre></div>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Be careful to not assign AttributePropertys to names of properties and methods already existing on the class, like key or at_object_creation. That could lead to very confusing errors.</p>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">autocreate=False</span></code> (default is <code class="docutils literal notranslate"><span class="pre">True</span></code>) used for <code class="docutils literal notranslate"><span class="pre">sleepy</span></code> and <code class="docutils literal notranslate"><span class="pre">poisoned</span></code> is worth a closer explanation. When <code class="docutils literal notranslate"><span class="pre">False</span></code>, <em>no</em> Attribute will be auto-created for these AttributProperties unless they are <em>explicitly</em> set.
The advantage of not creating an Attribute is that the default value given to <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> is returned with no database access unless you change it. This also means that if you want to change the default later, all entities previously create will inherit the new default.
The drawback is that without a database precense you cant find the Attribute via <code class="docutils literal notranslate"><span class="pre">.db</span></code> and <code class="docutils literal notranslate"><span class="pre">.attributes.get</span></code> (or by querying for it in other ways in the database):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">char</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># returns False, no db access</span>
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># returns None - no Attribute exists</span>
<span class="n">char</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;sleepy&quot;</span><span class="p">)</span> <span class="c1"># returns None too</span>
<span class="n">char</span><span class="o">.</span><span class="n">sleepy</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># now an Attribute is created</span>
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># now returns True!</span>
<span class="n">char</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;sleepy&quot;</span><span class="p">)</span> <span class="c1"># now returns True</span>
<span class="n">char</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># now returns True, involves db access</span>
</pre></div>
</div>
<p>You can e.g. <code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">char.strength</span></code> to set the value back to the default (the value defined
in the <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>).</p>
<p>See the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeProperty" title="evennia.typeclasses.attributes.AttributeProperty"><span class="xref myst py py-class">AttributeProperty API</span></a> for more details on how to create it with special options, like giving access-restrictions.</p>
</section>
</section>
<section id="managing-attributes-in-game">
<h2>Managing Attributes in-game<a class="headerlink" href="#managing-attributes-in-game" title="Permalink to this headline"></a></h2>
<p>Attributes are mainly used by code. But one can also allow the builder to use Attributes to
turn knobs in-game. For example a builder could want to manually tweak the “level” Attribute of an
enemy NPC to lower its difficuly.</p>
<p>When setting Attributes this way, you are severely limited in what can be stored - this is because
giving players (even builders) the ability to store arbitrary Python would be a severe security
problem.</p>
<p>In game you can set an Attribute like this:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>set myobj/foo = &quot;bar&quot;
</pre></div>
</div>
<p>To view, do</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>set myobj/foo
</pre></div>
</div>
<p>or see them together with all object-info with</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>examine myobj
</pre></div>
</div>
<p>The first <code class="docutils literal notranslate"><span class="pre">set</span></code>-example will store a new Attribute <code class="docutils literal notranslate"><span class="pre">foo</span></code> on the object <code class="docutils literal notranslate"><span class="pre">myobj</span></code> and give it the
value “bar”.
You can store numbers, booleans, strings, tuples, lists and dicts this way. But if
you store a list/tuple/dict they must be proper Python structures and may <em>only</em> contain strings
or numbers. If you try to insert an unsupported structure, the input will be converted to a
string.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>set myobj/mybool = True
set myobj/mybool = True
set myobj/mytuple = (1, 2, 3, &quot;foo&quot;)
set myobj/mylist = [&quot;foo&quot;, &quot;bar&quot;, 2]
set myobj/mydict = {&quot;a&quot;: 1, &quot;b&quot;: 2, 3: 4}
set mypobj/mystring = [1, 2, foo] # foo is invalid Python (no quotes)
</pre></div>
</div>
<p>For the last line youll get a warning and the value instead will be saved as a string <code class="docutils literal notranslate"><span class="pre">&quot;[1,</span> <span class="pre">2,</span> <span class="pre">foo]&quot;</span></code>.</p>
</section>
<section id="locking-and-checking-attributes">
<h2>Locking and checking Attributes<a class="headerlink" href="#locking-and-checking-attributes" title="Permalink to this headline"></a></h2>
<p>While the <code class="docutils literal notranslate"><span class="pre">set</span></code> command is limited to builders, individual Attributes are usually not
locked down. You may want to lock certain sensitive Attributes, in particular for games
where you allow player building. You can add such limitations by adding a <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock string</span></a>
to your Attribute. A NAttribute have no locks.</p>
<p>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 must use the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> to assign the lockstring to the Attribute:</p>
<div class="highlight-python notranslate"><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">add</span><span class="p">(</span><span class="s2">&quot;myattr&quot;</span><span class="p">,</span> <span class="s2">&quot;bar&quot;</span><span class="p">,</span> <span class="n">lockstring</span><span class="o">=</span><span class="n">lockstring</span><span class="p">)</span><span class="s2">&quot;</span>
</pre></div>
</div>
<p>If you already have an Attribute and want to add a lock in-place you can do so
by having the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> return the <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object itself (rather than
its value) and then assign the lock to it directly:</p>
<div class="highlight-python notranslate"><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="kc">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>
</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.
To check the <code class="docutils literal notranslate"><span class="pre">lockstring</span></code> you provided, make sure you include <code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> and set
<code class="docutils literal notranslate"><span class="pre">default_access=False</span></code> as you make a <code class="docutils literal notranslate"><span class="pre">get</span></code> call.</p>
<div class="highlight-python notranslate"><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="kc">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="kc">None</span><span class="p">,</span>
<span class="n">default_access</span><span class="o">=</span><span class="kc">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>
</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>
</section>
<section id="what-types-of-data-can-i-save-in-an-attribute">
<h2>What types of data can I save in an Attribute?<a class="headerlink" href="#what-types-of-data-can-i-save-in-an-attribute" title="Permalink to this headline"></a></h2>
<p>The database doesnt know anything about Python objects, so Evennia must <em>serialize</em> Attribute
values into a string representation before storing it to the database. This is done using the
<a class="reference external" href="https://docs.python.org/library/pickle.html">pickle</a> module of Python.</p>
<blockquote>
<div><p>The only exception is if you use the <code class="docutils literal notranslate"><span class="pre">strattr</span></code> keyword of the
<code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> to save to the <code class="docutils literal notranslate"><span class="pre">strvalue</span></code> field of the Attribute. In that case you can <em>only</em> save
<em>strings</em> and those will not be pickled).</p>
</div></blockquote>
<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 <em>pickled</em>.</p></li>
<li><p>Single database objects/typeclasses can be stored, despite them normally not
being possible to pickle. Evennia will convert them to an internal
representation using theihr classname, database-id and creation-date with a
microsecond precision. When retrieving, the object instance will be re-fetched
from the database using this information.</p></li>
<li><p>If you hide a db-obj as a property on a custom class, Evennia will not be
able to find it to serialize it. For that you need to help it out (see below).</p></li>
</ul>
<div class="literal-block-wrapper docutils container" id="id5">
<div class="code-block-caption"><span class="caption-text">Valid assignments</span><a class="headerlink" href="#id5" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><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="kc">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>
</pre></div>
</div>
</div>
<p>As mentioned, Evennia will not be able to automatically serialize db-objects
hidden in arbitrary properties on an object. This will lead to an error
when saving the Attribute.</p>
<div class="literal-block-wrapper docutils container" id="id6">
<div class="code-block-caption"><span class="caption-text">Invalid, hidden dbobject</span><a class="headerlink" href="#id6" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># example of storing an invalid, &quot;hidden&quot; dbobject in Attribute</span>
<span class="k">class</span> <span class="nc">Container</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">mydbobj</span><span class="p">):</span>
<span class="c1"># no way for Evennia to know this is a database object!</span>
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span> <span class="o">=</span> <span class="n">mydbobj</span>
<span class="c1"># let&#39;s assume myobj is a db-object</span>
<span class="n">container</span> <span class="o">=</span> <span class="n">Container</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">mydata</span> <span class="o">=</span> <span class="n">container</span> <span class="c1"># will raise error!</span>
</pre></div>
</div>
</div>
<p>By adding two methods <code class="docutils literal notranslate"><span class="pre">__serialize_dbobjs__</span></code> and <code class="docutils literal notranslate"><span class="pre">__deserialize_dbobjs__</span></code> to the
object you want to save, you can pre-serialize and post-deserialize all hidden
objects before Evennias main serializer gets to work. Inside these methods, use Evennias
<a class="reference internal" href="../api/evennia.utils.dbserialize.html#evennia.utils.dbserialize.dbserialize" title="evennia.utils.dbserialize.dbserialize"><span class="xref myst py py-func">evennia.utils.dbserialize.dbserialize</span></a> and
<a class="reference internal" href="../api/evennia.utils.dbserialize.html#evennia.utils.dbserialize.dbunserialize" title="evennia.utils.dbserialize.dbunserialize"><span class="xref myst py py-func">dbunserialize</span></a> functions to safely
serialize the db-objects you want to store.</p>
<div class="literal-block-wrapper docutils container" id="id7">
<div class="code-block-caption"><span class="caption-text">Fixing an invalid hidden dbobj for storing in Attribute</span><a class="headerlink" href="#id7" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">dbserialize</span> <span class="c1"># important</span>
<span class="k">class</span> <span class="nc">Container</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">mydbobj</span><span class="p">):</span>
<span class="c1"># A &#39;hidden&#39; db-object</span>
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span> <span class="o">=</span> <span class="n">mydbobj</span>
<span class="k">def</span> <span class="nf">__serialize_dbobjs__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;This is called before serialization and allows</span>
<span class="sd"> us to custom-handle those &#39;hidden&#39; dbobjs&quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span> <span class="o">=</span> <span class="n">dbserialize</span><span class="o">.</span><span class="n">dbserialize</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span>
<span class="k">def</span> <span class="nf">__deserialize_dbobjs__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;This is called after deserialization and allows you to</span>
<span class="sd"> restore the &#39;hidden&#39; dbobjs you serialized before&quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
<span class="c1"># make sure to check if it&#39;s bytes before trying dbunserialize</span>
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span> <span class="o">=</span> <span class="n">dbserialize</span><span class="o">.</span><span class="n">dbunserialize</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span><span class="p">)</span>
<span class="c1"># let&#39;s assume myobj is a db-object</span>
<span class="n">container</span> <span class="o">=</span> <span class="n">Container</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">mydata</span> <span class="o">=</span> <span class="n">container</span> <span class="c1"># will now work fine!</span>
</pre></div>
</div>
</div>
<blockquote>
<div><p>Note the extra check in <code class="docutils literal notranslate"><span class="pre">__deserialize_dbobjs__</span></code> to make sure the thing you
are deserializing is a <code class="docutils literal notranslate"><span class="pre">bytes</span></code> object. This is needed because the Attributes
cache reruns deserializations in some situations when the data was already
once deserialized. If you see errors in the log saying
<code class="docutils literal notranslate"><span class="pre">Could</span> <span class="pre">not</span> <span class="pre">unpickle</span> <span class="pre">data</span> <span class="pre">for</span> <span class="pre">storage:</span> <span class="pre">...</span></code>, the reason is
likely that you forgot to add this check.</p>
</div></blockquote>
</section>
<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><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></li>
<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 internal" href="#storing-single-objects"><span class="std std-doc">Single object</span></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"><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="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>
</div>
<p>Note that if make some advanced iterable object, and store an db-object on it in
a way such that it is <em>not</em> returned by iterating over it, you have created a
hidden db-object. See <a class="reference internal" href="#storing-single-objects"><span class="std std-doc">the previous section</span></a> for how
to tell Evennia how to serialize such hidden objects safely.</p>
</section>
<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"><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="nb">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="nb">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"># now also [1, 2, 3, 5]</span>
</pre></div>
</div>
<p>When you extract your mutable Attribute data into a variable like <code class="docutils literal notranslate"><span class="pre">mylist</span></code>, think of it as getting a <em>snapshot</em>
of the variable. If you update the snapshot, it will save to the database, but this change <em>will not propagate to
any other snapshots you may have done previously</em>.</p>
<div class="highlight-python notranslate"><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">mylist1</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">mylist2</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">mylist1</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="nb">print</span><span class="p">(</span><span class="n">mylist1</span><span class="p">)</span> <span class="c1"># this is now [1, 2, 3, 5]</span>
<span class="nb">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"># also updated to [1, 2, 3, 5]</span>
<span class="nb">print</span><span class="p">(</span><span class="n">mylist2</span><span class="p">)</span> <span class="c1"># still [1, 2, 3, 4] !</span>
</pre></div>
</div>
<aside class="sidebar">
<p>Remember, the complexities of this section only relate to <em>mutable</em> iterables - things you can update
in-place, like lists and dicts. <a class="reference external" href="https://en.wikipedia.org/wiki/Immutable">Immutable</a> objects (strings,
numbers, tuples etc) are already disconnected from the database from the onset.</p>
</aside>
<p>To avoid confusion with mutable Attributes, only work with one variable (snapshot) at a time and save
back the results as needed.</p>
<p>You can also choose to “disconnect” the Attribute entirely from the
database with the help of the <code class="docutils literal notranslate"><span class="pre">.deserialize()</span></code> method:</p>
<div class="highlight-python notranslate"><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="p">{</span><span class="mi">1</span><span class="p">:</span> <span class="mi">2</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="o">.</span><span class="n">deserialize</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>, <code class="docutils literal notranslate"><span class="pre">dict</span></code> instead of <code class="docutils literal notranslate"><span class="pre">_SaverDict</span></code> and so on). If you update it, you need to
explicitly save it back to the Attribute for it to save.</p>
</section>
</section>
<section id="properties-of-attributes">
<h2>Properties of Attributes<a class="headerlink" href="#properties-of-attributes" title="Permalink to this headline"></a></h2>
<p>An <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object is stored in the database. It has the following properties:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - the name of the Attribute. When doing e.g. <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, this property is set
to <code class="docutils literal notranslate"><span class="pre">attrname</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">value</span></code> - this is the value of the Attribute. This value can be anything which can be pickled -
objects, lists, numbers or what have you (see
<a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute"><span class="std std-doc">this section</span></a> for more info). In the
example
<code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, the <code class="docutils literal notranslate"><span class="pre">value</span></code> is stored here.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">category</span></code> - this is an optional property that is set to None for most Attributes. Setting this
allows to use Attributes for different functionality. This is usually not needed unless you want
to use Attributes for very different functionality (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> is an example of using
Attributes in this way). To modify this property you need to use the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">strvalue</span></code> - this is a separate value field that only accepts strings. This severely limits the
data possible to store, but allows for easier database lookups. This property is usually not used
except when re-using Attributes for some other purpose (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> use it). It is only
accessible via the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a>.</p></li>
</ul>
<p>There are also two special properties:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">attrtype</span></code> - this is used internally by Evennia to separate <a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a>, from Attributes (Nicks
use Attributes behind the scenes).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">model</span></code> - this is a <em>natural-key</em> describing the model this Attribute is attached to. This is on
the form <em>appname.modelclass</em>, like <code class="docutils literal notranslate"><span class="pre">objects.objectdb</span></code>. It is used by the Attribute and
NickHandler to quickly sort matches in the database. Neither this nor <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> should normally
need to be modified.</p></li>
</ul>
<p>Non-database attributes are not stored in the database and have no equivalence
to <code class="docutils literal notranslate"><span class="pre">category</span></code> nor <code class="docutils literal notranslate"><span class="pre">strvalue</span></code>, <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> or <code class="docutils literal notranslate"><span class="pre">model</span></code>.</p>
</section>
<section id="in-memory-attributes-nattributes">
<h2>In-memory Attributes (NAttributes)<a class="headerlink" href="#in-memory-attributes-nattributes" title="Permalink to this headline"></a></h2>
<p><em>NAttributes</em> (short of Non-database Attributes) mimic Attributes in most things except they
are <strong>non-persistent</strong> - they will <em>not</em> survive a server reload.</p>
<ul class="simple">
<li><p>Instead of <code class="docutils literal notranslate"><span class="pre">.db</span></code> use <code class="docutils literal notranslate"><span class="pre">.ndb</span></code>.</p></li>
<li><p>Instead of <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> use <code class="docutils literal notranslate"><span class="pre">.nattributes</span></code></p></li>
<li><p>Instead of <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>, use <code class="docutils literal notranslate"><span class="pre">NAttributeProperty</span></code>.</p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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="kc">True</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>
<span class="n">rose</span><span class="o">.</span><span class="n">nattributes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;has_thorns&quot;</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
<span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">nattributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;has_thorns&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Differences between <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">NAttribute</span></code>s are always wiped on a server reload.</p></li>
<li><p>They only exist in memory and never involve the database at all, making them faster to
access and edit than <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>s.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">NAttribute</span></code>s can store <em>any</em> Python structure (and database object) without limit.</p></li>
<li><p>They can <em>not</em> be set with the standard <code class="docutils literal notranslate"><span class="pre">set</span></code> command (but they are visible with <code class="docutils literal notranslate"><span class="pre">examine</span></code>)</p></li>
</ul>
<p>There are some important reasons we recommend using <code class="docutils literal notranslate"><span class="pre">ndb</span></code> to store temporary data rather than
the simple alternative of just storing a variable directly on an object:</p>
<ul class="simple">
<li><p>NAttributes are tracked by Evennia and will not be purged in various cache-cleanup operations
the server may do. So using them guarantees that theyll remain available at least as long as
the server lives.</p></li>
<li><p>Its a consistent style - <code class="docutils literal notranslate"><span class="pre">.db/.attributes</span></code> and <code class="docutils literal notranslate"><span class="pre">.ndb/.nattributes</span></code> makes for clean-looking code
where its clear how long-lived (or not) your data is to be.</p></li>
</ul>
<section id="persistent-vs-non-persistent">
<h3>Persistent vs non-persistent<a class="headerlink" href="#persistent-vs-non-persistent" title="Permalink to this headline"></a></h3>
<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 std std-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><code class="docutils literal notranslate"><span class="pre">NAttribute</span></code>s have no restrictions at all on what they can store, 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>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Nicks.html" title="Nicks"
>next</a> |</li>
<li class="right" >
<a href="Msg.html" title="Msg"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Attributes</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,374 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Batch Command Processor" href="Batch-Command-Processor.html" />
<link rel="prev" title="Batch Processors" href="Batch-Processors.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Batch-Processors.html" title="Batch Processors"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Code Processor</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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="#dont-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="#dont-let-code-rely-on-the-batch-files-real-file-path">Dont let code rely on the batch-files real file path</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Batch-Processors.html"
title="previous chapter">Batch Processors</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Batch-Command-Processor.html"
title="next chapter">Batch Command Processor</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Batch-Code-Processor.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="batch-code-processor">
<h1>Batch Code Processor<a class="headerlink" href="#batch-code-processor" title="Permalink to this headline"></a></h1>
<p>For an introduction and motivation to using batch processors, see <a class="reference internal" href="Batch-Processors.html"><span class="doc std std-doc">here</span></a>. This
page describes the Batch-<em>code</em> processor. The Batch-<em>command</em> one is covered [here](Batch-Command-
Processor).</p>
<section id="basic-usage">
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline"></a></h2>
<p>The batch-code processor is a superuser-only function, invoked by</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; @batchcode path.to.batchcodefile
</pre></div>
</div>
<p>Where <code class="docutils literal notranslate"><span class="pre">path.to.batchcodefile</span></code> is the path to a <em>batch-code file</em>. Such a file should have a name
ending in “<code class="docutils literal notranslate"><span class="pre">.py</span></code>” (but you 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-none notranslate"><div class="highlight"><pre><span></span> &gt; @batchcode batch_code
</pre></div>
</div>
<p>This will try to run through the entire batch file in one go. For more gradual, <em>interactive</em>
control you can use the <code class="docutils literal notranslate"><span class="pre">/interactive</span></code> switch. The switch <code class="docutils literal notranslate"><span class="pre">/debug</span></code> will put the processor in
<em>debug</em> mode. Read below for more info.</p>
</section>
<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"><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="sa">f</span><span class="s2">&quot;A </span><span class="si">{</span><span class="n">table</span><span class="si">}</span><span class="s2"> and </span><span class="si">{</span><span class="n">chair</span><span class="si">}</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, 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="p">)</span>
</pre></div>
</div>
<p>This uses Evennias Python API to create three objects in sequence.</p>
</section>
<section id="debug-mode">
<h2>Debug mode<a class="headerlink" href="#debug-mode" title="Permalink to this headline"></a></h2>
<p>Try to run the example script with</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; @batchcode/debug tutorial_examples.example_batch_code
</pre></div>
</div>
<p>The batch script will run to the end and tell you it completed. You will also get messages that the
button and the two pieces of furniture were created. Look around and you should see the button
there. But you 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>
</section>
<section id="interactive-mode">
<h2>Interactive mode<a class="headerlink" href="#interactive-mode" title="Permalink to this headline"></a></h2>
<p>Interactive mode works very similar to the [batch-command processor counterpart](Batch-Command-
Processor). It allows you more step-wise control over how the batch file is executed. This is useful
for debugging or for picking and choosing only particular blocks to run. Use <code class="docutils literal notranslate"><span class="pre">&#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-none notranslate"><div class="highlight"><pre><span></span> &gt; @batchcode/interactive tutorial_examples.batch_code
</pre></div>
</div>
<p>You should see the following:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>01/02: red_button = create_object(red_button.RedButton, [...] (hh for help)
</pre></div>
</div>
<p>This shows that you are on the first <code class="docutils literal notranslate"><span class="pre">#CODE</span></code> block, the first of only two commands in this batch
file. Observe that the block has <em>not</em> actually been executed at this point!</p>
<p>To take a look at the full code snippet you are about to run, use <code class="docutils literal notranslate"><span class="pre">ll</span></code> (a batch-processor version of
<code class="docutils literal notranslate"><span class="pre">look</span></code>).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">create</span><span class="p">,</span> <span class="n">search</span>
<span class="kn">from</span> <span class="nn">evennia.contrib.tutorial_examples</span> <span class="kn">import</span> <span class="n">red_button</span>
<span class="kn">from</span> <span class="nn">typeclasses.objects</span> <span class="kn">import</span> <span class="n">Object</span>
<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="kc">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>
</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>
</section>
<section id="limitations-and-caveats">
<h2>Limitations and Caveats<a class="headerlink" href="#limitations-and-caveats" title="Permalink to this headline"></a></h2>
<p>The batch-code processor is by far the most flexible way to build a world in Evennia. There are
however some caveats you need to keep in mind.</p>
<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>
</section>
<section id="no-communication-between-code-blocks">
<h3>No communication between code blocks<a class="headerlink" href="#no-communication-between-code-blocks" title="Permalink to this headline"></a></h3>
<p>Global variables 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 std std-doc">Tags</span></a> or <em>Aliases</em>. You
can assign any number of tags and/or aliases to any object. Make sure that one of those tags or
aliases is unique to the room (like “room56”) and you will henceforth be able to always uniquely
search and find it later.</p></li>
<li><p>Use the <code class="docutils literal notranslate"><span class="pre">caller</span></code> global property as an inter-block storage. For example, you could have a
dictionary of room references in an <code class="docutils literal notranslate"><span class="pre">ndb</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1">#HEADER </span>
<span class="k">if</span> <span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">all_rooms</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="n">caller</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">all_rooms</span> <span class="o">=</span> <span class="p">{}</span>
<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>
</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>
</section>
<section id="dont-treat-a-batchcode-file-like-any-python-file">
<h3>Dont treat a batchcode file like any Python file<a class="headerlink" href="#dont-treat-a-batchcode-file-like-any-python-file" title="Permalink to this headline"></a></h3>
<p>Despite being a valid Python file, a batchcode file should <em>only</em> be run by the batchcode processor.
You should not do things like define Typeclasses or Commands in them, or import them into other
code. Importing a module in Python will execute base level of the module, which in the case of your
average batchcode file could mean creating a lot of new objects every time.</p>
</section>
<section id="dont-let-code-rely-on-the-batch-files-real-file-path">
<h3>Dont let code rely on the batch-files real file path<a class="headerlink" href="#dont-let-code-rely-on-the-batch-files-real-file-path" title="Permalink to this headline"></a></h3>
<p>When you import things into your batchcode file, 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>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
>next</a> |</li>
<li class="right" >
<a href="Batch-Processors.html" title="Batch Processors"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Code Processor</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,318 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Coding Utils" href="Coding-Utils.html" />
<link rel="prev" title="Batch Code Processor" href="Batch-Code-Processor.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Coding-Utils.html" title="Coding Utils"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Command Processor</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Batch-Code-Processor.html"
title="previous chapter">Batch Code Processor</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Coding-Utils.html"
title="next chapter">Coding Utils</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Batch-Command-Processor.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-doc">here</span></a>. This
page describes the Batch-<em>command</em> processor. The Batch-<em>code</em> one is covered [here](Batch-Code-
Processor).</p>
<section id="basic-usage">
<h2>Basic Usage<a class="headerlink" href="#basic-usage" title="Permalink to this headline"></a></h2>
<p>The batch-command processor is a superuser-only function, invoked by</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; @batchcommand path.to.batchcmdfile
</pre></div>
</div>
<p>Where <code class="docutils literal notranslate"><span class="pre">path.to.batchcmdfile</span></code> is the path to a <em>batch-command file</em> with the “<code class="docutils literal notranslate"><span class="pre">.ev</span></code>” file ending.
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-none notranslate"><div class="highlight"><pre><span></span> &gt; @batchcommand batch_cmds
</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>
</section>
<section id="the-batch-file">
<h2>The batch file<a class="headerlink" href="#the-batch-file" title="Permalink to this headline"></a></h2>
<p>The batch file is a simple plain-text file containing Evennia commands. Just like you would write
them in-game, except you have more freedom with line breaks.</p>
<p>Here are the rules of syntax of an <code class="docutils literal notranslate"><span class="pre">*.ev</span></code> file. 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"><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 <span class="k">in</span> 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>
</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-none notranslate"><div class="highlight"><pre><span></span>&gt; @batchcommand contrib.tutorial_examples.batch_cmds
</pre></div>
</div>
<p>A button will be created, described and dropped in Limbo. All commands will be executed by the user
calling the command.</p>
<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>
</section>
<section id="interactive-mode">
<h2>Interactive mode<a class="headerlink" href="#interactive-mode" title="Permalink to this headline"></a></h2>
<p>Interactive mode allows you to more step-wise control over how the batch file is executed. This is
useful for debugging and also if you have a large batch file and is only updating a small part of it
running the entire file again would be a waste of time (and in the case of <code class="docutils literal notranslate"><span class="pre">&#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-none notranslate"><div class="highlight"><pre><span></span> &gt; @batchcommand/interactive tutorial_examples.batch_cmds
</pre></div>
</div>
<p>You will see this:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>01/04: @create button:tutorial_examples.red_button.RedButton (hh for help)
</pre></div>
</div>
<p>This shows that you are on the <code class="docutils literal notranslate"><span class="pre">&#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>
</section>
<section id="limitations-and-caveats">
<h2>Limitations and Caveats<a class="headerlink" href="#limitations-and-caveats" title="Permalink to this headline"></a></h2>
<p>The batch-command processor is great for automating smaller builds or for testing new commands and
objects repeatedly without having to write so much. There are several caveats you have to be aware
of when using the batch-command processor for building larger, complex worlds though.</p>
<p>The 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 std std-doc">Command Set</span></a></em>: Imagine that you build a dark room, which
severely limits the cmdsets of those entering it (maybe you have to find the light switch to
proceed). In your batch script you would create this room, then teleport to it - and promptly be
shifted into the dark state where none of your normal build commands work …</p></li>
<li><p><em>Auto-teleportation</em>: Rooms that automatically teleport those that enter them to another place
(like a trap room, for example). You would be teleported away too.</p></li>
<li><p><em>Mobiles</em>: If you add aggressive mobs, they might attack you, drawing you into combat. If they
have AI they might even follow you around when building - or they might move away from you before
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>
</section>
<section id="assorted-notes">
<h2>Assorted notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline"></a></h2>
<p>The fact that you build as yourself can also be considered an advantage however, should you ever
decide to change the default command to allow others than superusers to call the processor. Since
normal access-checks are still performed, a malevolent builder with access to the processor should
not be able to do all that much damage (this is the main drawback of the <a class="reference internal" href="Batch-Code-Processor.html"><span class="doc std std-doc">Batch Code
Processor</span></a>)</p>
<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="https://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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Coding-Utils.html" title="Coding Utils"
>next</a> |</li>
<li class="right" >
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Command Processor</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,211 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Batch Code Processor" href="Batch-Code-Processor.html" />
<link rel="prev" title="Connection Screen" href="Connection-Screen.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Connection-Screen.html" title="Connection Screen"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Processors</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Connection-Screen.html"
title="previous chapter">Connection Screen</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Batch-Code-Processor.html"
title="next chapter">Batch Code Processor</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Batch-Processors.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Batch-Processors.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-doc">Batch Command Processor</span></a></p></li>
<li><p>The <a class="reference internal" href="Batch-Code-Processor.html"><span class="doc std std-doc">Batch Code Processor</span></a></p></li>
</ul>
<p>If you plan to use international characters in your batchfiles you are wise to read about <em>file
encodings</em> below.</p>
<section id="a-note-on-file-encodings">
<h2>A note on File Encodings<a class="headerlink" href="#a-note-on-file-encodings" title="Permalink to this headline"></a></h2>
<p>As mentioned, both the processors take text files as input and then proceed to process them. As long
as you stick to the standard <a class="reference external" href="https://en.wikipedia.org/wiki/Ascii">ASCII</a> character set (which means
the normal English characters, basically) you should not have to worry much about this section.</p>
<p>Many languages however use characters outside the simple <code class="docutils literal notranslate"><span class="pre">ASCII</span></code> table. Common examples are various
apostrophes and umlauts but also completely different symbols like those of the greek or cyrillic
alphabets.</p>
<p>First, we should make it clear that Evennia itself handles international characters just fine. It
(and Django) uses <a class="reference external" href="https://en.wikipedia.org/wiki/Unicode">unicode</a> strings internally.</p>
<p>The problem is that when reading a text file like the batchfile, we need to know how to decode the
byte-data stored therein to universal unicode. That means we need an <em>encoding</em> (a mapping) for how
the file stores its data. There are many, many byte-encodings used around the world, with opaque
names such as <code class="docutils literal notranslate"><span class="pre">Latin-1</span></code>, <code class="docutils literal notranslate"><span class="pre">ISO-8859-3</span></code> or <code class="docutils literal notranslate"><span class="pre">ARMSCII-8</span></code> to pick just a few examples. Problem is that
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 std std-doc">Text Encodings</span></a> and also in the
Wikipedia article <a class="reference external" href="https://en.wikipedia.org/wiki/Text_encodings">here</a>.</p>
<p><strong>A footnote for the batch-code processor</strong>: Just because <em>Evennia</em> can parse your file and your
fancy special characters, 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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Batch-Code-Processor.html" title="Batch Code Processor"
>next</a> |</li>
<li class="right" >
<a href="Connection-Screen.html" title="Connection Screen"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Batch Processors</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,245 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Core Concepts" href="../Concepts/Concepts-Overview.html" />
<link rel="prev" title="Web Client" href="Webclient.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="../Concepts/Concepts-Overview.html" title="Core Concepts"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Webclient.html" title="Web Client"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Bootstrap Components and Utilities</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Webclient.html"
title="previous chapter">Web Client</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="../Concepts/Concepts-Overview.html"
title="next chapter">Core Concepts</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Bootstrap-Components-and-Utilities.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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="../Howtos/Beginner-Tutorial/Part5/Add-a-simple-new-web-page.html"><span class="doc std std-doc">the basic web tutorial</span></a> or
<a class="reference internal" href="../Howtos/Web-Character-View-Tutorial.html"><span class="doc std std-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>
<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>
<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>
</section>
<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>
</section>
<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>
</section>
</section>
<hr class="docutils" />
<section id="components">
<h2>Components<a class="headerlink" href="#components" title="Permalink to this headline"></a></h2>
<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>
</section>
<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>
</section>
<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>
</section>
<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="../Howtos/Web-Character-Generation.html"><span class="doc std std-doc">the web character gen tutorial.</span></a></p>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="../Concepts/Concepts-Overview.html" title="Core Concepts"
>next</a> |</li>
<li class="right" >
<a href="Webclient.html" title="Web Client"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Bootstrap Components and Utilities</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,514 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Msg" href="Msg.html" />
<link rel="prev" title="Scripts" href="Scripts.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Msg.html" title="Msg"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Scripts.html" title="Scripts"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Channels</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Channels</a><ul>
<li><a class="reference internal" href="#using-channels-in-game">Using channels in-game</a><ul>
<li><a class="reference internal" href="#viewing-and-joining-channels">Viewing and joining channels</a></li>
<li><a class="reference internal" href="#chat-on-channels">Chat on channels</a></li>
<li><a class="reference internal" href="#channel-administration">Channel administration</a><ul>
<li><a class="reference internal" href="#restricting-channel-administration">Restricting channel administration</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#allowing-characters-to-use-channels">Allowing Characters to use Channels</a></li>
<li><a class="reference internal" href="#customizing-channel-output-and-behavior">Customizing channel output and behavior</a></li>
<li><a class="reference internal" href="#channels-in-code">Channels in code</a></li>
<li><a class="reference internal" href="#channel-logging">Channel logging</a><ul>
<li><a class="reference internal" href="#properties-on-channels">Properties on Channels</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Scripts.html"
title="previous chapter">Scripts</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Msg.html"
title="next chapter">Msg</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Channels.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="channels">
<h1>Channels<a class="headerlink" href="#channels" title="Permalink to this headline"></a></h1>
<p>In a multiplayer game, players often need other means of in-game communication
than moving to the same room and use <code class="docutils literal notranslate"><span class="pre">say</span></code> or <code class="docutils literal notranslate"><span class="pre">emote</span></code>.</p>
<p><em>Channels</em> allows Evennias to act as a fancy chat program. When a player is
connected to a channel, sending a message to it will automatically distribute
it to every other subscriber.</p>
<p>Channels can be used both for chats between <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a> and between
<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> (usually Characters). Chats could be both OOC
(out-of-character) or IC (in-charcter) in nature. Some examples:</p>
<ul class="simple">
<li><p>A support channel for contacting staff (OOC)</p></li>
<li><p>A general chat for discussing anything and foster community (OOC)</p></li>
<li><p>Admin channel for private staff discussions (OOC)</p></li>
<li><p>Private guild channels for planning and organization (IC/OOC depending on game)</p></li>
<li><p>Cyberpunk-style retro chat rooms (IC)</p></li>
<li><p>In-game radio channels (IC)</p></li>
<li><p>Group telephathy (IC)</p></li>
<li><p>Walkie talkies (IC)</p></li>
</ul>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>Channel system changed to use a central channel command and nicks instead of
auto-generated channel-commands and -cmdset. ChannelHandler was removed.</p>
</div>
<section id="using-channels-in-game">
<h2>Using channels in-game<a class="headerlink" href="#using-channels-in-game" title="Permalink to this headline"></a></h2>
<p>In the default command set, channels are all handled via the mighty
<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">channel
command</span></a>, <code class="docutils literal notranslate"><span class="pre">channel</span></code> (or
<code class="docutils literal notranslate"><span class="pre">chan</span></code>). By default, this command will assume all entities dealing with
channels are <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>.</p>
<section id="viewing-and-joining-channels">
<h3>Viewing and joining channels<a class="headerlink" href="#viewing-and-joining-channels" title="Permalink to this headline"></a></h3>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel - shows your subscriptions
channel/all - shows all subs available to you
channel/who - shows who subscribes to this channel
</pre></div>
</div>
<p>To join/unsub a channel do</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/sub channelname
channel/unsub channelname
</pre></div>
</div>
<p>If you temporarily dont want to hear the channel for a while (without actually
unsubscribing), you can mute it:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/mute channelname
channel/unmute channelname
</pre></div>
</div>
</section>
<section id="chat-on-channels">
<h3>Chat on channels<a class="headerlink" href="#chat-on-channels" title="Permalink to this headline"></a></h3>
<p>To speak on a channel, do</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel public Hello world!
</pre></div>
</div>
<p>If the channel-name has spaces in it, you need to use a <code class="docutils literal notranslate"><span class="pre">=</span></code>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel rest room = Hello world!
</pre></div>
</div>
<p>Now, this is more to type than wed like, so when you join a channel, the
system automatically sets up an personal alias so you can do this instead:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>public Hello world
</pre></div>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>This shortcut will not work if the channel-name has spaces in it.
So channels with long names should make sure to provide a one-word alias as
well.</p>
</div>
<p>Any user can make up their own channel aliases:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/alias public = foo;bar
</pre></div>
</div>
<p>You can now just do</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>foo Hello world!
bar Hello again!
</pre></div>
</div>
<p>And even remove the default one if they dont want to use it</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/unalias public
public Hello (gives a command-not-found error now)
</pre></div>
</div>
<p>But you can also use your alias with the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel foo Hello world!
</pre></div>
</div>
<blockquote>
<div><p>What happens when aliasing is that a <a class="reference internal" href="Nicks.html"><span class="doc std std-doc">nick</span></a> is created that maps your
alias + argument onto calling the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command. So when you enter <code class="docutils literal notranslate"><span class="pre">foo</span> <span class="pre">hello</span></code>,
what the server sees is actually <code class="docutils literal notranslate"><span class="pre">channel</span> <span class="pre">foo</span> <span class="pre">=</span> <span class="pre">hello</span></code>. The system is also
clever enough to know that whenever you search for channels, your channel-nicks
should also be considered so as to convert your input to an existing channel name.</p>
</div></blockquote>
<p>You can check if you missed channel conversations by viewing the channels
scrollback with</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/history public
</pre></div>
</div>
<p>This retrieves the last 20 lines of text (also from a time when you were
offline). You can step further back by specifying how many lines back to start:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/history public = 30
</pre></div>
</div>
<p>This again retrieve 20 lines, but starting 30 lines back (so youll get lines
30-50 counting backwards).</p>
</section>
<section id="channel-administration">
<h3>Channel administration<a class="headerlink" href="#channel-administration" title="Permalink to this headline"></a></h3>
<p>To create/destroy a new channel you can do</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/create channelname;alias;alias = description
channel/destroy channelname
</pre></div>
</div>
<p>Aliases are optional but can be good for obvious shortcuts everyone may want to
use. The description is used in channel-listings. You will automatically join a
channel you created and will be controlling it. You can also use <code class="docutils literal notranslate"><span class="pre">channel/desc</span></code> to
change the description on a channel you wnn later.</p>
<p>If you control a channel you can also kick people off it:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/boot mychannel = annoyinguser123 : stop spamming!
</pre></div>
</div>
<p>The last part is an optional reason to send to the user before they are booted.
You can give a comma-separated list of channels to kick the same user from all
those channels at once. The user will be unsubbed from the channel and all
their aliases will be wiped. But they can still rejoin if they like.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/ban mychannel = annoyinguser123
channel/ban - view bans
channel/unban mychannel = annoyinguser123
</pre></div>
</div>
<p>Banning adds the user to the channels blacklist. This means they will not be
able to <em>rejoin</em> if you boot them. You will need to run <code class="docutils literal notranslate"><span class="pre">channel/boot</span></code> to
actually kick them out.</p>
<p>See the <a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">Channel command</span></a> api
docs (and in-game help) for more details.</p>
<p>Admin-level users can also modify channels <a class="reference internal" href="Locks.html"><span class="doc std std-doc">locks</span></a>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>channel/lock buildchannel = listen:all();send:perm(Builders)
</pre></div>
</div>
<p>Channels use three lock-types by default:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">listen</span></code> - who may listen to the channel. Users without this access will not
even be able to join the channel and it will not appear in listings for them.</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">control</span></code> - this is assigned to you automatically when you create the channel. With
control over the channel you can edit it, boot users and do other management tasks.</p></li>
</ul>
<section id="restricting-channel-administration">
<h4>Restricting channel administration<a class="headerlink" href="#restricting-channel-administration" title="Permalink to this headline"></a></h4>
<p>By default everyone can use the channel command (<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdChannel</span></a>)
to create channels and will then control the channels they created (to boot/ban
people etc). If you as a developer does not want regular players to do this
(perhaps you want only staff to be able to spawn new channels), you can
override the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command and change its <code class="docutils literal notranslate"><span class="pre">locks</span></code> property.</p>
<p>The default <code class="docutils literal notranslate"><span class="pre">help</span></code> command has the following <code class="docutils literal notranslate"><span class="pre">locks</span></code> property:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:not perm(channel_banned); admin:all(); manage:all(); changelocks: perm(Admin)&quot;</span>
</pre></div>
</div>
<p>This is a regular <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lockstring</span></a>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">cmd:</span> <span class="pre">pperm(channel_banned)</span></code> - The <code class="docutils literal notranslate"><span class="pre">cmd</span></code> locktype is the standard one used for all Commands.
an accessing object failing this will not even know that the command exists. The <code class="docutils literal notranslate"><span class="pre">pperm()</span></code> lockfunc
checks an on-account [Permission](Building Permissions) channel_banned - and the <code class="docutils literal notranslate"><span class="pre">not</span></code> means
that if they <em>have</em> that permission they are cut off from using the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command. You usually
dont need to change this lock.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">admin:all()</span></code> - this is a lock checked in the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command itself. It controls access to the
<code class="docutils literal notranslate"><span class="pre">/boot</span></code>, <code class="docutils literal notranslate"><span class="pre">/ban</span></code> and <code class="docutils literal notranslate"><span class="pre">/unban</span></code> switches (by default letting everyone use them).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">manage:all()</span></code> - this controls access to the <code class="docutils literal notranslate"><span class="pre">/create</span></code>, <code class="docutils literal notranslate"><span class="pre">/destroy</span></code>, <code class="docutils literal notranslate"><span class="pre">/desc</span></code> switches.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">changelocks:</span> <span class="pre">perm(Admin)</span></code> - this controls access to the <code class="docutils literal notranslate"><span class="pre">/lock</span></code> and <code class="docutils literal notranslate"><span class="pre">/unlock</span></code> switches. By
default this is something only [Admins](Building Permissions) can change.</p></li>
</ul>
<blockquote>
<div><p>Note - while <code class="docutils literal notranslate"><span class="pre">admin:all()</span></code> and <code class="docutils literal notranslate"><span class="pre">manage:all()</span></code> will let everyone use these switches, users
will still only be able to admin or destroy channels they actually control!</p>
</div></blockquote>
<p>If you only want (say) Builders and higher to be able to create and admin
channels you could override the <code class="docutils literal notranslate"><span class="pre">help</span></code> command and change the lockstring to:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># in for example mygame/commands/commands.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
<span class="k">class</span> <span class="nc">MyCustomChannelCmd</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CmdChannel</span><span class="p">):</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd: not pperm(channel_banned);admin:perm(Builder);manage:perm(Builder);changelocks:perm(Admin)&quot;</span>
</pre></div>
</div>
<p>Add this custom command to your default cmdset and regular users wil now get an
access-denied error when trying to use use these switches.</p>
</section>
</section>
</section>
<section id="allowing-characters-to-use-channels">
<h2>Allowing Characters to use Channels<a class="headerlink" href="#allowing-characters-to-use-channels" title="Permalink to this headline"></a></h2>
<p>The default <code class="docutils literal notranslate"><span class="pre">channel</span></code> command (<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdChannel</span></a>)
sits in the <code class="docutils literal notranslate"><span class="pre">Account</span></code> <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">command set</span></a>. It is set up such that it will
always operate on <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>, even if you were to add it to the
<code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>.</p>
<p>Its a one-line change to make this command accept non-account callers. But for
convenience we provide a version for Characters/Objects. Just import
<a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdObjectChannel" title="evennia.commands.default.comms.CmdObjectChannel"><span class="xref myst py py-class">evennia.commands.default.comms.CmdObjectChannel</span></a>
and inherit from that instead.</p>
</section>
<section id="customizing-channel-output-and-behavior">
<h2>Customizing channel output and behavior<a class="headerlink" href="#customizing-channel-output-and-behavior" title="Permalink to this headline"></a></h2>
<p>When distributing a message, the channel will call a series of hooks on itself
and (more importantly) on each recipient. So you can customize things a lot by
just modifying hooks on your normal Object/Account typeclasses.</p>
<p>Internally, the message is sent with
<code class="docutils literal notranslate"><span class="pre">channel.msg(message,</span> <span class="pre">senders=sender,</span> <span class="pre">bypass_mute=False,</span> <span class="pre">**kwargs)</span></code>, where
<code class="docutils literal notranslate"><span class="pre">bypass_mute=True</span></code> means the message ignores muting (good for alerts or if you
delete the channel etc) and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> are any extra info you may want to pass
to the hooks. The <code class="docutils literal notranslate"><span class="pre">senders</span></code> (its always only one in the default implementation
but could in principle be multiple) and <code class="docutils literal notranslate"><span class="pre">bypass_mute</span></code> are part of the <code class="docutils literal notranslate"><span class="pre">kwargs</span></code>
below:</p>
<ol class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">channel.at_pre_msg(message,</span> <span class="pre">**kwargs)</span></code></p></li>
<li><p>For each recipient:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">message</span> <span class="pre">=</span> <span class="pre">recipient.at_pre_channel_msg(message,</span> <span class="pre">channel,</span> <span class="pre">**kwargs)</span></code> -
allows for the message to be tweaked per-receiver (for example coloring it depending
on the users preferences). If this method returns <code class="docutils literal notranslate"><span class="pre">False/None</span></code>, that
recipient is skipped.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">recipient.channel_msg(message,</span> <span class="pre">channel,</span> <span class="pre">**kwargs)</span></code> - actually sends to recipient.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">recipient.at_post_channel_msg(message,</span> <span class="pre">channel,</span> <span class="pre">**kwargs)</span></code> - any post-receive effects.</p></li>
</ul>
</li>
<li><p><code class="docutils literal notranslate"><span class="pre">channel.at_post_channel_msg(message,</span> <span class="pre">**kwargs)</span></code></p></li>
</ol>
<p>Note that <code class="docutils literal notranslate"><span class="pre">Accounts</span></code> and <code class="docutils literal notranslate"><span class="pre">Objects</span></code> both have their have separate sets of hooks.
So make sure you modify the set actually used by your subcribers (or both).
Default channels all use <code class="docutils literal notranslate"><span class="pre">Account</span></code> subscribers.</p>
</section>
<section id="channels-in-code">
<h2>Channels in code<a class="headerlink" href="#channels-in-code" title="Permalink to this headline"></a></h2>
<p>For most common changes, the default channel, the recipient hooks and possibly
overriding the <code class="docutils literal notranslate"><span class="pre">channel</span></code> command will get you very far. But you can also tweak
channels themselves.</p>
<p>Channels are <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities. This means they are
persistent in the database, can have <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">attributes</span></a> and <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a>
and can be easily extended.</p>
<p>To change which channel typeclass Evennia uses for default commands, change
<code class="docutils literal notranslate"><span class="pre">settings.BASE_CHANNEL_TYPECLASS</span></code>. The base command class is
<a class="reference internal" href="../api/evennia.comms.comms.html#evennia.comms.comms.DefaultChannel" title="evennia.comms.comms.DefaultChannel"><span class="xref myst py py-class"><code class="docutils literal notranslate"><span class="pre">evennia.comms.comms.DefaultChannel</span></code></span></a>.
There is an empty child class in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/channels.py</span></code>, same
as for other typelass-bases.</p>
<p>In code you create a new channel with <code class="docutils literal notranslate"><span class="pre">evennia.create_channel</span></code> or
<code class="docutils literal notranslate"><span class="pre">Channel.create</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_channel</span><span class="p">,</span> <span class="n">search_object</span>
<span class="kn">from</span> <span class="nn">typeclasses.channels</span> <span class="kn">import</span> <span class="n">Channel</span>
<span class="n">channel</span> <span class="o">=</span> <span class="n">create_channel</span><span class="p">(</span><span class="s2">&quot;my channel&quot;</span><span class="p">,</span> <span class="n">aliases</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;mychan&quot;</span><span class="p">],</span> <span class="n">locks</span><span class="o">=...</span><span class="p">,</span> <span class="n">typeclass</span><span class="o">=...</span><span class="p">)</span>
<span class="c1"># alternative</span>
<span class="n">channel</span> <span class="o">=</span> <span class="n">Channel</span><span class="o">.</span><span class="n">create</span><span class="p">(</span><span class="s2">&quot;my channel&quot;</span><span class="p">,</span> <span class="n">aliases</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;mychan&quot;</span><span class="p">],</span> <span class="n">locks</span><span class="o">=...</span><span class="p">)</span>
<span class="c1"># connect to it</span>
<span class="n">me</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;Foo&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span>
<span class="n">channel</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">me</span><span class="p">)</span>
<span class="c1"># send to it (this will trigger the channel_msg hooks described earlier)</span>
<span class="n">channel</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;Hello world!&quot;</span><span class="p">,</span> <span class="n">senders</span><span class="o">=</span><span class="n">me</span><span class="p">)</span>
<span class="c1"># view subscriptions (the SubscriptionHandler handles all subs under the hood)</span>
<span class="n">channel</span><span class="o">.</span><span class="n">subscriptions</span><span class="o">.</span><span class="n">has</span><span class="p">(</span><span class="n">me</span><span class="p">)</span> <span class="c1"># check we subbed</span>
<span class="n">channel</span><span class="o">.</span><span class="n">subscriptions</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="c1"># get all subs</span>
<span class="n">channel</span><span class="o">.</span><span class="n">subscriptions</span><span class="o">.</span><span class="n">online</span><span class="p">()</span> <span class="c1"># get only subs currently online</span>
<span class="n">channel</span><span class="o">.</span><span class="n">subscriptions</span><span class="o">.</span><span class="n">clear</span><span class="p">()</span> <span class="c1"># unsub all</span>
<span class="c1"># leave channel</span>
<span class="n">channel</span><span class="o">.</span><span class="n">disconnect</span><span class="p">(</span><span class="n">me</span><span class="p">)</span>
<span class="c1"># permanently delete channel (will unsub everyone)</span>
<span class="n">channel</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</div>
<p>The Channels <code class="docutils literal notranslate"><span class="pre">.connect</span></code> method will accept both <code class="docutils literal notranslate"><span class="pre">Account</span></code> and <code class="docutils literal notranslate"><span class="pre">Object</span></code> subscribers
and will handle them transparently.</p>
<p>The channel has many more hooks, both hooks shared with all typeclasses as well
as special ones related to muting/banning etc. See the channel class for
details.</p>
</section>
<section id="channel-logging">
<h2>Channel logging<a class="headerlink" href="#channel-logging" title="Permalink to this headline"></a></h2>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 0.7: </span>Channels changed from using Msg to TmpMsg and optional log files.</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>Channels stopped supporting Msg and TmpMsg, using only log files.</p>
</div>
<p>The channel messages are not stored in the database. A channel is instead
always logged to a regular text log-file
<code class="docutils literal notranslate"><span class="pre">mygame/server/logs/channel_&lt;channelname&gt;.log</span></code>. This is where <code class="docutils literal notranslate"><span class="pre">channels/history</span> <span class="pre">channelname</span></code>
gets its data from. A channels log will rotate when it grows too big, which
thus also automatically limits the max amount of history a user can view with
<code class="docutils literal notranslate"><span class="pre">/history</span></code>.</p>
<p>The log file name is set on the channel class as the <code class="docutils literal notranslate"><span class="pre">log_file</span></code> property. This
is a string that takes the formatting token <code class="docutils literal notranslate"><span class="pre">{channelname}</span></code> to be replaced with
the (lower-case) name of the channel. By default the log is written to in the
channels <code class="docutils literal notranslate"><span class="pre">at_post_channel_msg</span></code> method.</p>
<section id="properties-on-channels">
<h3>Properties on Channels<a class="headerlink" href="#properties-on-channels" title="Permalink to this headline"></a></h3>
<p>Channels have all the standard properties of a Typeclassed entity (<code class="docutils literal notranslate"><span class="pre">key</span></code>,
<code class="docutils literal notranslate"><span class="pre">aliases</span></code>, <code class="docutils literal notranslate"><span class="pre">attributes</span></code>, <code class="docutils literal notranslate"><span class="pre">tags</span></code>, <code class="docutils literal notranslate"><span class="pre">locks</span></code> etc). This is not an exhaustive list;
see the <a class="reference internal" href="../api/evennia.comms.comms.html#evennia.comms.comms.DefaultChannel" title="evennia.comms.comms.DefaultChannel"><span class="xref myst py py-class">Channel api docs</span></a> for details.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">send_to_online_only</span></code> - this class boolean defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code> and is a
sensible optimization since people offline people will not see the message anyway.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">log_file</span></code> - this is a string that determines the name of the channel log file. Default
is <code class="docutils literal notranslate"><span class="pre">&quot;channel_{channelname}.log&quot;</span></code>. The log file will appear in <code class="docutils literal notranslate"><span class="pre">settings.LOG_DIR</span></code> (usually
<code class="docutils literal notranslate"><span class="pre">mygame/server/logs/</span></code>). You should usually not change this.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">channel_prefix_string</span></code> - this property is a string to easily change how
the channel is prefixed. It takes the <code class="docutils literal notranslate"><span class="pre">channelname</span></code> format key. Default is <code class="docutils literal notranslate"><span class="pre">&quot;[{channelname}]</span> <span class="pre">&quot;</span></code>
and produces output like <code class="docutils literal notranslate"><span class="pre">[public]</span> <span class="pre">...</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">subscriptions</span></code> - this is the <a class="reference internal" href="../api/evennia.comms.models.html#evennia.comms.models.SubscriptionHandler" title="evennia.comms.models.SubscriptionHandler"><span class="xref myst py py-class">SubscriptionHandler</span></a>, which
has methods <code class="docutils literal notranslate"><span class="pre">has</span></code>, <code class="docutils literal notranslate"><span class="pre">add</span></code>, <code class="docutils literal notranslate"><span class="pre">remove</span></code>, <code class="docutils literal notranslate"><span class="pre">all</span></code>, <code class="docutils literal notranslate"><span class="pre">clear</span></code> and also <code class="docutils literal notranslate"><span class="pre">online</span></code> (to get
only actually online channel-members).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">wholist</span></code>, <code class="docutils literal notranslate"><span class="pre">mutelist</span></code>, <code class="docutils literal notranslate"><span class="pre">banlist</span></code> are properties that return a list of subscribers,
as well as who are currently muted or banned.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">channel_msg_nick_pattern</span></code> - this is a regex pattern for performing the in-place nick
replacement (detect that <code class="docutils literal notranslate"><span class="pre">channelalias</span> <span class="pre">&lt;msg</span></code> means that you want to send a message to a channel).
This pattern accepts an <code class="docutils literal notranslate"><span class="pre">{alias}</span></code> formatting marker. Dont mess with this unless you really
want to change how channels work.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">channel_msg_nick_replacement</span></code> - this is a string on the [nick replacement</p></li>
<li><p>form](./Nicks.md). It accepts the <code class="docutils literal notranslate"><span class="pre">{channelname}</span></code> formatting tag. This is strongly tied to the
<code class="docutils literal notranslate"><span class="pre">channel</span></code> command and is by default <code class="docutils literal notranslate"><span class="pre">channel</span> <span class="pre">{channelname}</span> <span class="pre">=</span> <span class="pre">$1</span></code>.</p></li>
</ul>
<p>Notable <code class="docutils literal notranslate"><span class="pre">Channel</span></code> hooks:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">at_pre_channel_msg(message,</span> <span class="pre">**kwargs)</span></code> - called before sending a message, to
modify it. Not used by default.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">msg(message,</span> <span class="pre">senders=...,</span> <span class="pre">bypass_mute=False,</span> <span class="pre">**kwargs)</span></code> - send the message onto
the channel. The <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> are passed on into the other call hooks (also on the recipient).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_post_channel_msg(message,</span> <span class="pre">**kwargs)</span></code> - by default this is used to store the message
to the log file.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">channel_prefix(message)</span></code> - this is called to allow the channel to prefix. This is called
by the object/account when they build the message, so if wanting something else one can
also just remove that call.</p></li>
<li><p>every channel message. By default it just returns <code class="docutils literal notranslate"><span class="pre">channel_prefix_string</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">has_connection(subscriber)</span></code> - shortcut to check if an entity subscribes to
this channel.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">mute/unmute(subscriber)</span></code> - this mutes the channel for this user.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">ban/unban(subscriber)</span></code> - adds/remove user from banlist.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">connect/disconnect(subscriber)</span></code> - adds/removes a subscriber.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">add_user_channel_alias(user,</span> <span class="pre">alias,</span> <span class="pre">**kwargs)</span></code> - sets up a user-nick for this channel. This is
what maps e.g. <code class="docutils literal notranslate"><span class="pre">alias</span> <span class="pre">&lt;msg&gt;</span></code> to <code class="docutils literal notranslate"><span class="pre">channel</span> <span class="pre">channelname</span> <span class="pre">=</span> <span class="pre">&lt;msg&gt;</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">remove_user_channel_alias(user,</span> <span class="pre">alias,</span> <span class="pre">**kwargs)</span></code> - remove an alias. Note that this is
a class-method that will happily remove found channel-aliases from the user linked to <em>any</em>
channel, not only from the channel the method is called on.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pre_join_channel(subscriber)</span></code> - if this returns <code class="docutils literal notranslate"><span class="pre">False</span></code>, connection will be refused.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">post_join_channel(subscriber)</span></code> - by default this sets up a userss channel-nicks/aliases.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pre_leave_channel(subscriber)</span></code> - if this returns <code class="docutils literal notranslate"><span class="pre">False</span></code>, the user is not allowed to leave.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">post_leave_channel(subscriber)</span></code> - this will clean up any channel aliases/nicks of the user.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">delete</span></code> the standard typeclass-delete mechanism will also automatically un-subscribe all
subscribers (and thus wipe all their aliases).</p></li>
</ul>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Msg.html" title="Msg"
>next</a> |</li>
<li class="right" >
<a href="Scripts.html" title="Scripts"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Channels</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,447 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="EvEditor" href="EvEditor.html" />
<link rel="prev" title="Batch Command Processor" href="Batch-Command-Processor.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvEditor.html" title="EvEditor"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Coding Utils</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Batch-Command-Processor.html"
title="previous chapter">Batch Command Processor</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="EvEditor.html"
title="next chapter">EvEditor</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Coding-Utils.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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>
<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"><div class="highlight"><pre><span></span> <span class="n">obj</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="n">objname</span><span class="p">)</span>
</pre></div>
</div>
<p>The most common time one needs to do this is inside a command body. <code class="docutils literal notranslate"><span class="pre">obj</span> <span class="pre">=</span> <span class="pre">self.caller.search(objname)</span></code> will search inside the 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"><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>
</div>
<ul class="simple">
<li><p><a class="reference internal" href="../api/evennia.accounts.manager.html#evennia.accounts.manager.AccountDBManager.search_account" title="evennia.accounts.manager.AccountDBManager.search_account"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_account</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.objects.manager.html#evennia.objects.manager.ObjectDBManager.search_object" title="evennia.objects.manager.ObjectDBManager.search_object"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_object</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.utils.search.html#evennia.utils.search.search_tag" title="evennia.utils.search.search_tag"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.search(object)_by_tag</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.scripts.manager.html#evennia.scripts.manager.ScriptDBManager.search_script" title="evennia.scripts.manager.ScriptDBManager.search_script"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_script</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.comms.managers.html#evennia.comms.managers.ChannelDBManager.search_channel" title="evennia.comms.managers.ChannelDBManager.search_channel"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_channel</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.comms.managers.html#evennia.comms.managers.MsgManager.search_message" title="evennia.comms.managers.MsgManager.search_message"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_message</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.help.manager.html#evennia.help.manager.HelpEntryManager.search_help" title="evennia.help.manager.HelpEntryManager.search_help"><span class="xref myst py py-meth"><code class="docutils literal notranslate"><span class="pre">evennia.search_help</span></code></span></a></p></li>
</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>
</section>
<section id="create">
<h2>Create<a class="headerlink" href="#create" title="Permalink to this headline"></a></h2>
<p>Apart from the in-game build commands (<code class="docutils literal notranslate"><span class="pre">&#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"><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>
</div>
<ul class="simple">
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_account" title="evennia.utils.create.create_account"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_account</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_object" title="evennia.utils.create.create_object"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_object</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_script</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_channel" title="evennia.utils.create.create_channel"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_channel</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_help_entry" title="evennia.utils.create.create_help_entry"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_help_entry</span></code></span></a></p></li>
<li><p><a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_message" title="evennia.utils.create.create_message"><span class="xref myst py py-func"><code class="docutils literal notranslate"><span class="pre">evennia.create_message</span></code></span></a></p></li>
</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>
</section>
<section id="logging">
<h2>Logging<a class="headerlink" href="#logging" title="Permalink to this headline"></a></h2>
<p>Normally you can use Python <code class="docutils literal notranslate"><span class="pre">print</span></code> statements to see output to the terminal/log. The <code class="docutils literal notranslate"><span class="pre">print</span></code>
statement should only be used for debugging though. For producion output, use the <code class="docutils literal notranslate"><span class="pre">logger</span></code> which
will create proper logs either to terminal or to file.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="c1">#</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_err</span><span class="p">(</span><span class="s2">&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>
</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"><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>
</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"><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>
</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>
</section>
<section id="time-utilities">
<h2>Time Utilities<a class="headerlink" href="#time-utilities" title="Permalink to this headline"></a></h2>
<section id="game-time">
<h3>Game time<a class="headerlink" href="#game-time" title="Permalink to this headline"></a></h3>
<p>Evennia tracks the current server time. You can access this time via the <code class="docutils literal notranslate"><span class="pre">evennia.gametime</span></code>
shortcut:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">gametime</span>
<span class="c1"># all the functions below return times in seconds).</span>
<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="kc">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>
</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 internal" href="../api/evennia.utils.gametime.html#evennia.utils.gametime.schedule" title="evennia.utils.gametime.schedule"><span class="xref myst py py-func">gametime.schedule</span></a> function:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">evennia</span>
<span class="k">def</span> <span class="nf">church_clock</span><span class="p">:</span>
<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>
</div>
</section>
<section id="utils-time-format">
<h3>utils.time_format()<a class="headerlink" href="#utils-time-format" title="Permalink to this headline"></a></h3>
<p>This function takes a number of seconds as input (e.g. from the <code class="docutils literal notranslate"><span class="pre">gametime</span></code> module above) and
converts it to a nice text output in days, hours etc. 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>
</section>
<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"><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="kc">False</span><span class="p">)</span>
<span class="c1"># code here will run immediately, not waiting for the delay to fire!</span>
</pre></div>
</div>
<p>This creates an asynchronous delayed call. It will fire the given callback function after the given
number of seconds. This is a very light wrapper over a Twisted
<a class="reference external" href="https://twistedmatrix.com/documents/current/core/howto/defer.html">Deferred</a>. Normally this is run
non-persistently, which means that if the server is <code class="docutils literal notranslate"><span class="pre">&#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 std std-doc">Attribute</span></a>.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">deferred</span></code> return object can usually be ignored, but calling its <code class="docutils literal notranslate"><span class="pre">.cancel()</span></code> method will abort
the delay prematurely.</p>
<p><code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> is the lightest form of delayed call in Evennia. For other way to create time-bound
tasks, see the <a class="reference internal" href="TickerHandler.html"><span class="doc std std-doc">TickerHandler</span></a> and <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>.</p>
<blockquote>
<div><p>Note that many delayed effects can be achieved without any need for an active timer. For example
if you have a trait that should recover a point every 5 seconds you might just need its value when
its needed, but checking the current time and calculating on the fly what value it should have.</p>
</div></blockquote>
</section>
</section>
<section id="object-classes">
<h2>Object Classes<a class="headerlink" href="#object-classes" title="Permalink to this headline"></a></h2>
<section id="utils-inherits-from">
<h3>utils.inherits_from()<a class="headerlink" href="#utils-inherits-from" title="Permalink to this headline"></a></h3>
<p>This useful function takes two arguments - an object to check and a parent. It returns <code class="docutils literal notranslate"><span class="pre">True</span></code> if
object inherits from parent <em>at any distance</em> (as opposed to 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="https://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 std std-doc">Typeclass</span></a> as a way of identification. Say
for example that we have a typeclass <em>Animal</em>. This has a subclass <em>Felines</em> which in turn has a
subclass <em>HouseCat</em>. Maybe there are a bunch of other animal types too, like horses and dogs. Using
<code class="docutils literal notranslate"><span class="pre">inherits_from</span></code> will allow you to check for all animals in one go:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">utils</span>
<span class="k">if</span> <span class="p">(</span><span class="n">utils</span><span class="o">.</span><span class="n">inherits_from</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="s2">&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>
</div>
</section>
</section>
<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>
<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"><div class="highlight"><pre><span></span> <span class="n">outtxt</span> <span class="o">=</span> <span class="n">fill</span><span class="p">(</span><span class="n">intxt</span><span class="p">,</span> <span class="n">width</span><span class="o">=</span><span class="mi">78</span><span class="p">,</span> <span class="n">indent</span><span class="o">=</span><span class="mi">4</span><span class="p">)</span>
</pre></div>
</div>
</section>
<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"><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>
</div>
</section>
<section id="utils-dedent">
<h3>utils.dedent()<a class="headerlink" href="#utils-dedent" title="Permalink to this headline"></a></h3>
<p>This solves what may at first glance appear to be a trivial problem with text - removing
indentations. It is used to shift entire paragraphs to the left, without disturbing any further
formatting they may have. A common case for this is when using Python triple-quoted strings in code</p>
<ul class="simple">
<li><p>they will retain whichever indentation they have in the code, and to make easily-readable source
code one usually dont want to shift the string to the left edge.</p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1">#python code is entered at a given indentation</span>
<span class="n">intxt</span> <span class="o">=</span> <span class="s2">&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>
</div>
<p>Normally you do the dedent in the display code (this is for example how the help system homogenizes
help entries).</p>
</section>
<section id="to-str-and-to-bytes">
<h3>to_str() and to_bytes()<a class="headerlink" href="#to-str-and-to-bytes" title="Permalink to this headline"></a></h3>
<p>Evennia supplies two utility functions for converting text to the correct
encodings. <code class="docutils literal notranslate"><span class="pre">to_str()</span></code> and <code class="docutils literal notranslate"><span class="pre">to_bytes()</span></code>. Unless you are adding a custom protocol and
need to send byte-data over the wire, <code class="docutils literal notranslate"><span class="pre">to_str</span></code> is the only one 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 std std-doc">here</span></a> for more info.</p>
</section>
<section id="ansi-coloring-tools">
<h3>Ansi Coloring Tools<a class="headerlink" href="#ansi-coloring-tools" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p><a class="reference internal" href="../api/evennia.utils.ansi.html#evennia-utils-ansi"><span class="std std-ref">evennia.utils.ansi</span></a></p></li>
</ul>
</section>
</section>
<section id="display-utilities">
<h2>Display utilities<a class="headerlink" href="#display-utilities" title="Permalink to this headline"></a></h2>
<section id="making-ascii-tables">
<h3>Making ascii tables<a class="headerlink" href="#making-ascii-tables" title="Permalink to this headline"></a></h3>
<p>The <a class="reference internal" href="../api/evennia.utils.evtable.html#evennia.utils.evtable.EvTable" title="evennia.utils.evtable.EvTable"><span class="xref myst py py-class">EvTable</span></a> class (<code class="docutils literal notranslate"><span class="pre">evennia/utils/evtable.py</span></code>) can be used
to create correctly formatted text tables. There is also
<a class="reference internal" href="../api/evennia.utils.evform.html#evennia.utils.evform.EvForm" title="evennia.utils.evform.EvForm"><span class="xref myst py py-class">EvForm</span></a> (<code class="docutils literal notranslate"><span class="pre">evennia/utils/evform.py</span></code>). This reads a fixed-format
text template from a file in order to create any level of sophisticated ascii layout. Both evtable
and evform have lots of options and inputs so see the header of each module for help.</p>
<p>The third-party <a class="reference external" href="https://code.google.com/p/prettytable/">PrettyTable</a> module is also included in
Evennia. PrettyTable is considered deprecated in favor of EvTable since PrettyTable cannot handle
ANSI colour. PrettyTable can be found in <code class="docutils literal notranslate"><span class="pre">evennia/utils/prettytable/</span></code>. See its homepage above for
instructions.</p>
</section>
<section id="menus">
<h3>Menus<a class="headerlink" href="#menus" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p><a class="reference internal" href="../api/evennia.utils.evmenu.html#evennia.utils.evmenu.EvMenu" title="evennia.utils.evmenu.EvMenu"><span class="xref myst py py-class">evennia.EvMenu</span></a></p></li>
</ul>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvEditor.html" title="EvEditor"
>next</a> |</li>
<li class="right" >
<a href="Batch-Command-Processor.html" title="Batch Command Processor"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Coding Utils</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.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" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<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" />
<link rel="next" title="Default Commands" href="Default-Commands.html" />
<link rel="prev" title="Commands" href="Commands.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Default-Commands.html" title="Default Commands"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Commands.html" title="Commands"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command Sets</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Commands.html"
title="previous chapter">Commands</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Default-Commands.html"
title="next chapter">Default Commands</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Command-Sets.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-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 internal" href="Permissions.html"><span class="doc std std-doc">permissions</span></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="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">Adding Command Tutorial</span></a> which steps through things
without the explanations.</p>
<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"><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>
</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"><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>
</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"><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>
</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"><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>
</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">persistent</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="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-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 std std-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>
<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.md#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 internal" href="#adding-and-merging-command-sets"><span class="std std-doc">merge
type</span></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 internal" href="#adding-and-merging-command-sets"><span class="std std-doc">merge
order</span></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>
</section>
</section>
<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.md#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 std std-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 std std-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="Channels.html"><span class="doc std std-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 std std-doc">lock</span></a>. For example, <a class="reference internal" href="Objects.html"><span class="doc std std-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>
</section>
<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>
<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="https://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-none notranslate"><div class="highlight"><pre><span></span> # Union
A1,A2 + B1,B2,B3,B4 = A1,A2,B3,B4
</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-none notranslate"><div class="highlight"><pre><span></span> # Intersect
A1,A3,A5 + B1,B2,B4,B5 = A1,A5
</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-none notranslate"><div class="highlight"><pre><span></span> # Replace
A1,A3 + B1,B2,B4,B5 = A1,A3
</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-none notranslate"><div class="highlight"><pre><span></span> # Remove
A1,A3 + B1,B2,B3,B4,B5 = B2,B4,B5
</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"><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>
</div>
</section>
<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>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Default-Commands.html" title="Default Commands"
>next</a> |</li>
<li class="right" >
<a href="Commands.html" title="Commands"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command Sets</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,143 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Commands" href="Commands.html" />
<link rel="prev" title="Permissions" href="Permissions.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Commands.html" title="Commands"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Permissions.html" title="Permissions"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command System</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="Permissions.html"
title="previous chapter">Permissions</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Commands.html"
title="next chapter">Commands</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Command-System.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Command-System.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-doc">Commands</span></a></p></li>
<li><p><a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Command Sets</span></a></p></li>
<li><p><a class="reference internal" href="Help-System.html#command-auto-help-system"><span class="std std-doc">Command Auto-help</span></a></p></li>
</ul>
<p>See also:</p>
<ul class="simple">
<li><p><a class="reference internal" href="Default-Commands.html"><span class="doc std std-doc">Default Commands</span></a></p></li>
<li><p><a class="reference internal" href="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">Adding Command Tutorial</span></a></p></li>
</ul>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Commands.html" title="Commands"
>next</a> |</li>
<li class="right" >
<a href="Permissions.html" title="Permissions"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Command System</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,824 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Command Sets" href="Command-Sets.html" />
<link rel="prev" title="Command System" href="Command-System.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Command-Sets.html" title="Command Sets"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Command-System.html" title="Command System"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Commands</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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="#command-prefixes">Command prefixes</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Command-System.html"
title="previous chapter">Command System</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Command-Sets.html"
title="next chapter">Command Sets</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-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 internal" href="Default-Commands.html"><span class="doc std std-doc">default commands</span></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 std std-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 std std-doc">Command Sets</span></a>. There is also a step-by-step
<a class="reference internal" href="../Howtos/Beginner-Tutorial/Part1/Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">Adding Command Tutorial</span></a> that will get you started quickly without the
extra explanations.</p>
<section id="defining-commands">
<h2>Defining Commands<a class="headerlink" href="#defining-commands" title="Permalink to this headline"></a></h2>
<p>All commands are implemented as normal Python classes inheriting from the base class <code class="docutils literal notranslate"><span class="pre">Command</span></code>
(<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"><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>
</div>
<p>Here is a minimalistic command with no custom parsing:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
<span class="k">class</span> <span class="nc">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="sa">f</span><span class="s2">&quot;Echo: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</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>
<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 std std-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 std std-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 std std-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 std std-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 std std-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 std std-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>
</section>
<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 std std-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 std std-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 std std-doc">Object</span></a> on which this command is defined. This need not be the caller,
but since <code class="docutils literal notranslate"><span class="pre">look</span></code> is a common (default) command, this is probably defined directly on <em>BigGuy</em> - so
<code class="docutils literal notranslate"><span class="pre">obj</span></code> will point to BigGuy. Otherwise <code class="docutils literal notranslate"><span class="pre">obj</span></code> could be an Account or any interactive object with
commands defined on it, like in the example of the “check time” command defined on a “Clock” object.</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>
<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](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>
</section>
</section>
<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 std std-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 internal" href="#on-arg-regex"><span class="std std-doc">See the arg_regex section</span></a> for the details.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">auto_help</span></code> (optional boolean). Defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code>. This allows for turning off the
<a class="reference internal" href="Help-System.html#command-auto-help-system"><span class="std std-doc">auto-help system</span></a> on a per-command basis. This could be useful if you
either want to write your help entries manually or hide the existence of a command from <code class="docutils literal notranslate"><span class="pre">help</span></code>s
generated list.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">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="https://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 std std-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"><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="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">caller</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> 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="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">caller</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2"> smiles at </span><span class="si">{</span><span class="n">target</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">&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>
</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 std std-doc">Command Sets</span></a> page.</p>
</section>
<section id="command-prefixes">
<h3>Command prefixes<a class="headerlink" href="#command-prefixes" title="Permalink to this headline"></a></h3>
<p>Historically, many MU* servers used to use prefix, such as <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> or <code class="docutils literal notranslate"><span class="pre">&amp;</span></code> to signify that
a command is used for administration or requires staff privileges. The problem with this is that
newcomers to MU often find such extra symbols confusing. Evennia allows commands that can be
accessed both with- or without such a prefix.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>CMD_IGNORE_PREFIXES = &quot;@&amp;/+`
</pre></div>
</div>
<p>This is a setting consisting of a string of characters. Each is a prefix that will be considered
a skippable prefix - <em>if the command is still unique in its cmdset when skipping the prefix</em>.</p>
<p>So if you wanted to write <code class="docutils literal notranslate"><span class="pre">&#64;look</span></code> instead of <code class="docutils literal notranslate"><span class="pre">look</span></code> you can do so - the <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> will be ignored. But If
we added an actual <code class="docutils literal notranslate"><span class="pre">&#64;look</span></code> command (with a <code class="docutils literal notranslate"><span class="pre">key</span></code> or alias <code class="docutils literal notranslate"><span class="pre">&#64;look</span></code>) then we would need to use the
<code class="docutils literal notranslate"><span class="pre">&#64;</span></code> to separate between the two.</p>
<p>This is also used in the default commands. For example, <code class="docutils literal notranslate"><span class="pre">&#64;open</span></code> is a building
command that allows you to create new exits to link two rooms together. Its <code class="docutils literal notranslate"><span class="pre">key</span></code> is set to <code class="docutils literal notranslate"><span class="pre">&#64;open</span></code>,
including the <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> (no alias is set). By default you can use both <code class="docutils literal notranslate"><span class="pre">&#64;open</span></code> and <code class="docutils literal notranslate"><span class="pre">open</span></code> for
this command. But “open” is a pretty common word and lets say a developer adds a new <code class="docutils literal notranslate"><span class="pre">open</span></code> command
for opening a door. Now <code class="docutils literal notranslate"><span class="pre">&#64;open</span></code> and <code class="docutils literal notranslate"><span class="pre">open</span></code> are two different commands and the <code class="docutils literal notranslate"><span class="pre">&#64;</span></code> must be used to
separate them.</p>
<blockquote>
<div><p>The <code class="docutils literal notranslate"><span class="pre">help</span></code> command will prefer to show all command names without prefix if
possible. Only if there is a collision, will the prefix be shown in the help system.</p>
</div></blockquote>
</section>
<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="https://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>
</section>
</section>
<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"><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>
</div>
</section>
<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"><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;Beginner-Tutorial 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>
</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>
</section>
<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"><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>
</div>
<p>Heres a very simple example:</p>
<div class="highlight-python notranslate"><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>
</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 std std-doc">EvMenu</span></a> might be more appropriate in this case.</p>
</div></blockquote>
</section>
<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="Channels.html"><span class="doc std std-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"><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>
</div>
</section>
<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 internal" href="#exits"><span class="std std-doc">Exits</span></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"><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>
</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>
</section>
<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 internal" href="#dynamic-commands"><span class="std std-doc">Dynamic Command</span></a>.</p>
<p>The functionality of <a class="reference internal" href="Objects.html"><span class="doc std std-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 std std-doc">typeclassed</span></a> objects that auto-create a <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">CmdSet</span></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>
</section>
<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"><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="sa">f</span><span class="s2">&quot;Command memory ID: </span><span class="si">{</span><span class="nb">id</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span><span class="si">}</span><span class="s2"> (xval=</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">xval</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
</pre></div>
</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>
</section>
<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>
</section>
<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 internal" href="Objects.html#exits"><span class="std std-doc">Exits</span></a>.</p></li>
<li><p>Sets of dynamically created <em>System commands</em> representing available
<a class="reference internal" href="Channels.html"><span class="doc std std-doc">Communications</span></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>
</section>
<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="https://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"><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="sa">f</span><span class="s2">&quot;Returned is </span><span class="si">{</span><span class="n">ret</span><span class="si">}</span><span class="s2">&quot;</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>
</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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Command-Sets.html" title="Command Sets"
>next</a> |</li>
<li class="right" >
<a href="Command-System.html" title="Command System"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Commands</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,450 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Typeclasses" href="Typeclasses.html" />
<link rel="prev" title="Making a sittable object" href="../Howtos/A-Sittable-Object.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Typeclasses.html" title="Typeclasses"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="../Howtos/A-Sittable-Object.html" title="Making a sittable object"
accesskey="P">previous</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 class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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="#web-components">Web components</a></li>
<li><a class="reference internal" href="#server-and-network">Server and network</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="../Howtos/A-Sittable-Object.html"
title="previous chapter">Making a sittable object</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Typeclasses.html"
title="next chapter">Typeclasses</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Components-Overview.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Components-Overview.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="core-components">
<h1>Core Components<a class="headerlink" href="#core-components" title="Permalink to this headline"></a></h1>
<p>These are the building blocks out of which Evennia is built. This documentation is complementary to, and often goes deeper than, the doc-strings of each component in the <a class="reference internal" href="../Evennia-API.html"><span class="doc std std-doc">API</span></a>.</p>
<section id="database-entites">
<h2>Database entites<a class="headerlink" href="#database-entites" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Typeclasses.html">Typeclasses</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#difference-between-typeclasses-and-classes">Difference between typeclasses and classes</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#creating-a-new-typeclass">Creating a new typeclass</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#about-typeclass-properties">About typeclass properties</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#overloading-hooks">Overloading hooks</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#querying-for-typeclasses">Querying for typeclasses</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#updating-existing-typeclass-instances">Updating existing typeclass instances</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#swap-typeclass">Swap typeclass</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#how-typeclasses-actually-work">How typeclasses actually work</a></li>
<li class="toctree-l2"><a class="reference internal" href="Typeclasses.html#caveats">Caveats</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Sessions.html">Sessions</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#properties-on-sessions">Properties on Sessions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#multisession-mode">Multisession mode</a></li>
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#returning-data-to-the-session">Returning data to the session</a></li>
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#customizing-the-session-object">Customizing the Session object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#portal-and-server-sessions">Portal and Server Sessions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Sessions.html#sessionhandlers">Sessionhandlers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Accounts.html">Accounts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Accounts.html#how-to-create-your-own-account-types">How to create your own Account types</a></li>
<li class="toctree-l2"><a class="reference internal" href="Accounts.html#properties-on-accounts">Properties on Accounts</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Objects.html">Objects</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Objects.html#how-to-create-your-own-object-types">How to create your own object types</a></li>
<li class="toctree-l2"><a class="reference internal" href="Objects.html#adding-common-functionality">Adding common functionality</a></li>
<li class="toctree-l2"><a class="reference internal" href="Objects.html#properties-and-functions-on-objects">Properties and functions on Objects</a></li>
<li class="toctree-l2"><a class="reference internal" href="Objects.html#subclasses-of-object">Subclasses of <code class="docutils literal notranslate"><span class="pre">Object</span></code></a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Scripts.html">Scripts</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#in-game-command-examples">In-game command examples</a></li>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#code-examples">Code examples</a></li>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#defining-new-scripts">Defining new Scripts</a></li>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#timed-scripts">Timed Scripts</a></li>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#script-attached-to-another-object">Script attached to another object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#other-script-methods">Other Script methods</a></li>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#the-global-scripts-container">The GLOBAL_SCRIPTS container</a></li>
<li class="toctree-l2"><a class="reference internal" href="Scripts.html#hints-dealing-with-script-errors">Hints: Dealing with Script Errors</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Channels.html">Channels</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Channels.html#using-channels-in-game">Using channels in-game</a></li>
<li class="toctree-l2"><a class="reference internal" href="Channels.html#allowing-characters-to-use-channels">Allowing Characters to use Channels</a></li>
<li class="toctree-l2"><a class="reference internal" href="Channels.html#customizing-channel-output-and-behavior">Customizing channel output and behavior</a></li>
<li class="toctree-l2"><a class="reference internal" href="Channels.html#channels-in-code">Channels in code</a></li>
<li class="toctree-l2"><a class="reference internal" href="Channels.html#channel-logging">Channel logging</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Msg.html">Msg</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Msg.html#msg-in-code">Msg in code</a></li>
<li class="toctree-l2"><a class="reference internal" href="Msg.html#tempmsg">TempMsg</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Attributes.html">Attributes</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#managing-attributes-in-code">Managing Attributes in Code</a></li>
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#managing-attributes-in-game">Managing Attributes in-game</a></li>
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#locking-and-checking-attributes">Locking and checking Attributes</a></li>
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#what-types-of-data-can-i-save-in-an-attribute">What types of data can I save in an Attribute?</a></li>
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#properties-of-attributes">Properties of Attributes</a></li>
<li class="toctree-l2"><a class="reference internal" href="Attributes.html#in-memory-attributes-nattributes">In-memory Attributes (NAttributes)</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Nicks.html">Nicks</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Nicks.html#coding-with-nicks">Coding with nicks</a></li>
<li class="toctree-l2"><a class="reference internal" href="Nicks.html#advanced-note">Advanced note</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Tags.html">Tags</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Tags.html#properties-of-tags-and-aliases-and-permissions">Properties of Tags (and Aliases and Permissions)</a></li>
<li class="toctree-l2"><a class="reference internal" href="Tags.html#adding-removing-tags">Adding/Removing Tags</a></li>
<li class="toctree-l2"><a class="reference internal" href="Tags.html#searching-for-objects-with-a-given-tag">Searching for objects with a given tag</a></li>
<li class="toctree-l2"><a class="reference internal" href="Tags.html#using-aliases-and-permissions">Using Aliases and Permissions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Tags.html#assorted-notes">Assorted notes</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Prototypes.html">Spawner and Prototypes</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#using-the-olc">Using the OLC</a></li>
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#the-prototype">The prototype</a></li>
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#storing-prototypes">Storing prototypes</a></li>
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#using-spawn">Using &#64;spawn</a></li>
<li class="toctree-l2"><a class="reference internal" href="Prototypes.html#using-evennia-prototypes-spawner">Using evennia.prototypes.spawner()</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Help-System.html">Help System</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#using-the-help-system-from-in-game">Using the help system from in-game</a></li>
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#sources-of-help-entries">Sources of help entries</a></li>
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#entry-priority">Entry priority</a></li>
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#locking-help-entries">Locking help entries</a></li>
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#customizing-the-look-of-the-help-system">Customizing the look of the help system</a></li>
<li class="toctree-l2"><a class="reference internal" href="Help-System.html#technical-notes">Technical notes</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Permissions.html">Permissions</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#managing-permissions">Managing Permissions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#the-permission-hierarchy">The permission hierarchy</a></li>
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#checking-permissions">Checking permissions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#superusers">Superusers</a></li>
<li class="toctree-l2"><a class="reference internal" href="Permissions.html#quelling">Quelling</a></li>
</ul>
</li>
</ul>
</div>
</section>
<section id="commands">
<h2>Commands<a class="headerlink" href="#commands" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Command-System.html">Command System</a></li>
<li class="toctree-l1"><a class="reference internal" href="Commands.html">Commands</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#defining-commands">Defining Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#exiting-a-command">Exiting a command</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#pauses-in-commands">Pauses in commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#asking-for-user-input">Asking for user input</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#system-commands">System commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#dynamic-commands">Dynamic Commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#exits">Exits</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#command-instances-are-re-used">Command instances are re-used</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#dynamically-created-commands">Dynamically created commands</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#how-commands-actually-work">How commands actually work</a></li>
<li class="toctree-l2"><a class="reference internal" href="Commands.html#assorted-notes">Assorted notes</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Command-Sets.html">Command Sets</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Command-Sets.html#defining-command-sets">Defining Command Sets</a></li>
<li class="toctree-l2"><a class="reference internal" href="Command-Sets.html#command-sets-searched">Command Sets Searched</a></li>
<li class="toctree-l2"><a class="reference internal" href="Command-Sets.html#adding-and-merging-command-sets">Adding and Merging Command Sets</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Default-Commands.html">Default Commands</a></li>
<li class="toctree-l1"><a class="reference internal" href="Connection-Screen.html">Connection Screen</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Connection-Screen.html#commands-available-at-the-connection-screen">Commands available at the Connection Screen</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Batch-Processors.html">Batch Processors</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Batch-Processors.html#a-note-on-file-encodings">A note on File Encodings</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Batch-Code-Processor.html">Batch Code Processor</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#basic-usage">Basic Usage</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#the-batch-file">The batch file</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#debug-mode">Debug mode</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#interactive-mode">Interactive mode</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Code-Processor.html#limitations-and-caveats">Limitations and Caveats</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Batch-Command-Processor.html">Batch Command Processor</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#basic-usage">Basic Usage</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#the-batch-file">The batch file</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#interactive-mode">Interactive mode</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#limitations-and-caveats">Limitations and Caveats</a></li>
<li class="toctree-l2"><a class="reference internal" href="Batch-Command-Processor.html#assorted-notes">Assorted notes</a></li>
</ul>
</li>
</ul>
</div>
</section>
<section id="utils-and-tools">
<h2>Utils and tools<a class="headerlink" href="#utils-and-tools" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Coding-Utils.html">Coding Utils</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#searching">Searching</a></li>
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#create">Create</a></li>
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#logging">Logging</a></li>
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#time-utilities">Time Utilities</a></li>
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#object-classes">Object Classes</a></li>
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#text-utilities">Text utilities</a></li>
<li class="toctree-l2"><a class="reference internal" href="Coding-Utils.html#display-utilities">Display utilities</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="EvEditor.html">EvEditor</a><ul>
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#launching-the-editor">Launching the editor</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#example-of-usage">Example of usage</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#persistent-editor">Persistent editor</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#line-editor-usage">Line editor usage</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvEditor.html#the-eveditor-to-edit-code">The EvEditor to edit code</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="EvForm.html">EvForm</a></li>
<li class="toctree-l1"><a class="reference internal" href="EvMenu.html">EvMenu</a><ul>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#introduction">Introduction</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#launching-the-menu">Launching the menu</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#the-menu-nodes">The Menu nodes</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#temporary-storage">Temporary storage</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#customizing-menu-formatting">Customizing Menu formatting</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#evmenu-templating-language">EvMenu templating language</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#id1">Examples:</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#ask-for-simple-input">Ask for simple input</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#the-list-node-decorator">The <code class="docutils literal notranslate"><span class="pre">&#64;list_node</span></code> decorator</a></li>
<li class="toctree-l2"><a class="reference internal" href="EvMenu.html#assorted-notes">Assorted notes</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="EvMore.html">EvMore</a><ul>
<li class="toctree-l2"><a class="reference internal" href="EvMore.html#using-evmore">Using EvMore</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="EvTable.html">EvTable</a></li>
<li class="toctree-l1"><a class="reference internal" href="FuncParser.html">The Inline Function Parser</a><ul>
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#uses-in-default-evennia">Uses in default Evennia</a></li>
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#using-the-funcparser">Using the FuncParser</a></li>
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#defining-custom-callables">Defining custom callables</a></li>
<li class="toctree-l2"><a class="reference internal" href="FuncParser.html#default-callables">Default callables</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="MonitorHandler.html">MonitorHandler</a><ul>
<li class="toctree-l2"><a class="reference internal" href="MonitorHandler.html#using-the-monitorhandler">Using the MonitorHandler</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="TickerHandler.html">TickerHandler</a><ul>
<li class="toctree-l2"><a class="reference internal" href="TickerHandler.html#about-tickers">About Tickers</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Locks.html">Locks</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Locks.html#setting-and-checking-a-lock">Setting and checking a lock</a></li>
<li class="toctree-l2"><a class="reference internal" href="Locks.html#defining-locks">Defining locks</a></li>
<li class="toctree-l2"><a class="reference internal" href="Locks.html#checking-simple-strings">Checking simple strings</a></li>
<li class="toctree-l2"><a class="reference internal" href="Locks.html#default-locks">Default locks</a></li>
<li class="toctree-l2"><a class="reference internal" href="Locks.html#more-lock-definition-examples">More Lock definition examples</a></li>
<li class="toctree-l2"><a class="reference internal" href="Locks.html#a-complete-example-of-setting-locks-on-an-object">A complete example of setting locks on an object</a></li>
<li class="toctree-l2"><a class="reference internal" href="Locks.html#on-djangos-permission-system">On Djangos permission system</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Signals.html">Signals</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Signals.html#attaching-a-handler-to-a-signal">Attaching a handler to a signal</a></li>
<li class="toctree-l2"><a class="reference internal" href="Signals.html#available-signals">Available signals</a></li>
</ul>
</li>
</ul>
</div>
</section>
<section id="web-components">
<h2>Web components<a class="headerlink" href="#web-components" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Website.html">Game website</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Website.html#modifying-the-default-website">Modifying the default Website</a></li>
<li class="toctree-l2"><a class="reference internal" href="Website.html#examples-of-commom-web-changes">Examples of commom web changes</a></li>
<li class="toctree-l2"><a class="reference internal" href="Website.html#adding-a-new-web-page">Adding a new web page</a></li>
<li class="toctree-l2"><a class="reference internal" href="Website.html#user-forms">User forms</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Web-API.html">Evennia REST API</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Web-API.html#usage">Usage</a></li>
<li class="toctree-l2"><a class="reference internal" href="Web-API.html#customizing-the-api">Customizing the API</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Web-Admin.html">The Web Admin</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Web-Admin.html#usage">Usage</a></li>
<li class="toctree-l2"><a class="reference internal" href="Web-Admin.html#grant-others-access-to-the-admin">Grant others access to the admin</a></li>
<li class="toctree-l2"><a class="reference internal" href="Web-Admin.html#customizing-the-web-admin">Customizing the web admin</a></li>
</ul>
</li>
</ul>
</div>
</section>
<section id="server-and-network">
<h2>Server and network<a class="headerlink" href="#server-and-network" title="Permalink to this headline"></a></h2>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Portal-And-Server.html">Portal And Server</a></li>
<li class="toctree-l1"><a class="reference internal" href="Inputfuncs.html">Inputfuncs</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Inputfuncs.html#adding-your-own-inputfuncs">Adding your own inputfuncs</a></li>
<li class="toctree-l2"><a class="reference internal" href="Inputfuncs.html#default-inputfuncs">Default inputfuncs</a></li>
<li class="toctree-l2"><a class="reference internal" href="Inputfuncs.html#unmonitor">unmonitor</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Outputfuncs.html">Outputfuncs</a></li>
<li class="toctree-l1"><a class="reference internal" href="Server.html">Server component</a></li>
<li class="toctree-l1"><a class="reference internal" href="Webserver.html">Webserver</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Webserver.html#basic-webserver-data-flow">Basic Webserver data flow</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Webclient.html">Web Client</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Webclient.html#customizing-the-web-client">Customizing the web client</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Webclient.html#evennia-web-client-api-from-evennia-js">Evennia Web Client API (from evennia.js)</a></li>
<li class="toctree-l1"><a class="reference internal" href="Webclient.html#plugin-manager-api-from-webclient-gui-js">Plugin Manager API (from webclient_gui.js)</a></li>
<li class="toctree-l1"><a class="reference internal" href="Webclient.html#plugin-callbacks-api">Plugin callbacks API</a></li>
<li class="toctree-l1"><a class="reference internal" href="Webclient.html#example-default-plugins-plugins-js">Example/Default Plugins (plugins/*.js)</a></li>
<li class="toctree-l1"><a class="reference internal" href="Webclient.html#a-side-note-on-html-messages-vrs-text2html-messages">A side note on html messages vrs text2html messages</a></li>
<li class="toctree-l1"><a class="reference internal" href="Webclient.html#writing-your-own-plugins">Writing your own Plugins</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Webclient.html#goldenlayout">GoldenLayout</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Bootstrap-Components-and-Utilities.html">Bootstrap Components and Utilities</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Bootstrap-Components-and-Utilities.html#general-styling">General Styling</a></li>
<li class="toctree-l2"><a class="reference internal" href="Bootstrap-Components-and-Utilities.html#components">Components</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Signals.html">Signals</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Signals.html#attaching-a-handler-to-a-signal">Attaching a handler to a signal</a></li>
<li class="toctree-l2"><a class="reference internal" href="Signals.html#available-signals">Available signals</a></li>
</ul>
</li>
</ul>
</div>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Typeclasses.html" title="Typeclasses"
>next</a> |</li>
<li class="right" >
<a href="../Howtos/A-Sittable-Object.html" title="Making a sittable object"
>previous</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 class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,173 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Connection Screen &#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" />
<link rel="next" title="Batch Processors" href="Batch-Processors.html" />
<link rel="prev" title="Default Commands" href="Default-Commands.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Batch-Processors.html" title="Batch Processors"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Default-Commands.html" title="Default Commands"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Connection Screen</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Connection Screen</a><ul>
<li><a class="reference internal" href="#commands-available-at-the-connection-screen">Commands available at the Connection Screen</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Default-Commands.html"
title="previous chapter">Default Commands</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Batch-Processors.html"
title="next chapter">Batch Processors</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Connection-Screen.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Connection-Screen.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="connection-screen">
<h1>Connection Screen<a class="headerlink" href="#connection-screen" title="Permalink to this headline"></a></h1>
<p>When you first connect to your game you are greeted by Evennias default connection screen.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>==============================================================
Welcome to Evennia, version Beta-ra4d24e8a3cab+!
If you have an existing account, connect to it by typing:
connect &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 std std-doc">Reload</span></a> Evennia.</p></li>
</ol>
<p>Evennia will look into this module and locate all <em>globally defined strings</em> in it. These strings
are used as the text in your connection screen and are shown to the user at startup. If more than
one such string/screen is defined in the module, a <em>random</em> screen will be picked from among those
available.</p>
<section id="commands-available-at-the-connection-screen">
<h2>Commands available at the Connection Screen<a class="headerlink" href="#commands-available-at-the-connection-screen" title="Permalink to this headline"></a></h2>
<p>You can also customize the <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> available to use while the connection screen is
shown (<code class="docutils literal notranslate"><span class="pre">connect</span></code>, <code class="docutils literal notranslate"><span class="pre">create</span></code> etc). These commands are a bit special since when the screen is running
the account is not yet logged in. A command is made available at the login screen by adding them to
<code class="docutils literal notranslate"><span class="pre">UnloggedinCmdSet</span></code> in <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdset.py</span></code>. See <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> and the
tutorial section on how to add new commands to a default command set.</p>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Batch-Processors.html" title="Batch Processors"
>next</a> |</li>
<li class="right" >
<a href="Default-Commands.html" title="Default Commands"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Connection Screen</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2020, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,228 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Default 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" />
<link rel="next" title="Connection Screen" href="Connection-Screen.html" />
<link rel="prev" title="Command Sets" href="Command-Sets.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Connection-Screen.html" title="Connection Screen"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Command-Sets.html" title="Command Sets"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Default Commands</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="Command-Sets.html"
title="previous chapter">Command Sets</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Connection-Screen.html"
title="next chapter">Connection Screen</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Default-Commands.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Default-Commands.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="default-commands">
<h1>Default Commands<a class="headerlink" href="#default-commands" title="Permalink to this headline"></a></h1>
<p>The full set of default Evennia commands currently contains 88 commands in 9 source
files. Our policy for adding default commands is outlined <a class="reference internal" href="../Concepts/Using-MUX-as-a-Standard.html"><span class="doc std std-doc">here</span></a>. The
<a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> documentation explains how Commands work as well as how to make new or customize
existing ones.</p>
<blockquote>
<div><p>Note that this page is auto-generated. Report problems to the <a class="reference external" href="https://github.com/evennia/evennia/blob/master/issues">issue tracker</a>.</p>
</div></blockquote>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Some game-states add their own Commands which are not listed here. Examples include editing a text
with <a class="reference internal" href="EvEditor.html"><span class="doc std std-doc">EvEditor</span></a>, flipping pages in <a class="reference internal" href="EvMore.html"><span class="doc std std-doc">EvMore</span></a> or using the
<a class="reference internal" href="Batch-Processors.html"><span class="doc std std-doc">Batch-Processor</span></a>s interactive mode.</p>
</div>
<ul class="simple">
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdAbout" title="evennia.commands.default.system.CmdAbout"><span class="xref myst py py-class"><strong>&#64;about</strong> [&#64;version]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdAccounts" title="evennia.commands.default.system.CmdAccounts"><span class="xref myst py py-class"><strong>&#64;accounts</strong> [&#64;account]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdSetObjAlias" title="evennia.commands.default.building.CmdSetObjAlias"><span class="xref myst py py-class"><strong>&#64;alias</strong> [setobjalias]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdChannel" title="evennia.commands.default.comms.CmdChannel"><span class="xref myst py py-class"><strong>&#64;channel</strong> [&#64;chan, &#64;channels]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>Comms</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdListCmdSets" title="evennia.commands.default.building.CmdListCmdSets"><span class="xref myst py py-class"><strong>&#64;cmdsets</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdCopy" title="evennia.commands.default.building.CmdCopy"><span class="xref myst py py-class"><strong>&#64;copy</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdCpAttr" title="evennia.commands.default.building.CmdCpAttr"><span class="xref myst py py-class"><strong>&#64;cpattr</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdCreate" title="evennia.commands.default.building.CmdCreate"><span class="xref myst py py-class"><strong>&#64;create</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdDesc" title="evennia.commands.default.building.CmdDesc"><span class="xref myst py py-class"><strong>&#64;desc</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdDestroy" title="evennia.commands.default.building.CmdDestroy"><span class="xref myst py py-class"><strong>&#64;destroy</strong> [&#64;del, &#64;delete]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdDig" title="evennia.commands.default.building.CmdDig"><span class="xref myst py py-class"><strong>&#64;dig</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdExamine" title="evennia.commands.default.building.CmdExamine"><span class="xref myst py py-class"><strong>&#64;examine</strong> [&#64;ex, &#64;exam]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdFind" title="evennia.commands.default.building.CmdFind"><span class="xref myst py py-class"><strong>&#64;find</strong> [&#64;locate, &#64;search]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdLink" title="evennia.commands.default.building.CmdLink"><span class="xref myst py py-class"><strong>&#64;link</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdLock" title="evennia.commands.default.building.CmdLock"><span class="xref myst py py-class"><strong>&#64;lock</strong> [&#64;locks]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdMvAttr" title="evennia.commands.default.building.CmdMvAttr"><span class="xref myst py py-class"><strong>&#64;mvattr</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdName" title="evennia.commands.default.building.CmdName"><span class="xref myst py py-class"><strong>&#64;name</strong> [&#64;rename]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdObjects" title="evennia.commands.default.building.CmdObjects"><span class="xref myst py py-class"><strong>&#64;objects</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdOpen" title="evennia.commands.default.building.CmdOpen"><span class="xref myst py py-class"><strong>&#64;open</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdPy" title="evennia.commands.default.system.CmdPy"><span class="xref myst py py-class"><strong>&#64;py</strong> [&#64;!]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdReload" title="evennia.commands.default.system.CmdReload"><span class="xref myst py py-class"><strong>&#64;reload</strong> [&#64;restart]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdReset" title="evennia.commands.default.system.CmdReset"><span class="xref myst py py-class"><strong>&#64;reset</strong> [&#64;reboot]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdScripts" title="evennia.commands.default.building.CmdScripts"><span class="xref myst py py-class"><strong>&#64;scripts</strong> [&#64;script]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdServerLoad" title="evennia.commands.default.system.CmdServerLoad"><span class="xref myst py py-class"><strong>&#64;server</strong> [&#64;serverload]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdService" title="evennia.commands.default.system.CmdService"><span class="xref myst py py-class"><strong>&#64;service</strong> [&#64;services]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdSetAttribute" title="evennia.commands.default.building.CmdSetAttribute"><span class="xref myst py py-class"><strong>&#64;set</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdSetHome" title="evennia.commands.default.building.CmdSetHome"><span class="xref myst py py-class"><strong>&#64;sethome</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdShutdown" title="evennia.commands.default.system.CmdShutdown"><span class="xref myst py py-class"><strong>&#64;shutdown</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdSpawn" title="evennia.commands.default.building.CmdSpawn"><span class="xref myst py py-class"><strong>&#64;spawn</strong> [&#64;olc]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdTag" title="evennia.commands.default.building.CmdTag"><span class="xref myst py py-class"><strong>&#64;tag</strong> [&#64;tags]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdTasks" title="evennia.commands.default.system.CmdTasks"><span class="xref myst py py-class"><strong>&#64;tasks</strong> [&#64;delays, &#64;task]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdTeleport" title="evennia.commands.default.building.CmdTeleport"><span class="xref myst py py-class"><strong>&#64;teleport</strong> [&#64;tel]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdTickers" title="evennia.commands.default.system.CmdTickers"><span class="xref myst py py-class"><strong>&#64;tickers</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.system.html#evennia.commands.default.system.CmdTime" title="evennia.commands.default.system.CmdTime"><span class="xref myst py py-class"><strong>&#64;time</strong> [&#64;uptime]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>System</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdTunnel" title="evennia.commands.default.building.CmdTunnel"><span class="xref myst py py-class"><strong>&#64;tunnel</strong> [&#64;tun]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdTypeclass" title="evennia.commands.default.building.CmdTypeclass"><span class="xref myst py py-class"><strong>&#64;typeclass</strong> [&#64;parent, &#64;swap, &#64;type, &#64;typeclasses, &#64;update]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdWipe" title="evennia.commands.default.building.CmdWipe"><span class="xref myst py py-class"><strong>&#64;wipe</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedLook" title="evennia.commands.default.unloggedin.CmdUnconnectedLook"><span class="xref myst py py-class"><strong>__unloggedin_look_command</strong> [l, look]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdAccess" title="evennia.commands.default.general.CmdAccess"><span class="xref myst py py-class"><strong>access</strong> [groups, hierarchy]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.batchprocess.html#evennia.commands.default.batchprocess.CmdBatchCode" title="evennia.commands.default.batchprocess.CmdBatchCode"><span class="xref myst py py-class"><strong>batchcode</strong> [batchcodes]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.batchprocess.html#evennia.commands.default.batchprocess.CmdBatchCommands" title="evennia.commands.default.batchprocess.CmdBatchCommands"><span class="xref myst py py-class"><strong>batchcommands</strong> [batchcmd, batchcommand]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdCharCreate" title="evennia.commands.default.account.CmdCharCreate"><span class="xref myst py py-class"><strong>charcreate</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdCharDelete" title="evennia.commands.default.account.CmdCharDelete"><span class="xref myst py py-class"><strong>chardelete</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdColorTest" title="evennia.commands.default.account.CmdColorTest"><span class="xref myst py py-class"><strong>color</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedConnect" title="evennia.commands.default.unloggedin.CmdUnconnectedConnect"><span class="xref myst py py-class"><strong>connect</strong> [co, con, conn]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedCreate" title="evennia.commands.default.unloggedin.CmdUnconnectedCreate"><span class="xref myst py py-class"><strong>create</strong> [cr, cre]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdDrop" title="evennia.commands.default.general.CmdDrop"><span class="xref myst py py-class"><strong>drop</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedEncoding" title="evennia.commands.default.unloggedin.CmdUnconnectedEncoding"><span class="xref myst py py-class"><strong>encoding</strong> [encode]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdGet" title="evennia.commands.default.general.CmdGet"><span class="xref myst py py-class"><strong>get</strong> [grab]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdGive" title="evennia.commands.default.general.CmdGive"><span class="xref myst py py-class"><strong>give</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdGrapevine2Chan" title="evennia.commands.default.comms.CmdGrapevine2Chan"><span class="xref myst py py-class"><strong>grapevine2chan</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>Comms</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.help.html#evennia.commands.default.help.CmdHelp" title="evennia.commands.default.help.CmdHelp"><span class="xref myst py py-class"><strong>help</strong> [?]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedHelp" title="evennia.commands.default.unloggedin.CmdUnconnectedHelp"><span class="xref myst py py-class"><strong>help</strong> [?, h]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdHome" title="evennia.commands.default.general.CmdHome"><span class="xref myst py py-class"><strong>home</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdIC" title="evennia.commands.default.account.CmdIC"><span class="xref myst py py-class"><strong>ic</strong> [puppet]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedInfo" title="evennia.commands.default.unloggedin.CmdUnconnectedInfo"><span class="xref myst py py-class"><strong>info</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdInventory" title="evennia.commands.default.general.CmdInventory"><span class="xref myst py py-class"><strong>inventory</strong> [i, inv]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdIRC2Chan" title="evennia.commands.default.comms.CmdIRC2Chan"><span class="xref myst py py-class"><strong>irc2chan</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>Comms</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdIRCStatus" title="evennia.commands.default.comms.CmdIRCStatus"><span class="xref myst py py-class"><strong>ircstatus</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>Comms</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdOOCLook" title="evennia.commands.default.account.CmdOOCLook"><span class="xref myst py py-class"><strong>look</strong> [l, ls]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdLook" title="evennia.commands.default.general.CmdLook"><span class="xref myst py py-class"><strong>look</strong> [l, ls]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdNick" title="evennia.commands.default.general.CmdNick"><span class="xref myst py py-class"><strong>nick</strong> [nickname, nicks]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdOOC" title="evennia.commands.default.account.CmdOOC"><span class="xref myst py py-class"><strong>ooc</strong> [unpuppet]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdOption" title="evennia.commands.default.account.CmdOption"><span class="xref myst py py-class"><strong>option</strong> [options]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdPage" title="evennia.commands.default.comms.CmdPage"><span class="xref myst py py-class"><strong>page</strong> [tell]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>Comms</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdPassword" title="evennia.commands.default.account.CmdPassword"><span class="xref myst py py-class"><strong>password</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdPose" title="evennia.commands.default.general.CmdPose"><span class="xref myst py py-class"><strong>pose</strong> [:, emote]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdQuell" title="evennia.commands.default.account.CmdQuell"><span class="xref myst py py-class"><strong>quell</strong> [unquell]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdQuit" title="evennia.commands.default.account.CmdQuit"><span class="xref myst py py-class"><strong>quit</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedQuit" title="evennia.commands.default.unloggedin.CmdUnconnectedQuit"><span class="xref myst py py-class"><strong>quit</strong> [q, qu]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.comms.html#evennia.commands.default.comms.CmdRSS2Chan" title="evennia.commands.default.comms.CmdRSS2Chan"><span class="xref myst py py-class"><strong>rss2chan</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>Comms</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdSay" title="evennia.commands.default.general.CmdSay"><span class="xref myst py py-class"><strong>say</strong> [”, ]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.unloggedin.html#evennia.commands.default.unloggedin.CmdUnconnectedScreenreader" title="evennia.commands.default.unloggedin.CmdUnconnectedScreenreader"><span class="xref myst py py-class"><strong>screenreader</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_unloggedin.html#evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet" title="evennia.commands.default.cmdset_unloggedin.UnloggedinCmdSet"><span class="xref myst py py-class">UnloggedinCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdSessions" title="evennia.commands.default.account.CmdSessions"><span class="xref myst py py-class"><strong>sessions</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_session.html#evennia.commands.default.cmdset_session.SessionCmdSet" title="evennia.commands.default.cmdset_session.SessionCmdSet"><span class="xref myst py py-class">SessionCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdSetDesc" title="evennia.commands.default.general.CmdSetDesc"><span class="xref myst py py-class"><strong>setdesc</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.help.html#evennia.commands.default.help.CmdSetHelp" title="evennia.commands.default.help.CmdSetHelp"><span class="xref myst py py-class"><strong>sethelp</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdStyle" title="evennia.commands.default.account.CmdStyle"><span class="xref myst py py-class"><strong>style</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.building.html#evennia.commands.default.building.CmdUnLink" title="evennia.commands.default.building.CmdUnLink"><span class="xref myst py py-class"><strong>unlink</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>Building</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.general.html#evennia.commands.default.general.CmdWhisper" title="evennia.commands.default.general.CmdWhisper"><span class="xref myst py py-class"><strong>whisper</strong></span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_character.html#evennia.commands.default.cmdset_character.CharacterCmdSet" title="evennia.commands.default.cmdset_character.CharacterCmdSet"><span class="xref myst py py-class">CharacterCmdSet</span></a>, help-category: <em>General</em>)</p></li>
<li><p><a class="reference internal" href="../api/evennia.commands.default.account.html#evennia.commands.default.account.CmdWho" title="evennia.commands.default.account.CmdWho"><span class="xref myst py py-class"><strong>who</strong> [doing]</span></a> (cmdset: <a class="reference internal" href="../api/evennia.commands.default.cmdset_account.html#evennia.commands.default.cmdset_account.AccountCmdSet" title="evennia.commands.default.cmdset_account.AccountCmdSet"><span class="xref myst py py-class">AccountCmdSet</span></a>, help-category: <em>General</em>)</p></li>
</ul>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Connection-Screen.html" title="Connection Screen"
>next</a> |</li>
<li class="right" >
<a href="Command-Sets.html" title="Command Sets"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Default Commands</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,318 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="EvForm" href="EvForm.html" />
<link rel="prev" title="Coding Utils" href="Coding-Utils.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvForm.html" title="EvForm"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Coding-Utils.html" title="Coding Utils"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvEditor</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Coding-Utils.html"
title="previous chapter">Coding Utils</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="EvForm.html"
title="next chapter">EvForm</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="EvEditor.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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>
<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"><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="kc">None</span><span class="p">,</span> <span class="n">savefunc</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">quitfunc</span><span class="o">=</span><span class="kc">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>
</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>
</section>
<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"><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="n">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">add</span><span class="p">(</span><span class="s2">&quot;test&quot;</span><span class="p">,</span> <span class="n">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="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="si">}</span><span class="s2">/test&quot;</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>
</div>
</section>
<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"><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="n">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">add</span><span class="p">(</span><span class="s2">&quot;test&quot;</span><span class="p">,</span> <span class="n">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="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="si">}</span><span class="s2">/test&quot;</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="kc">True</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="line-editor-usage">
<h2>Line editor usage<a class="headerlink" href="#line-editor-usage" title="Permalink to this headline"></a></h2>
<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>
</section>
<section id="the-eveditor-to-edit-code">
<h2>The EvEditor to edit code<a class="headerlink" href="#the-eveditor-to-edit-code" title="Permalink to this headline"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">EvEditor</span></code> is also used to edit some Python code in Evennia. The <code class="docutils literal notranslate"><span class="pre">&#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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvForm.html" title="EvForm"
>next</a> |</li>
<li class="right" >
<a href="Coding-Utils.html" title="Coding Utils"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvEditor</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,134 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>EvForm &#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" />
<link rel="next" title="EvMenu" href="EvMenu.html" />
<link rel="prev" title="EvEditor" href="EvEditor.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvMenu.html" title="EvMenu"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="EvEditor.html" title="EvEditor"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvForm</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="EvEditor.html"
title="previous chapter">EvEditor</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="EvMenu.html"
title="next chapter">EvMenu</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/EvForm.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="EvForm.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="evform">
<h1>EvForm<a class="headerlink" href="#evform" title="Permalink to this headline"></a></h1>
<p><a class="reference internal" href="../api/evennia.utils.evform.html#evennia-utils-evform"><span class="std std-ref">Docstring in evennia/utils/evform.py</span></a></p>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvMenu.html" title="EvMenu"
>next</a> |</li>
<li class="right" >
<a href="EvEditor.html" title="EvEditor"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvForm</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,172 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="EvTable" href="EvTable.html" />
<link rel="prev" title="EvMenu" href="EvMenu.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvTable.html" title="EvTable"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="EvMenu.html" title="EvMenu"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvMore</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">EvMore</a><ul>
<li><a class="reference internal" href="#using-evmore">Using EvMore</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="EvMenu.html"
title="previous chapter">EvMenu</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="EvTable.html"
title="next chapter">EvTable</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="EvMore.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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>
<section id="using-evmore">
<h2>Using EvMore<a class="headerlink" href="#using-evmore" title="Permalink to this headline"></a></h2>
<p>To use the pager, just pass the long text through it:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">evmore</span>
<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>
</div>
<p>Where receiver is an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> or a <a class="reference internal" href="Accounts.html"><span class="doc std std-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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="EvTable.html" title="EvTable"
>next</a> |</li>
<li class="right" >
<a href="EvMenu.html" title="EvMenu"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvMore</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,134 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>EvTable &#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" />
<link rel="next" title="The Inline Function Parser" href="FuncParser.html" />
<link rel="prev" title="EvMore" href="EvMore.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="FuncParser.html" title="The Inline Function Parser"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="EvMore.html" title="EvMore"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvTable</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="EvMore.html"
title="previous chapter">EvMore</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="FuncParser.html"
title="next chapter">The Inline Function Parser</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/EvTable.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="EvTable.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="evtable">
<h1>EvTable<a class="headerlink" href="#evtable" title="Permalink to this headline"></a></h1>
<p><a class="reference internal" href="../api/evennia.utils.evtable.html#evennia-utils-evtable"><span class="std std-ref">Docstring in evennia/utils/evtable.py</span></a></p>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="FuncParser.html" title="The Inline Function Parser"
>next</a> |</li>
<li class="right" >
<a href="EvMore.html" title="EvMore"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">EvTable</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,569 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>The Inline Function Parser &#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" />
<link rel="next" title="MonitorHandler" href="MonitorHandler.html" />
<link rel="prev" title="EvTable" href="EvTable.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="EvTable.html" title="EvTable"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">The Inline Function Parser</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">The Inline Function Parser</a><ul>
<li><a class="reference internal" href="#uses-in-default-evennia">Uses in default Evennia</a></li>
<li><a class="reference internal" href="#using-the-funcparser">Using the FuncParser</a></li>
<li><a class="reference internal" href="#defining-custom-callables">Defining custom callables</a><ul>
<li><a class="reference internal" href="#escaping-special-character">Escaping special character</a></li>
<li><a class="reference internal" href="#safe-convertion-of-inputs">Safe convertion of inputs</a></li>
</ul>
</li>
<li><a class="reference internal" href="#default-callables">Default callables</a><ul>
<li><a class="reference internal" href="#evennia-utils-funcparser-funcparser-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.FUNCPARSER_CALLABLES</span></code></a></li>
<li><a class="reference internal" href="#evennia-utils-funcparser-searching-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.SEARCHING_CALLABLES</span></code></a></li>
<li><a class="reference internal" href="#evennia-utils-funcparser-actor-stance-callables"><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ACTOR_STANCE_CALLABLES</span></code></a></li>
<li><a class="reference internal" href="#example">Example</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="EvTable.html"
title="previous chapter">EvTable</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="MonitorHandler.html"
title="next chapter">MonitorHandler</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/FuncParser.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="FuncParser.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="the-inline-function-parser">
<h1>The Inline Function Parser<a class="headerlink" href="#the-inline-function-parser" title="Permalink to this headline"></a></h1>
<p>The <a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.FuncParser" title="evennia.utils.funcparser.FuncParser"><span class="xref myst py py-class">FuncParser</span></a> extracts and executes
inline functions
embedded in a string on the form <code class="docutils literal notranslate"><span class="pre">$funcname(args,</span> <span class="pre">kwargs)</span></code>. Under the hood, this will
lead to a call to a Python function you control. The inline function call will be replaced by
the return from the function.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.funcparser</span> <span class="kn">import</span> <span class="n">FuncParser</span>
<span class="k">def</span> <span class="nf">_power_callable</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;This will be callable as $pow(number, power=&lt;num&gt;) in string&quot;&quot;&quot;</span>
<span class="nb">pow</span> <span class="o">=</span> <span class="nb">int</span><span class="p">(</span><span class="n">kwargs</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s1">&#39;power&#39;</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<span class="k">return</span> <span class="nb">float</span><span class="p">(</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">**</span> <span class="nb">pow</span>
<span class="c1"># create a parser and tell it that &#39;$pow&#39; means using _power_callable</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">FuncParser</span><span class="p">({</span><span class="s2">&quot;pow&quot;</span><span class="p">:</span> <span class="n">_power_callable</span><span class="p">})</span>
</pre></div>
</div>
<p>Next, just pass a string into the parser, containing <code class="docutils literal notranslate"><span class="pre">$func(...)</span></code> markers:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s2">&quot;We have that 4 x 4 x 4 is $pow(4, power=3).&quot;</span><span class="p">)</span>
<span class="s2">&quot;We have that 4 x 4 x 4 is 64.&quot;</span>
</pre></div>
</div>
<p>Normally the return is always converted to a string but you can also get the actual data type from the call:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;$pow(4)&quot;</span><span class="p">)</span>
<span class="mi">16</span>
</pre></div>
</div>
<p>To show a <code class="docutils literal notranslate"><span class="pre">$func()</span></code> verbatim in your code without parsing it, escape it as either <code class="docutils literal notranslate"><span class="pre">$$func()</span></code> or <code class="docutils literal notranslate"><span class="pre">\$func()</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s2">&quot;This is an escaped $$pow(4) and so is this \$pow(3)&quot;</span><span class="p">)</span>
<span class="s2">&quot;This is an escaped $pow(4) and so is this $pow(3)&quot;</span>
</pre></div>
</div>
<section id="uses-in-default-evennia">
<h2>Uses in default Evennia<a class="headerlink" href="#uses-in-default-evennia" title="Permalink to this headline"></a></h2>
<p>The FuncParser can be applied to any string. Out of the box its applied in a few situations:</p>
<ul class="simple">
<li><p><em>Outgoing messages</em>. All messages sent from the server is processed through FuncParser and every
callable is provided the <a class="reference internal" href="Sessions.html"><span class="doc std std-doc">Session</span></a> of the object receiving the message. This potentially
allows a message to be modified on the fly to look different for different recipients.</p></li>
<li><p><em>Prototype values</em>. A <a class="reference internal" href="Prototypes.html"><span class="doc std std-doc">Prototype</span></a> dicts values are run through the parser such that every
callable gets a reference to the rest of the prototype. In the Prototype ORM, this would allow builders
to safely call functions to set non-string values to prototype values, get random values, reference
other fields of the prototype, and more.</p></li>
<li><p><em>Actor-stance in messages to others</em>. In the
<a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">Object.msg_contents</span></a> method,
the outgoing string is parsed for special <code class="docutils literal notranslate"><span class="pre">$You()</span></code> and <code class="docutils literal notranslate"><span class="pre">$conj()</span></code> callables to decide if a given recipient
should see “You” or the characters name.</p></li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>The inline-function parser is not intended as a softcode programming language. It does not
have things like loops and conditionals, for example. While you could in principle extend it to
do very advanced things and allow builders a lot of power, all-out coding is something
Evennia expects you to do in a proper text editor, outside of the game, not from inside it.</p>
</div>
</section>
<section id="using-the-funcparser">
<h2>Using the FuncParser<a class="headerlink" href="#using-the-funcparser" title="Permalink to this headline"></a></h2>
<p>You can apply inline function parsing to any string. The
<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.FuncParser" title="evennia.utils.funcparser.FuncParser"><span class="xref myst py py-class">FuncParser</span></a> is imported as <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">funcparser</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">FuncParser</span><span class="p">(</span><span class="n">callables</span><span class="p">,</span> <span class="o">**</span><span class="n">default_kwargs</span><span class="p">)</span>
<span class="n">parsed_string</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">input_string</span><span class="p">,</span> <span class="n">raise_errors</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">escape</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">strip</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
<span class="n">return_str</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">**</span><span class="n">reserved_kwargs</span><span class="p">)</span>
<span class="c1"># callables can also be passed as paths to modules</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">FuncParser</span><span class="p">([</span><span class="s2">&quot;game.myfuncparser_callables&quot;</span><span class="p">,</span> <span class="s2">&quot;game.more_funcparser_callables&quot;</span><span class="p">])</span>
</pre></div>
</div>
<p>Here, <code class="docutils literal notranslate"><span class="pre">callables</span></code> points to a collection of normal Python functions (see next section) for you to make
available to the parser as you parse strings with it. It can either be</p>
<ul class="simple">
<li><p>A <code class="docutils literal notranslate"><span class="pre">dict</span></code> of <code class="docutils literal notranslate"><span class="pre">{&quot;functionname&quot;:</span> <span class="pre">callable,</span> <span class="pre">...}</span></code>. This allows you do pick and choose exactly which callables
to include and how they should be named. Do you want a callable to be available under more than one name?
Just add it multiple times to the dict, with a different key.</p></li>
<li><p>A <code class="docutils literal notranslate"><span class="pre">module</span></code> or (more commonly) a <code class="docutils literal notranslate"><span class="pre">python-path</span></code> to a module. This module can define a dict
<code class="docutils literal notranslate"><span class="pre">FUNCPARSER_CALLABLES</span> <span class="pre">=</span> <span class="pre">{&quot;funcname&quot;:</span> <span class="pre">callable,</span> <span class="pre">...}</span></code> - this will be imported and used like the <code class="docutils literal notranslate"><span class="pre">dict</span></code> above.
If no such variable is defined, <em>every</em> top-level function in the module (whose name doesnt start with
an underscore <code class="docutils literal notranslate"><span class="pre">_</span></code>) will be considered a suitable callable. The name of the function will be the <code class="docutils literal notranslate"><span class="pre">$funcname</span></code>
by which it can be called.</p></li>
<li><p>A <code class="docutils literal notranslate"><span class="pre">list</span></code> of modules/paths. This allows you to pull in modules from many sources for your parsing.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">**default</span></code> kwargs are optional kwargs that will be passed to <em>all</em>
callables every time this parser is used - unless the user overrides it explicitly in
their call. This is great for providing sensible standards that the user can
tweak as needed.</p></li>
</ul>
<p><code class="docutils literal notranslate"><span class="pre">FuncParser.parse</span></code> takes further arguments, and can vary for every string parsed.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> - By default, any errors from a callable will be quietly ignored and the result
will be that the failing function call will show verbatim. If <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> is set,
then parsing will stop and whatever exception happened will be raised. Itd be up to you to handle
this properly.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">escape</span></code> - Returns a string where every <code class="docutils literal notranslate"><span class="pre">$func(...)</span></code> has been escaped as <code class="docutils literal notranslate"><span class="pre">\$func()</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">strip</span></code> - Remove all <code class="docutils literal notranslate"><span class="pre">$func(...)</span></code> calls from string (as if each returned <code class="docutils literal notranslate"><span class="pre">''</span></code>).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">return_str</span></code> - When <code class="docutils literal notranslate"><span class="pre">True</span></code> (default), <code class="docutils literal notranslate"><span class="pre">parser</span></code> always returns a string. If <code class="docutils literal notranslate"><span class="pre">False</span></code>, it may return
the return value of a single function call in the string. This is the same as using the <code class="docutils literal notranslate"><span class="pre">.parse_to_any</span></code>
method.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">**reserved_keywords</span></code> are <em>always</em> passed to every callable in the string.
They override any <code class="docutils literal notranslate"><span class="pre">**defaults</span></code> given when instantiating the parser and cannot
be overridden by the user - if they enter the same kwarg it will be ignored.
This is great for providing the current session, settings etc.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">funcparser</span></code> and <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code>
are always added as reserved keywords - the first is a
back-reference to the <code class="docutils literal notranslate"><span class="pre">FuncParser</span></code> instance and the second
is the <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> boolean given to <code class="docutils literal notranslate"><span class="pre">FuncParser.parse</span></code>.</p></li>
</ul>
<p>Heres an example of using the default/reserved keywords:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">_test</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"># do stuff</span>
<span class="k">return</span> <span class="n">something</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">funcparser</span><span class="o">.</span><span class="n">FuncParser</span><span class="p">({</span><span class="s2">&quot;test&quot;</span><span class="p">:</span> <span class="n">_test</span><span class="p">},</span> <span class="n">mydefault</span><span class="o">=</span><span class="mi">2</span><span class="p">)</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="s2">&quot;$test(foo, bar=4)&quot;</span><span class="p">,</span> <span class="n">myreserved</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>
</pre></div>
</div>
<p>Here the callable will be called as</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">_test</span><span class="p">(</span><span class="s1">&#39;foo&#39;</span><span class="p">,</span> <span class="n">bar</span><span class="o">=</span><span class="s1">&#39;4&#39;</span><span class="p">,</span> <span class="n">mydefault</span><span class="o">=</span><span class="mi">2</span><span class="p">,</span> <span class="n">myreserved</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="n">funcparser</span><span class="o">=&lt;</span><span class="n">FuncParser</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">raise_errors</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">mydefault=2</span></code> kwarg could be overwritten if we made the call as <code class="docutils literal notranslate"><span class="pre">$test(mydefault=...)</span></code>
but <code class="docutils literal notranslate"><span class="pre">myreserved=[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> will <em>always</em> be sent as-is and will override a call <code class="docutils literal notranslate"><span class="pre">$test(myreserved=...)</span></code>.
The <code class="docutils literal notranslate"><span class="pre">funcparser</span></code>/<code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> kwargs are also always included as reserved kwargs.</p>
</section>
<section id="defining-custom-callables">
<h2>Defining custom callables<a class="headerlink" href="#defining-custom-callables" title="Permalink to this headline"></a></h2>
<p>All callables made available to the parser must have the following signature:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">funcname</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>
<span class="k">return</span> <span class="n">something</span>
</pre></div>
</div>
<blockquote>
<div><p>The <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> must always be included. If you are unsure how <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> work in Python,
<a class="reference external" href="https://www.digitalocean.com/community/tutorials/how-to-use-args-and-kwargs-in-python-3">read about them here</a>.</p>
</div></blockquote>
<p>The input from the innermost <code class="docutils literal notranslate"><span class="pre">$funcname(...)</span></code> call in your callable will always be a <code class="docutils literal notranslate"><span class="pre">str</span></code>. Heres
an example of an <code class="docutils literal notranslate"><span class="pre">$toint</span></code> function; it converts numbers to integers.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&quot;There&#39;s a $toint(22.0)% chance of survival.&quot;
</pre></div>
</div>
<p>What will enter the <code class="docutils literal notranslate"><span class="pre">$toint</span></code> callable (as <code class="docutils literal notranslate"><span class="pre">args[0]</span></code>) is the <em>string</em> <code class="docutils literal notranslate"><span class="pre">&quot;22.0&quot;</span></code>. The function is responsible
for converting this to a number so that we can convert it to an integer. We must also properly handle invalid
inputs (like non-numbers).</p>
<p>If you want to mark an error, raise <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ParsingError</span></code>. This stops the entire parsing
of the string and may or may not raise the exception depending on what you set <code class="docutils literal notranslate"><span class="pre">raise_errors</span></code> to when you
created the parser.</p>
<p>However, if you <em>nest</em> functions, the return of the innermost function may be something other than
a string. Lets introduce the <code class="docutils literal notranslate"><span class="pre">$eval</span></code> function, which evaluates simple expressions using
Pythons <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> and/or <code class="docutils literal notranslate"><span class="pre">simple_eval</span></code>. It returns whatever data type it
evaluates to.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&quot;There&#39;s a $toint($eval(10 * 2.2))% chance of survival.&quot;
</pre></div>
</div>
<p>Since the <code class="docutils literal notranslate"><span class="pre">$eval</span></code> is the innermost call, it will get a string as input - the string <code class="docutils literal notranslate"><span class="pre">&quot;10</span> <span class="pre">*</span> <span class="pre">2.2&quot;</span></code>.
It evaluates this and returns the <code class="docutils literal notranslate"><span class="pre">float</span></code> <code class="docutils literal notranslate"><span class="pre">22.0</span></code>. This time the outermost <code class="docutils literal notranslate"><span class="pre">$toint</span></code> will be called with
this <code class="docutils literal notranslate"><span class="pre">float</span></code> instead of with a string.</p>
<blockquote>
<div><p>Its important to safely validate your inputs since users may end up nesting your callables in any order.
See the next section for useful tools to help with this.</p>
</div></blockquote>
<p>In these examples, the result will be embedded in the larger string, so the result of the entire parsing
will be a string:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">above_string</span><span class="p">)</span>
<span class="s2">&quot;There&#39;s a 22</span><span class="si">% c</span><span class="s2">hance of survival.&quot;</span>
</pre></div>
</div>
<p>However, if you use the <code class="docutils literal notranslate"><span class="pre">parse_to_any</span></code> (or <code class="docutils literal notranslate"><span class="pre">parse(...,</span> <span class="pre">return_str=False)</span></code>) and
<em>dont add any extra string around the outermost function call</em>,
youll get the return type of the outermost callable back:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;$toint($eval(10 * 2.2)&quot;</span><span class="p">)</span>
<span class="mi">22</span>
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;the number $toint($eval(10 * 2.2).&quot;</span><span class="p">)</span>
<span class="s2">&quot;the number 22&quot;</span>
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="s2">&quot;$toint($eval(10 * 2.2)%&quot;</span><span class="p">)</span>
<span class="s2">&quot;22%&quot;</span>
</pre></div>
</div>
<section id="escaping-special-character">
<h3>Escaping special character<a class="headerlink" href="#escaping-special-character" title="Permalink to this headline"></a></h3>
<p>When entering funcparser callables in strings, it looks like a regular
function call inside a string:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;This is a $myfunc(arg1, arg2, kwarg=foo).&quot;</span>
</pre></div>
</div>
<p>Commas (<code class="docutils literal notranslate"><span class="pre">,</span></code>) and equal-signs (<code class="docutils literal notranslate"><span class="pre">=</span></code>) are considered to separate the arguments and
kwargs. In the same way, the right parenthesis (<code class="docutils literal notranslate"><span class="pre">)</span></code>) closes the argument list.
Sometimes you want to include commas in the argument without it breaking the
argument list.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;The $format(forest&#39;s smallest meadow, with dandelions) is to the west.&quot;</span>
</pre></div>
</div>
<p>You can escape in various ways.</p>
<ul class="simple">
<li><p>Prepending special characters like <code class="docutils literal notranslate"><span class="pre">,</span></code> and <code class="docutils literal notranslate"><span class="pre">=</span></code> with the escape character <code class="docutils literal notranslate"><span class="pre">\</span></code></p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s2">&quot;The $format(forest&#39;s smallest meadow\, with dandelions) is to the west.&quot;</span>
</pre></div>
</div>
<ul class="simple">
<li><p>Wrapping your strings in double quotes. Unlike in raw Python, you
cant escape with single quotes <code class="docutils literal notranslate"><span class="pre">'</span></code> since these could also be apostrophes (like
<code class="docutils literal notranslate"><span class="pre">forest's</span></code> above). The result will be a verbatim string that contains
everything but the outermost double quotes.</p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;The $format(&quot;forest&#39;</span><span class="n">s</span> <span class="n">smallest</span> <span class="n">meadow</span><span class="p">,</span> <span class="k">with</span> <span class="n">dandelions</span><span class="s2">&quot;) is to the west.&#39;</span>
</pre></div>
</div>
<ul class="simple">
<li><p>If you want verbatim double-quotes to appear in your string, you can escape
them with <code class="docutils literal notranslate"><span class="pre">\&quot;</span></code> in turn.</p></li>
</ul>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="s1">&#39;The $format(&quot;forest&#39;</span><span class="n">s</span> <span class="n">smallest</span> <span class="n">meadow</span><span class="p">,</span> <span class="k">with</span> \<span class="s2">&quot;dandelions</span><span class="se">\&quot;</span><span class="s2">&#39;) is to the west.&#39;</span>
</pre></div>
</div>
</section>
<section id="safe-convertion-of-inputs">
<h3>Safe convertion of inputs<a class="headerlink" href="#safe-convertion-of-inputs" title="Permalink to this headline"></a></h3>
<p>Since you dont know in which order users may use your callables, they should
always check the types of its inputs and convert to the type the callable needs.
Note also that when converting from strings, there are limits what inputs you
can support. This is because FunctionParser strings can be used by
non-developer players/builders and some things (such as complex
classes/callables etc) are just not safe/possible to convert from string
representation.</p>
<p>In <code class="docutils literal notranslate"><span class="pre">evennia.utils.utils</span></code> is a helper called
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.safe_convert_to_types" title="evennia.utils.utils.safe_convert_to_types"><span class="xref myst py py-func">safe_convert_to_types</span></a>. This function
automates the conversion of simple data types in a safe way:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">safe_convert_to_types</span>
<span class="k">def</span> <span class="nf">_process_callable</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> $process(expression, local, extra1=34, extra2=foo)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">safe_convert_to_type</span><span class="p">(</span>
<span class="p">((</span><span class="s1">&#39;py&#39;</span><span class="p">,</span> <span class="nb">str</span><span class="p">),</span> <span class="p">{</span><span class="s1">&#39;extra1&#39;</span><span class="p">:</span> <span class="nb">int</span><span class="p">,</span> <span class="s1">&#39;extra2&#39;</span><span class="p">:</span> <span class="nb">str</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"># args/kwargs should be correct types now</span>
</pre></div>
</div>
<p>In other words, in the callable <code class="docutils literal notranslate"><span class="pre">$process(expression,</span> <span class="pre">local,</span> <span class="pre">extra1=..,</span> <span class="pre">extra2=...)</span></code>, the first argument will be handled by the py converter
(described below), the second will passed through regular Python <code class="docutils literal notranslate"><span class="pre">str</span></code>,
kwargs will be handled by <code class="docutils literal notranslate"><span class="pre">int</span></code> and <code class="docutils literal notranslate"><span class="pre">str</span></code> respectively. You can supply
your own converter function as long as it takes one argument and returns
the converted result.</p>
<p>In other words,</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">args</span><span class="p">,</span> <span class="n">kwargs</span> <span class="o">=</span> <span class="n">safe_convert_to_type</span><span class="p">(</span>
<span class="p">(</span><span class="n">tuple_of_arg_converters</span><span class="p">,</span> <span class="n">dict_of_kwarg_converters</span><span class="p">),</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</div>
<p>The special converter <code class="docutils literal notranslate"><span class="pre">&quot;py&quot;</span></code> will try to convert a string argument to a Python structure with the help of the
following tools (which you may also find useful to experiment with on your own):</p>
<ul class="simple">
<li><p><a class="reference external" href="https://docs.python.org/3.8/library/ast.html#ast.literal_eval">ast.literal_eval</a> is an in-built Python
function. It
<em>only</em> supports strings, bytes, numbers, tuples, lists, dicts, sets, booleans and <code class="docutils literal notranslate"><span class="pre">None</span></code>. Thats
it - no arithmetic or modifications of data is allowed. This is good for converting individual values and
lists/dicts from the input line to real Python objects.</p></li>
<li><p><a class="reference external" href="https://pypi.org/project/simpleeval/">simpleeval</a> is a third-party tool included with Evennia. This
allows for evaluation of simple (and thus safe) expressions. One can operate on numbers and strings
with <code class="docutils literal notranslate"><span class="pre">+-/*</span></code> as well as do simple comparisons like <code class="docutils literal notranslate"><span class="pre">4</span> <span class="pre">&gt;</span> <span class="pre">3</span></code> and more. It does <em>not</em> accept more complex
containers like lists/dicts etc, so this and <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> are complementary to each other.</p></li>
</ul>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>It may be tempting to run use Pythons in-built <code class="docutils literal notranslate"><span class="pre">eval()</span></code> or <code class="docutils literal notranslate"><span class="pre">exec()</span></code> functions as converters since
these are able to convert any valid Python source code to Python. NEVER DO THIS unless you really, really
know that ONLY developers will ever modify the string going into the callable. The parser is intended
for untrusted users (if you were trusted youd have access to Python already). Letting untrusted users
pass strings to <code class="docutils literal notranslate"><span class="pre">eval</span></code>/<code class="docutils literal notranslate"><span class="pre">exec</span></code> is a MAJOR security risk. It allows the caller to run arbitrary
Python code on your server. This is the path to maliciously deleted hard drives. Just dont do it and
sleep better at night.</p>
</div>
</section>
</section>
<section id="default-callables">
<h2>Default callables<a class="headerlink" href="#default-callables" title="Permalink to this headline"></a></h2>
<p>These are some example callables you can import and add your parser. They are divided into
global-level dicts in <code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser</span></code>. Just import the dict(s) and merge/add one or
more to them when you create your <code class="docutils literal notranslate"><span class="pre">FuncParser</span></code> instance to have those callables be available.</p>
<section id="evennia-utils-funcparser-funcparser-callables">
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.FUNCPARSER_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-funcparser-callables" title="Permalink to this headline"></a></h3>
<p>These are the base callables.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">$eval(expression)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_eval" title="evennia.utils.funcparser.funcparser_callable_eval"><span class="xref myst py py-func">code</span></a>) -
this uses <code class="docutils literal notranslate"><span class="pre">literal_eval</span></code> and <code class="docutils literal notranslate"><span class="pre">simple_eval</span></code> (see previous section) attemt to convert a string expression
to a python object. This handles e.g. lists of literals <code class="docutils literal notranslate"><span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3]</span></code> and simple expressions like <code class="docutils literal notranslate"><span class="pre">&quot;1</span> <span class="pre">+</span> <span class="pre">2&quot;</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$toint(number)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_toint" title="evennia.utils.funcparser.funcparser_callable_toint"><span class="xref myst py py-func">code</span></a>) -
always converts an output to an integer, if possible.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$add/sub/mult/div(obj1,</span> <span class="pre">obj2)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_add" title="evennia.utils.funcparser.funcparser_callable_add"><span class="xref myst py py-func">code</span></a>) -
this adds/subtracts/multiplies and divides to elements together. While simple addition could be done with
<code class="docutils literal notranslate"><span class="pre">$eval</span></code>, this could for example be used also to add two lists together, which is not possible with <code class="docutils literal notranslate"><span class="pre">eval</span></code>;
for example <code class="docutils literal notranslate"><span class="pre">$add($eval([1,2,3]),</span> <span class="pre">$eval([4,5,6]))</span> <span class="pre">-&gt;</span> <span class="pre">[1,</span> <span class="pre">2,</span> <span class="pre">3,</span> <span class="pre">4,</span> <span class="pre">5,</span> <span class="pre">6]</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$round(float,</span> <span class="pre">significant)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_round" title="evennia.utils.funcparser.funcparser_callable_round"><span class="xref myst py py-func">code</span></a>) -
rounds an input float into the number of provided significant digits. For example <code class="docutils literal notranslate"><span class="pre">$round(3.54343,</span> <span class="pre">3)</span> <span class="pre">-&gt;</span> <span class="pre">3.543</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$random([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_random" title="evennia.utils.funcparser.funcparser_callable_random"><span class="xref myst py py-func">code</span></a>) -
this works like the Python <code class="docutils literal notranslate"><span class="pre">random()</span></code> function, but will randomize to an integer value if both start/end are
integers. Without argument, will return a float between 0 and 1.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$randint([start,</span> <span class="pre">[end]])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_randint" title="evennia.utils.funcparser.funcparser_callable_randint"><span class="xref myst py py-func">code</span></a>) -
works like the <code class="docutils literal notranslate"><span class="pre">randint()</span></code> python function and always returns an integer.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$choice(list)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_choice" title="evennia.utils.funcparser.funcparser_callable_choice"><span class="xref myst py py-func">code</span></a>) -
the input will automatically be parsed the same way as <code class="docutils literal notranslate"><span class="pre">$eval</span></code> and is expected to be an iterable. A random
element of this list will be returned.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$pad(text[,</span> <span class="pre">width,</span> <span class="pre">align,</span> <span class="pre">fillchar])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_pad" title="evennia.utils.funcparser.funcparser_callable_pad"><span class="xref myst py py-func">code</span></a>) -
this will pad content. <code class="docutils literal notranslate"><span class="pre">$pad(&quot;Hello&quot;,</span> <span class="pre">30,</span> <span class="pre">c,</span> <span class="pre">-)</span></code> will lead to a text centered in a 30-wide block surrounded by <code class="docutils literal notranslate"><span class="pre">-</span></code>
characters.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$crop(text,</span> <span class="pre">width=78,</span> <span class="pre">suffix='[...]')</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_crop" title="evennia.utils.funcparser.funcparser_callable_crop"><span class="xref myst py py-func">code</span></a>) -
this will crop a text longer than the width, by default ending it with a <code class="docutils literal notranslate"><span class="pre">[...]</span></code>-suffix that also fits within
the width. If no width is given, the client width or <code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_CLIENT_WIDTH</span></code> will be used.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$space(num)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_space" title="evennia.utils.funcparser.funcparser_callable_space"><span class="xref myst py py-func">code</span></a>) -
this will insert <code class="docutils literal notranslate"><span class="pre">num</span></code> spaces.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$just(string,</span> <span class="pre">width=40,</span> <span class="pre">align=c,</span> <span class="pre">indent=2)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_justify" title="evennia.utils.funcparser.funcparser_callable_justify"><span class="xref myst py py-func">code</span></a>) -
justifies the text to a given width, aligning it left/right/center or f for full (spread text across width).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$ljust</span></code> - shortcut to justify-left. Takes all other kwarg of <code class="docutils literal notranslate"><span class="pre">$just</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$rjust</span></code> - shortcut to right justify.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$cjust</span></code> - shortcut to center justify.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$clr(startcolor,</span> <span class="pre">text[,</span> <span class="pre">endcolor])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_clr" title="evennia.utils.funcparser.funcparser_callable_clr"><span class="xref myst py py-func">code</span></a>) -
color text. The color is given with one or two characters without the preceeding <code class="docutils literal notranslate"><span class="pre">|</span></code>. If no endcolor is
given, the string will go back to neutral, so <code class="docutils literal notranslate"><span class="pre">$clr(r,</span> <span class="pre">Hello)</span></code> is equivalent to <code class="docutils literal notranslate"><span class="pre">|rHello|n</span></code>.</p></li>
</ul>
</section>
<section id="evennia-utils-funcparser-searching-callables">
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.SEARCHING_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-searching-callables" title="Permalink to this headline"></a></h3>
<p>These are callables that requires access-checks in order to search for objects. So they require some
extra reserved kwargs to be passed when running the parser:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="n">parser</span><span class="o">.</span><span class="n">parse_to_any</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">caller</span><span class="o">=&lt;</span><span class="nb">object</span> <span class="ow">or</span> <span class="n">account</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">access</span><span class="o">=</span><span class="s2">&quot;control&quot;</span><span class="p">,</span> <span class="o">...</span><span class="p">)</span>
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">caller</span></code> is required, its the the object to do the access-check for. The <code class="docutils literal notranslate"><span class="pre">access</span></code> kwarg is the
<a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock type</span></a> to check, default being <code class="docutils literal notranslate"><span class="pre">&quot;control&quot;</span></code>.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">$search(query,type=account|script,return_list=False)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_search" title="evennia.utils.funcparser.funcparser_callable_search"><span class="xref myst py py-func">code</span></a>) -
this will look up and try to match an object by key or alias. Use the <code class="docutils literal notranslate"><span class="pre">type</span></code> kwarg to
search for <code class="docutils literal notranslate"><span class="pre">account</span></code> or <code class="docutils literal notranslate"><span class="pre">script</span></code> instead. By default this will return nothing if there are more than one
match; if <code class="docutils literal notranslate"><span class="pre">return_list</span></code> is <code class="docutils literal notranslate"><span class="pre">True</span></code> a list of 0, 1 or more matches will be returned instead.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$obj(query)</span></code>, <code class="docutils literal notranslate"><span class="pre">$dbref(query)</span></code> - legacy aliases for <code class="docutils literal notranslate"><span class="pre">$search</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$objlist(query)</span></code> - legacy alias for <code class="docutils literal notranslate"><span class="pre">$search</span></code>, always returning a list.</p></li>
</ul>
</section>
<section id="evennia-utils-funcparser-actor-stance-callables">
<h3><code class="docutils literal notranslate"><span class="pre">evennia.utils.funcparser.ACTOR_STANCE_CALLABLES</span></code><a class="headerlink" href="#evennia-utils-funcparser-actor-stance-callables" title="Permalink to this headline"></a></h3>
<p>These are used to implement actor-stance emoting. They are used by the
<a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.msg_contents" title="evennia.objects.objects.DefaultObject.msg_contents"><span class="xref myst py py-meth">DefaultObject.msg_contents</span></a> method
by default. You can read a lot more about this on the page
<a class="reference internal" href="../Concepts/Change-Messages-Per-Receiver.html"><span class="doc std std-doc">Change messages per receiver</span></a>.</p>
<p>On the parser side, all these inline functions require extra kwargs be passed into the parser
(done by <code class="docutils literal notranslate"><span class="pre">msg_contents</span></code> by default):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">string</span><span class="p">,</span> <span class="n">caller</span><span class="o">=&lt;</span><span class="n">obj</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">receiver</span><span class="o">=&lt;</span><span class="n">obj</span><span class="o">&gt;</span><span class="p">,</span> <span class="n">mapping</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;key&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">obj</span><span class="o">&gt;</span><span class="p">,</span> <span class="o">...</span><span class="p">})</span>
</pre></div>
</div>
<p>Here the <code class="docutils literal notranslate"><span class="pre">caller</span></code> is the one sending the message and <code class="docutils literal notranslate"><span class="pre">receiver</span></code> the one to see it. The <code class="docutils literal notranslate"><span class="pre">mapping</span></code> contains
references to other objects accessible via these callables.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">$you([key])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_you" title="evennia.utils.funcparser.funcparser_callable_you"><span class="xref myst py py-func">code</span></a>) -
if no <code class="docutils literal notranslate"><span class="pre">key</span></code> is given, this represents the <code class="docutils literal notranslate"><span class="pre">caller</span></code>, otherwise an object from <code class="docutils literal notranslate"><span class="pre">mapping</span></code>
will be used. As this message is sent to different recipients, the <code class="docutils literal notranslate"><span class="pre">receiver</span></code> will change and this will
be replaced either with the string <code class="docutils literal notranslate"><span class="pre">you</span></code> (if you and the receiver is the same entity) or with the
result of <code class="docutils literal notranslate"><span class="pre">you_obj.get_display_name(looker=receiver)</span></code>. This allows for a single string to echo differently
depending on who sees it, and also to reference other people in the same way.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$You([key])</span></code> - same as <code class="docutils literal notranslate"><span class="pre">$you</span></code> but always capitalized.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$conj(verb)</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_conjugate" title="evennia.utils.funcparser.funcparser_callable_conjugate"><span class="xref myst py py-func">code</span></a>) - conjugates a verb
between 2nd person presens to 3rd person presence depending on who
sees the string. For example <code class="docutils literal notranslate"><span class="pre">&quot;$You()</span> <span class="pre">$conj(smiles)&quot;.</span></code> will show as “You smile.” and “Tom smiles.” depending
on who sees it. This makes use of the tools in <a class="reference internal" href="../api/evennia.utils.verb_conjugation.html#evennia-utils-verb-conjugation"><span class="std std-ref">evennia.utils.verb_conjugation</span></a>
to do this, and only works for English verbs.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">$pron(pronoun</span> <span class="pre">[,options])</span></code> (<a class="reference internal" href="../api/evennia.utils.funcparser.html#evennia.utils.funcparser.funcparser_callable_pronoun" title="evennia.utils.funcparser.funcparser_callable_pronoun"><span class="xref myst py py-func">code</span></a>) - Dynamically
map pronouns (like his, herself, you, its etc) between 1st/2nd person to 3rd person.</p></li>
</ul>
</section>
<section id="example">
<h3>Example<a class="headerlink" href="#example" title="Permalink to this headline"></a></h3>
<p>Heres an example of including the default callables together with two custom ones.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">funcparser</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">gametime</span>
<span class="k">def</span> <span class="nf">_dashline</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="k">return</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="se">\n</span><span class="s2">-------- </span><span class="si">{</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2"> --------&quot;</span>
<span class="k">return</span> <span class="s1">&#39;&#39;</span>
<span class="k">def</span> <span class="nf">_uptime</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">return</span> <span class="n">gametime</span><span class="o">.</span><span class="n">uptime</span><span class="p">()</span>
<span class="n">callables</span> <span class="o">=</span> <span class="p">{</span>
<span class="s2">&quot;dashline&quot;</span><span class="p">:</span> <span class="n">_dashline</span><span class="p">,</span>
<span class="s2">&quot;uptime&quot;</span><span class="p">:</span> <span class="n">_uptime</span><span class="p">,</span>
<span class="o">**</span><span class="n">funcparser</span><span class="o">.</span><span class="n">FUNCPARSER_CALLABLES</span><span class="p">,</span>
<span class="o">**</span><span class="n">funcparser</span><span class="o">.</span><span class="n">ACTOR_STANCE_CALLABLES</span><span class="p">,</span>
<span class="o">**</span><span class="n">funcparser</span><span class="o">.</span><span class="n">SEARCHING_CALLABLES</span>
<span class="p">}</span>
<span class="n">parser</span> <span class="o">=</span> <span class="n">funcparser</span><span class="o">.</span><span class="n">FuncParser</span><span class="p">(</span><span class="n">callables</span><span class="p">)</span>
<span class="n">string</span> <span class="o">=</span> <span class="s2">&quot;This is the current uptime:$dashline($toint($uptime()) seconds)&quot;</span>
<span class="n">result</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
</pre></div>
</div>
<p>Above we define two callables <code class="docutils literal notranslate"><span class="pre">_dashline</span></code> and <code class="docutils literal notranslate"><span class="pre">_uptime</span></code> and map them to names <code class="docutils literal notranslate"><span class="pre">&quot;dashline&quot;</span></code> and <code class="docutils literal notranslate"><span class="pre">&quot;uptime&quot;</span></code>,
which is what we then can call as <code class="docutils literal notranslate"><span class="pre">$header</span></code> and <code class="docutils literal notranslate"><span class="pre">$uptime</span></code> in the string. We also have access to
all the defaults (like <code class="docutils literal notranslate"><span class="pre">$toint()</span></code>).</p>
<p>The parsed result of the above would be something like this:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>This is the current uptime:
------- 343 seconds -------
</pre></div>
</div>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
>next</a> |</li>
<li class="right" >
<a href="EvTable.html" title="EvTable"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">The Inline Function Parser</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,534 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Permissions" href="Permissions.html" />
<link rel="prev" title="Spawner and Prototypes" href="Prototypes.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Permissions.html" title="Permissions"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Prototypes.html" title="Spawner and Prototypes"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Help System</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Help System</a><ul>
<li><a class="reference internal" href="#using-the-help-system-from-in-game">Using the help system from in-game</a></li>
<li><a class="reference internal" href="#sources-of-help-entries">Sources of help entries</a><ul>
<li><a class="reference internal" href="#the-help-entry">The Help Entry</a><ul>
<li><a class="reference internal" href="#subtopics">Subtopics</a></li>
</ul>
</li>
<li><a class="reference internal" href="#command-auto-help-system">Command Auto-help system</a></li>
<li><a class="reference internal" href="#database-help-entries">Database-help entries</a></li>
<li><a class="reference internal" href="#file-help-entries">File-help entries</a></li>
</ul>
</li>
<li><a class="reference internal" href="#entry-priority">Entry priority</a></li>
<li><a class="reference internal" href="#locking-help-entries">Locking help entries</a></li>
<li><a class="reference internal" href="#customizing-the-look-of-the-help-system">Customizing the look of the help system</a></li>
<li><a class="reference internal" href="#technical-notes">Technical notes</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Prototypes.html"
title="previous chapter">Spawner and Prototypes</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Permissions.html"
title="next chapter">Permissions</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Help-System.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="help-system">
<h1>Help System<a class="headerlink" href="#help-system" title="Permalink to this headline"></a></h1>
<p>Evennia has an extensive help system covering both command-help and regular
free-form help documentation. It supports subtopics and if failing to find a
match it will provide suggestsions, first from alternative topics and then by
finding mentions of the search term in help entries.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; help theatre
</pre></div>
</div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">------------------------------------------------------------------------------</span>
<span class="n">Help</span> <span class="k">for</span> <span class="n">The</span> <span class="n">theatre</span> <span class="p">(</span><span class="n">aliases</span><span class="p">:</span> <span class="n">the</span> <span class="n">hub</span><span class="p">,</span> <span class="n">curtains</span><span class="p">)</span>
<span class="n">The</span> <span class="n">theatre</span> <span class="ow">is</span> <span class="n">at</span> <span class="n">the</span> <span class="n">centre</span> <span class="n">of</span> <span class="n">the</span> <span class="n">city</span><span class="p">,</span> <span class="n">both</span> <span class="n">literally</span> <span class="ow">and</span> <span class="n">figuratively</span> <span class="o">...</span>
<span class="p">(</span><span class="n">A</span> <span class="n">lot</span> <span class="n">more</span> <span class="n">text</span> <span class="n">about</span> <span class="n">it</span> <span class="n">follows</span> <span class="o">...</span><span class="p">)</span>
<span class="n">Subtopics</span><span class="p">:</span>
<span class="n">theatre</span><span class="o">/</span><span class="n">lore</span>
<span class="n">theatre</span><span class="o">/</span><span class="n">layout</span>
<span class="n">theatre</span><span class="o">/</span><span class="n">dramatis</span> <span class="n">personae</span>
<span class="o">------------------------------------------------------------------------------</span>
</pre></div>
</div>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; help evennia
</pre></div>
</div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">------------------------------------------------------------------------------</span>
<span class="n">No</span> <span class="n">help</span> <span class="n">found</span>
<span class="n">There</span> <span class="ow">is</span> <span class="n">no</span> <span class="n">help</span> <span class="n">topic</span> <span class="n">matching</span> <span class="s1">&#39;evennia&#39;</span><span class="o">.</span>
<span class="o">...</span> <span class="n">But</span> <span class="n">matches</span> <span class="n">where</span> <span class="n">found</span> <span class="n">within</span> <span class="n">the</span> <span class="n">help</span> <span class="n">texts</span> <span class="n">of</span> <span class="n">the</span> <span class="n">suggestions</span> <span class="n">below</span><span class="o">.</span>
<span class="n">Suggestions</span><span class="p">:</span>
<span class="n">grapevine2chan</span><span class="p">,</span> <span class="n">about</span><span class="p">,</span> <span class="n">irc2chan</span>
<span class="o">-----------------------------------------------------------------------------</span>
</pre></div>
</div>
<section id="using-the-help-system-from-in-game">
<h2>Using the help system from in-game<a class="headerlink" href="#using-the-help-system-from-in-game" title="Permalink to this headline"></a></h2>
<p>The help system is accessed in-game by use of the <code class="docutils literal notranslate"><span class="pre">help</span></code> command:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>help &lt;topic&gt;
</pre></div>
</div>
<p>Sub-topics are accessed as <code class="docutils literal notranslate"><span class="pre">help</span> <span class="pre">&lt;topic&gt;/&lt;subtopic&gt;/...</span></code>.</p>
<p>Creating a new help entry from in-game is done with</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>sethelp &lt;topic&gt;[;aliases] [,category] [,lockstring] = &lt;text&gt;
</pre></div>
</div>
<p>For example</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>sethelp The Gods;pantheon, Lore = In the beginning all was dark ...
</pre></div>
</div>
<p>Use the <code class="docutils literal notranslate"><span class="pre">/edit</span></code> switch to open the EvEditor for more convenient in-game writing
(but note that devs can also create help entries outside the game using their
regular code editor, see below).</p>
<blockquote>
<div><p>You can also create help entries as Python modules, outside of the game. See
<em>FileHelp</em> entries below.</p>
</div></blockquote>
</section>
<section id="sources-of-help-entries">
<h2>Sources of help entries<a class="headerlink" href="#sources-of-help-entries" title="Permalink to this headline"></a></h2>
<p>Evennia collects help entries from three sources:</p>
<ul class="simple">
<li><p><em>Auto-generated command help</em> - this is literally the doc-strings of
the <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Command classes</span></a>. The idea is that the command docs are
easier to maintain and keep up-to-date if the developer can change them at the
same time as they do the code.</p></li>
<li><p><em>Database-stored help entries</em> - These are created in-game (using the
default <code class="docutils literal notranslate"><span class="pre">sethelp</span></code> command as exemplified in the previous section).</p></li>
<li><p><em>File-stored help entries</em> - These are created outside the game, as dicts in
normal Python modules. They allows developers to write and maintain their help
files using a proper text editor.</p></li>
</ul>
<section id="the-help-entry">
<h3>The Help Entry<a class="headerlink" href="#the-help-entry" title="Permalink to this headline"></a></h3>
<p>All help entries (no matter the source) have the following properties:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - This is the main topic-name. For Commands, this is literally the
commands <code class="docutils literal notranslate"><span class="pre">key</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">aliases</span></code> - Alternate names for the help entry. This can be useful if the main
name is hard to remember.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">help_category</span></code> - The general grouping of the entry. This is optional. If not
given it will use the default category given by
<code class="docutils literal notranslate"><span class="pre">settings.COMMAND_DEFAULT_HELP_CATEGORY</span></code> for Commands and
<code class="docutils literal notranslate"><span class="pre">settings.DEFAULT_HELP_CATEGORY</span></code> for file+db help entries.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> - Lock string (for commands) or LockHandler (all help entries).
This defines who may read this entry. See the next section.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">tags</span></code> - This is not used by default, but could be used to further organize
help entries.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">text</span></code> - The actual help entry text. This will be dedented and stripped of
extra space at beginning and end.</p></li>
</ul>
<p>A <code class="docutils literal notranslate"><span class="pre">text</span></code> that scrolls off the screen will automatically be paginated by
the <a class="reference internal" href="EvMore.html"><span class="doc std std-doc">EvMore</span></a> pager (you can control this with
<code class="docutils literal notranslate"><span class="pre">settings.HELP_MORE_ENABLED=False</span></code>). If you use EvMore and want to control
exactly where the pager should break the page, mark the break with the control
character <code class="docutils literal notranslate"><span class="pre">\f</span></code>.</p>
<section id="subtopics">
<h4>Subtopics<a class="headerlink" href="#subtopics" title="Permalink to this headline"></a></h4>
<div class="versionadded">
<p><span class="versionmodified added">New in version 1.0.</span></p>
</div>
<p>Rather than making a very long help entry, the <code class="docutils literal notranslate"><span class="pre">text</span></code> may also be broken up
into <em>subtopics</em>. A list of the next level of subtopics are shown below the
main help text and allows the user to read more about some particular detail
that wouldnt fit in the main text.</p>
<p>Subtopics use a markup slightly similar to markdown headings. The top level
heading must be named <code class="docutils literal notranslate"><span class="pre">#</span> <span class="pre">subtopics</span></code> (non case-sensitive) and the following
headers must be sub-headings to this (so <code class="docutils literal notranslate"><span class="pre">##</span> <span class="pre">subtopic</span> <span class="pre">name</span></code> etc). All headings
are non-case sensitive (the help command will format them). The topics can be
nested at most to a depth of 5 (which is probably too many levels already). The
parser uses fuzzy matching to find the subtopic, so one does not have to type
it all out exactly.</p>
<p>Below is an example of a <code class="docutils literal notranslate"><span class="pre">text</span></code> with sub topics.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>The theatre is the heart of the city, here you can find ...
(This is the main help text, what you get with `help theatre`)
# subtopics
## lore
The theatre holds many mysterious things...
(`help theatre/lore`)
### the grand opening
The grand opening is the name for a mysterious event where ghosts appeared ...
(`this is a subsub-topic to lore, accessible as `help theatre/lore/grand` or
any other partial match).
### the Phantom
Deep under the theatre, rumors has it a monster hides ...
(another subsubtopic, accessible as `help theatre/lore/phantom`)
## layout
The theatre is a two-story building situated at ...
(`help theatre/layout`)
## dramatis personae
There are many interesting people prowling the halls of the theatre ...
(`help theatre/dramatis` or `help theathre/drama` or `help theatre/personae` would work)
### Primadonna Ada
Everyone knows the primadonna! She is ...
(A subtopic under dramatis personae, accessible as `help theatre/drama/ada` etc)
### The gatekeeper
He always keeps an eye on the door and ...
(`help theatre/drama/gate`)
</pre></div>
</div>
</section>
</section>
<section id="command-auto-help-system">
<h3>Command Auto-help system<a class="headerlink" href="#command-auto-help-system" title="Permalink to this headline"></a></h3>
<p>The auto-help system uses the <code class="docutils literal notranslate"><span class="pre">__doc__</span></code> strings of your command classes and
formats this to a nice- looking help entry. This makes for a very easy way to
keep the help updated - just document your commands well and updating the help
file is just a <code class="docutils literal notranslate"><span class="pre">reload</span></code> away.</p>
<p>Example (from a module with command definitions):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">class</span> <span class="nc">CmdMyCmd</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> mycmd - my very own command</span>
<span class="sd"> Usage:</span>
<span class="sd"> mycmd[/switches] &lt;args&gt;</span>
<span class="sd"> Switches:</span>
<span class="sd"> test - test the command</span>
<span class="sd"> run - do something else</span>
<span class="sd"> This is my own command that does this and that.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># [...]</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:all();read:all()&quot;</span> <span class="c1"># default</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="kc">True</span> <span class="c1"># default</span>
<span class="c1"># [...]</span>
</pre></div>
</div>
<p>The text at the very top of the command class definition is the class
<code class="docutils literal notranslate"><span class="pre">__doc__</span></code>-string and will be shown to users looking for help. Try to use a
consistent format - all default commands are using the structure shown above.</p>
<p>You can limit access to the help entry by the <code class="docutils literal notranslate"><span class="pre">view</span></code> and/or <code class="docutils literal notranslate"><span class="pre">read</span></code> locks on the
Command. See <a class="reference internal" href="#locking-help-entries"><span class="std std-doc">the section below</span></a> for details.</p>
<p>You should also supply the <code class="docutils literal notranslate"><span class="pre">help_category</span></code> class property if you can; this helps
to group help entries together for people to more easily find them. See the
<code class="docutils literal notranslate"><span class="pre">help</span></code> command in-game to see the default categories. If you dont specify the
category, <code class="docutils literal notranslate"><span class="pre">settings.COMMAND_DEFAULT_HELP_CATEGORY</span></code> (default is “General”) is
used.</p>
<p>If you 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 std std-doc">cmdset</span></a> that has its own help functionality) you
can explicitly set <code class="docutils literal notranslate"><span class="pre">auto_help</span></code> class property to <code class="docutils literal notranslate"><span class="pre">False</span></code> in your command
definition.</p>
<p>Alternatively, you can keep the advantages of <em>auto-help</em> in commands, but
control the display of command helps. You can do so by overriding the commands
<code class="docutils literal notranslate"><span class="pre">get_help(caller,</span> <span class="pre">cmdset)</span></code> method. By default, this method will return the
class docstring. You could modify it to add custom behavior: the text returned
by this method will be displayed to the character asking for help in this
command.</p>
</section>
<section id="database-help-entries">
<h3>Database-help entries<a class="headerlink" href="#database-help-entries" title="Permalink to this headline"></a></h3>
<p>These are most commonly created in-game using the <code class="docutils literal notranslate"><span class="pre">sethelp</span></code> command. If you need to create one
manually, you can do so with <code class="docutils literal notranslate"><span class="pre">evennia.create_help_entry()</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_help_entry</span>
<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>
</div>
<p>The entity being created is a <a class="reference internal" href="../api/evennia.help.models.html#evennia.help.models.HelpEntry" title="evennia.help.models.HelpEntry"><span class="xref myst py py-class">evennia.help.models.HelpEntry</span></a>
object. This is <em>not</em> a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entity and is not meant to
be modified to any great degree. It holds the properties listed earlier. The
text is stored in a field <code class="docutils literal notranslate"><span class="pre">entrytext</span></code>. It does not provide a <code class="docutils literal notranslate"><span class="pre">get_help</span></code> method
like commands, stores and returns the <code class="docutils literal notranslate"><span class="pre">entrytext</span></code> directly.</p>
<p>You can search for (db-)-<code class="docutils literal notranslate"><span class="pre">HelpEntry</span></code> objects using <code class="docutils literal notranslate"><span class="pre">evennia.search_help</span></code> but note that
this will not return the two other types of help entries.</p>
</section>
<section id="file-help-entries">
<h3>File-help entries<a class="headerlink" href="#file-help-entries" title="Permalink to this headline"></a></h3>
<div class="versionadded">
<p><span class="versionmodified added">New in version 1.0.</span></p>
</div>
<p>File-help entries are created by the game development team outside of the game. The
help entries are defined in normal Python modules (<code class="docutils literal notranslate"><span class="pre">.py</span></code> file ending) containing
a <code class="docutils literal notranslate"><span class="pre">dict</span></code> to represent each entry. They require a server <code class="docutils literal notranslate"><span class="pre">reload</span></code> before any changes
apply.</p>
<ul class="simple">
<li><p>Evennia will look through all modules given by
<code class="docutils literal notranslate"><span class="pre">settings.FILE_HELP_ENTRY_MODULES</span></code>. This should be a list of python-paths for
Evennia to import.</p></li>
<li><p>If this module contains a top-level variable <code class="docutils literal notranslate"><span class="pre">HELP_ENTRY_DICTS</span></code>, this will be
imported and must be a <code class="docutils literal notranslate"><span class="pre">list</span></code> of help-entry dicts.</p></li>
<li><p>If no <code class="docutils literal notranslate"><span class="pre">HELP_ENTRY_DICTS</span></code> list is found, <em>every</em> top-level variable in the
module that is a <code class="docutils literal notranslate"><span class="pre">dict</span></code> will be read as a help entry. The variable-names will
be ignored in this case.</p></li>
</ul>
<p>If you add multiple modules to be read, same-keyed help entries added later in
the list will override coming before.</p>
<p>Each entry dict must define keys to match that needed by all help entries.
Heres an example of a help module:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="c1"># in a module pointed to by settings.FILE_HELP_ENTRY_MODULES</span>
<span class="n">HELP_ENTRY_DICTS</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">{</span>
<span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;The Gods&quot;</span><span class="p">,</span> <span class="c1"># case-insensitive, can be searched by &#39;gods&#39; too</span>
<span class="s2">&quot;aliases&quot;</span><span class="p">:</span> <span class="p">[</span><span class="s1">&#39;pantheon&#39;</span><span class="p">,</span> <span class="s1">&#39;religion&#39;</span><span class="p">]</span>
<span class="s2">&quot;category&quot;</span><span class="p">:</span> <span class="s2">&quot;Lore&quot;</span><span class="p">,</span>
<span class="s2">&quot;locks&quot;</span><span class="p">:</span> <span class="s2">&quot;read:all()&quot;</span><span class="p">,</span> <span class="c1"># optional</span>
<span class="s2">&quot;text&quot;</span><span class="p">:</span> <span class="s1">&#39;&#39;&#39;</span>
<span class="s1"> The gods formed the world ...</span>
<span class="s1"> # Subtopics</span>
<span class="s1"> ## Pantheon</span>
<span class="s1"> The pantheon consists of 40 gods that ...</span>
<span class="s1"> ### God of love</span>
<span class="s1"> The most prominent god is ...</span>
<span class="s1"> ### God of war</span>
<span class="s1"> Also known as &#39;the angry god&#39;, this god is known to ...</span>
<span class="s1"> &#39;&#39;&#39;</span>
<span class="p">},</span>
<span class="p">{</span>
<span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="s2">&quot;The mortals&quot;</span><span class="p">,</span>
<span class="p">}</span>
<span class="p">]</span>
</pre></div>
</div>
<p>The help entry text will be dedented and will retain paragraphs. You should try
to keep your strings a reasonable width (it will look better). Just reload the
server and the file-based help entries will be available to view.</p>
</section>
</section>
<section id="entry-priority">
<h2>Entry priority<a class="headerlink" href="#entry-priority" title="Permalink to this headline"></a></h2>
<p>Should you have clashing help-entries between the three types of available
entries, the priority is</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Command-auto-help &gt; Db-help &gt; File-help
</pre></div>
</div>
<p>So if you create a db-help entry foo, it will replace any file-based help
entry foo. But if there is a Command foo, thats the help youll get when
you enter <code class="docutils literal notranslate"><span class="pre">help</span> <span class="pre">foo</span></code>.</p>
<p>The reasoning for this is that commands must always be understood in order to
play the game. Meanwhile db-based help can be kept up-to-date from in-game
builders and may be less static than the file-based ones.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">sethelp</span></code> command (which only deals with creating db-based help entries)
will warn you if a new help entry might shadow/be shadowed by a
same/similar-named command or file-based help entry.</p>
</section>
<section id="locking-help-entries">
<h2>Locking help entries<a class="headerlink" href="#locking-help-entries" title="Permalink to this headline"></a></h2>
<p>The default <code class="docutils literal notranslate"><span class="pre">help</span></code> command gather all available commands and help entries
together so they can be searched or listed. By setting locks on the command/help
entry one can limit who can read help about it.</p>
<ul class="simple">
<li><p>Commands failing the normal <code class="docutils literal notranslate"><span class="pre">cmd</span></code>-lock will be removed before even getting
to the help command. In this case the other two lock types below are ignored.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">view</span></code> access type determines if the command/help entry should be visible in
the main help index. If not given, it is assumed everyone can view.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">read</span></code> access type determines if the command/help entry can be actually read.
If a <code class="docutils literal notranslate"><span class="pre">read</span></code> lock is given and <code class="docutils literal notranslate"><span class="pre">view</span></code> is not, the <code class="docutils literal notranslate"><span class="pre">read</span></code>-lock is assumed to
apply to <code class="docutils literal notranslate"><span class="pre">view</span></code>-access as well (so if you cant read the help entry it will
also not show up in the index). If <code class="docutils literal notranslate"><span class="pre">read</span></code>-lock is not given, its assume
everyone can read the help entry.</p></li>
</ul>
<p>For Commands you set the help-related locks the same way you would any lock:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyCommand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> &lt;docstring for command&gt;</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="c1"># everyone can use the command, builders can view it in the help index</span>
<span class="c1"># but only devs can actually read the help (a weird setup for sure!)</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;cmd:all();view:perm(Builders);read:perm(Developers)</span>
</pre></div>
</div>
<p>Db-help entries and File-Help entries work the same way (except the <code class="docutils literal notranslate"><span class="pre">cmd</span></code>-type
lock is not used. A file-help example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">help_entry</span> <span class="o">=</span> <span class="p">{</span>
<span class="c1"># ...</span>
<span class="n">locks</span> <span class="o">=</span> <span class="s2">&quot;read:perm(Developer)&quot;</span><span class="p">,</span>
<span class="c1"># ...</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>Changed the old view lock to control the help-index inclusion and added
the new read lock-type to control access to the entry itself.</p>
</div>
</section>
<section id="customizing-the-look-of-the-help-system">
<h2>Customizing the look of the help system<a class="headerlink" href="#customizing-the-look-of-the-help-system" title="Permalink to this headline"></a></h2>
<p>This is done almost exclusively by overriding the <code class="docutils literal notranslate"><span class="pre">help</span></code> command
<a class="reference internal" href="../api/evennia.commands.default.help.html#evennia.commands.default.help.CmdHelp" title="evennia.commands.default.help.CmdHelp"><span class="xref myst py py-class">evennia.commands.default.help.CmdHelp</span></a>.</p>
<p>Since the available commands may vary from moment to moment, <code class="docutils literal notranslate"><span class="pre">help</span></code> is
responsible for collating the three sources of help-entries (commands/db/file)
together and search through them on the fly. It also does all the formatting of
the output.</p>
<p>To make it easier to tweak the look, the parts of the code that changes the
visual presentation and entity searching has been broken out into separate
methods on the command class. Override these in your version of <code class="docutils literal notranslate"><span class="pre">help</span></code> to change
the display or tweak as you please. See the api link above for details.</p>
</section>
<section id="technical-notes">
<h2>Technical notes<a class="headerlink" href="#technical-notes" title="Permalink to this headline"></a></h2>
<p>Since it needs to search so different types of data, the help system has to
collect all possibilities in memory before searching through the entire set. It
uses the <a class="reference external" href="https://github.com/yeraydiazdiaz/lunr.py">Lunr</a> search engine to
search through the main bulk of help entries. Lunr is a mature engine used for
web-pages and produces much more sensible results than previous solutions.</p>
<p>Once the main entry has been found, subtopics are then searched with
simple <code class="docutils literal notranslate"><span class="pre">==</span></code>, <code class="docutils literal notranslate"><span class="pre">startswith</span></code> and <code class="docutils literal notranslate"><span class="pre">in</span></code> matching (there are so relatively few of them
at that point).</p>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>Replaced the old bag-of-words algorithm with lunr package.</p>
</div>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Permissions.html" title="Permissions"
>next</a> |</li>
<li class="right" >
<a href="Prototypes.html" title="Spawner and Prototypes"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Help System</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,334 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Outputfuncs" href="Outputfuncs.html" />
<link rel="prev" title="Portal And Server" href="Portal-And-Server.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Outputfuncs.html" title="Outputfuncs"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Portal-And-Server.html" title="Portal And Server"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Inputfuncs</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Portal-And-Server.html"
title="previous chapter">Portal And Server</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Outputfuncs.html"
title="next chapter">Outputfuncs</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Inputfuncs.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="inputfuncs">
<h1>Inputfuncs<a class="headerlink" href="#inputfuncs" title="Permalink to this headline"></a></h1>
<p>An <em>inputfunc</em> is an Evennia function that handles a particular input (an <a class="reference internal" href="../Concepts/OOB.html"><span class="doc std std-doc">inputcommand</span></a>) from
the client. The inputfunc is the last destination for the inputcommand along the <a class="reference internal" href="../Concepts/Messagepath.html#the-ingoing-message-path"><span class="std std-doc">ingoing message
path</span></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"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">commandname</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>Or, if no match was found, it will call an inputfunc named “default” on this form</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">default</span><span class="p">(</span><span class="n">session</span><span class="p">,</span> <span class="n">cmdname</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># cmdname is the name of the mismatched inputcommand</span>
</pre></div>
</div>
<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>
</section>
<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>
<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 std std-doc">Command</span></a>, this inputfunc will do things like nick-replacement
and then pass on the input to the central Commandhandler.</p>
</section>
<section id="echo">
<h3>echo<a class="headerlink" href="#echo" title="Permalink to this headline"></a></h3>
<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>
</section>
<section id="default">
<h3>default<a class="headerlink" href="#default" title="Permalink to this headline"></a></h3>
<p>The default function, as mentioned above, absorbs all non-recognized inputcommands. The default one
will just log an error.</p>
</section>
<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>
</section>
<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>
</section>
<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>
</section>
<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>
</section>
<section id="get-value">
<h3>get_value<a class="headerlink" href="#get-value" title="Permalink to this headline"></a></h3>
<p>Input: <code class="docutils literal notranslate"><span class="pre">(&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>
</section>
<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;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#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 std std-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>
</section>
<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;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#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>
</section>
<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 std std-doc">MonitorHandler</span></a> behind the scenes. Pass the “stop” key to stop monitoring. Note
that you must supply the name also when stopping to let the system know which monitor should be
cancelled.</p>
<p>Only fields/attributes in a whitelist are allowed to be used, you have to overload this function to
add more. By default the following fields/attributes can be monitored:</p>
<ul class="simple">
<li><p>“name”: The current character name</p></li>
<li><p>“location”: The current location</p></li>
<li><p>“desc”: The description Argument</p></li>
</ul>
</section>
</section>
<section id="unmonitor">
<h2>unmonitor<a class="headerlink" href="#unmonitor" title="Permalink to this headline"></a></h2>
<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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Outputfuncs.html" title="Outputfuncs"
>next</a> |</li>
<li class="right" >
<a href="Portal-And-Server.html" title="Portal And Server"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Inputfuncs</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,525 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Signals" href="Signals.html" />
<link rel="prev" title="TickerHandler" href="TickerHandler.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Signals.html" title="Signals"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="TickerHandler.html" title="TickerHandler"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Locks</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<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-djangos-permission-system">On Djangos permission system</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="TickerHandler.html"
title="previous chapter">TickerHandler</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Signals.html"
title="next chapter">Signals</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Locks.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Locks.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="locks">
<h1>Locks<a class="headerlink" href="#locks" title="Permalink to this headline"></a></h1>
<p>For most games it is a good idea to restrict what people can do. In Evennia such restrictions are
applied and checked by something called <em>locks</em>. All Evennia entities (<a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a>,
<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Help-System.html"><span class="doc std std-doc">Help System</span></a>,
<a class="reference internal" href="Msg.html"><span class="doc std std-doc">messages</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">channels</span></a>) are accessed through locks.</p>
<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>
<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-none notranslate"><div class="highlight"><pre><span></span> &gt; lock obj = &lt;lockstring&gt;
</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"><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>
</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"><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>
</div>
</section>
<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"><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>
</div>
<p>Formally, a lockstring has the following syntax:</p>
<div class="highlight-python notranslate"><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>
</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-none notranslate"><div class="highlight"><pre><span></span>delete:id(34);edit:all();get: not attr(very_weak) or perm(Admin)
</pre></div>
</div>
<section 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 std std-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 std std-doc">Objects</span></a>:</p>
<ul>
<li><p><code class="docutils literal notranslate"><span class="pre">control</span></code> - who is the “owner” of the object. Can set locks, delete it etc. Defaults to the
creator of the object.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">call</span></code> - who may call Object-commands stored on this Object except for the Object itself. By
default, Objects share their Commands with anyone in the same location (e.g. so you can press a
<code class="docutils literal notranslate"><span class="pre">Button</span></code> object in the room). For Characters and Mobs (who likely only use those Commands for
themselves and 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 in descriptions
and if you will be able to see its description. Note that if
you target it specifically by name, the system will still find it, just
not be able to look at it. See <code class="docutils literal notranslate"><span class="pre">search</span></code> lock to completely hide the item.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">search</span></code> - this controls if the object can be found with the
<code class="docutils literal notranslate"><span class="pre">DefaultObject.search</span></code> method (usually referred to with <code class="docutils literal notranslate"><span class="pre">caller.search</span></code>
in Commands). This is how to create entirely undetectable in-game objects.
If not setting this lock excplicitly, all objects are assumed searchable.
Note that if you are aiming to make some _permanently invisible game system,
using a <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Script</span></a> is a better bet.</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 internal" href="Objects.html#characters"><span class="std std-doc">Characters</span></a>:</p>
<ul>
<li><p>Same as for Objects</p></li>
</ul>
</li>
<li><p><a class="reference internal" href="Objects.html#exits"><span class="std std-doc">Exits</span></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 std std-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 std std-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 internal" href="Channels.html"><span class="doc std std-doc">Channels</span></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 std std-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>
</section>
<section id="custom-access-types">
<h3>Custom access_types<a class="headerlink" href="#custom-access-types" title="Permalink to this headline"></a></h3>
<p>As stated above, the <code class="docutils literal notranslate"><span class="pre">access_type</span></code> part of the lock is simply the name or type of the lock. The
text is an arbitrary string that must be unique for an object. If adding a lock with the same
<code class="docutils literal notranslate"><span class="pre">access_type</span></code> as one that already exists on the object, the new one override the old one.</p>
<p>For example, if you wanted to create a bulletin board system and wanted to restrict who can either
read a board or post to a board. You could then define locks such as:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">obj</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;read:perm(Player);post:perm(Admin)&quot;</span><span class="p">)</span>
</pre></div>
</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"><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>
</div>
</section>
<section id="lock-functions">
<h3>Lock functions<a class="headerlink" href="#lock-functions" title="Permalink to this headline"></a></h3>
<p>A lock function is a normal Python function put in a place Evennia looks for such functions. The
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"><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="kc">False</span>
</pre></div>
</div>
<p>The above could for example be used in a lock function like this:</p>
<div class="highlight-python notranslate"><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="sa">f</span><span class="s2">&quot;edit: id(</span><span class="si">{</span><span class="n">owner_object</span><span class="o">.</span><span class="n">id</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>We could check if the “edit” lock is passed with something like this:</p>
<div class="highlight-python notranslate"><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>
</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 internal" href="Permissions.html"><span class="doc std std-doc">below</span></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 std std-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>
</section>
</section>
<section id="checking-simple-strings">
<h2>Checking simple strings<a class="headerlink" href="#checking-simple-strings" title="Permalink to this headline"></a></h2>
<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"><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>
</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>
</section>
<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 std std-doc">Typeclasses</span></a>
of the respective entity, in the hook method <code class="docutils literal notranslate"><span class="pre">basetype_setup()</span></code> (which you usually 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>
</section>
<section id="more-lock-definition-examples">
<h2>More Lock definition examples<a class="headerlink" href="#more-lock-definition-examples" title="Permalink to this headline"></a></h2>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>examine: attr(eyesight, excellent) or perm(Builders)
</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-none notranslate"><div class="highlight"><pre><span></span>open: holds(&#39;the green key&#39;) or perm(Builder)
</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-none notranslate"><div class="highlight"><pre><span></span>cmd: perm(Builders)
</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-none notranslate"><div class="highlight"><pre><span></span>cmd: not perm(no_tell)
</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"><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>
</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>
</section>
<section id="a-complete-example-of-setting-locks-on-an-object">
<h2>A complete example of setting locks on an object<a class="headerlink" href="#a-complete-example-of-setting-locks-on-an-object" title="Permalink to this headline"></a></h2>
<p>Assume we have two objects - one is ourselves (not superuser) and the other is an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a>
called <code class="docutils literal notranslate"><span class="pre">box</span></code>.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; create/drop box
&gt; desc box = &quot;This is a very big and heavy box.&quot;
</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-none notranslate"><div class="highlight"><pre><span></span> &gt; set self/strength = 45
</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"><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>
</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 std std-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-none notranslate"><div class="highlight"><pre><span></span> &gt; set box/get_err_msg = You are not strong enough to lift this box.
</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-none notranslate"><div class="highlight"><pre><span></span> lock box = get:attr_gt(strength, 50)
</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"><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="kc">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="kc">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>
</div>
</section>
<section id="on-djangos-permission-system">
<h2>On Djangos permission system<a class="headerlink" href="#on-djangos-permission-system" title="Permalink to this headline"></a></h2>
<p>Django also implements a comprehensive permission/security system of its own. The reason we 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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Signals.html" title="Signals"
>next</a> |</li>
<li class="right" >
<a href="TickerHandler.html" title="TickerHandler"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Locks</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,208 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="TickerHandler" href="TickerHandler.html" />
<link rel="prev" title="The Inline Function Parser" href="FuncParser.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="TickerHandler.html" title="TickerHandler"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="FuncParser.html" title="The Inline Function Parser"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">MonitorHandler</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">MonitorHandler</a><ul>
<li><a class="reference internal" href="#using-the-monitorhandler">Using the MonitorHandler</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="FuncParser.html"
title="previous chapter">The Inline Function Parser</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="TickerHandler.html"
title="next chapter">TickerHandler</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="MonitorHandler.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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>
<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"><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="kc">False</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</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 std std-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 std std-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 std std-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"><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="kc">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="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">fieldname</span><span class="si">}</span><span class="s2"> changed to &#39;</span><span class="si">{</span><span class="n">new_value</span><span class="si">}</span><span class="s2">&#39;.&quot;</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>
</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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="TickerHandler.html" title="TickerHandler"
>next</a> |</li>
<li class="right" >
<a href="FuncParser.html" title="The Inline Function Parser"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">MonitorHandler</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.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" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Msg &#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" />
<link rel="next" title="Attributes" href="Attributes.html" />
<link rel="prev" title="Channels" href="Channels.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Attributes.html" title="Attributes"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Channels.html" title="Channels"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Msg</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Msg</a><ul>
<li><a class="reference internal" href="#msg-in-code">Msg in code</a><ul>
<li><a class="reference internal" href="#properties-on-msg">Properties on Msg</a></li>
</ul>
</li>
<li><a class="reference internal" href="#tempmsg">TempMsg</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Channels.html"
title="previous chapter">Channels</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Attributes.html"
title="next chapter">Attributes</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Msg.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Msg.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="msg">
<h1>Msg<a class="headerlink" href="#msg" title="Permalink to this headline"></a></h1>
<p>The <a class="reference internal" href="../api/evennia.comms.models.html#evennia.comms.models.Msg" title="evennia.comms.models.Msg"><span class="xref myst py py-class">Msg</span></a> object represents a database-saved
piece of communication. Think of it as a discrete piece of email - it contains
a message, some metadata and will always have a sender and one or more
recipients.</p>
<p>Once created, a Msg is normally not changed. It is persitently saved in the
database. This allows for comprehensive logging of communications. Here are some
good uses for <code class="docutils literal notranslate"><span class="pre">Msg</span></code> objects:</p>
<ul class="simple">
<li><p>page/tells (the <code class="docutils literal notranslate"><span class="pre">page</span></code> command is how Evennia uses them out of the box)</p></li>
<li><p>messages in a bulletin board</p></li>
<li><p>game-wide email stored in mailboxes.</p></li>
</ul>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>A <code class="docutils literal notranslate"><span class="pre">Msg</span></code> does not have any in-game representation. So if you want to use them
to represent in-game mail/letters, the physical letters would never be
visible in a room (possible to steal, spy on etc) unless you make your
spy-system access the Msgs directly (or go to the trouble of spawning an
actual in-game letter-object based on the Msg)</p>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>Channels dropped Msg-support. Now only used in <code class="docutils literal notranslate"><span class="pre">page</span></code> command by default.</p>
</div>
<section id="msg-in-code">
<h2>Msg in code<a class="headerlink" href="#msg-in-code" title="Permalink to this headline"></a></h2>
<p>The Msg is intended to be used exclusively in code, to build other game systems. It is <em>not</em>
a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entity, which means it cannot (easily) be overridden. It
doesnt support Attributes (but it <em>does</em> support <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a>). It tries to be lean
and small since a new one is created for every message.</p>
<p>You create a new message with <code class="docutils literal notranslate"><span class="pre">evennia.create_message</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_message</span>
<span class="n">message</span> <span class="o">=</span> <span class="n">create_message</span><span class="p">(</span><span class="n">senders</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="n">receivers</span><span class="p">,</span>
<span class="n">locks</span><span class="o">=...</span><span class="p">,</span> <span class="n">tags</span><span class="o">=...</span><span class="p">,</span> <span class="n">header</span><span class="o">=...</span><span class="p">)</span>
</pre></div>
</div>
<p>You can search for <code class="docutils literal notranslate"><span class="pre">Msg</span></code> objects in various ways:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">search_message</span><span class="p">,</span> <span class="n">Msg</span>
<span class="c1"># args are optional. Only a single sender/receiver should be passed</span>
<span class="n">messages</span> <span class="o">=</span> <span class="n">search_message</span><span class="p">(</span><span class="n">sender</span><span class="o">=...</span><span class="p">,</span> <span class="n">receiver</span><span class="o">=...</span><span class="p">,</span> <span class="n">freetext</span><span class="o">=...</span><span class="p">,</span> <span class="n">dbref</span><span class="o">=...</span><span class="p">)</span>
<span class="c1"># get all messages for a given sender/receiver</span>
<span class="n">messages</span> <span class="o">=</span> <span class="n">Msg</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_msg_by_sender</span><span class="p">(</span><span class="n">sender</span><span class="p">)</span>
<span class="n">messages</span> <span class="o">=</span> <span class="n">Msg</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_msg_by_receiver</span><span class="p">(</span><span class="n">recipient</span><span class="p">)</span>
</pre></div>
</div>
<section id="properties-on-msg">
<h3>Properties on Msg<a class="headerlink" href="#properties-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> - there must always be at least one sender. This is a set of</p></li>
<li><p><a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Script</span></a>
or <code class="docutils literal notranslate"><span class="pre">str</span></code> in any combination (but usually a message only targets one type).
Using a <code class="docutils literal notranslate"><span class="pre">str</span></code> for a sender indicates its an external sender and
and can be used to point to a sender that is not a typeclassed entity. This is not used by default
and what this would be depends on the system (it could be a unique id or a
python-path, for example). While most systems expect a single sender, its
possible to have any number of them.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">receivers</span></code> - these are the ones to see the Msg. These are again any combination of
<a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> or <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Script</span></a> or <code class="docutils literal notranslate"><span class="pre">str</span></code> (an external receiver).
Its in principle possible to have zero receivers but most usages of Msg expects one or more.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">header</span></code> - this is an optional text field that can contain meta-information about the message. For
an email-like system it would be the subject line. This can be independently searched, making
this a powerful place for quickly finding messages.</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> - this is auto-set to the time the Msg was created (and thus presumably sent).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> - the Evennia <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock handler</span></a>. Use with <code class="docutils literal notranslate"><span class="pre">locks.add()</span></code> etc and check locks with <code class="docutils literal notranslate"><span class="pre">msg.access()</span></code>
like for all other lockable entities. This can be used to limit access to the contents
of the Msg. The default lock-type to check is <code class="docutils literal notranslate"><span class="pre">'read'</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">hide_from</span></code> - this is an optional list of <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a> or <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> that
will not see this Msg. This relationship is available mainly for optimization
reasons since it allows quick filtering of messages not intended for a given
target.</p></li>
</ul>
</section>
</section>
<section id="tempmsg">
<h2>TempMsg<a class="headerlink" href="#tempmsg" title="Permalink to this headline"></a></h2>
<p><a class="reference internal" href="../api/evennia.comms.models.html#evennia.comms.models.TempMsg" title="evennia.comms.models.TempMsg"><span class="xref myst py py-class">evennia.comms.models.TempMsg</span></a> is an object
that implements the same API as the regular <code class="docutils literal notranslate"><span class="pre">Msg</span></code>, but which has no database
component (and thus cannot be searched). Its meant to plugged into systems
expecting a <code class="docutils literal notranslate"><span class="pre">Msg</span></code> but where you just want to process the message without saving
it.</p>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Attributes.html" title="Attributes"
>next</a> |</li>
<li class="right" >
<a href="Channels.html" title="Channels"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Msg</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,252 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Tags" href="Tags.html" />
<link rel="prev" title="Attributes" href="Attributes.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Tags.html" title="Tags"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Attributes.html" title="Attributes"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Nicks</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Nicks</a><ul>
<li><a class="reference internal" href="#coding-with-nicks">Coding with nicks</a></li>
<li><a class="reference internal" href="#advanced-note">Advanced note</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Attributes.html"
title="previous chapter">Attributes</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Tags.html"
title="next chapter">Tags</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Nicks.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-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-none notranslate"><div class="highlight"><pre><span></span> nick ls = look
</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-none notranslate"><div class="highlight"><pre><span></span> nick/object mycar2 = The red sports car
</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-none notranslate"><div class="highlight"><pre><span></span> look mycar2
</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-none notranslate"><div class="highlight"><pre><span></span> nick/accounts tom = Thomas Johnsson
</pre></div>
</div>
<p>This is useful for commands searching for accounts explicitly:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> @find *tom
</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-none notranslate"><div class="highlight"><pre><span></span> nick rb = @create button:examples.red_button.RedButton
</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-none notranslate"><div class="highlight"><pre><span></span> nick/account Arnold = The mysterious hooded man
</pre></div>
</div>
<p>The nick replacer also supports unix-style <em>templating</em>:</p>
<div class="highlight-none 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>
<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 std std-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"><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>
</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="Channels.html"><span class="doc std std-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>
</section>
<section id="advanced-note">
<h2>Advanced note<a class="headerlink" href="#advanced-note" title="Permalink to this headline"></a></h2>
<p>Internally, nicks are <a class="reference internal" href="Attributes.html"><span class="doc std std-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"><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="kc">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="kc">True</span><span class="p">)</span><span class="o">.</span><span class="n">value</span>
</pre></div>
</div>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Tags.html" title="Tags"
>next</a> |</li>
<li class="right" >
<a href="Attributes.html" title="Attributes"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Nicks</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,377 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Scripts" href="Scripts.html" />
<link rel="prev" title="Accounts" href="Accounts.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Scripts.html" title="Scripts"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Accounts.html" title="Accounts"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Objects</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Objects</a><ul>
<li><a class="reference internal" href="#how-to-create-your-own-object-types">How to create your own object types</a></li>
<li><a class="reference internal" href="#adding-common-functionality">Adding common functionality</a></li>
<li><a class="reference internal" href="#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>
<h4>Previous topic</h4>
<p class="topless"><a href="Accounts.html"
title="previous chapter">Accounts</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Scripts.html"
title="next chapter">Scripts</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Objects.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-doc">Typeclassed</span></a> entities.</p>
<p>An Evennia Object is, by definition, a Python class that includes
<a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject" title="evennia.objects.objects.DefaultObject"><span class="xref myst py py-class">evennia.objects.objects.DefaultObject</span></a> among its
parents. Evennia defines several subclasses of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>:</p>
<ul class="simple">
<li><p><a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultCharacter" title="evennia.objects.objects.DefaultCharacter"><span class="xref myst py py-class">evennia.objects.objects.DefaultCharacter</span></a> -
the normal in-game Character, controlled by a player.</p></li>
<li><p><a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom" title="evennia.objects.objects.DefaultRoom"><span class="xref myst py py-class">evennia.objects.objects.DefaultRoom</span></a> - a location in the game world.</p></li>
<li><p><a class="reference internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultExit" title="evennia.objects.objects.DefaultExit"><span class="xref myst py py-class">evennia.objects.objects.DefaultExit</span></a> - an entity that (usually) sits
in a room and represents a one-way connection to another location.</p></li>
</ul>
<p>You will usually not use the <code class="docutils literal notranslate"><span class="pre">Default*</span></code> parents themselves. In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/</span></code> there are
convenient subclasses to use. They are empty, and thus identical to
the defaults. Tweaking them is one of the main ways to customize you game!</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.objects.Object</span></code> (inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.characters.Character</span></code> (inherits from <code class="docutils literal notranslate"><span class="pre">DefaultCharacter</span></code>)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.rooms.Room</span></code> (inherits from <code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code>)</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.exits.Exit</span></code> (inherits from <code class="docutils literal notranslate"><span class="pre">DefaultExit</span></code>)</p></li>
</ul>
<section id="how-to-create-your-own-object-types">
<h2>How to create your own object types<a class="headerlink" href="#how-to-create-your-own-object-types" title="Permalink to this headline"></a></h2>
<p>You can easily add your own in-game behavior by either modifying one of the typeclasses in
your game dir or by inheriting from them.</p>
<p>You can put your new typeclass directly in the relevant parent
module, or you could organize your code in some other way. Here we assume we make a new module
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/flowers.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># mygame/typeclasses/flowers.py</span>
<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>
</div>
<p>Now you just need to point to the class <em>Rose</em> with the <code class="docutils literal notranslate"><span class="pre">create</span></code> command
to make a new rose:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> @create/drop MyRose:flowers.Rose
</pre></div>
</div>
<p>What the <code class="docutils literal notranslate"><span class="pre">create</span></code> command actually <em>does</em> is to use the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_object" title="evennia.utils.create.create_object"><span class="xref myst py py-func">evennia.create_object</span></a>
function. You can do the same thing yourself in code:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">create_object</span>
<span class="n">new_rose</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="s2">&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>
</div>
<p>(The <code class="docutils literal notranslate"><span class="pre">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).</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">desc</span></code> command or using the
<a class="reference internal" href="Prototypes.html"><span class="doc std std-doc">Spawner</span></a>).</p>
</section>
<section id="adding-common-functionality">
<h2>Adding common functionality<a class="headerlink" href="#adding-common-functionality" title="Permalink to this headline"></a></h2>
<p><code class="docutils literal notranslate"><span class="pre">Object</span></code>, <code class="docutils literal notranslate"><span class="pre">Character</span></code>, <code class="docutils literal notranslate"><span class="pre">Room</span></code> and <code class="docutils literal notranslate"><span class="pre">Exit</span></code> also inherit from <code class="docutils literal notranslate"><span class="pre">mygame.typeclasses.objects.ObjectParent</span></code>.
This is an empty mixin class. Optionally, you can modify this class if you want to easily add some <em>common</em> functionality to all
your Objects, Characters, Rooms and Exits at once. You can still customize each subclass separately (see the Python
docs on <a class="reference external" href="https://docs.python.org/3/tutorial/classes.html#multiple-inheritance">multiple inheritance</a> for details).</p>
<p>For example:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/objects.py</span>
<span class="c1"># ... </span>
<span class="kn">from</span> <span class="nn">evennia.objects.objects</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
<span class="k">class</span> <span class="nc">ObjectParent</span><span class="p">:</span>
<span class="k">def</span> <span class="nf">at_pre_get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">getter</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="c1"># make all entities by default un-pickable</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">class</span> <span class="nc">Object</span><span class="p">(</span><span class="n">ObjectParent</span><span class="p">,</span> <span class="n">DefaultObject</span><span class="p">):</span>
<span class="c1"># replaces at_pre_get with its own</span>
<span class="k">def</span> <span class="nf">at_pre_get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">getter</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">True</span>
<span class="c1"># each in their respective modules ...</span>
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">ObjectParent</span><span class="p">,</span> <span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="c1"># will inherit at_pre_get from ObjectParent</span>
<span class="k">pass</span>
<span class="k">class</span> <span class="nc">Exit</span><span class="p">(</span><span class="n">ObjectParent</span><span class="p">,</span> <span class="n">DefaultExit</span><span class="p">):</span>
<span class="c1"># Overrides and uses the DefaultExit version of at_pre_get instead</span>
<span class="k">def</span> <span class="nf">at_pre_get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">getter</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="k">return</span> <span class="n">DefaultExit</span><span class="o">.</span><span class="n">at_pre_get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">getter</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
</pre></div>
</div>
</section>
<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 std std-doc">typeclassed</span></a> objects (see that page for a list
of those), the Object also has the following custom properties:</p>
<ul class="simple">
<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 internal" href="#exits"><span class="std std-doc">Exits</span></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 std std-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 std std-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 internal" href="Command-Sets.html"><span class="doc std std-doc">command sets</span></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 std std-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 internal" href="#exits"><span class="std std-doc">Exits</span></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 internal" href="../api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject" title="evennia.objects.objects.DefaultObject"><span class="xref myst py py-class">API for DefaultObject here</span></a>.</p>
</section>
<section id="subclasses-of-object">
<h2>Subclasses of <code class="docutils literal notranslate"><span class="pre">Object</span></code><a class="headerlink" href="#subclasses-of-object" title="Permalink to this headline"></a></h2>
<p>There are three special subclasses of <em>Object</em> in default Evennia - <em>Characters</em>, <em>Rooms</em> and
<em>Exits</em>. The reason they are separated is because these particular object types are fundamental,
something you will always need and in some cases requires some extra attention in order to be
recognized by the game engine (there is nothing stopping you from redefining them though). In
practice they are all pretty similar to the base Object.</p>
<section id="characters">
<h3>Characters<a class="headerlink" href="#characters" title="Permalink to this headline"></a></h3>
<p>Characters are objects controlled by <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>. When a new Account
logs in to Evennia for the first time, a new <code class="docutils literal notranslate"><span class="pre">Character</span></code> object is created and
the Account object is assigned to the <code class="docutils literal notranslate"><span class="pre">account</span></code> attribute. A <code class="docutils literal notranslate"><span class="pre">Character</span></code> object
must have a <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Default Commandset</span></a> set on itself at
creation, or the account will not be able to issue any commands! If you just
inherit your own class from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultCharacter</span></code> and make sure to use
<code class="docutils literal notranslate"><span class="pre">super()</span></code> to call the parent methods you should be fine. In
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> is an empty <code class="docutils literal notranslate"><span class="pre">Character</span></code> class ready for you
to modify.</p>
</section>
<section id="rooms">
<h3>Rooms<a class="headerlink" href="#rooms" title="Permalink to this headline"></a></h3>
<p><em>Rooms</em> are the root containers of all other objects. The only thing really separating a room from
any other object is that they have no <code class="docutils literal notranslate"><span class="pre">location</span></code> of their own and that default commands like <code class="docutils literal notranslate"><span class="pre">&#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>
</section>
<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 std std-doc">Transit Command</span></a> on themselves when they are created. This command is
named the same as the exit object and will, when called, handle the practicalities of moving the
character to the 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 std std-doc">locked</span></a> using an access_type called <em>traverse</em> and also make use of a few
hook methods for giving feedback if the traversal fails. See <code class="docutils literal notranslate"><span class="pre">evennia.DefaultExit</span></code> for more info.
In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/exits.py</span></code> there is an empty <code class="docutils literal notranslate"><span class="pre">Exit</span></code> class for you to modify.</p>
<p>The process of traversing an exit is as follows:</p>
<ol class="simple">
<li><p>The traversing <code class="docutils literal notranslate"><span class="pre">obj</span></code> sends a command that matches the Exit-command name on the Exit object. The
<a class="reference internal" href="Commands.html"><span class="doc std std-doc">cmdhandler</span></a> detects this and triggers the command defined on the Exit. Traversal always
involves the “source” (the current location) and the <code class="docutils literal notranslate"><span class="pre">destination</span></code> (this is stored on the Exit
object).</p></li>
<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_pre_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_pre_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_post_move(source)</span></code></p></li>
</ol>
</li>
<li><p>On the Exit object, <code class="docutils literal notranslate"><span class="pre">at_post_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>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Scripts.html" title="Scripts"
>next</a> |</li>
<li class="right" >
<a href="Accounts.html" title="Accounts"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Objects</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,134 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Server component" href="Server.html" />
<link rel="prev" title="Inputfuncs" href="Inputfuncs.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Server.html" title="Server component"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Inputfuncs.html" title="Inputfuncs"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Outputfuncs</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="Inputfuncs.html"
title="previous chapter">Inputfuncs</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Server.html"
title="next chapter">Server component</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Outputfuncs.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-doc">OOB</span></a>.</p>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Server.html" title="Server component"
>next</a> |</li>
<li class="right" >
<a href="Inputfuncs.html" title="Inputfuncs"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Outputfuncs</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,336 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Permissions &#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" />
<link rel="next" title="Command System" href="Command-System.html" />
<link rel="prev" title="Help System" href="Help-System.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Command-System.html" title="Command System"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Help-System.html" title="Help System"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Permissions</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Permissions</a><ul>
<li><a class="reference internal" href="#managing-permissions">Managing Permissions</a></li>
<li><a class="reference internal" href="#the-permission-hierarchy">The permission hierarchy</a></li>
<li><a class="reference internal" href="#checking-permissions">Checking permissions</a><ul>
<li><a class="reference internal" href="#checking-with-obj-permissions-check">Checking with obj.permissions.check()</a></li>
<li><a class="reference internal" href="#lock-funcs">Lock funcs</a></li>
<li><a class="reference internal" href="#some-examples">Some examples</a></li>
</ul>
</li>
<li><a class="reference internal" href="#superusers">Superusers</a></li>
<li><a class="reference internal" href="#quelling">Quelling</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Help-System.html"
title="previous chapter">Help System</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Command-System.html"
title="next chapter">Command System</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Permissions.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Permissions.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="permissions">
<h1>Permissions<a class="headerlink" href="#permissions" title="Permalink to this headline"></a></h1>
<p>A <em>permission</em> is simply a text string 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>. Think of it as a specialized sort of <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tag</span></a> - one specifically dedicated
to access checking. They are thus often tightly coupled to <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Locks</span></a>.
Permission strings are not case-sensitive, so “Builder” is the same as “builder”
etc.</p>
<p>Permissions are 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 and checked by the
<code class="docutils literal notranslate"><span class="pre">PermissionHandler.check</span></code> method as well as by the specially the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> and
<code class="docutils literal notranslate"><span class="pre">pperm()</span></code> <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock functions</span></a>.</p>
<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>
<section id="managing-permissions">
<h2>Managing Permissions<a class="headerlink" href="#managing-permissions" title="Permalink to this headline"></a></h2>
<p>In-game, you use the <code class="docutils literal notranslate"><span class="pre">perm</span></code> command to add and remove permissions
j
perm/account Tommy = Builders
perm/account/del Tommy = Builders</p>
<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 std std-doc">Accounts</span></a> Tommy instead of any <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Character</span></a> that also
happens to be named “Tommy”.</p>
<p>There can be reasons for putting permissions on Objects (especially NPCS), but
for granting powers to players, you should usually put the permission on the
<code class="docutils literal notranslate"><span class="pre">Account</span></code> - this 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> (see below), as 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 internal" href="#quelling"><span class="std std-doc">quelling</span></a>).</p>
<p>In code, you add/remove Permissions via the <code class="docutils literal notranslate"><span class="pre">PermissionHandler</span></code>, which sits on all
typeclassed entities as the property <code class="docutils literal notranslate"><span class="pre">.permissions</span></code>:</p>
<div class="highlight-python notranslate"><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;Builders&quot;</span><span class="p">)</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;cool_guy&quot;</span><span class="p">)</span>
<span class="n">obj</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;Blacksmith&quot;</span><span class="p">)</span>
<span class="n">obj</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">&quot;Blacksmith&quot;</span><span class="p">)</span>
</pre></div>
</div>
</section>
<section id="the-permission-hierarchy">
<h2>The permission hierarchy<a class="headerlink" href="#the-permission-hierarchy" title="Permalink to this headline"></a></h2>
<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
(in increasing order of power):</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> Player # can chat and send tells (default level) (lowest)
Helper # can edit help files
Builder # can edit the world
Admin # can administrate accounts
Developer # like superuser but affected by locks (highest)
</pre></div>
</div>
<p>(Besides being case-insensitive, hierarchical permissions also understand the
plural form, so you could use <code class="docutils literal notranslate"><span class="pre">Developers</span></code> and <code class="docutils literal notranslate"><span class="pre">Developer</span></code> interchangeably).</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. The Guest is is never part of <code class="docutils literal notranslate"><span class="pre">settings.PERMISSION_HIERARCHY</span></code>.</p>
</div></blockquote>
<p>When checking a hierarchical permission (using one of the methods to follow),
you will pass checks for your level and all <em>below</em> you. That is, even if the
check explicitly checks for “Builder” level access, you will actually pass if you have
one of “Builder”, “Admin” or “Developer”. By contrast, if you check for a
non-hierarchical permission, like “Blacksmith” you <em>must</em> have exactly
that permission to pass.</p>
</section>
<section id="checking-permissions">
<h2>Checking permissions<a class="headerlink" href="#checking-permissions" title="Permalink to this headline"></a></h2>
<p>Its important to note that you check for the permission of a <em>puppeted</em>
<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> (like a Character), the check will always first use the
permissions of any <code class="docutils literal notranslate"><span class="pre">Account</span></code> connected to that Object before checking for
permissions on the Object. In the case of hierarchical permissions (Admins,
Builders etc), the Account permission will always be used (this stops an Account
from escalating their permission by puppeting a high-level Character). If the
permission looked for is not in the hierarchy, an exact match is required, first
on the Account and if not found there (or if no Account is connected), then on
the Object itself.</p>
<section id="checking-with-obj-permissions-check">
<h3>Checking with obj.permissions.check()<a class="headerlink" href="#checking-with-obj-permissions-check" title="Permalink to this headline"></a></h3>
<p>The simplest way to check if an entity has a permission is to check its
<em>PermissionHandler</em>, stored as <code class="docutils literal notranslate"><span class="pre">.permissions</span></code> on all typeclassed entities.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>if obj.permissions.check(&quot;Builder&quot;):
# allow builder to do stuff
if obj.permissions.check(&quot;Blacksmith&quot;, &quot;Warrior&quot;):
# do stuff for blacksmiths OR warriors
if obj.permissions.check(&quot;Blacksmith&quot;, &quot;Warrior&quot;, require_all=True):
# only for those that are both blacksmiths AND warriors
</pre></div>
</div>
<p>Using the <code class="docutils literal notranslate"><span class="pre">.check</span></code> method is the way to go, it will take hierarchical
permissions into account, check accounts/sessions etc.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Don&#39;t confuse `.permissions.check()` with `.permissions.has()`. The .has()
method checks if a string is defined specifically on that PermissionHandler.
It will not consider permission-hierarchy, puppeting etc. `.has` can be useful
if you are manipulating permissions, but use `.check` for access checking.
</pre></div>
</div>
</div>
</section>
<section id="lock-funcs">
<h3>Lock funcs<a class="headerlink" href="#lock-funcs" title="Permalink to this headline"></a></h3>
<p>While the <code class="docutils literal notranslate"><span class="pre">PermissionHandler</span></code> offers a simple way to check perms, <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Lock
strings</span></a> offers a mini-language for describing how something is accessed.
The <code class="docutils literal notranslate"><span class="pre">perm()</span></code> <em>lock function</em> is the main tool for using Permissions in locks.</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-none notranslate"><div class="highlight"><pre><span></span>perm red_key = unlocks_red_chests
</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-none notranslate"><div class="highlight"><pre><span></span>lock red chest = unlock:perm(unlocks_red_chests)
</pre></div>
</div>
<p>When trying to unlock the red chest with this key, the chest Typeclass could
then take the key and do an access check:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in some typeclass file where chest is defined</span>
<span class="k">class</span> <span class="nc">TreasureChest</span><span class="p">(</span><span class="n">Object</span><span class="p">):</span>
<span class="c1"># ...</span>
<span class="k">def</span> <span class="nf">open_chest</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">who</span><span class="p">,</span> <span class="n">tried_key</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">chest</span><span class="o">.</span><span class="n">access</span><span class="p">(</span><span class="n">who</span><span class="p">,</span> <span class="n">tried_key</span><span class="p">,</span> <span class="s2">&quot;unlock&quot;</span><span class="p">):</span>
<span class="n">who</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>
<span class="k">else</span><span class="p">:</span>
<span class="n">who</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;The key fits! The chest opens.&quot;</span><span class="p">)</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>There are several variations to the default <code class="docutils literal notranslate"><span class="pre">perm</span></code> lockfunc:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">perm_above</span></code> - requires a hierarchical permission <em>higher</em> than the one
provided. Example: <code class="docutils literal notranslate"><span class="pre">&quot;edit:</span> <span class="pre">perm_above(Player)&quot;</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pperm</span></code> - looks <em>only</em> for permissions on <code class="docutils literal notranslate"><span class="pre">Accounts</span></code>, never at any puppeted
objects (regardless of hierarchical perm or not).</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">pperm_above</span></code> - like <code class="docutils literal notranslate"><span class="pre">perm_above</span></code>, but for Accounts only.</p></li>
</ul>
</section>
<section id="some-examples">
<h3>Some examples<a class="headerlink" href="#some-examples" title="Permalink to this headline"></a></h3>
<p>Adding permissions and checking with locks</p>
<div class="highlight-python notranslate"><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;Builder&quot;</span><span class="p">)</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;cool_guy&quot;</span><span class="p">)</span>
<span class="n">account</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(Player) and perm(cool_guy)&quot;</span><span class="p">)</span>
<span class="n">account</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>
</div>
<p>An example of a puppet with a connected account:</p>
<div class="highlight-python notranslate"><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;Player&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="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;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, since puppet permission</span>
<span class="c1"># is lower than Account&#39;s perm, and perm takes</span>
<span class="c1"># precedence.</span>
</pre></div>
</div>
</section>
</section>
<section id="superusers">
<h2>Superusers<a class="headerlink" href="#superusers" title="Permalink to this headline"></a></h2>
<p>There is normally only one <em>superuser</em> account and that is the one first created
when starting Evennia (User #1). This is sometimes known as the “Owner” or “God”
user. A superuser has more than full access - it completely <em>bypasses</em> all
locks and will always pass the <code class="docutils literal notranslate"><span class="pre">PermissionHandler.check()</span></code> check. This allows
for the superuser to always have access to everything in an emergency. But it
could also hide any eventual errors you might have made in your lock definitions. So
when trying out game systems you should either use quelling (see below) or make
a second Developer-level character that does not bypass such checks.</p>
</section>
<section id="quelling">
<h2>Quelling<a class="headerlink" href="#quelling" title="Permalink to this headline"></a></h2>
<p>The <code class="docutils literal notranslate"><span class="pre">quell</span></code> command can be used to enforce the <code class="docutils literal notranslate"><span class="pre">perm()</span></code> lockfunc to ignore
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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Command-System.html" title="Command System"
>next</a> |</li>
<li class="right" >
<a href="Help-System.html" title="Help System"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Permissions</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,142 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Inputfuncs" href="Inputfuncs.html" />
<link rel="prev" title="The Web Admin" href="Web-Admin.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Inputfuncs.html" title="Inputfuncs"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Web-Admin.html" title="The Web Admin"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Portal And Server</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="Web-Admin.html"
title="previous chapter">The Web Admin</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Inputfuncs.html"
title="next chapter">Inputfuncs</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Portal-And-Server.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Portal-And-Server.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-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-
<a class="reference external" href="http://sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia_server_portal.png">sites.googlegroups.com/site/evenniaserver/file-cabinet/evennia_server_portal.png</a>)</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>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Inputfuncs.html" title="Inputfuncs"
>next</a> |</li>
<li class="right" >
<a href="Web-Admin.html" title="The Web Admin"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Portal And Server</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,508 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Help System" href="Help-System.html" />
<link rel="prev" title="Tags" href="Tags.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Help-System.html" title="Help System"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Tags.html" title="Tags"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Spawner and Prototypes</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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><ul>
<li><a class="reference internal" href="#more-on-prototype-inheritance">More on prototype inheritance</a></li>
</ul>
</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>
<h4>Previous topic</h4>
<p class="topless"><a href="Tags.html"
title="previous chapter">Tags</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Help-System.html"
title="next chapter">Help System</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Prototypes.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Prototypes.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="spawner-and-prototypes">
<h1>Spawner and Prototypes<a class="headerlink" href="#spawner-and-prototypes" title="Permalink to this headline"></a></h1>
<p>The <em>spawner</em> is a system for defining and creating individual objects from a base template called a
<em>prototype</em>. It is only designed for use with in-game <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, not any other type of
entity.</p>
<p>The normal way to create a custom object in Evennia is to make a <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclass</span></a>. If you
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>
<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>
</section>
<section id="the-prototype">
<h2>The prototype<a class="headerlink" href="#the-prototype" title="Permalink to this headline"></a></h2>
<p>The prototype dictionary can either be created for you by the OLC (see above), be written manually
in a Python module (and then referenced by the <code class="docutils literal notranslate"><span class="pre">&#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"><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>
</div>
<p>If you wanted to load it into the spawner in-game you could just put all on one line:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@spawn {&quot;prototype_key=&quot;house&quot;, &quot;key&quot;: &quot;Large house&quot;, ...}
</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>
<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, used for referencing the prototype
when spawning and inheritance. If defining a prototype in a module and this
not set, it will be auto-set to the name of the prototypes variable in the module.</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 std std-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 std std-doc">Tags</span></a>. These are given as tuples <code class="docutils literal notranslate"><span class="pre">(tag,</span> <span class="pre">category,</span> <span class="pre">data)</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">attrs</span></code> - list of <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>. These are given as tuples <code class="docutils literal notranslate"><span class="pre">(attrname,</span> <span class="pre">value,</span> <span class="pre">category,</span> <span class="pre">lockstring)</span></code></p></li>
<li><p>Any other keywords are interpreted as non-category <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and their values.
This is convenient for simple Attributes - use <code class="docutils literal notranslate"><span class="pre">attrs</span></code> for full control of Attributes.</p></li>
</ul>
<section id="more-on-prototype-inheritance">
<h4>More on prototype inheritance<a class="headerlink" href="#more-on-prototype-inheritance" title="Permalink to this headline"></a></h4>
<ul class="simple">
<li><p>A prototype can inherit by defining a <code class="docutils literal notranslate"><span class="pre">prototype_parent</span></code> pointing to the name
(<code class="docutils literal notranslate"><span class="pre">prototype_key</span></code> of another prototype). If a list of <code class="docutils literal notranslate"><span class="pre">prototype_keys</span></code>, this
will be stepped through from left to right, giving priority to the first in
the list over those appearing later. That is, if your inheritance is
<code class="docutils literal notranslate"><span class="pre">prototype_parent</span> <span class="pre">=</span> <span class="pre">('A',</span> <span class="pre">'B,'</span> <span class="pre">'C')</span></code>, and all parents contain colliding keys,
then the one from <code class="docutils literal notranslate"><span class="pre">A</span></code> will apply.</p></li>
<li><p>The prototype keys that start with <code class="docutils literal notranslate"><span class="pre">prototype_*</span></code> are all unique to each
prototype. They are <em>never</em> inherited from parent to child.</p></li>
<li><p>The prototype fields <code class="docutils literal notranslate"><span class="pre">'attr':</span> <span class="pre">[(key,</span> <span class="pre">value,</span> <span class="pre">category,</span> <span class="pre">lockstring),...]</span></code>
and <code class="docutils literal notranslate"><span class="pre">'tags':</span> <span class="pre">[(key,</span> <span class="pre">category,</span> <span class="pre">data),</span> <span class="pre">...]</span></code> are inherited in a <em>complementary</em>
fashion. That means that only colliding key+category matches will be replaced, not the entire list.
Remember that the category <code class="docutils literal notranslate"><span class="pre">None</span></code> is also considered a valid category!</p></li>
<li><p>Adding an Attribute as a simple <code class="docutils literal notranslate"><span class="pre">key:value</span></code> will under the hood be translated
into an Attribute tuple <code class="docutils literal notranslate"><span class="pre">(key,</span> <span class="pre">value,</span> <span class="pre">None,</span> <span class="pre">'')</span></code> and may replace an Attribute
in the parent if it the same key and a <code class="docutils literal notranslate"><span class="pre">None</span></code> category.</p></li>
<li><p>All other keys (<code class="docutils literal notranslate"><span class="pre">permissions</span></code>, <code class="docutils literal notranslate"><span class="pre">destination</span></code>, <code class="docutils literal notranslate"><span class="pre">aliases</span></code> etc) are completely
<em>replaced</em> by the childs value if given. For the parents value to be
retained, the child must not define these keys at all.</p></li>
</ul>
</section>
</section>
<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"><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>
</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"><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>
</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"><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>
</div>
<section id="protfuncs">
<h4>Protfuncs<a class="headerlink" href="#protfuncs" title="Permalink to this headline"></a></h4>
<p>Finally, the value can be a <em>prototype function</em> (<em>Protfunc</em>). These look like simple function calls
that you embed in strings and that has a <code class="docutils literal notranslate"><span class="pre">$</span></code> in front, like</p>
<div class="highlight-python notranslate"><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>
</div>
<p>At execution time, the place of the protfunc will be replaced with the result of that protfunc being
called (this is always a string). A protfunc is a <a class="reference internal" href="FuncParser.html"><span class="doc std std-doc">FuncParser function</span></a> run
every time the prototype is used to spawn a new object.</p>
<p>Here is how a protfunc is defined (same as an inlinefunc).</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># this is a silly example, you can just color the text red with |r directly!</span>
<span class="k">def</span> <span class="nf">red</span><span class="p">(</span><span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
<span class="sd">&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="sa">f</span><span class="s2">&quot;|r</span><span class="si">{</span><span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="si">}</span><span class="s2">|n&quot;</span>
</pre></div>
</div>
<blockquote>
<div><p>Note that we must make sure to validate input and raise <code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if that fails. Also, it is
<em>not</em> possible to use keywords in the call to the protfunc (so something like <code class="docutils literal notranslate"><span class="pre">$echo(text,</span> <span class="pre">align=left)</span></code> is invalid). The <code class="docutils literal notranslate"><span class="pre">kwargs</span></code> requred is for internal evennia use and not used at all for
protfuncs (only by inlinefuncs).</p>
</div></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"><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>
</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>
<table class="colwidths-auto docutils align-default">
<thead>
<tr class="row-odd"><th class="head"><p>Protfunc</p></th>
<th class="head"><p>Description</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$random()</span></code></p></td>
<td><p>Returns random value in range [0, 1)</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$randint(start,</span> <span class="pre">end)</span></code></p></td>
<td><p>Returns random value in range [start, end]</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$left_justify(&lt;text&gt;)</span></code></p></td>
<td><p>Left-justify text</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$right_justify(&lt;text&gt;)</span></code></p></td>
<td><p>Right-justify text to screen width</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$center_justify(&lt;text&gt;)</span></code></p></td>
<td><p>Center-justify text to screen width</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$full_justify(&lt;text&gt;)</span></code></p></td>
<td><p>Spread text across screen width by adding spaces</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$protkey(&lt;name&gt;)</span></code></p></td>
<td><p>Returns value of another key in this prototype (self-reference)</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$add(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code></p></td>
<td><p>Returns value1 + value2. Can also be lists, dicts etc</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$sub(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code></p></td>
<td><p>Returns value1 - value2</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$mult(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code></p></td>
<td><p>Returns value1 * value2</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$div(&lt;value1&gt;,</span> <span class="pre">&lt;value2&gt;)</span></code></p></td>
<td><p>Returns value2 / value1</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$toint(&lt;value&gt;)</span></code></p></td>
<td><p>Returns value converted to integer (or value if not possible)</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$eval(&lt;code&gt;)</span></code></p></td>
<td><p>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.</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$obj(&lt;query&gt;)</span></code></p></td>
<td><p>Returns object #dbref searched globally by key, tag or #dbref. Error if more than one found.</p></td>
</tr>
<tr class="row-even"><td><p><code class="docutils literal notranslate"><span class="pre">$objlist(&lt;query&gt;)</span></code></p></td>
<td><p>Like <code class="docutils literal notranslate"><span class="pre">$obj</span></code>, except always returns a list of zero, one or more results.</p></td>
</tr>
<tr class="row-odd"><td><p><code class="docutils literal notranslate"><span class="pre">$dbref(dbref)</span></code></p></td>
<td><p>Returns argument if it is formed as a #dbref (e.g. #1234), otherwise error.</p></td>
</tr>
</tbody>
</table>
<p>For developers with access to Python, using protfuncs in prototypes is generally not useful. Passing
real Python functions is a lot more powerful and flexible. Their main use is to allow in-game
builders to
do limited coding/scripting for their prototypes without giving them direct access to raw Python.</p>
</section>
</section>
</section>
<section id="storing-prototypes">
<h2>Storing prototypes<a class="headerlink" href="#storing-prototypes" title="Permalink to this headline"></a></h2>
<p>A prototype can be defined and stored in two ways, either in the database or as a dict in a module.</p>
<section id="database-prototypes">
<h3>Database prototypes<a class="headerlink" href="#database-prototypes" title="Permalink to this headline"></a></h3>
<p>Stored as <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> in the database. These are sometimes referred to as <em>database-
prototypes</em> This is the only way for in-game builders to modify and add prototypes. They have the
advantage of being easily modifiable and sharable between builders but you need to work with them
using in-game tools.</p>
</section>
<section id="module-based-prototypes">
<h3>Module-based prototypes<a class="headerlink" href="#module-based-prototypes" title="Permalink to this headline"></a></h3>
<p>These prototypes are defined as dictionaries assigned to global variables in one of the modules
defined in <code class="docutils literal notranslate"><span class="pre">settings.PROTOTYPE_MODULES</span></code>. They can only be modified from outside the game so they are
are necessarily “read-only” from in-game and cannot be modified (but copies of them could be made
into database-prototypes). These were the only prototypes available before Evennia 0.8. Module based
prototypes can be useful in order for developers to provide read-only “starting” or “base”
prototypes to build from or if they just prefer to work offline in an external code editor.</p>
<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"><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>
</div>
<p>Here is an example of a prototype defined in a module:</p>
<div class="highlight-none 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>
</section>
</section>
<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-none notranslate"><div class="highlight"><pre><span></span>@spawn goblin
</pre></div>
</div>
<p>You can also specify the prototype directly as a valid Python dictionary:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@spawn {&quot;prototype_key&quot;: &quot;shaman&quot;, \
&quot;key&quot;:&quot;Orc shaman&quot;, \
&quot;prototype_parent&quot;: &quot;goblin&quot;, \
&quot;weapon&quot;: &quot;wooden staff&quot;, \
&quot;health&quot;: 20}
</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>
</section>
<section id="using-evennia-prototypes-spawner">
<h2>Using evennia.prototypes.spawner()<a class="headerlink" href="#using-evennia-prototypes-spawner" title="Permalink to this headline"></a></h2>
<p>In code you access the spawner mechanism directly via the call</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">new_objects</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">prototypes</span><span class="o">.</span><span class="n">spawner</span><span class="o">.</span><span class="n">spawn</span><span class="p">(</span><span class="o">*</span><span class="n">prototypes</span><span class="p">)</span>
</pre></div>
</div>
<p>All arguments are prototype dictionaries. The function will return a
matching list of created objects. Example:</p>
<div class="highlight-python notranslate"><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>
</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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Help-System.html" title="Help System"
>next</a> |</li>
<li class="right" >
<a href="Tags.html" title="Tags"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Spawner and Prototypes</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,552 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Channels" href="Channels.html" />
<link rel="prev" title="Objects" href="Objects.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Channels.html" title="Channels"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Objects.html" title="Objects"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Scripts</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Scripts</a><ul>
<li><a class="reference internal" href="#in-game-command-examples">In-game command examples</a></li>
<li><a class="reference internal" href="#code-examples">Code examples</a></li>
<li><a class="reference internal" href="#defining-new-scripts">Defining new Scripts</a><ul>
<li><a class="reference internal" href="#simple-storage-script">Simple storage script</a></li>
</ul>
</li>
<li><a class="reference internal" href="#timed-scripts">Timed Scripts</a><ul>
<li><a class="reference internal" href="#script-timers-vs-delay-repeat">Script timers vs delay/repeat</a></li>
</ul>
</li>
<li><a class="reference internal" href="#script-attached-to-another-object">Script attached to another object</a></li>
<li><a class="reference internal" href="#other-script-methods">Other Script methods</a></li>
<li><a class="reference internal" href="#the-global-scripts-container">The GLOBAL_SCRIPTS container</a></li>
<li><a class="reference internal" href="#hints-dealing-with-script-errors">Hints: Dealing with Script Errors</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Objects.html"
title="previous chapter">Objects</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Channels.html"
title="next chapter">Channels</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Scripts.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="scripts">
<h1>Scripts<a class="headerlink" href="#scripts" title="Permalink to this headline"></a></h1>
<p><a class="reference internal" href="../api/evennia.scripts.scripts.html#evennia-scripts-scripts"><span class="std std-ref">Script API reference</span></a></p>
<p><em>Scripts</em> are the out-of-character siblings to the in-character
<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>. Scripts are so flexible that the name “Script” is a bit limiting
in itself - but we had to pick <em>something</em> to name them. Other possible names
(depending on what 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>
<p>If you ever consider creating an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> with a <code class="docutils literal notranslate"><span class="pre">None</span></code>-location just to store some game data,
you should really be using a Script instead.</p>
<ul class="simple">
<li><p>Scripts are full <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities - they have <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and
can be modified in the same way. But they have <em>no in-game existence</em>, so no
location or command-execution like <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> and no connection to a particular
player/session like <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>. This means they are perfectly suitable for acting
as database-storage backends for game <em>systems</em>: Storing the current state of the economy,
who is involved in the current fight, tracking an ongoing barter and so on. They are great as
persistent system handlers.</p></li>
<li><p>Scripts have an optional <em>timer component</em>. This means that you can set up the script
to tick the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook on the Script at a certain interval. The timer can be controlled
independently of the rest of the script as needed. This component is optional
and complementary to other timing functions in Evennia, like
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a>.</p></li>
<li><p>Scripts can <em>attach</em> to Objects and Accounts via e.g. <code class="docutils literal notranslate"><span class="pre">obj.scripts.add/remove</span></code>. In the
script you can then access the object/account as <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">self.account</span></code>. This can be used to
dynamically extend other typeclasses but also to use the timer component to affect the parent object
in various ways. For historical reasons, a Script <em>not</em> attached to an object is referred to as a
<em>Global</em> Script.</p></li>
</ul>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>In previus Evennia versions, stopping the Scripts timer also meant deleting the Script object.
Starting with this version, the timer can be start/stopped separately and <code class="docutils literal notranslate"><span class="pre">.delete()</span></code> must be called
on the Script explicitly to delete it.</p>
</div>
<section id="in-game-command-examples">
<h2>In-game command examples<a class="headerlink" href="#in-game-command-examples" title="Permalink to this headline"></a></h2>
<p>There are two main commands controlling scripts in the default cmdset:</p>
<p>The <code class="docutils literal notranslate"><span class="pre">addscript</span></code> command is used for attaching scripts to existing objects:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; addscript obj = bodyfunctions.BodyFunctions
</pre></div>
</div>
<p>The <code class="docutils literal notranslate"><span class="pre">scripts</span></code> command is used to view all scripts and perform operations on them:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; scripts
&gt; scripts/stop bodyfunctions.BodyFunctions
&gt; scripts/start #244
&gt; scripts/pause #11
&gt; scripts/delete #566
</pre></div>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>The <code class="docutils literal notranslate"><span class="pre">addscript</span></code> command used to be only <code class="docutils literal notranslate"><span class="pre">script</span></code> which was easy to confuse with <code class="docutils literal notranslate"><span class="pre">scripts</span></code>.</p>
</div>
</section>
<section id="code-examples">
<h2>Code examples<a class="headerlink" href="#code-examples" title="Permalink to this headline"></a></h2>
<p>Here are some examples of working with Scripts in-code (more details to follow in later
sections).</p>
<p>Create a new script:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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>
</pre></div>
</div>
<p>Create script with timer component:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># (note that this will call `timed_script.at_repeat` which is empty by default)</span>
<span class="n">timed_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;Timed script&quot;</span><span class="p">,</span>
<span class="n">interval</span><span class="o">=</span><span class="mi">34</span><span class="p">,</span> <span class="c1"># seconds &lt;=0 means off</span>
<span class="n">start_delay</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># wait interval before first call</span>
<span class="n">autostart</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># start timer (else needing .start() )</span>
<span class="c1"># manipulate the script&#39;s timer</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">pause</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">unpause</span><span class="p">()</span>
</pre></div>
</div>
<p>Attach script to another object:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">myobj</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">new_script</span><span class="p">)</span>
<span class="n">myobj</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">evennia</span><span class="o">.</span><span class="n">DefaultScript</span><span class="p">)</span>
<span class="n">all_scripts_on_obj</span> <span class="o">=</span> <span class="n">myobj</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</div>
<p>Search/find scripts in various ways:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># regular search (this is always a list, also if there is only one match)</span>
<span class="n">list_of_myscripts</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>
<span class="c1"># search through Evennia&#39;s GLOBAL_SCRIPTS container (based on</span>
<span class="c1"># script&#39;s key only)</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">myscript</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">myscript</span>
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;Timed script&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span> <span class="o">=</span> <span class="s2">&quot;bar&quot;</span>
</pre></div>
</div>
<p>Delete the Script (this will also stop its timer):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">new_script</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
<span class="n">timed_script</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</div>
</section>
<section id="defining-new-scripts">
<h2>Defining new Scripts<a class="headerlink" href="#defining-new-scripts" title="Permalink to this headline"></a></h2>
<p>A Script is defined as a class and is created in the same way as other
<a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">typeclassed</span></a> entities. The parent class is <code class="docutils literal notranslate"><span class="pre">evennia.DefaultScript</span></code>.</p>
<section id="simple-storage-script">
<h3>Simple storage script<a class="headerlink" href="#simple-storage-script" title="Permalink to this headline"></a></h3>
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/scripts.py</span></code> is an empty <code class="docutils literal notranslate"><span class="pre">Script</span></code> class already set up. You
can use this as a base for your own scripts.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
<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">Script</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
<span class="c1"># stuff common for all your scripts goes here</span>
<span class="k">class</span> <span class="nc">MyScript</span><span class="p">(</span><span class="n">Script</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="sd">&quot;&quot;&quot;Called once, when script is first created&quot;&quot;&quot;</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">db</span><span class="o">.</span><span class="n">foo</span> <span class="o">=</span> <span class="s2">&quot;bar&quot;</span>
</pre></div>
</div>
<p>Once created, this simple Script could act as a global storage:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.scripts.MyScript&#39;</span><span class="p">)</span>
<span class="c1"># from somewhere else</span>
<span class="n">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><span class="o">.</span><span class="n">first</span><span class="p">()</span>
<span class="n">bar</span> <span class="o">=</span> <span class="n">myscript</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span>
<span class="n">myscript</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">something_else</span> <span class="o">=</span> <span class="mi">1000</span>
</pre></div>
</div>
<p>Note that if you give keyword arguments to <code class="docutils literal notranslate"><span class="pre">create_script</span></code> you can override the values
you set in your <code class="docutils literal notranslate"><span class="pre">at_script_creation</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="s1">&#39;typeclasses.scripts.MyScript&#39;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;another name&quot;</span><span class="p">,</span>
<span class="n">attributes</span><span class="o">=</span><span class="p">[(</span><span class="s2">&quot;foo&quot;</span><span class="p">,</span> <span class="s2">&quot;bar-alternative&quot;</span><span class="p">)])</span>
</pre></div>
</div>
<p>See the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">create_script</span></a> and
<a class="reference internal" href="../api/evennia.utils.search.html#evennia.utils.search.search_script" title="evennia.utils.search.search_script"><span class="xref myst py py-func">search_script</span></a> API documentation for more options
on creating and finding Scripts.</p>
</section>
</section>
<section id="timed-scripts">
<h2>Timed Scripts<a class="headerlink" href="#timed-scripts" title="Permalink to this headline"></a></h2>
<p>There are several properties one can set on the Script to control its timer component.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
<span class="k">class</span> <span class="nc">TimerScript</span><span class="p">(</span><span class="n">Script</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">desc</span> <span class="o">=</span> <span class="s2">&quot;An example script&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>
</div>
<p>This example will call <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> every minute. The <code class="docutils literal notranslate"><span class="pre">create_script</span></code> function has an <code class="docutils literal notranslate"><span class="pre">autostart=True</span></code> keyword
set by default - this means the scripts timer component will be started automatically. Otherwise
<code class="docutils literal notranslate"><span class="pre">.start()</span></code> must be called separately.</p>
<p>Supported properties are:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (str): The name of the script. This makes it easier to search for it later. If its a script
attached to another object one can also get all scripts off that object and get the script that way.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">desc</span></code> (str): Note - not <code class="docutils literal notranslate"><span class="pre">.db.desc</span></code>! This is a database field on the Script shown in script listings
to help identifying what does what.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">interval</span></code> (int): The amount of time (in seconds) between every tick of the timer. Note that
its generally bad practice to use sub-second timers for anything in a text-game - the player will
not be able to appreciate the precision (and if you print it, it will just spam the screen). For
calculations you can pretty much always do them on-demand, or at a much slower interval without the
player being the wiser.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">start_delay</span></code> (bool): If timer should start right away or wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds first.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">repeats</span></code> (int): If &gt;0, the timer will only run this many times before stopping. Otherwise the
number of repeats are infinite. If set to 1, the Script mimics a <code class="docutils literal notranslate"><span class="pre">delay</span></code> action.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code> (bool): This defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code> and means the timer will survive a server reload/reboot.
If not, a reload will have the timer come back in a stopped state. Setting this to <code class="docutils literal notranslate"><span class="pre">False</span></code> will <em>not</em>
delete the Script object itself (use <code class="docutils literal notranslate"><span class="pre">.delete()</span></code> for this).</p></li>
</ul>
<p>The timer component is controlled with methods on the Script class:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">.at_repeat()</span></code> - this method is called every <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds while the timer is
active.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.is_valid()</span></code> - this method is called by the timer just before <code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code>. If it returns <code class="docutils literal notranslate"><span class="pre">False</span></code>
the timer is immediately stopped.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.start()</span></code> - start/update the timer. If keyword arguments are given, they can be used to
change <code class="docutils literal notranslate"><span class="pre">interval</span></code>, <code class="docutils literal notranslate"><span class="pre">start_delay</span></code> etc on the fly. This calls the <code class="docutils literal notranslate"><span class="pre">.at_start()</span></code> hook.
This is also called after a server reload assuming the timer was not previously stopped.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.update()</span></code> - legacy alias for <code class="docutils literal notranslate"><span class="pre">.start</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.stop()</span></code> - stops and resets the timer. This calls the <code class="docutils literal notranslate"><span class="pre">.at_stop()</span></code> hook.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.pause()</span></code> - pauses the timer where it is, storing its current position. This calls
the <code class="docutils literal notranslate"><span class="pre">.at_pause(manual_pause=True)</span></code> hook. This is also called on a server reload/reboot,
at which time the <code class="docutils literal notranslate"><span class="pre">manual_pause</span></code> will be <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.unpause()</span></code> - unpause a previously paused script. This will call the <code class="docutils literal notranslate"><span class="pre">at_start</span></code> hook.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.time_until_next_repeat()</span></code> - get the time until next time the timer fires.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.remaining_repeats()</span></code> - get the number of repeats remaining, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if repeats are infinite.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.reset_callcount()</span></code> - this resets the repeat counter to start over from 0. Only useful if <code class="docutils literal notranslate"><span class="pre">repeats&gt;0</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.force_repeat()</span></code> - this prematurely forces <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> to be called right away. Doing so will reset the
countdown so that next call will again happen after <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds.</p></li>
</ul>
<section id="script-timers-vs-delay-repeat">
<h3>Script timers vs delay/repeat<a class="headerlink" href="#script-timers-vs-delay-repeat" title="Permalink to this headline"></a></h3>
<p>If the <em>only</em> goal is to get a repeat/delay effect, the
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and
<a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a> functions
should generally be considered first. A Script is a lot heavier to create/delete on the fly.
In fact, for making a single delayed call (<code class="docutils literal notranslate"><span class="pre">script.repeats==1</span></code>), the <code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> call is
probably always the better choice.</p>
<p>For repeating tasks, the <code class="docutils literal notranslate"><span class="pre">utils.repeat</span></code> is optimized for quick repeating of a large number of objects. It
uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to
start/stop the repeating action for an object. The side effect is however that all objects set to tick
at a given interval will <em>all do so at the same time</em>. This may or may not look strange in-game depending
on the situation. By contrast the Script uses its own ticker that will operate independently from the
tickers of all other Scripts.</p>
<p>Its also worth noting that once the script object has <em>already been created</em>,
starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update
methods of the script also offers a bit more fine-control than using <code class="docutils literal notranslate"><span class="pre">utils.delays/repeat</span></code>.</p>
</section>
</section>
<section id="script-attached-to-another-object">
<h2>Script attached to another object<a class="headerlink" href="#script-attached-to-another-object" title="Permalink to this headline"></a></h2>
<p>Scripts can be attached to an <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a> or (more commonly) an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a>.
If so, the parent object will be available to the script as either <code class="docutils literal notranslate"><span class="pre">.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">.account</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># mygame/typeclasses/scripts.py</span>
<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"> &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="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>
</div>
<p>If attached to a room, this Script will randomly report some weather
to everyone in the room every 5 minutes.</p>
<div class="highlight-python 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 attach the script as part of creating it:</p>
<div class="highlight-python notranslate"><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>
</pre></div>
</div>
</section>
<section id="other-script-methods">
<h2>Other Script methods<a class="headerlink" href="#other-script-methods" title="Permalink to this headline"></a></h2>
<p>A Script has all the properties of a typeclassed object, such as <code class="docutils literal notranslate"><span class="pre">db</span></code> and <code class="docutils literal notranslate"><span class="pre">ndb</span></code>(see
<a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclasses</span></a>). Setting <code class="docutils literal notranslate"><span class="pre">key</span></code> is useful in order to manage scripts (delete them by name
etc). These are usually set up in the 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">at_script_creation()</span></code> - this is only called once - when the script is first created.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_reload()</span></code> - this is called whenever the server is warm-rebooted (e.g. with the
<code class="docutils literal notranslate"><span class="pre">reload</span></code> command). 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>
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_start()</span></code> - this is called when the server comes back (from reload/shutdown/reboot). It
can be usuful for initializations and caching of non-persistent data when starting up a scripts
functionality.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_start()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_pause()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">at_stop()</span></code></p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">delete()</span></code> - same as for other typeclassed entities, this will delete the Script. Of note is that
it will also stop the timer (if it runs), leading to the <code class="docutils literal notranslate"><span class="pre">at_stop</span></code> hook being called.</p></li>
</ul>
<p>In addition, Scripts support <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> and <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Locks</span></a> etc like other
Typeclassed entities.</p>
<p>See also the methods involved in controlling a <a class="reference internal" href="#timed-scripts"><span class="std std-doc">Timed Script</span></a> above.</p>
</section>
<section id="the-global-scripts-container">
<h2>The GLOBAL_SCRIPTS container<a class="headerlink" href="#the-global-scripts-container" title="Permalink to this headline"></a></h2>
<p>A Script not attached to another entity is commonly referred to as a <em>Global</em> script since itt available
to access from anywhere. This means they need to be searched for in order to be used.</p>
<p>Evennia supplies a convenient “container” <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS</span></code> to help organize your global
scripts. All you need is the Scripts <code class="docutils literal notranslate"><span class="pre">key</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
<span class="c1"># access as a property on the container, named the same as the key</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 Django 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>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`.
If you were to create two global scripts with the same `key` (even with different typeclasses),
the `GLOBAL_SCRIPTS` container will only return one of them (which one depends on order in
the database). Best is to organize your scripts so that this does not happen. Otherwise, use
`evennia.search_scripts` to get exactly the script you want.
</pre></div>
</div>
</div>
<p>There are two ways to make a script appear as a property on <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>:</p>
<ol class="simple">
<li><p>Manually create a new global script with a <code class="docutils literal notranslate"><span class="pre">key</span></code> using <code class="docutils literal notranslate"><span class="pre">create_script</span></code>.</p></li>
<li><p>Define the scripts properties in the <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> settings variable. This tells Evennia
that it should check if a script with that <code class="docutils literal notranslate"><span class="pre">key</span></code> exists and if not, create it for you.
This is very useful for scripts that must always exist and/or should be auto-created
when your server restarts. If you use this method, you must make sure all
script keys are globally unique.</p></li>
</ol>
<p>Heres how to tell Evennia to manage the script in settings:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/server/conf/settings.py</span>
<span class="n">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;typeclasses.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="p">},</span>
<span class="s2">&quot;storagescript&quot;</span><span class="p">:</span> <span class="p">{}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>Above we add two scripts with keys <code class="docutils literal notranslate"><span class="pre">myscript</span></code> and <code class="docutils literal notranslate"><span class="pre">storagescript</span></code>respectively. The following dict
can be empty - the <code class="docutils literal notranslate"><span class="pre">settings.BASE_SCRIPT_TYPECLASS</span></code> will then be used. Under the hood, the provided
dict (along with the <code class="docutils literal notranslate"><span class="pre">key</span></code>) will be passed into <code class="docutils literal notranslate"><span class="pre">create_script</span></code> automatically, so
all the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">same keyword arguments as for create_script</span></a> are
supported here.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Before setting up Evennia to manage your script like this, make sure that your Script typeclass
does not have any critical errors (test it separately). If there are, you&#39;ll see errors in your log
and your Script will temporarily fall back to being a `DefaultScript` type.
</pre></div>
</div>
</div>
<p>Moreover, a script defined this way is <em>guaranteed</em> to exist when you try to access it:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
<span class="c1"># Delete 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">delete</span><span class="p">()</span>
<span class="c1"># running the `scripts` command now will show no storagescript</span>
<span class="c1"># but below it&#39;s automatically 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>
</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>, Evennia will use the
information in settings to recreate it for you on the fly.</p>
</section>
<section id="hints-dealing-with-script-errors">
<h2>Hints: Dealing with Script Errors<a class="headerlink" href="#hints-dealing-with-script-errors" title="Permalink to this headline"></a></h2>
<p>Errors inside a timed, executing script can sometimes be rather terse or point to
parts of the execution mechanism that is hard to interpret. One way to make it
easier to debug scripts is to import 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"><div class="highlight"><pre><span></span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
<span class="c1"># [...]</span>
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="k">try</span><span class="p">:</span>
<span class="c1"># [...]</span>
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">()</span>
</pre></div>
</div>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Channels.html" title="Channels"
>next</a> |</li>
<li class="right" >
<a href="Objects.html" title="Objects"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Scripts</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,134 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Webserver" href="Webserver.html" />
<link rel="prev" title="Outputfuncs" href="Outputfuncs.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Webserver.html" title="Webserver"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Outputfuncs.html" title="Outputfuncs"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Server component</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="Outputfuncs.html"
title="previous chapter">Outputfuncs</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Webserver.html"
title="next chapter">Webserver</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Server.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-doc">Portal-and-Server</span></a>.</p>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Webserver.html" title="Webserver"
>next</a> |</li>
<li class="right" >
<a href="Outputfuncs.html" title="Outputfuncs"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Server component</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,324 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Accounts" href="Accounts.html" />
<link rel="prev" title="Typeclasses" href="Typeclasses.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Accounts.html" title="Accounts"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Typeclasses.html" title="Typeclasses"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Sessions</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Typeclasses.html"
title="previous chapter">Typeclasses</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Accounts.html"
title="next chapter">Accounts</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Sessions.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Sessions.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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 std std-doc">cmdset</span></a>, usually the “unloggedin” cmdset. This is what
is used to show the login screen and to handle commands to create a new account (or
<a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a> in evennia lingo) read initial help and to log into the game with an existing
account. A session object can either be “logged in” or not. Logged in means that the user has
authenticated. When this happens the session is associated with an Account object (which is what
holds account-centric stuff). The account can then in turn puppet any number of objects/characters.</p>
<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 std std-doc">Typeclass</span></a> and has no
connection to the database. The Session will go away when a user disconnects and you will lose any
custom data on it if the server reloads. The <code class="docutils literal notranslate"><span class="pre">.db</span></code> handler on Sessions is there to present a uniform
API (so you can assume <code class="docutils literal notranslate"><span class="pre">.db</span></code> exists even if you 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>
<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 std std-doc">Account</span></a> this Session is attached to. If not logged in yet, this is
<code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">puppet</span></code> - The <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Character/Object</span></a> currently puppeted by this Account/Session combo. If
not logged in or in OOC mode, this is <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">ndb</span></code> - The <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Non-persistent Attribute</span></a> handler.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">db</span></code> - As noted above, Sessions 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 std std-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>
</section>
<section id="multisession-mode">
<h2>Multisession mode<a class="headerlink" href="#multisession-mode" title="Permalink to this headline"></a></h2>
<p>The number of sessions possible to connect to a given account at the same time and how it works is
given by the <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> setting:</p>
<ul 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>
</section>
<section id="returning-data-to-the-session">
<h2>Returning data to the session<a class="headerlink" href="#returning-data-to-the-session" title="Permalink to this headline"></a></h2>
<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 std std-doc">Accounts</span></a> and <a class="reference internal" href="Objects.html"><span class="doc std std-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>
</section>
<section id="customizing-the-session-object">
<h2>Customizing the Session object<a class="headerlink" href="#customizing-the-session-object" title="Permalink to this headline"></a></h2>
<p>When would one want to customize the Session object? Consider for example a character creation
system: You might decide to keep this on the out-of-character level. This would mean that you create
the character at the end of some sort of menu choice. The actual char-create cmdset would then
normally be put on the account. This works fine as long as you are <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> below 2.
For higher modes, replacing the Account cmdset will affect <em>all</em> your connected sessions, also those
not involved in character creation. In this case you want to instead put the char-create cmdset on
the Session level - then all other sessions will keep working normally despite you creating a new
character in one of them.</p>
<p>By default, the session object gets the <code class="docutils literal notranslate"><span class="pre">commands.default_cmdsets.UnloggedinCmdSet</span></code> when the user
first connects. Once the session is authenticated it has <em>no</em> default sets. To add a “logged-in”
cmdset to the Session, give the path to the cmdset class with <code class="docutils literal notranslate"><span class="pre">settings.CMDSET_SESSION</span></code>. This set
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>
</section>
<section id="portal-and-server-sessions">
<h2>Portal and Server Sessions<a class="headerlink" href="#portal-and-server-sessions" title="Permalink to this headline"></a></h2>
<p><em>Note: This is considered an advanced topic. You 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 std std-doc">Portal and the Server</span></a>. Each side tracks
its own Sessions, syncing them to each other.</p>
<p>The “Session” we normally refer to is actually the <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code>. Its counter-part on the Portal
side is the <code class="docutils literal notranslate"><span class="pre">PortalSession</span></code>. Whereas the server sessions deal with game states, the portal session
deals with details of the connection-protocol itself. The two are also acting as backups of critical
data such as when the server reboots.</p>
<p>New Account connections are listened for and handled by the Portal using the [protocols](Portal-And-
Server) it understands (such as telnet, ssh, webclient etc). When a new connection is established, a
<code class="docutils literal notranslate"><span class="pre">PortalSession</span></code> is created on the Portal side. This session object looks different depending on
which protocol is used to connect, but all still have a minimum set of attributes that are generic
to all
sessions.</p>
<p>These common properties are piped from the Portal, through the AMP connection, to the Server, which
is now informed a new connection has been established. On the Server side, a <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code> object
is created to represent this. There is only one type of <code class="docutils literal notranslate"><span class="pre">ServerSession</span></code>; It looks the same
regardless of how the Account connects.</p>
<p>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>
</section>
<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 std std-doc">protocols</span></a> for more info
on building new protocols.</p>
<p>To get all Sessions in the game (i.e. all currently connected clients), you access the server-side
Session handler, which you get by</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia.server.sessionhandler</span> <span class="kn">import</span> <span class="n">SESSION_HANDLER</span>
</pre></div>
</div>
<blockquote>
<div><p>Note: The <code class="docutils literal notranslate"><span class="pre">SESSION_HANDLER</span></code> singleton has an older alias <code class="docutils literal notranslate"><span class="pre">SESSIONS</span></code> that is commonly seen in
various places as well.</p>
</div></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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Accounts.html" title="Accounts"
>next</a> |</li>
<li class="right" >
<a href="Typeclasses.html" title="Typeclasses"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Sessions</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,251 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Game website" href="Website.html" />
<link rel="prev" title="Locks" href="Locks.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Website.html" title="Game website"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Locks.html" title="Locks"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Signals</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Locks.html"
title="previous chapter">Locks</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Website.html"
title="next chapter">Game website</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Signals.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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>
<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"><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>
</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"><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>
</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"><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>
</div>
</section>
<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 std std-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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Website.html" title="Game website"
>next</a> |</li>
<li class="right" >
<a href="Locks.html" title="Locks"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Signals</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,313 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Spawner and Prototypes" href="Prototypes.html" />
<link rel="prev" title="Nicks" href="Nicks.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Prototypes.html" title="Spawner and Prototypes"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Nicks.html" title="Nicks"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Tags</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="Nicks.html"
title="previous chapter">Nicks</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Prototypes.html"
title="next chapter">Spawner and Prototypes</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Tags.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="tags">
<h1>Tags<a class="headerlink" href="#tags" title="Permalink to this headline"></a></h1>
<div class="literal-block-wrapper docutils container" id="id1">
<div class="code-block-caption"><span class="caption-text">In game</span><a class="headerlink" href="#id1" title="Permalink to this code"></a></div>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">tag</span> <span class="n">obj</span> <span class="o">=</span> <span class="n">tagname</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id2">
<div class="code-block-caption"><span class="caption-text">In code, using .tags (TagHandler)</span><a class="headerlink" href="#id2" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">obj</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;mytag&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;foo&quot;</span><span class="p">)</span>
<span class="n">obj</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;mytag&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;foo&quot;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<div class="literal-block-wrapper docutils container" id="id3">
<div class="code-block-caption"><span class="caption-text">In code, using TagProperty (auto-assign tag to all instances of the class)</span><a class="headerlink" href="#id3" title="Permalink to this code"></a></div>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">TagProperty</span>
<span class="k">class</span> <span class="nc">Sword</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
<span class="n">can_be_wielded</span> <span class="o">=</span> <span class="n">TagProperty</span><span class="p">(</span><span class="n">category</span><span class="o">=</span><span class="s1">&#39;combat&#39;</span><span class="p">)</span>
<span class="n">has_sharp_edge</span> <span class="o">=</span> <span class="n">TagProperty</span><span class="p">(</span><span class="n">category</span><span class="o">=</span><span class="s1">&#39;combat&#39;</span><span class="p">)</span>
</pre></div>
</div>
</div>
<p><em>Tags</em> are short text lables one can hang on objects in order to organize, group and quickly find out their properties. An Evennia entity can be tagged by any number of tags. They are more efficient than <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> since on the database-side, Tags are <em>shared</em> between all objects with that particular tag. A tag does not carry a value in itself; it either sits on the entity</p>
<p>Above, the tags inform us that the <code class="docutils literal notranslate"><span class="pre">Sword</span></code> is both sharp and can be wielded. If thats all they do, they could just be a normal Python flag. When tags become important is if there are a lot of objects with different combinations of tags. Maybe you have a magical spell that dulls <em>all</em> sharp-edged objects in the castle - whether sword, dagger, spear or kitchen knife! You can then just grab all objects with the <code class="docutils literal notranslate"><span class="pre">has_sharp_edge</span></code> tag.
Another example would be a weather script affecting all rooms tagged as <code class="docutils literal notranslate"><span class="pre">outdoors</span></code> or finding all characters tagged with <code class="docutils literal notranslate"><span class="pre">belongs_to_fighter_guild</span></code>.</p>
<p>In Evennia, Tags are technically also used to implement <code class="docutils literal notranslate"><span class="pre">Aliases</span></code> (alternative names for objects) and <code class="docutils literal notranslate"><span class="pre">Permissions</span></code> (simple strings for <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Locks</span></a> to check for).</p>
<section id="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 std std-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>
</section>
<section id="adding-removing-tags">
<h2>Adding/Removing Tags<a class="headerlink" href="#adding-removing-tags" title="Permalink to this headline"></a></h2>
<p>You can tag any <em>typeclassed</em> object, namely <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>,
<a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>. General tags are added by the <em>Taghandler</em>. The
tag handler is accessed as a property <code class="docutils literal notranslate"><span class="pre">tags</span></code> on the relevant entity:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">mychair</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&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>
</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-none notranslate"><div class="highlight"><pre><span></span> @tag mychair = furniture
</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>
</section>
<section id="searching-for-objects-with-a-given-tag">
<h2>Searching for objects with a given tag<a class="headerlink" href="#searching-for-objects-with-a-given-tag" title="Permalink to this headline"></a></h2>
<p>Usually tags are used as a quick way to find tagged database entities. You can retrieve all objects
with a given Tag like this in code:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">import</span> <span class="nn">evennia</span>
<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>
</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"><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>
</div>
<p>There is also an in-game command that deals with assigning and using (<a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object-</span></a>) tags:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> @tag/search furniture
</pre></div>
</div>
</section>
<section id="using-aliases-and-permissions">
<h2>Using Aliases and Permissions<a class="headerlink" href="#using-aliases-and-permissions" title="Permalink to this headline"></a></h2>
<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"><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>
</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>
</section>
<section id="assorted-notes">
<h2>Assorted notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline"></a></h2>
<p>Generally, tags are enough on their own for grouping objects. Having no tag <code class="docutils literal notranslate"><span class="pre">category</span></code> is perfectly
fine and the normal operation. Simply adding a new Tag for grouping objects is often better than
making a new category. So think hard before deciding you really need to categorize your Tags.</p>
<p>That said, tag categories can be useful if you build some game system that uses tags. You can then
use tag categories to make sure to separate tags created with this system from any other tags
created elsewhere. You can then supply custom search methods that <em>only</em> find objects tagged with
tags of that category. An example of this
is found in the <a class="reference internal" href="../Concepts/Zones.html"><span class="doc std std-doc">Zone tutorial</span></a>.</p>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Prototypes.html" title="Spawner and Prototypes"
>next</a> |</li>
<li class="right" >
<a href="Nicks.html" title="Nicks"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Tags</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,254 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Locks" href="Locks.html" />
<link rel="prev" title="MonitorHandler" href="MonitorHandler.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Locks.html" title="Locks"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">TickerHandler</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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>
<h4>Previous topic</h4>
<p class="topless"><a href="MonitorHandler.html"
title="previous chapter">MonitorHandler</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Locks.html"
title="next chapter">Locks</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="TickerHandler.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="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>
<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 std std-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"><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>
</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"><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>
</div>
<p>Removing (stopping) the ticker works as expected:</p>
<div class="highlight-python notranslate"><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>
</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"><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="kc">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>
</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"><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="kc">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="kc">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>
</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"><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>
</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"><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>
</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 std std-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="../Howtos/Weather-Tutorial.html"><span class="doc std std-doc">Weather Tutorial</span></a> for an example of using the TickerHandler.</p>
<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>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Locks.html" title="Locks"
>next</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">TickerHandler</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,458 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Sessions" href="Sessions.html" />
<link rel="prev" title="Core Components" href="Components-Overview.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Sessions.html" title="Sessions"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Components-Overview.html" title="Core Components"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Typeclasses</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">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></li>
<li><a class="reference internal" href="#about-typeclass-properties">About typeclass properties</a></li>
<li><a class="reference internal" href="#overloading-hooks">Overloading hooks</a></li>
<li><a class="reference internal" href="#querying-for-typeclasses">Querying for typeclasses</a></li>
<li><a class="reference internal" href="#updating-existing-typeclass-instances">Updating existing typeclass instances</a></li>
<li><a class="reference internal" href="#swap-typeclass">Swap typeclass</a></li>
<li><a class="reference internal" href="#how-typeclasses-actually-work">How typeclasses actually work</a></li>
<li><a class="reference internal" href="#caveats">Caveats</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Components-Overview.html"
title="previous chapter">Core Components</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Sessions.html"
title="next chapter">Sessions</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Typeclasses.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="typeclasses">
<h1>Typeclasses<a class="headerlink" href="#typeclasses" title="Permalink to this headline"></a></h1>
<p><em>Typeclasses</em> form the core of Evennias data storage. It allows Evennia to represent any number of
different game entities as Python classes, without having to modify the database schema for every
new type.</p>
<p>In Evennia the most important game entities, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>,
<a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a> are all Python classes inheriting, at
varying distance, from <code class="docutils literal notranslate"><span class="pre">evennia.typeclasses.models.TypedObject</span></code>. In the documentation we refer to
these objects as being “typeclassed” or even “being a typeclass”.</p>
<p>This is how the inheritance looks for the typeclasses in Evennia:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">TypedObject</span>
<span class="n">_________________</span><span class="o">|</span><span class="n">_________________________________</span>
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
<span class="mi">1</span><span class="p">:</span> <span class="n">AccountDB</span> <span class="n">ObjectDB</span> <span class="n">ScriptDB</span> <span class="n">ChannelDB</span>
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
<span class="mi">2</span><span class="p">:</span> <span class="n">DefaultAccount</span> <span class="n">DefaultObject</span> <span class="n">DefaultScript</span> <span class="n">DefaultChannel</span>
<span class="o">|</span> <span class="n">DefaultCharacter</span> <span class="o">|</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">DefaultRoom</span> <span class="o">|</span> <span class="o">|</span>
<span class="o">|</span> <span class="n">DefaultExit</span> <span class="o">|</span> <span class="o">|</span>
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
<span class="mi">3</span><span class="p">:</span> <span class="n">Account</span> <span class="n">Object</span> <span class="n">Script</span> <span class="n">Channel</span>
<span class="n">Character</span>
<span class="n">Room</span>
<span class="n">Exit</span>
</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>
<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 internal" href="#about-typeclass-properties"><span class="std std-doc">below</span></a>.</p></li>
<li><p>Due to its connection to the database, the typeclass name must be <em>unique</em> across the <em>entire</em>
server namespace. That is, there must never be two same-named classes defined anywhere. So the below
code would give an error (since <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is now globally found both in this module and in the
default library):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultObject</span> <span class="k">as</span> <span class="n">BaseObject</span>
<span class="k">class</span> <span class="nc">DefaultObject</span><span class="p">(</span><span class="n">BaseObject</span><span class="p">):</span>
<span class="k">pass</span>
</pre></div>
</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"><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>
</div>
</li>
</ol>
<p>Apart from this, a typeclass works like any normal Python class and you can
treat it as such.</p>
</section>
<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"><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>
</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"><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>
</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"><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>
</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 std std-doc">Attributes</span></a> and
<a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> all in one go. These keywords 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>
</section>
<section id="about-typeclass-properties">
<h2>About typeclass properties<a class="headerlink" href="#about-typeclass-properties" title="Permalink to this headline"></a></h2>
<p>An example of a database field is <code class="docutils literal notranslate"><span class="pre">db_key</span></code>. This stores the “name” of the entity you are modifying
and can thus only hold a string. This is one way of making sure to update the <code class="docutils literal notranslate"><span class="pre">db_key</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">chair</span><span class="o">.</span><span class="n">db_key</span> <span class="o">=</span> <span class="s2">&quot;Table&quot;</span>
<span class="n">chair</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="nb">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>
</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"><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="nb">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>
</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 std std-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 std std-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 std std-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 std std-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 std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a> and
<a class="reference internal" href="Channels.html"><span class="doc std std-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 std std-doc">Evennias flat API</span></a> to explore which properties and methods they have
available.</p>
</section>
<section id="overloading-hooks">
<h2>Overloading hooks<a class="headerlink" href="#overloading-hooks" title="Permalink to this headline"></a></h2>
<p>The way to customize typeclasses is usually to overload <em>hook methods</em> on them. Hooks are methods
that Evennia call in various situations. An example is the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> hook on <code class="docutils literal notranslate"><span class="pre">Objects</span></code>,
which is only called once, the very first time this object is saved to the database. Other examples
are the <code class="docutils literal notranslate"><span class="pre">at_login</span></code> hook of Accounts and the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook of Scripts.</p>
</section>
<section id="querying-for-typeclasses">
<h2>Querying for typeclasses<a class="headerlink" href="#querying-for-typeclasses" title="Permalink to this headline"></a></h2>
<p>Most of the time you search for objects in the database by using convenience methods like the
<code class="docutils literal notranslate"><span class="pre">caller.search()</span></code> of <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> or the search functions like <code class="docutils literal notranslate"><span class="pre">evennia.search_objects</span></code>.</p>
<p>You can however also query for them directly using <a class="reference external" href="https://docs.djangoproject.com/en/1.7/topics/db/queries/">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"><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>
</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"><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>
</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"><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>
</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>
</section>
<section id="updating-existing-typeclass-instances">
<h2>Updating existing typeclass instances<a class="headerlink" href="#updating-existing-typeclass-instances" title="Permalink to this headline"></a></h2>
<p>If you already have created instances of Typeclasses, you can modify the <em>Python code</em> at any time -
due to how Python inheritance works your changes will automatically be applied to all children once
you have reloaded the server.</p>
<p>However, database-saved data, like <code class="docutils literal notranslate"><span class="pre">db_*</span></code> fields, <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> etc, are
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"><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>
</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"><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>
</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="kn">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>
</section>
<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"><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="kc">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="kc">True</span><span class="p">,</span> <span class="n">clean_cmdsets</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
</pre></div>
</div>
<p>The arguments to this method are described <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.typeclasses.models#typedobjectswap_typeclass">in the API docs
here</a>.</p>
</section>
<section id="how-typeclasses-actually-work">
<h2>How typeclasses actually work<a class="headerlink" href="#how-typeclasses-actually-work" title="Permalink to this headline"></a></h2>
<p><em>This is considered an advanced section.</em></p>
<p>Technically, typeclasses are <a class="reference external" href="https://docs.djangoproject.com/en/1.7/topics/db/models/#proxy-models">Django proxy
models</a>. The only database
models that are “real” in the typeclass system (that is, are represented by actual tables in the
database) are <code class="docutils literal notranslate"><span class="pre">AccountDB</span></code>, <code class="docutils literal notranslate"><span class="pre">ObjectDB</span></code>, <code class="docutils literal notranslate"><span class="pre">ScriptDB</span></code> and <code class="docutils literal notranslate"><span class="pre">ChannelDB</span></code> (there are also
<a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> but they are not typeclasses themselves). All the
subclasses of them are “proxies”, extending them with Python code without actually modifying the
database layout.</p>
<p>Evennia modifies 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>
</section>
<section id="caveats">
<h2>Caveats<a class="headerlink" href="#caveats" title="Permalink to this headline"></a></h2>
<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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Sessions.html" title="Sessions"
>next</a> |</li>
<li class="right" >
<a href="Components-Overview.html" title="Core Components"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Typeclasses</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,253 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Evennia REST API &#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" />
<link rel="next" title="The Web Admin" href="Web-Admin.html" />
<link rel="prev" title="Game website" href="Website.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Web-Admin.html" title="The Web Admin"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Website.html" title="Game website"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Evennia REST API</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Evennia REST API</a><ul>
<li><a class="reference internal" href="#usage">Usage</a></li>
<li><a class="reference internal" href="#customizing-the-api">Customizing the API</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Website.html"
title="previous chapter">Game website</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Web-Admin.html"
title="next chapter">The Web Admin</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Web-API.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Web-API.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="evennia-rest-api">
<h1>Evennia REST API<a class="headerlink" href="#evennia-rest-api" title="Permalink to this headline"></a></h1>
<p>Evennia makes its database accessible via a REST API found on
<a class="reference external" href="http://localhost:4001/api">http://localhost:4001/api</a> if running locally with
default setup. The API allows you to retrieve, edit and create resources from
outside the game, for example with your own custom client or game editor.</p>
<p>While you can view and learn about the api in the web browser, it is really
meant to be accessed in code, by other programs.</p>
<p>The API is using <a class="reference external" href="https://www.django-rest-framework.org/">Django Rest Framework</a>. This automates the process
of setting up <em>views</em> (Python code) to process the result of web requests.
The process of retrieving data is similar to that explained on the
<a class="reference internal" href="Webserver.html"><span class="doc std std-doc">Webserver</span></a> page, except the views will here return <a class="reference external" href="https://en.wikipedia.org/wiki/JSON">JSON</a>
data for the resource you want. You can also <em>send</em> such JSON data
in order to update the database from the outside.</p>
<section id="usage">
<h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h2>
<p>To activate the API, add this to your settings file.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>REST_API_ENABLED = True
</pre></div>
</div>
<p>The main controlling setting is <code class="docutils literal notranslate"><span class="pre">REST_FRAMEWORK</span></code>, which is a dict. The keys
<code class="docutils literal notranslate"><span class="pre">DEFAULT_LIST_PERMISSION</span></code> and <code class="docutils literal notranslate"><span class="pre">DEFAULT_CREATE_PERMISSIONS</span></code> control who may
view and create new objects via the api respectively. By default, users with
<a class="reference internal" href="Permissions.html"><span class="doc std std-doc">Builder-level permission</span></a> or higher may access both actions.</p>
<p>While the api is meant to be expanded upon, Evennia supplies several operations
out of the box. If you click the <code class="docutils literal notranslate"><span class="pre">Autodoc</span></code> button in the upper right of the <code class="docutils literal notranslate"><span class="pre">/api</span></code>
website youll get a fancy graphical presentation of the available endpoints.</p>
<p>Here is an example of calling the api in Python using the standard <code class="docutils literal notranslate"><span class="pre">requests</span></code> library.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt;&gt;&gt; import requests
&gt;&gt;&gt; response = requests.get(&quot;https://www.mygame.com/api&quot;, auth=(&quot;MyUsername&quot;, &quot;password123&quot;))
&gt;&gt;&gt; response.json()
{&#39;accounts&#39;: &#39;http://www.mygame.com/api/accounts/&#39;,
&#39;objects&#39;: &#39;http://www.mygame.com/api/objects/&#39;,
&#39;characters&#39;: &#39;http://www.mygame.comg/api/characters/&#39;,
&#39;exits&#39;: &#39;http://www.mygame.com/api/exits/&#39;,
&#39;rooms&#39;: &#39;http://www.mygame.com/api/rooms/&#39;,
&#39;scripts&#39;: &#39;http://www.mygame.com/api/scripts/&#39;
&#39;helpentries&#39;: &#39;http://www.mygame.com/api/helpentries/&#39; }
</pre></div>
</div>
<p>To list a specific type of object:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt;&gt;&gt; response = requests.get(&quot;https://www.mygame.com/api/objects&quot;,
auth=(&quot;Myusername&quot;, &quot;password123&quot;))
&gt;&gt;&gt; response.json()
{
&quot;count&quot;: 125,
&quot;next&quot;: &quot;https://www.mygame.com/api/objects/?limit=25&amp;offset=25&quot;,
&quot;previous&quot;: null,
&quot;results&quot; : [{&quot;db_key&quot;: &quot;A rusty longsword&quot;, &quot;id&quot;: 57, &quot;db_location&quot;: 213, ...}]}
</pre></div>
</div>
<p>In the above example, it now displays the objects inside the “results” array,
while it has a “count” value for the number of total objects, and “next” and
“previous” links for the next and previous page, if any. This is called
<a class="reference external" href="https://www.django-rest-framework.org/api-guide/pagination/">pagination</a>, and the link displays “limit” and “offset” as query
parameters that can be added to the url to control the output.</p>
<p>Other query parameters can be defined as <a class="reference external" href="https://www.django-rest-framework.org/api-guide/filtering/#filtering">filters</a> which allow you to
further narrow the results. For example, to only get accounts with developer
permissions:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt;&gt;&gt; response = requests.get(&quot;https://www.mygame.com/api/accounts/?permission=developer&quot;,
auth=(&quot;MyUserName&quot;, &quot;password123&quot;))
&gt;&gt;&gt; response.json()
{
&quot;count&quot;: 1,
&quot;results&quot;: [{&quot;username&quot;: &quot;bob&quot;,...}]
}
</pre></div>
</div>
<p>Now suppose that you want to use the API to create an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt;&gt;&gt; data = {&quot;db_key&quot;: &quot;A shiny sword&quot;}
&gt;&gt;&gt; response = requests.post(&quot;https://www.mygame.com/api/objects&quot;,
data=data, auth=(&quot;Anotherusername&quot;, &quot;mypassword&quot;))
&gt;&gt;&gt; response.json()
{&quot;db_key&quot;: &quot;A shiny sword&quot;, &quot;id&quot;: 214, &quot;db_location&quot;: None, ...}
</pre></div>
</div>
<p>Here we made a HTTP POST request to the <code class="docutils literal notranslate"><span class="pre">/api/objects</span></code> endpoint with the <code class="docutils literal notranslate"><span class="pre">db_key</span></code>
we wanted. We got back info for the newly created object. You can now make
another request with PUT (replace everything) or PATCH (replace only what you
provide). By providing the id to the endpoint (<code class="docutils literal notranslate"><span class="pre">/api/objects/214</span></code>),
we make sure to update the right sword:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt;&gt;&gt; data = {&quot;db_key&quot;: &quot;An even SHINIER sword&quot;, &quot;db_location&quot;: 50}
&gt;&gt;&gt; response = requests.put(&quot;https://www.mygame.com/api/objects/214&quot;,
data=data, auth=(&quot;Anotherusername&quot;, &quot;mypassword&quot;))
&gt;&gt;&gt; response.json()
{&quot;db_key&quot;: &quot;An even SHINIER sword&quot;, &quot;id&quot;: 214, &quot;db_location&quot;: 50, ...}
</pre></div>
</div>
<p>In most cases, you wont be making API requests to the backend with Python,
but with Javascript from some frontend application.
There are many Javascript libraries which are meant to make this process
easier for requests from the frontend, such as <a class="reference external" href="https://github.com/axios/axios">AXIOS</a>, or using
the native <a class="reference external" href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API">Fetch</a>.</p>
</section>
<section id="customizing-the-api">
<h2>Customizing the API<a class="headerlink" href="#customizing-the-api" title="Permalink to this headline"></a></h2>
<p>Overall, reading up on <a class="reference external" href="https://www.django-rest-framework.org/api-guide/viewsets">Django Rest Framework ViewSets</a> and
other parts of their documentation is required for expanding and
customizing the API.</p>
<p>Check out the <a class="reference internal" href="Website.html"><span class="doc std std-doc">Website</span></a> page for help on how to override code, templates
and static files.</p>
<ul class="simple">
<li><p>API templates (for the web-display) is located in <code class="docutils literal notranslate"><span class="pre">evennia/web/api/templates/rest_framework/</span></code> (it must
be named such to allow override of the original REST framework templates).</p></li>
<li><p>Static files is in <code class="docutils literal notranslate"><span class="pre">evennia/web/api/static/rest_framework/</span></code></p></li>
<li><p>The api code is located in <code class="docutils literal notranslate"><span class="pre">evennia/web/api/</span></code> - the <code class="docutils literal notranslate"><span class="pre">url.py</span></code> file here is responsible for
collecting all view-classes.</p></li>
</ul>
<p>Contrary to other web components, there is no pre-made <a class="reference external" href="http://urls.py">urls.py</a> set up for
<code class="docutils literal notranslate"><span class="pre">mygame/web/api/</span></code>. This is because the registration of models with the api is
strongly integrated with the REST api functionality. Easiest is probably to
copy over <code class="docutils literal notranslate"><span class="pre">evennia/web/api/urls.py</span></code> and modify it in place.</p>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Web-Admin.html" title="The Web Admin"
>next</a> |</li>
<li class="right" >
<a href="Website.html" title="Game website"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Evennia REST API</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,300 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>The Web Admin &#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" />
<link rel="next" title="Portal And Server" href="Portal-And-Server.html" />
<link rel="prev" title="Evennia REST API" href="Web-API.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Portal-And-Server.html" title="Portal And Server"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Web-API.html" title="Evennia REST API"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">The Web Admin</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">The Web Admin</a><ul>
<li><a class="reference internal" href="#usage">Usage</a><ul>
<li><a class="reference internal" href="#adding-objects-to-attributes">Adding objects to Attributes</a></li>
<li><a class="reference internal" href="#linking-accounts-and-characters">Linking Accounts and Characters</a></li>
<li><a class="reference internal" href="#building-with-the-admin">Building with the Admin</a></li>
</ul>
</li>
<li><a class="reference internal" href="#grant-others-access-to-the-admin">Grant others access to the admin</a></li>
<li><a class="reference internal" href="#customizing-the-web-admin">Customizing the web admin</a><ul>
<li><a class="reference internal" href="#change-the-title-of-the-admin">Change the title of the admin</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Web-API.html"
title="previous chapter">Evennia REST API</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Portal-And-Server.html"
title="next chapter">Portal And Server</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Web-Admin.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Web-Admin.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="the-web-admin">
<h1>The Web Admin<a class="headerlink" href="#the-web-admin" title="Permalink to this headline"></a></h1>
<p>The Evennia <em>Web admin</em> is a customized <a class="reference external" href="https://docs.djangoproject.com/en/3.2/ref/contrib/admin/">Django admin site</a>
used for manipulating the game database using a graphical interface. You
have to be logged into the site to use it. It then appears as an <code class="docutils literal notranslate"><span class="pre">Admin</span></code> link
the top of your website. You can also go to <a class="reference external" href="http://localhost:4001/admin">http://localhost:4001/admin</a> when
running locally.</p>
<p>Almost all actions done in the admin can also be done in-game by use of Admin-
or Builder-commands.</p>
<section id="usage">
<h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h2>
<p>The admin is pretty self-explanatory - you can see lists of each object type,
create new instances of each type and also add new Attributes/tags them. The
admin frontpage will give a summary of all relevant entities and how they are
used.</p>
<p>There are a few use cases that requires some additional explanation though.</p>
<section id="adding-objects-to-attributes">
<h3>Adding objects to Attributes<a class="headerlink" href="#adding-objects-to-attributes" title="Permalink to this headline"></a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">value</span></code> field of an Attribute is pickled into a special form. This is usually not
something you need to worry about (the admin will pickle/unpickle) the value
for you), <em>except</em> if you want to store a database-object in an attribute. Such
objects are actually stored as a <code class="docutils literal notranslate"><span class="pre">tuple</span></code> with object-unique data.</p>
<ol>
<li><p>Find the object you want to add to the Attribute. At the bottom of the first section
youll find the field <em>Serialized string</em>. This string shows a Python tuple like</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>(&#39;__packed_dbobj__&#39;, (&#39;objects&#39;, &#39;objectdb&#39;), &#39;2021:05:15-08:59:30:624660&#39;, 358)
</pre></div>
</div>
<p>Mark and copy this tuple-string to your clipboard exactly as it stands (parentheses and all).</p>
</li>
<li><p>Go to the entity that should have the new Attribute and create the Attribute. In its <code class="docutils literal notranslate"><span class="pre">value</span></code>
field, paste the tuple-string you copied before. Save!</p></li>
<li><p>If you want to store multiple objects in, say, a list, you can do so by literally
typing a python list <code class="docutils literal notranslate"><span class="pre">[tuple,</span> <span class="pre">tuple,</span> <span class="pre">tuple,</span> <span class="pre">...]</span></code> where you paste in the serialized
tuple-strings with commas. At some point its probably easier to do this in code though …</p></li>
</ol>
</section>
<section id="linking-accounts-and-characters">
<h3>Linking Accounts and Characters<a class="headerlink" href="#linking-accounts-and-characters" title="Permalink to this headline"></a></h3>
<p>In <code class="docutils literal notranslate"><span class="pre">MULTISESSION_MODE</span></code> 0 or 1, each connection can have one Account and one
Character, usually with the same name. Normally this is done by the user
creating a new account and logging in - a matching Character will then be
created for them. You can however also do so manually in the admin:</p>
<ol class="simple">
<li><p>First create the complete Account in the admin.</p></li>
<li><p>Next, create the Object (usually of <code class="docutils literal notranslate"><span class="pre">Character</span></code> typeclass) and name it the same
as the Account. It also needs a command-set. The default CharacterCmdset is a good bet.</p></li>
<li><p>In the <code class="docutils literal notranslate"><span class="pre">Puppeting</span> <span class="pre">Account</span></code> field, select the Account.</p></li>
<li><p>Make sure to save everything.</p></li>
<li><p>Click the <code class="docutils literal notranslate"><span class="pre">Link</span> <span class="pre">to</span> <span class="pre">Account</span></code> button (this will only work if you saved first). This will
add the needed locks and Attributes to the Account to allow them to immediately
connect to the Character when they next log in. This will (where possible):</p>
<ul class="simple">
<li><p>Set <code class="docutils literal notranslate"><span class="pre">account.db._last_puppet</span></code> to the Character.</p></li>
<li><p>Add Character to <code class="docutils literal notranslate"><span class="pre">account.db._playabel_characters</span></code> list.</p></li>
<li><p>Add/extend the <code class="docutils literal notranslate"><span class="pre">puppet:</span></code> lock on the Character to include <code class="docutils literal notranslate"><span class="pre">puppet:pid(&lt;Character.id&gt;)</span></code></p></li>
</ul>
</li>
</ol>
</section>
<section id="building-with-the-admin">
<h3>Building with the Admin<a class="headerlink" href="#building-with-the-admin" title="Permalink to this headline"></a></h3>
<p>Its possible (if probably not very practical at scale) to build and describe
rooms in the Admin.</p>
<ol class="simple">
<li><p>Create an <code class="docutils literal notranslate"><span class="pre">Object</span></code> of a Room-typeclass with a suitable room-name.</p></li>
<li><p>Set an Attribute desc on the room - the value of this Attribute is the
rooms description.</p></li>
<li><p>Add <code class="docutils literal notranslate"><span class="pre">Tags</span></code> of <code class="docutils literal notranslate"><span class="pre">type</span></code> alias to add room-aliases (no type for regular tags)</p></li>
</ol>
<p>Exits:</p>
<ol class="simple">
<li><p>Exits are <code class="docutils literal notranslate"><span class="pre">Objects</span></code> of an <code class="docutils literal notranslate"><span class="pre">Exit</span></code> typeclass, so create one.</p></li>
<li><p>The exit has <code class="docutils literal notranslate"><span class="pre">Location</span></code> of the room you just created.</p></li>
<li><p>Set <code class="docutils literal notranslate"><span class="pre">Destination</span></code> set to where the exit leads to.</p></li>
<li><p>Set a desc Attribute, this is shown if someone looks at the exit.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">Tags</span></code> of <code class="docutils literal notranslate"><span class="pre">type</span></code> alias are alternative names users can use to go through
this exit.</p></li>
</ol>
</section>
</section>
<section id="grant-others-access-to-the-admin">
<h2>Grant others access to the admin<a class="headerlink" href="#grant-others-access-to-the-admin" title="Permalink to this headline"></a></h2>
<p>The access to the admin is controlled by the <code class="docutils literal notranslate"><span class="pre">Staff</span> <span class="pre">status</span></code> flag on the
Account. Without this flag set, even superusers will not even see the admin
link on the web page. The staff-status has no in-game equivalence.</p>
<p>Only Superusers can change the <code class="docutils literal notranslate"><span class="pre">Superuser</span> <span class="pre">status</span></code> flag, and grant new
permissions to accounts. The superuser is the only permission level that is
also relevant in-game. <code class="docutils literal notranslate"><span class="pre">User</span> <span class="pre">Permissions</span></code> and <code class="docutils literal notranslate"><span class="pre">Groups</span></code> found on the <code class="docutils literal notranslate"><span class="pre">Account</span></code>
admin page <em>only</em> affects the admin - they have no connection to the in-game
<a class="reference internal" href="Permissions.html"><span class="doc std std-doc">Permissions</span></a> (Player, Builder, Admin etc).</p>
<p>For a staffer with <code class="docutils literal notranslate"><span class="pre">Staff</span> <span class="pre">status</span></code> to be able to actually do anything, the
superuser must grant at least some permissions for them on their Account. This
can also be good in order to limit mistakes. It can be a good idea to not allow
the <code class="docutils literal notranslate"><span class="pre">Can</span> <span class="pre">delete</span> <span class="pre">Account</span></code> permission, for example.</p>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>If you grant staff-status and permissions to an Account and they still cannot
access the admins content, try reloading the server.</p>
</div>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>If a staff member has access to the in-game ``py`` command, they can just as
well have their admin ``Superuser status`` set too. The reason is that ``py``
grants them all the power they need to set the ``is_superuser`` flag on their
account manually. There is a reason access to the ``py`` command must be
considered carefully ...
</pre></div>
</div>
</div>
</section>
<section id="customizing-the-web-admin">
<h2>Customizing the web admin<a class="headerlink" href="#customizing-the-web-admin" title="Permalink to this headline"></a></h2>
<p>Customizing the admin is a big topic and something beyond the scope of this
documentation. See the <a class="reference external" href="https://docs.djangoproject.com/en/3.2/ref/contrib/admin/">official Django docs</a> for
the details. This is just a brief summary.</p>
<p>See the <a class="reference internal" href="Website.html"><span class="doc std std-doc">Website</span></a> page for an overview of the components going into
generating a web page. The Django admin uses the same principle except that
Django provides a lot of tools to automate the admin-generation for us.</p>
<p>Admin templates are found in <code class="docutils literal notranslate"><span class="pre">evennia/web/templates/admin/</span></code> but youll find
this is relatively empty. This is because most of the templates are just
inherited directly from their original location in the Django package
(<code class="docutils literal notranslate"><span class="pre">django/contrib/admin/templates/</span></code>). So if you wanted to override one youd have
to copy it from <em>there</em> into your <code class="docutils literal notranslate"><span class="pre">mygame/templates/admin/</span></code> folder. Same is true
for CSS files.</p>
<p>The admin sites backend code (the views) is found in <code class="docutils literal notranslate"><span class="pre">evennia/web/admin/</span></code>. It
is organized into <code class="docutils literal notranslate"><span class="pre">admin</span></code>-classes, like <code class="docutils literal notranslate"><span class="pre">ObjectAdmin</span></code>, <code class="docutils literal notranslate"><span class="pre">AccountAdmin</span></code> etc.
These automatically use the underlying database models to generate useful views
for us without us havint go code the forms etc ourselves.</p>
<p>The top level <code class="docutils literal notranslate"><span class="pre">AdminSite</span></code> (the admin configuration referenced in django docs)
is found in <code class="docutils literal notranslate"><span class="pre">evennia/web/utils/adminsite.py</span></code>.</p>
<section id="change-the-title-of-the-admin">
<h3>Change the title of the admin<a class="headerlink" href="#change-the-title-of-the-admin" title="Permalink to this headline"></a></h3>
<p>By default the admins title is <code class="docutils literal notranslate"><span class="pre">Evennia</span> <span class="pre">web</span> <span class="pre">admin</span></code>. To change this, add the
following to your <code class="docutils literal notranslate"><span class="pre">mygame/web/urls.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/web/urls.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">django.conf.admin</span> <span class="kn">import</span> <span class="n">site</span>
<span class="c1">#...</span>
<span class="n">site</span><span class="o">.</span><span class="n">site_header</span> <span class="o">=</span> <span class="s2">&quot;My great game admin&quot;</span>
</pre></div>
</div>
<p>Reload the server and the admins title header will have changed.</p>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Portal-And-Server.html" title="Portal And Server"
>next</a> |</li>
<li class="right" >
<a href="Web-API.html" title="Evennia REST API"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">The Web Admin</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,443 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Web Client &#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" />
<link rel="next" title="Bootstrap Components and Utilities" href="Bootstrap-Components-and-Utilities.html" />
<link rel="prev" title="Webserver" href="Webserver.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Bootstrap-Components-and-Utilities.html" title="Bootstrap Components and Utilities"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Webserver.html" title="Webserver"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Web Client</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Web Client</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="#a-side-note-on-html-messages-vrs-text2html-messages">A side note on html messages vrs text2html messages</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>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Webserver.html"
title="previous chapter">Webserver</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Bootstrap-Components-and-Utilities.html"
title="next chapter">Bootstrap Components and Utilities</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Webclient.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="web-client">
<h1>Web Client<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</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, and a couple of example plugins to show how you could implement new plugin features.</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>
<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 locations within your projects <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> directories.
These 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/server/.static/</span></code> and then
copies in all of your <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> files. 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 list of in-use plugins, you need to override base.html by copying
<code class="docutils literal notranslate"><span class="pre">evennia/web/templates/webclient/base.html</span></code> to
<code class="docutils literal notranslate"><span class="pre">mygame/web/templates/webclient/base.html</span></code> and editing it to add your new plugin.</p>
</section>
</section>
<section class="tex2jax_ignore mathjax_ignore" 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>
</section>
<section class="tex2jax_ignore mathjax_ignore" 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>
</section>
<section class="tex2jax_ignore mathjax_ignore" 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>
</section>
<section class="tex2jax_ignore mathjax_ignore" 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">html.js</span></code> A basic plugin to allow the client to handle “raw html” messages from the server, this
allows the server to send native HTML messages like &gt;div style=s&lt;styled text&gt;/div&lt;</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">text2html.js</span></code> Provides a new message handler type: <code class="docutils literal notranslate"><span class="pre">text2html</span></code>, similar to the multimedia and html
plugins. This plugin provides a way to offload rendering the regular pipe-styled ASCII messages
to the client. This allows the server to do less work, while also allowing the client a place to
customize this conversion process. To use this plugin you will need to override the current commands
in Evennia, changing any place where a raw text output message is generated and turn it into a
<code class="docutils literal notranslate"><span class="pre">text2html</span></code> message. For example: <code class="docutils literal notranslate"><span class="pre">target.msg(&quot;my</span> <span class="pre">text&quot;)</span></code> becomes: <code class="docutils literal notranslate"><span class="pre">target.msg(text2html=(&quot;my</span> <span class="pre">text&quot;))</span></code>
(even better, use a webclient pane routing tag: <code class="docutils literal notranslate"><span class="pre">target.msg(text2html=(&quot;my</span> <span class="pre">text&quot;,</span> <span class="pre">{&quot;type&quot;:</span> <span class="pre">&quot;sometag&quot;}))</span></code>)
<code class="docutils literal notranslate"><span class="pre">text2html</span></code> messages should format and behave identically to the server-side generated text2html() output.</p></li>
</ul>
</section>
<section class="tex2jax_ignore mathjax_ignore" id="a-side-note-on-html-messages-vrs-text2html-messages">
<h1>A side note on html messages vrs text2html messages<a class="headerlink" href="#a-side-note-on-html-messages-vrs-text2html-messages" title="Permalink to this headline"></a></h1>
<p>So…lets say you have a desire to make your webclient output more like standard webpages…
For telnet clients, you could collect a bunch of text lines together, with ASCII formatted borders, etc.
Then send the results to be rendered client-side via the text2html plugin.</p>
<p>But for webclients, you could format a message directly with the html plugin to render the whole thing as an
HTML table, like so:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="c1"># Server Side Python Code:</span>
<span class="k">if</span> <span class="n">target</span><span class="o">.</span><span class="n">is_webclient</span><span class="p">():</span>
<span class="c1"># This can be styled however you like using CSS, just add the CSS file to web/static/webclient/css/...</span>
<span class="n">table</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">&quot;&lt;table&gt;&quot;</span><span class="p">,</span>
<span class="s2">&quot;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;3&lt;/td&gt;&lt;/tr&gt;&quot;</span><span class="p">,</span>
<span class="s2">&quot;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;6&lt;/td&gt;&lt;/tr&gt;&quot;</span><span class="p">,</span>
<span class="s2">&quot;&lt;/table&gt;&quot;</span>
<span class="p">]</span>
<span class="n">target</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span> <span class="n">html</span><span class="o">=</span><span class="p">(</span> <span class="s2">&quot;&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">table</span><span class="p">),</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;mytag&quot;</span><span class="p">})</span> <span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># This will use the client to render this as &quot;plain, simple&quot; ASCII text, the same</span>
<span class="c1"># as if it was rendered server-side via the Portal&#39;s text2html() functions</span>
<span class="n">table</span> <span class="o">=</span> <span class="p">[</span>
<span class="s2">&quot;#############&quot;</span><span class="p">,</span>
<span class="s2">&quot;# 1 # 2 # 3 #&quot;</span><span class="p">,</span>
<span class="s2">&quot;#############&quot;</span><span class="p">,</span>
<span class="s2">&quot;# 4 # 5 # 6 #&quot;</span><span class="p">,</span>
<span class="s2">&quot;#############&quot;</span>
<span class="p">]</span>
<span class="n">target</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span> <span class="n">html2html</span><span class="o">=</span><span class="p">(</span> <span class="s2">&quot;</span><span class="se">\n</span><span class="s2">&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">table</span><span class="p">),</span> <span class="p">{</span><span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="s2">&quot;mytag&quot;</span><span class="p">})</span> <span class="p">)</span>
</pre></div>
</div>
</section>
<section class="tex2jax_ignore mathjax_ignore" 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.
The Goldenlayout plugin framework can help with this.</p>
<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/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/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>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Bootstrap-Components-and-Utilities.html" title="Bootstrap Components and Utilities"
>next</a> |</li>
<li class="right" >
<a href="Webserver.html" title="Webserver"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Web Client</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,213 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>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" />
<link rel="next" title="Web Client" href="Webclient.html" />
<link rel="prev" title="Server component" href="Server.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Webclient.html" title="Web Client"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Server.html" title="Server component"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webserver</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Webserver</a><ul>
<li><a class="reference internal" href="#basic-webserver-data-flow">Basic Webserver data flow</a><ul>
<li><a class="reference internal" href="#a-note-on-the-webclient">A note on the webclient</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Server.html"
title="previous chapter">Server component</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Webclient.html"
title="next chapter">Web Client</a></p>
<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>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Webserver.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="webserver">
<h1>Webserver<a class="headerlink" href="#webserver" title="Permalink to this headline"></a></h1>
<p>When Evennia starts it also spins up its own Twisted-based web server. The
webserver is responsible for serving the html pages of the games website. It
can also serve static resources like images and music.</p>
<p>The webclient runs as part of the <a class="reference internal" href="Portal-And-Server.html"><span class="doc std std-doc">Server</span></a> process of
Evennia. This means that it can directly access cached objects modified
in-game, and there is no risk of working with objects that are temporarily
out-of-sync in the database.</p>
<p>The webserver runs on Twisted and is meant to be used in a production
environment. It leverages the Django web framework and provides:</p>
<ul class="simple">
<li><p>A <a class="reference internal" href="Website.html"><span class="doc std std-doc">Game Website</span></a> - this is what you see when you go to
<code class="docutils literal notranslate"><span class="pre">localhost:4001</span></code>. The look of the website is meant to be customized to your
game. Users logged into the website will be auto-logged into the game if they
do so with the webclient since they share the same login credentials (there
is no way to safely do auto-login with telnet clients).</p></li>
<li><p>The <a class="reference internal" href="Web-Admin.html"><span class="doc std std-doc">Web Admin</span></a> is based on the Django web admin and allows you to
edit the game database in a graphical interface.</p></li>
<li><p>The <a class="reference internal" href="Webclient.html"><span class="doc std std-doc">Webclient</span></a> page is served by the webserver, but the actual
game communication (sending/receiving data) is done by the javascript client
on the page opening a websocket connection directly to Evennias Portal.</p></li>
<li><p>The <a class="reference internal" href="Web-API.html"><span class="doc std std-doc">Evennia REST-API</span></a> allows for accessing the database from outside the game
(only if `REST_API_ENABLED=True).</p></li>
</ul>
<section id="basic-webserver-data-flow">
<h2>Basic Webserver data flow<a class="headerlink" href="#basic-webserver-data-flow" title="Permalink to this headline"></a></h2>
<ol class="simple">
<li><p>A user enters an url in their browser (or clicks a button). This leads to
the browser sending a <em>HTTP request</em> to the server containing an url-path
(like for <code class="docutils literal notranslate"><span class="pre">https://localhost:4001/</span></code>, the part of the url we need to consider
<code class="docutils literal notranslate"><span class="pre">/</span></code>). Other possibilities would be <code class="docutils literal notranslate"><span class="pre">/admin/</span></code>, <code class="docutils literal notranslate"><span class="pre">/login/</span></code>, <code class="docutils literal notranslate"><span class="pre">/channels/</span></code> etc.</p></li>
<li><p>evennia (through Django) will make use of the regular expressions registered
in the <code class="docutils literal notranslate"><span class="pre">urls.py</span></code> file. This acts as a rerouter to <em>views</em>, which are
regular Python functions or callable classes able to process the incoming
request (think of these as similar to the right Evennia Command being
selected to handle your input - views are like Commands in this sense). In
the case of <code class="docutils literal notranslate"><span class="pre">/</span></code> we reroute to a view handling the main index-page of the
website.</p></li>
<li><p>The view code will prepare all the data needed by the web page. For the default
index page, this means gather the game statistics so you can see how many
are currently connected to the game etc.</p></li>
<li><p>The view will next fetch a <em>template</em>. A template is a HTML-document with special
placeholder tags (written as <code class="docutils literal notranslate"><span class="pre">{{...}}</span></code> or <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">...</span> <span class="pre">%}</span></code> usually). These
placeholders allow the view to inject dynamic content into the HTML and make
the page customized to the current situation. For the index page, it means
injecting the current player-count in the right places of the html page. This
is called rendering the template. The result is a complete HTML page.</p></li>
<li><p>(The view can also pull in a <em>form</em> to customize user-input in a similar way.)</p></li>
<li><p>The finished HTML page is packed into a <em>HTTP response</em> and returned to the
web browser, which can now display the page!</p></li>
</ol>
<section id="a-note-on-the-webclient">
<h3>A note on the webclient<a class="headerlink" href="#a-note-on-the-webclient" title="Permalink to this headline"></a></h3>
<p>The web browser can also execute code directly without talking to the Server.
This code must be written/loaded into the web page and is written using the
Javascript programming language (there is no way around this, it is what web
browsers understand). Executing Javascript is something the web browser does,
it operates independently from Evennia. Small snippets of javascript can be
used on a page to have buttons react, make small animations etc that doesnt
require the server.</p>
<p>In the case of the <a class="reference internal" href="Webclient.html"><span class="doc std std-doc">Webclient</span></a>, Evennia will load the Webclient page
as above, but the page then initiates Javascript code (a lot of it) responsible
for actually displaying the client GUI, allows you to resize windows etc.</p>
<p>After it starts, the webclient calls home and spins up a
<a class="reference external" href="https://en.wikipedia.org/wiki/WebSocket">websocket</a> link to the Evennia Portal - this
is how all data is then exchanged. So after the initial loading of the
webclient page, the above sequence doesnt happen again until close the tab and
come back or you reload it manually in your browser.</p>
</section>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Webclient.html" title="Web Client"
>next</a> |</li>
<li class="right" >
<a href="Server.html" title="Server component"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Webserver</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>

View file

@ -0,0 +1,534 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<title>Game website &#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" />
<link rel="next" title="Evennia REST API" href="Web-API.html" />
<link rel="prev" title="Signals" href="Signals.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Web-API.html" title="Evennia REST API"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="Signals.html" title="Signals"
accesskey="P">previous</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-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Game website</a></li>
</ul>
<div class="develop">develop branch</div>
</div>
<div class="document">
<div class="documentwrapper">
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
<div class="sphinxsidebarwrapper">
<p class="logo"><a href="../index.html">
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
</a></p>
<div id="searchbox" style="display: none" role="search">
<h3 id="searchlabel">Quick search</h3>
<div class="searchformwrapper">
<form class="search" action="../search.html" method="get">
<input type="text" name="q" aria-labelledby="searchlabel" />
<input type="submit" value="Go" />
</form>
</div>
</div>
<script>$('#searchbox').show(0);</script>
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Game website</a><ul>
<li><a class="reference internal" href="#modifying-the-default-website">Modifying the default Website</a></li>
<li><a class="reference internal" href="#examples-of-commom-web-changes">Examples of commom web changes</a><ul>
<li><a class="reference internal" href="#change-title-and-blurb">Change Title and blurb</a></li>
<li><a class="reference internal" href="#change-the-logo">Change the Logo</a></li>
<li><a class="reference internal" href="#change-front-page-html">Change front page HTML</a></li>
<li><a class="reference internal" href="#change-webpage-colors-and-styling">Change webpage colors and styling</a></li>
<li><a class="reference internal" href="#change-front-page-functionality">Change front page functionality</a></li>
<li><a class="reference internal" href="#change-other-website-pages">Change other website pages</a></li>
</ul>
</li>
<li><a class="reference internal" href="#adding-a-new-web-page">Adding a new web page</a><ul>
<li><a class="reference internal" href="#using-flat-pages">Using Flat Pages</a></li>
<li><a class="reference internal" href="#add-custom-new-page">Add Custom new page</a></li>
</ul>
</li>
<li><a class="reference internal" href="#user-forms">User forms</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="Signals.html"
title="previous chapter">Signals</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Web-API.html"
title="next chapter">Evennia REST API</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/Components/Website.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com">Home page</a> </li>
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
<li><a href="http://games.evennia.com">Game Index</a> </li>
<li>
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
<a href="https://evennia.blogspot.com/">Blog</a>
</li>
</ul>
<h3>Versions</h3>
<ul>
<li><a href="Website.html">1.0-dev (develop branch)</a></li>
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="game-website">
<h1>Game website<a class="headerlink" href="#game-website" title="Permalink to this headline"></a></h1>
<p>When Evennia starts it will also start a <a class="reference internal" href="Webserver.html"><span class="doc std std-doc">Webserver</span></a> as part of the
<a class="reference internal" href="Portal-And-Server.html"><span class="doc std std-doc">Server</span></a> process. This uses <a class="reference external" href="https://docs.djangoproject.com">Django</a>
to present a simple but functional default game website. With the default setup,
open your browser to <a class="reference external" href="http://localhost:4001">localhost:4001</a> or <a class="reference external" href="http://127.0.0.1:4001">127.0.0.1:4001</a>
to see it.</p>
<p>The website allows existing players to log in using an account-name and
password they previously used to register with the game. If a user logs in with
the <a class="reference internal" href="Webclient.html"><span class="doc std std-doc">Webclient</span></a> they will also log into the website and vice-versa.
So if you are logged into the website, opening the webclient will automatically
log you into the game as that account.</p>
<p>The default website shows a “Welcome!” page with a few links to useful
resources. It also shows some statistics about how many players are currently
connected.</p>
<p>In the top menu you can find</p>
<ul class="simple">
<li><p><em>Home</em> - Get back to front page.</p></li>
<li><p><em>Documentation</em> - A link to the latest stable Evennia documentation.</p></li>
<li><p><em>Characters</em> - This is a demo of connecting in-game characters to the website.
It will display a list of all entities of the
_typeclasses.characters.Character` typeclass and allow you to view their
description with an optional image. The list is only available to logged-in
users.</p></li>
<li><p><em>Channels</em> - This is a demo of connecting in-game chats to the website. It will
show a list of all channels available to you and allow you to view the latest
discussions. Most channels require logging in, but the <code class="docutils literal notranslate"><span class="pre">Public</span></code> channel can
also be viewed by non-loggedin users.</p></li>
<li><p><em>Help</em> - This ties the in-game <a class="reference internal" href="Help-System.html"><span class="doc std std-doc">Help system</span></a> to the website. All
database-based help entries that are publicly available or accessible to your
account can be read. This is a good way to present a body of help for people
to read outside of the game.</p></li>
<li><p><em>Play Online</em> - This opens the <a class="reference internal" href="Webclient.html"><span class="doc std std-doc">Webclient</span></a> in the browser.</p></li>
<li><p><em>Admin</em> The [Web admin](Web admin) will only show if you are logged in.</p></li>
<li><p><em>Log in/out</em> - Allows you to authenticate using the same credentials you use
in the game.</p></li>
<li><p><em>Register</em> - Allows you to register a new account. This is the same as
creating a new account upon first logging into the game).</p></li>
</ul>
<section id="modifying-the-default-website">
<h2>Modifying the default Website<a class="headerlink" href="#modifying-the-default-website" title="Permalink to this headline"></a></h2>
<p>You can modify and override all aspects of the web site from your game dir.
Youll mostly be doing so in your settings file
(<code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code> and in the gamedirs <code class="docutils literal notranslate"><span class="pre">web/folder</span></code>
(<code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> if your game folder is <code class="docutils literal notranslate"><span class="pre">mygame/</span></code>).</p>
<blockquote>
<div><p>When testing your modifications, its a good idea to add <code class="docutils literal notranslate"><span class="pre">DEBUG</span> <span class="pre">=</span> <span class="pre">True</span></code> to
your settings file. This will give you nice informative tracebacks directly
in your browser instead of generic 404 or 500 error pages. Just remember that
DEBUG mode leaks memory (for retaining debug info) and is <em>not</em> safe to use
for a production game!</p>
</div></blockquote>
<p>As explained on the <a class="reference internal" href="Webserver.html"><span class="doc std std-doc">Webserver</span></a> page, the process for getting a web
page is</p>
<ol class="simple">
<li><p>Web browser sends HTTP request to server with an URL</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">urls.py</span></code> uses regex to match that URL to a <em>view</em> (a Python function or callable class).</p></li>
<li><p>The correct Python view is loaded and executes.</p></li>
<li><p>The view pulls in a <em>template</em>, a HTML document with placeholder markers in it,
and fills those in as needed (it may also use a <em>form</em> to customize user-input in the same way).
A HTML page may also in turn point to static resources (usually CSS, sometimes images etc).</p></li>
<li><p>The rendered HTML page is returned to the browser as a HTTP response. If
the HTML page requires static resources are requested, the browser will
fetch those separately before displaying it to the user.</p></li>
</ol>
<p>If you look at the <a class="reference external" href="https://github.com/evennia/evennia/blob/develop/evennia/web">evennia/web/</a> directory youll find the following
structure (leaving out stuff not relevant to the website):</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">evennia</span><span class="o">/</span><span class="n">web</span><span class="o">/</span>
<span class="o">...</span>
<span class="n">static</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">css</span><span class="o">/</span>
<span class="p">(</span><span class="n">css</span> <span class="n">style</span> <span class="n">files</span><span class="p">)</span>
<span class="n">images</span><span class="o">/</span>
<span class="p">(</span><span class="n">images</span> <span class="n">to</span> <span class="n">show</span><span class="p">)</span>
<span class="n">templates</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="p">(</span><span class="n">html</span> <span class="n">files</span><span class="p">)</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
<span class="n">views</span><span class="o">/</span>
<span class="p">(</span><span class="n">python</span> <span class="n">files</span> <span class="n">related</span> <span class="n">to</span> <span class="n">website</span><span class="p">)</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<p>The top-level <code class="docutils literal notranslate"><span class="pre">web/urls.py</span></code> file includes the <code class="docutils literal notranslate"><span class="pre">web/website/urls.py</span></code> file -
that way all the website-related url-handling is kept in the same place.</p>
<p>This is the layout of the <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> folder relevant for the website:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">mygame</span><span class="o">/</span><span class="n">web</span><span class="o">/</span>
<span class="o">...</span>
<span class="n">static</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">css</span><span class="o">/</span>
<span class="n">images</span><span class="o">/</span>
<span class="n">templates</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">website</span><span class="o">/</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
<span class="n">views</span><span class="o">/</span>
<span class="n">urls</span><span class="o">.</span><span class="n">py</span>
</pre></div>
</div>
<div class="versionchanged">
<p><span class="versionmodified changed">Changed in version 1.0: </span>Game folders created with older versions of Evennia will lack most of this
convenient <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> layout. If you use a game dir from an older version,
you should copy over the missing <code class="docutils literal notranslate"><span class="pre">evennia/game_template/web/</span></code> folders from
there, as well as the main <a class="reference external" href="http://urls.py">urls.py</a> file.</p>
</div>
<p>As you can see, the <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> folder is a copy of the <code class="docutils literal notranslate"><span class="pre">evennia/web/</span></code> folder
structure except the <code class="docutils literal notranslate"><span class="pre">mygame</span></code> folders are mostly empty.</p>
<p>For static- and template-files, Evennia will <em>first</em>
look in <code class="docutils literal notranslate"><span class="pre">mygame/static</span></code> and <code class="docutils literal notranslate"><span class="pre">mygame/templates</span></code> before going to the default
locations in <code class="docutils literal notranslate"><span class="pre">evennia/web/</span></code>. So override these resources, you just need to put
a file with the same name in the right spot under <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code> (and then
reload the server). Easiest is often to copy the original over and modify it.</p>
<p>Overridden views (Python modules) also need an additional tweak to the
<code class="docutils literal notranslate"><span class="pre">website/urls.py</span></code> file - you must make sure to repoint the url to the new
version rather than it using the original.</p>
</section>
<section id="examples-of-commom-web-changes">
<h2>Examples of commom web changes<a class="headerlink" href="#examples-of-commom-web-changes" title="Permalink to this headline"></a></h2>
<div class="admonition important">
<p class="admonition-title">Important</p>
<p>Django is a very mature web-design framework. There are endless
internet-tutorials, courses and books available to explain how to use Django.
So these examples only serve as a first primer to get you started.</p>
</div>
<section id="change-title-and-blurb">
<h3>Change Title and blurb<a class="headerlink" href="#change-title-and-blurb" title="Permalink to this headline"></a></h3>
<p>The websites title and blurb are simply changed by tweaking
<code class="docutils literal notranslate"><span class="pre">settings.SERVERNAME</span></code> and <code class="docutils literal notranslate"><span class="pre">settings.GAME_SLOGAN</span></code>. Your settings file is in
<code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>, just set/add</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>SERVERNAME = &quot;My Awesome Game&quot;
GAME_SLOGAN = &quot;The best game in the world&quot;
</pre></div>
</div>
</section>
<section id="change-the-logo">
<h3>Change the Logo<a class="headerlink" href="#change-the-logo" title="Permalink to this headline"></a></h3>
<p>The Evennia googly-eyed snake logo is probably not what you want for your game.
The template looks for a file <code class="docutils literal notranslate"><span class="pre">web/static/website/images/evennia_logo.png</span></code>. Just
plop your own PNG logo (64x64 pixels large) in there and name it the same.</p>
</section>
<section id="change-front-page-html">
<h3>Change front page HTML<a class="headerlink" href="#change-front-page-html" title="Permalink to this headline"></a></h3>
<p>The front page of the website is usually referred to as the index in HTML
parlance.</p>
<p>The frontpage template is found in <code class="docutils literal notranslate"><span class="pre">evennia/web/templates/website/index.html</span></code>.
Just copy this to the equivalent place in <code class="docutils literal notranslate"><span class="pre">mygame/web/</span></code>. Modify it there and
reload the server to see your changes.</p>
<p>Django templates has a few special features that separate them from normal HTML
documents - they contain a special templating language marked with <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">...</span> <span class="pre">%}</span></code> and
<code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">...</span> <span class="pre">}}</span></code>.</p>
<p>Some important things to know:</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extends</span> <span class="pre">&quot;base.html&quot;</span> <span class="pre">%}</span></code> - This is equivalent to a Python
<code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">othermodule</span> <span class="pre">import</span> <span class="pre">*</span></code> statement, but for templates. It allows a given template
to use everything from the imported (extended) template, but also to override anything
it wants to change. This makes it easy to keep all pages looking the same and avoids
a lot of boiler plate.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">blockname</span> <span class="pre">%}...{%</span> <span class="pre">endblock</span> <span class="pre">%}</span></code> - Blocks are inheritable, named pieces of code
that are modified in one place and then used elsewhere. This works a bit in reverse to
normal inheritance, because its commonly in such a way that <code class="docutils literal notranslate"><span class="pre">base.html</span></code> defines an empty
block, lets say <code class="docutils literal notranslate"><span class="pre">contents</span></code>: <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">contents</span> <span class="pre">%}{%</span> <span class="pre">endblock</span> <span class="pre">%}</span></code> but makes sure to put
that <em>in the right place</em>, say in the main body, next to the sidebar etc. Then each page
does <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extends</span> <span class="pre">&quot;base.html</span> <span class="pre">%&quot;}</span></code> and makes their own <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">block</span> <span class="pre">contents}</span> <span class="pre">&lt;actual</span> <span class="pre">content&gt;</span> <span class="pre">{%</span> <span class="pre">endblock</span> <span class="pre">%}</span></code>.
Their <code class="docutils literal notranslate"><span class="pre">contents</span></code> block will now override the empty one in <code class="docutils literal notranslate"><span class="pre">base.html</span></code> and appear in the right
place in the document, without the extending template having to specifying everything else
around it!</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">...</span> <span class="pre">}}</span></code> are slots usually embedded inside HTML tags or content. They reference a
<em>context</em> (basically a dict) that the Python <em>view</em> makes available to it.
Keys on the context are accessed with dot-notation, so if you provide a
context <code class="docutils literal notranslate"><span class="pre">{&quot;stats&quot;:</span> <span class="pre">{&quot;hp&quot;:</span> <span class="pre">10,</span> <span class="pre">&quot;mp&quot;:</span> <span class="pre">5}}</span></code> to your template, you could access
that as <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">stats.hp</span> <span class="pre">}}</span></code> to display <code class="docutils literal notranslate"><span class="pre">10</span></code> at that location to display <code class="docutils literal notranslate"><span class="pre">10</span></code> at
that location.</p></li>
</ul>
<p>This allows for template inheritance (making it easier to make all
pages look the same without rewriting the same thing over and over)</p>
<p>Theres a lot more information to be found in the <a class="reference external" href="https://docs.djangoproject.com/en/3.2/ref/templates/language/">Django template language documentation</a>.</p>
</section>
<section id="change-webpage-colors-and-styling">
<h3>Change webpage colors and styling<a class="headerlink" href="#change-webpage-colors-and-styling" title="Permalink to this headline"></a></h3>
<p>You can tweak the <a class="reference external" href="https://en.wikipedia.org/wiki/Cascading_Style_Sheets">CSS</a> of the entire
website. If you investigate the <code class="docutils literal notranslate"><span class="pre">evennia/web/templates/website/base.html</span></code> file youll see that we
use the <a class="reference external" href="https://getbootstrap.com/docs/4.6/getting-started/introduction/">Bootstrap
4</a> toolkit.</p>
<p>Much structural HTML functionality is actually coming from bootstrap, so you
will often be able to just add bootstrap CSS classes to elements in the HTML
file to get various effects like text-centering or similar.</p>
<p>The websites custom CSS is found in
<code class="docutils literal notranslate"><span class="pre">evennia/web/static/website/css/website.css</span></code> but we also look for a (currently
empty) <code class="docutils literal notranslate"><span class="pre">custom.css</span></code> in the same location. You can override either, but it may
be easier to revert your changes if you only add things to <code class="docutils literal notranslate"><span class="pre">custom.css</span></code>.</p>
<p>Copy the CSS file you want to modify to the corresponding location in <code class="docutils literal notranslate"><span class="pre">mygame/web</span></code>.
Modify it and reload the server to see your changes.</p>
<p>You can also apply static files without reloading, but running this in the
terminal:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>evennia collectstatic --no-input
</pre></div>
</div>
<p>(this is run automatically when reloading the server).</p>
<blockquote>
<div><p>Note that before you see new CSS files applied you may need to refresh your
browser without cache (Ctrl-F5 in Firefox, for example).</p>
</div></blockquote>
<p>As an example, add/copy <code class="docutils literal notranslate"><span class="pre">custom.css</span></code> to <code class="docutils literal notranslate"><span class="pre">mygame/web/static/website/css/</span></code> and
add the following:</p>
<div class="highlight-css notranslate"><div class="highlight"><pre><span></span><span class="p">.</span><span class="nc">navbar</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#7a3d54</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
<span class="p">.</span><span class="nc">footer</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="k">background-color</span><span class="p">:</span><span class="w"> </span><span class="mh">#7a3d54</span><span class="p">;</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
<p>Reload and your website now has a red theme!</p>
<blockquote>
<div><p>Hint: Learn to use your web browsers <a class="reference external" href="https://torquemag.io/2020/06/browser-developer-tools-tutorial/">Developer tools</a>.
These allow you to tweak CSS live to find a look you like and copy it into
the .css file only when you want to make the changes permanent.</p>
</div></blockquote>
</section>
<section id="change-front-page-functionality">
<h3>Change front page functionality<a class="headerlink" href="#change-front-page-functionality" title="Permalink to this headline"></a></h3>
<p>The logic is all in the view. To find where the index-page view is found, we
look in <code class="docutils literal notranslate"><span class="pre">evennia/web/website/urls.py</span></code>. Here we find the following line:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in evennia/web/website/urls.py</span>
<span class="o">...</span>
<span class="c1"># website front page</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">index</span><span class="o">.</span><span class="n">EvenniaIndexView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;index&quot;</span><span class="p">),</span>
<span class="o">...</span>
</pre></div>
</div>
<p>The first <code class="docutils literal notranslate"><span class="pre">&quot;&quot;</span></code> is the empty url - root - what you get if you just enter <code class="docutils literal notranslate"><span class="pre">localhost:4001/</span></code>
with no extra path. As expected, this leads to the index page. By looking at the imports
we find the view is in in <code class="docutils literal notranslate"><span class="pre">evennia/web/website/views/index.py</span></code>.</p>
<p>Copy this file to the corresponding location in <code class="docutils literal notranslate"><span class="pre">mygame/web</span></code>. Then tweak your <code class="docutils literal notranslate"><span class="pre">mygame/web/website/urls.py</span></code>
file to point to the new file:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/web/website/urls.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">web.website.views</span> <span class="kn">import</span> <span class="n">index</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;&quot;</span><span class="p">,</span> <span class="n">index</span><span class="o">.</span><span class="n">EvenniaIndexView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;index&quot;</span><span class="p">)</span>
<span class="p">]</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>So we just import <code class="docutils literal notranslate"><span class="pre">index</span></code> from the new location and point to it. After a reload
the front page will now redirect to use your copy rather than the original.</p>
<p>The frontpage view is a class <code class="docutils literal notranslate"><span class="pre">EvenniaIndexView</span></code>. This is a <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/class-based-views/">Django class-based view</a>.
Its a little less visible what happens in a class-based view than in a function (since
the class implements a lot of functionality as methods), but its powerful and
much easier to extend/modify.</p>
<p>The class property <code class="docutils literal notranslate"><span class="pre">template_name</span></code> sets the location of the template used under
the <code class="docutils literal notranslate"><span class="pre">templates/</span></code> folder. So <code class="docutils literal notranslate"><span class="pre">website/index.html</span></code> points to
<code class="docutils literal notranslate"><span class="pre">web/templates/website/index.html</span></code> (as we already explored above.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">get_context_data</span></code> is a convenient method for providing the context for the
template. In the index-pages case we want the game stats (number of recent
players etc). These are then made available to use in <code class="docutils literal notranslate"><span class="pre">{{</span> <span class="pre">...</span> <span class="pre">}}</span></code> slots in the
template as described in the previous section.</p>
</section>
<section id="change-other-website-pages">
<h3>Change other website pages<a class="headerlink" href="#change-other-website-pages" title="Permalink to this headline"></a></h3>
<p>The other sub pages are handled in the same way - copy the template or static
resource to the right place, or copy the view and repoint your <code class="docutils literal notranslate"><span class="pre">website/urls.py</span></code> to
your copy. Just remember to reload.</p>
</section>
</section>
<section id="adding-a-new-web-page">
<h2>Adding a new web page<a class="headerlink" href="#adding-a-new-web-page" title="Permalink to this headline"></a></h2>
<section id="using-flat-pages">
<h3>Using Flat Pages<a class="headerlink" href="#using-flat-pages" title="Permalink to this headline"></a></h3>
<p>The absolutely simplest way to add a new web page is to use the <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">Pages</span></code>
app available in the <a class="reference internal" href="Web-Admin.html"><span class="doc std std-doc">Web Admin</span></a>. The page will appear with the same
styling as the rest of the site.</p>
<p>For the <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">pages</span></code> module to work you must first set up a <em>Site</em> (or
domain) to use. You only need to this once.</p>
<ul class="simple">
<li><p>Go to the Web admin and select <code class="docutils literal notranslate"><span class="pre">Sites</span></code>. If your
game is at <code class="docutils literal notranslate"><span class="pre">mygreatgame.com</span></code>, thats the domain you need to add. For local
experimentation, add the domain <code class="docutils literal notranslate"><span class="pre">localhost:4001</span></code>. Note the <code class="docutils literal notranslate"><span class="pre">id</span></code> of the domain
(look at the url when you click on the new domain, if its for example
<code class="docutils literal notranslate"><span class="pre">http://localhost:4001/admin/sites/site/2/change/</span></code>, then the id is <code class="docutils literal notranslate"><span class="pre">2</span></code>).</p></li>
<li><p>Now add the line <code class="docutils literal notranslate"><span class="pre">SITE_ID</span> <span class="pre">=</span> <span class="pre">&lt;id&gt;</span></code> to your settings file.</p></li>
</ul>
<p>Next you create new pages easily.</p>
<ul class="simple">
<li><p>Go the <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">Pages</span></code> web admin and choose to add a new flat page.</p></li>
<li><p>Set the url. If you want the page to appear as e.g. <code class="docutils literal notranslate"><span class="pre">localhost:4001/test/</span></code>, then
add <code class="docutils literal notranslate"><span class="pre">/test/</span></code> here. You need to add both leading and trailing slashes.</p></li>
<li><p>Set <code class="docutils literal notranslate"><span class="pre">Title</span></code> to the name of the page.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">Content</span></code> is the HTML content of the body of the page. Go wild!</p></li>
<li><p>Finally pick the <code class="docutils literal notranslate"><span class="pre">Site</span></code> you made before, and save.</p></li>
<li><p>(in the advanced section you can make it so that you have to login to see the page etc).</p></li>
</ul>
<p>You can now go to <code class="docutils literal notranslate"><span class="pre">localhost:4001/test/</span></code> and see your new page!</p>
</section>
<section id="add-custom-new-page">
<h3>Add Custom new page<a class="headerlink" href="#add-custom-new-page" title="Permalink to this headline"></a></h3>
<p>The <code class="docutils literal notranslate"><span class="pre">Flat</span> <span class="pre">Pages</span></code> page doesnt allow for (much) dynamic content and customization. For
this you need to add the needed components yourself.</p>
<p>Lets see how to make a <code class="docutils literal notranslate"><span class="pre">/test/</span></code> page from scratch.</p>
<ul>
<li><p>Add a new <code class="docutils literal notranslate"><span class="pre">test.html</span></code> file under <code class="docutils literal notranslate"><span class="pre">mygame/web/templates/website/</span></code>. Easiest is to base
this off an existing file. Make sure to <code class="docutils literal notranslate"><span class="pre">{%</span> <span class="pre">extend</span> <span class="pre">base.html</span> <span class="pre">%}</span></code> if you want to
get the same styling as the rest of your site.</p></li>
<li><p>Add a new view <code class="docutils literal notranslate"><span class="pre">testview.py</span></code> under <code class="docutils literal notranslate"><span class="pre">mygame/web/website/views/</span></code> (dont name it <code class="docutils literal notranslate"><span class="pre">test.py</span></code> or
Django/Evennia will think it contains unit tests). Add a view there to process
your page. This is a minimal view to start from (read much more <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/class-based-views/">in the Django docs</a>):</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/web/website/views/testview.py</span>
<span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">TemplateView</span>
<span class="k">class</span> <span class="nc">MyTestView</span><span class="p">(</span><span class="n">TemplateView</span><span class="p">):</span>
<span class="n">template_name</span> <span class="o">=</span> <span class="s2">&quot;website/test.html&quot;</span>
</pre></div>
</div>
</li>
<li><p>Finally, point to your view from the <code class="docutils literal notranslate"><span class="pre">mygame/web/website/urls.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/web/website/urls.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">web.website.views</span> <span class="kn">import</span> <span class="n">testview</span>
<span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
<span class="c1"># ...</span>
<span class="c1"># we can skip the initial / here</span>
<span class="n">path</span><span class="p">(</span><span class="s2">&quot;test/&quot;</span><span class="p">,</span> <span class="n">testview</span><span class="o">.</span><span class="n">MyTestView</span><span class="o">.</span><span class="n">as_view</span><span class="p">())</span>
<span class="p">]</span>
</pre></div>
</div>
</li>
<li><p>Reload the server and your new page is available. You can now continue to add
all sorts of advanced dynamic content through your view and template!</p></li>
</ul>
</section>
</section>
<section id="user-forms">
<h2>User forms<a class="headerlink" href="#user-forms" title="Permalink to this headline"></a></h2>
<p>All the pages created so far deal with <em>presenting</em> information to the user.
Its also possible for the user to <em>input</em> data on the page through <em>forms</em>. An
example would be a page of fields and sliders you fill in to create a
character, with a big Submit button at the bottom.</p>
<p>Firstly, this must be represented in HTML. The <code class="docutils literal notranslate"><span class="pre">&lt;form&gt;</span> <span class="pre">...</span> <span class="pre">&lt;/form&gt;</span></code> is a
standard HTML element you need to add to your template. It also has some other
requirements, such as <code class="docutils literal notranslate"><span class="pre">&lt;input&gt;</span></code> and often Javascript components as well (but
usually Django will help with this). If you are unfamiliar with how HTML forms
work, <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/forms/#html-forms">read about them here</a>.</p>
<p>The basic gist of it is that when you click to submit the form, a POST HTML
request will be sent to the server containing the data the user entered. Its
now up to the server to make sure the data makes sense (validation) and then
process the input somehow (like creating a new character).</p>
<p>On the backend side, we need to specify the logic for validating and processing
the form data. This is done by the <code class="docutils literal notranslate"><span class="pre">Form</span></code> <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/forms/#forms-in-django">Django class</a>.
This specifies <em>fields</em> on itself that define how to validate that piece of data.</p>
<p>The form is then linked into the view-class by adding <code class="docutils literal notranslate"><span class="pre">form_class</span> <span class="pre">=</span> <span class="pre">MyFormClass</span></code> to
the view (next to <code class="docutils literal notranslate"><span class="pre">template_name</span></code>).</p>
<p>There are several example forms in <code class="docutils literal notranslate"><span class="pre">evennia/web/website/forms.py</span></code>. Its also a good
idea to read <a class="reference external" href="https://docs.djangoproject.com/en/3.2/topics/forms/#building-a-form-in-django">Building a form in Django</a>
on the Django website - it covers all you need.</p>
</section>
</section>
</div>
</div>
</div>
</div>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../genindex.html" title="General Index"
>index</a></li>
<li class="right" >
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="Web-API.html" title="Evennia REST API"
>next</a> |</li>
<li class="right" >
<a href="Signals.html" title="Signals"
>previous</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-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Game website</a></li>
</ul>
<div class="develop">develop branch</div>
</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.2.1.
</div>
</body>
</html>