Updated HTML docs.

This commit is contained in:
Evennia docbuilder action 2024-02-04 00:21:07 +00:00
parent a86be6351f
commit 7a4f87a5a3
94 changed files with 3266 additions and 940 deletions

View file

@ -1,4 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 8480135f2f3b4966f08fa4fe3092812b
config: cec20a0c7704a71bacf07bdc52abcdf2
tags: 645f666f9bcd5a90fca523b33c5a78b7

View file

@ -66,6 +66,8 @@
<h3><a href="../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Changelog</a><ul>
<li><a class="reference internal" href="#main-branch">main branch</a></li>
<li><a class="reference internal" href="#evennia-3-1-1">Evennia 3.1.1</a></li>
<li><a class="reference internal" href="#evennia-3-1-0">Evennia 3.1.0</a></li>
<li><a class="reference internal" href="#evennia-3-0-0">Evennia 3.0.0</a></li>
<li><a class="reference internal" href="#evennia-2-3-0">Evennia 2.3.0</a></li>
@ -188,6 +190,32 @@
<section class="tex2jax_ignore mathjax_ignore" id="changelog">
<h1>Changelog<a class="headerlink" href="#changelog" title="Permalink to this headline"></a></h1>
<section id="main-branch">
<h2>main branch<a class="headerlink" href="#main-branch" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p>[Feature] Add <code class="docutils literal notranslate"><span class="pre">evennia.ON_DEMAND_HANDLER</span></code> for making it easier to implement
timed element with the on-demand approach (Griatch)</p></li>
<li><p>[Fix] Remove <code class="docutils literal notranslate"><span class="pre">AMP_ENABLED</span></code> setting since it services no real purpose and
erroring out on setting it would make it even less useful (Griatch).</p></li>
<li><p>[Fix] <code class="docutils literal notranslate"><span class="pre">services</span></code> command with no args would traceback (regression) (Griatch)</p></li>
<li><p><a class="reference external" href="https://github.com/evennia/evennia/pull/3412">Feature</a>: Make it possible to add custom webclient css in
<code class="docutils literal notranslate"><span class="pre">webclient/css/custom.css</span></code>, same as for website (InspectorCaracal)</p></li>
<li><p>Doc fixes (InspectorCaracal, Griatch)</p></li>
</ul>
</section>
<section id="evennia-3-1-1">
<h2>Evennia 3.1.1<a class="headerlink" href="#evennia-3-1-1" title="Permalink to this headline"></a></h2>
<p>Jan 14, 2024</p>
<ul class="simple">
<li><p><a class="reference external" href="https://github.com/evennia/evennia/pull/3398">Fix</a>: Fix to make e.g. <code class="docutils literal notranslate"><span class="pre">elvish&quot;Hello&quot;</span></code> work correctly in language rp
contrib (InspectorCaracal)</p></li>
<li><p><a class="reference external" href="https://github.com/evennia/evennia/pull/3405">Fix</a>: Fix/update of Godot client contrib to support Godot4 and
latest Evennia portal changes (ChrisLR)</p></li>
<li><p>Updated doc on wiki install (InspectorCaracal)</p></li>
<li><p>Docstring fixes (bradleymarques, Griatch)</p></li>
<li><p>Doc tutorial fixes (Griatch)</p></li>
</ul>
</section>
<section id="evennia-3-1-0">
<h2>Evennia 3.1.0<a class="headerlink" href="#evennia-3-1-0" title="Permalink to this headline"></a></h2>
<p>Jan 8, 2024</p>
@ -207,7 +235,7 @@ common mud command that should not be ignored. (alephate)</p></li>
<li><p><a class="reference external" href="https://github.com/evennia/evennia/pull/3382">Fix</a>: Make sure global scripts start properly on restart
(InspectorCaracal)</p></li>
<li><p><a class="reference external" href="https://github.com/evennia/evennia/pull/3394">Fix</a>: Fix time-of-day issue in ExpandedRoom contrib (jaborsh)</p></li>
<li><p>Doc fixes (homeofpoe, gas-public-wooden-clean, InspectorCaracal)</p></li>
<li><p>Doc fixes (homeofpoe, gas-public-wooden-clean, InspectorCaracal, Griatch)</p></li>
</ul>
</section>
<section id="evennia-3-0-0">
@ -285,9 +313,9 @@ successfully reconnected to the Server after a restart. (InspectorCaracal)</p></
other objects than oneself (InspectorCaracal)</p></li>
<li><p><a class="reference external" href="https://github.com/evennia/evennia/pull/3361">Fix</a>: Fix of monitoring Attributes with categories (scyfris)</p></li>
<li><p>Docs &amp; docstrings: Lots of Typo and other fixes (iLPdev, InspectorCaracal, jaborsh,
HouseOfPoe etc)</p></li>
HouseOfPoe, Griatch etc)</p></li>
<li><p>Beginner tutorial: Cleanup and starting earlier with explaining how to add to
the default cmdsets.</p></li>
the default cmdsets (Griatch).</p></li>
</ul>
</section>
<section id="evennia-2-3-0">
@ -301,8 +329,8 @@ the default cmdsets.</p></li>
<li><p>Fix: Traceback when printing CounterTrait contrib objects. (InspectorCaracal)</p></li>
<li><p>Fix: Typo in evadventure twitch combats call of <code class="docutils literal notranslate"><span class="pre">create_combathandler</span></code>.</p></li>
<li><p>Docs: Fix bug in evadventure equipmenthandler blocking creation of npcs.
in-game.</p></li>
<li><p>Docs: Plenty of typo fixes (iLPDev, moldikins, others)</p></li>
in-game (Griatch).</p></li>
<li><p>Docs: Plenty of typo fixes (iLPDev, moldikins, Griatch), others)</p></li>
</ul>
</section>
<section id="evennia-2-2-0">

View file

@ -174,6 +174,8 @@ make your game, also if you never coded before.</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="Changelog.html">Changelog</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Changelog.html#main-branch">main branch</a></li>
<li class="toctree-l2"><a class="reference internal" href="Changelog.html#evennia-3-1-1">Evennia 3.1.1</a></li>
<li class="toctree-l2"><a class="reference internal" href="Changelog.html#evennia-3-1-0">Evennia 3.1.0</a></li>
<li class="toctree-l2"><a class="reference internal" href="Changelog.html#evennia-3-0-0">Evennia 3.0.0</a></li>
<li class="toctree-l2"><a class="reference internal" href="Changelog.html#evennia-2-3-0">Evennia 2.3.0</a></li>

View file

@ -297,6 +297,11 @@
<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="OnDemandHandler.html">OnDemandHandler</a><ul>
<li class="toctree-l2"><a class="reference internal" href="OnDemandHandler.html#a-blooming-flower-using-the-ondemandhandler">A blooming flower using the OnDemandHandler</a></li>
<li class="toctree-l2"><a class="reference internal" href="OnDemandHandler.html#more-usage-examples">More usage examples</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#usage">Usage</a></li>
</ul>

View file

@ -17,7 +17,7 @@
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="TickerHandler" href="TickerHandler.html" />
<link rel="next" title="OnDemandHandler" href="OnDemandHandler.html" />
<link rel="prev" title="FuncParser inline text parsing" href="FuncParser.html" />
</head><body>
@ -34,7 +34,7 @@
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="TickerHandler.html" title="TickerHandler"
<a href="OnDemandHandler.html" title="OnDemandHandler"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="FuncParser.html" title="FuncParser inline text parsing"
@ -75,8 +75,8 @@
<p class="topless"><a href="FuncParser.html"
title="previous chapter">FuncParser inline text parsing</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="TickerHandler.html"
title="next chapter">TickerHandler</a></p>
<p class="topless"><a href="OnDemandHandler.html"
title="next chapter">OnDemandHandler</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
@ -203,7 +203,7 @@ the monitor to remove:</p>
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="TickerHandler.html" title="TickerHandler"
<a href="OnDemandHandler.html" title="OnDemandHandler"
>next</a> |</li>
<li class="right" >
<a href="FuncParser.html" title="FuncParser inline text parsing"

View file

@ -0,0 +1,316 @@
<!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>OnDemandHandler &#8212; Evennia latest 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="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="TickerHandler.html" title="TickerHandler"
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 latest</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="">OnDemandHandler</a></li>
</ul>
</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="#">OnDemandHandler</a><ul>
<li><a class="reference internal" href="#a-blooming-flower-using-the-ondemandhandler">A blooming flower using the OnDemandHandler</a></li>
<li><a class="reference internal" href="#more-usage-examples">More usage examples</a><ul>
<li><a class="reference internal" href="#looping-repeatedly">Looping repeatedly</a></li>
<li><a class="reference internal" href="#bouncing-back-and-forth">Bouncing back and forth</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="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/OnDemandHandler.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/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>Doc Versions</h3>
<ul>
<li><a href="OnDemandHandler.html">latest (main branch)</a></li>
<li><a href="../../3.x/index.html">v3.0.0 branch (outdated)</a></li>
<li><a href="../../2.x/index.html">v2.0.0 branch (outdated)</a></li>
<li><a href="../../1.x/index.html">v1.0.0 branch (outdated)</a></li>
<li><a href="../../0.x/index.html">v0.9.5 branch (outdated)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section class="tex2jax_ignore mathjax_ignore" id="ondemandhandler">
<h1>OnDemandHandler<a class="headerlink" href="#ondemandhandler" title="Permalink to this headline"></a></h1>
<p>This handler offers help for implementing on-demand state changes. On-demand means that the state wont be computed until the player <em>actually looks for it</em>. Until they do, nothing happens. This is the most compute-efficient way to handle your systems and you should consider using this style of system whenever you can.</p>
<p>Take for example a gardening system. A player goes to a room and plants a seed. After a certain time, that plant will then move through a set of stages; it will move from “seedling” to sprout to flowering and then on to wilting and eventually dead.</p>
<p>Now, you <em>could</em> use <code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> to track each phase, or use the <a class="reference internal" href="TickerHandler.html"><span class="doc std std-doc">TickerHandler</span></a> to tick the flower. You could even use a <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Script</span></a> on the flower.</p>
<ol class="simple">
<li><p>The ticker/task/Script would automatically fire at regular intervals to update the plant through its stages.</p></li>
<li><p>Whenever a player comes to the room, the state is already updated on the flower, so they just read the state.</p></li>
</ol>
<p>This will work fine, but if no one comes back to that room, thats a lot of updating that no one will see. While maybe not a big deal for a single player, what if you have flowers in thousands of rooms, all growing indepedently? Or some even more complex system requiring calculation on every state change. You should avoid spending computing on things that bring nothing extra to your player base.</p>
<p>Using the The on-demand style would instead work like this for the flower:</p>
<ol class="simple">
<li><p>When the player plants the seed, we register a new on-demand task with the <code class="docutils literal notranslate"><span class="pre">OnDemandHandler</span></code> (described below). This registes <em>the current timestamp</em> when the plant starts to grow.</p></li>
<li><p>When a player enters the room and/or looks at the plant, <em>then</em> (and only then) we call the <code class="docutils literal notranslate"><span class="pre">OnDemandHandler</span></code> to see what state the flower its in. It will then use the <em>current time</em> to figure out how much time passed and which state the plant is thus in. Until someone looks, the plant is in its previous found state, because no-one needed to know until then. Same thing, if some other system needs to know this - they just figure out the state on the fly.</p></li>
</ol>
<section id="a-blooming-flower-using-the-ondemandhandler">
<h2>A blooming flower using the OnDemandHandler<a class="headerlink" href="#a-blooming-flower-using-the-ondemandhandler" title="Permalink to this headline"></a></h2>
<p>This handler is found as <code class="docutils literal notranslate"><span class="pre">evennia.ON_DEMAND_HANDLER</span></code>. It is meant to be integrated into your other code. Heres an example of a flower that</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># e.g. in mygame/typeclasses/objects.py</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">ON_DEMAND_HANDLER</span>
<span class="c1"># ... </span>
<span class="k">class</span> <span class="nc">Flower</span><span class="p">(</span><span class="n">Object</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="n">minute</span> <span class="o">=</span> <span class="mi">60</span>
<span class="n">hour</span> <span class="o">=</span> <span class="n">minute</span> <span class="o">*</span> <span class="mi">60</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
<span class="bp">self</span><span class="p">,</span>
<span class="n">category</span><span class="o">=</span><span class="s2">&quot;plantgrowth&quot;</span>
<span class="n">stages</span><span class="o">=</span><span class="p">{</span>
<span class="mi">0</span><span class="p">:</span> <span class="s2">&quot;seedling&quot;</span><span class="p">,</span>
<span class="mi">10</span> <span class="o">*</span> <span class="n">minute</span><span class="p">:</span> <span class="s2">&quot;sprout&quot;</span><span class="p">,</span>
<span class="mi">5</span> <span class="o">*</span> <span class="n">hour</span><span class="p">:</span> <span class="s2">&quot;flowering&quot;</span><span class="p">,</span>
<span class="mi">10</span> <span class="o">*</span> <span class="n">hour</span><span class="p">:</span> <span class="s2">&quot;wilting&quot;</span><span class="p">,</span>
<span class="mi">12</span> <span class="o">*</span> <span class="n">hour</span><span class="p">:</span> <span class="s2">&quot;dead&quot;</span>
<span class="p">})</span>
<span class="k">def</span> <span class="nf">at_desc</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">looker</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Called whenever someone looks at this object</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">stage</span> <span class="o">=</span> <span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">get_state</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;plantgrowth&quot;</span><span class="p">)</span>
<span class="k">match</span> <span class="n">stage</span><span class="p">:</span>
<span class="k">case</span> <span class="s2">&quot;seedling&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;There&#39;s nothing to see. Nothing has grown yet.&quot;</span>
<span class="k">case</span> <span class="s2">&quot;sprout&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="s2">&quot;A small delicate sprout has emerged!&quot;</span>
<span class="k">case</span> <span class="s2">&quot;flowering&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;A beautiful </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">!&quot;</span>
<span class="k">case</span> <span class="s2">&quot;wilting&quot;</span><span class="p">:</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;This </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> has seen better days.&quot;</span>
<span class="k">case</span> <span class="s2">&quot;dead&quot;</span><span class="p">:</span>
<span class="c1"># it&#39;s dead and gone. Stop and delete </span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;plantgrowth&quot;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
</pre></div>
</div>
<p>You could now create the rose and it would figure out its state only when you are actually looking at it. It will stay a seedling for 10 minutes (of in-game real time) before it sprouts. Within 12 hours it will be dead again (a very quickly growing rose!).</p>
<p>If you had a <code class="docutils literal notranslate"><span class="pre">harvest</span></code> command in your game, you could equally have it check the stage of bloom and give you different results depending on if you pick the rose at the right time or not.</p>
<p>The on-demand handlers tasks survive a reload and will properly account for downtime.</p>
</section>
<section id="more-usage-examples">
<h2>More usage examples<a class="headerlink" href="#more-usage-examples" title="Permalink to this headline"></a></h2>
<p>The <a class="reference internal" href="../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler" title="evennia.scripts.ondemandhandler.OnDemandHandler"><span class="xref myst py py-class">OnDemandHandler API</span></a> describes how to use the handler in detail. While its available as <code class="docutils literal notranslate"><span class="pre">evennia.ON_DEMAND_HANDLER</span></code>, its code is located in <code class="docutils literal notranslate"><span class="pre">evennia.scripts.ondemandhandler.py</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">ON_DEMAND_HANDLER</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">stages</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
<span class="n">time_passed</span> <span class="o">=</span> <span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">get_dt</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
<span class="n">current_state</span> <span class="o">=</span> <span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">get_stage</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
<span class="c1"># remove things </span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">&quot;key&quot;</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">)</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">clear</span><span class="p">(</span><span class="n">cateogory</span><span class="o">=</span><span class="s2">&quot;category&quot;</span><span class="p">)</span> <span class="c1">#clear all with category</span>
</pre></div>
</div>
<ul class="simple">
<li><p>The <code class="docutils literal notranslate"><span class="pre">key</span></code> can be a string, but also a typeclassed object (its string representation will be used, which normally includes its <code class="docutils literal notranslate"><span class="pre">#dbref</span></code>). You can also pass a <code class="docutils literal notranslate"><span class="pre">callable</span></code> - this will be called without arguments and is expected to return a string to use for the <code class="docutils literal notranslate"><span class="pre">key</span></code>. Finally, you can also pass <a class="reference internal" href="../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><span class="xref myst py py-class">OnDemandTask</span></a> entities - these are the objects the handler uses under the hood to represent each task.</p></li>
<li><p>The <code class="docutils literal notranslate"><span class="pre">category</span></code> allows you to further categorize your demandhandler tasks to make sure they are unique. Since the handler is global, you need to make sure <code class="docutils literal notranslate"><span class="pre">key</span></code> + <code class="docutils literal notranslate"><span class="pre">category</span></code> is unique. While <code class="docutils literal notranslate"><span class="pre">category</span></code> is optional, if you use it you must also use it to retrieve your state later.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">stages</span></code> is a <code class="docutils literal notranslate"><span class="pre">dict</span></code> <code class="docutils literal notranslate"><span class="pre">{dt:</span> <span class="pre">statename}</span></code> or <code class="docutils literal notranslate"><span class="pre">{dt:</span> <span class="pre">(statename,</span> <span class="pre">callable}</span></code> that represents how much time (in seconds) before next stage begins. In the flower example above, it was 10 hours until the <code class="docutils literal notranslate"><span class="pre">wilting</span></code> state began. If a <code class="docutils literal notranslate"><span class="pre">callable</span></code> is also included, this will be called <em>the first time</em> that state is checked for. The callable takes a <code class="docutils literal notranslate"><span class="pre">evennia.OnDemandTask</span></code> as an argument and allows for tweaking the task on the fly. The <code class="docutils literal notranslate"><span class="pre">dt</span></code> can also be a <code class="docutils literal notranslate"><span class="pre">float</span></code> if you desire higher than per-second precision. Having <code class="docutils literal notranslate"><span class="pre">stages</span></code> is optional - sometimes you only want to know how much time has passed.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.get_dt()</span></code> - get the current time (in seconds) since the task started. This is a <code class="docutils literal notranslate"><span class="pre">float</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">.get_stage()</span></code> - get the current state name, such as “flowering” or “seedling”. If you didnt specify any <code class="docutils literal notranslate"><span class="pre">stages</span></code>, this will return <code class="docutils literal notranslate"><span class="pre">None</span></code>, and you need to interpret the <code class="docutils literal notranslate"><span class="pre">dt</span></code> yourself to determine which state you are in.</p></li>
</ul>
<p>Under the hood, the handler uses <a class="reference internal" href="../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><span class="xref myst py py-class">OnDemandTask</span></a> objects. It can sometimes be practical to create tasks directly with these, and pass them to the handler in bulk:</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">ON_DEMAND_HANDLER</span><span class="p">,</span> <span class="n">OnDemandTask</span>
<span class="n">task1</span> <span class="o">=</span> <span class="n">OnDemandTask</span><span class="p">(</span><span class="s2">&quot;key1&quot;</span><span class="p">,</span> <span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s2">&quot;state1&quot;</span><span class="p">,</span> <span class="mi">100</span><span class="p">:</span> <span class="s2">&quot;state2&quot;</span><span class="p">})</span>
<span class="n">task2</span> <span class="o">=</span> <span class="n">OnDemandTask</span><span class="p">(</span><span class="s2">&quot;key2&quot;</span><span class="p">,</span> <span class="n">category</span><span class="p">)</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">batch_add</span><span class="p">(</span><span class="n">task1</span><span class="p">,</span> <span class="n">task2</span><span class="p">)</span>
<span class="c1"># get tasks back </span>
<span class="n">task</span> <span class="o">=</span> <span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;key1&quot;</span><span class="p">)</span>
<span class="c1"># batch-delete (deactivate) from handler</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">batch_remove</span><span class="p">(</span><span class="n">task1</span><span class="p">,</span> <span class="n">task2</span><span class="p">)</span>
</pre></div>
</div>
<section id="looping-repeatedly">
<h3>Looping repeatedly<a class="headerlink" href="#looping-repeatedly" title="Permalink to this headline"></a></h3>
<p>Normally, when a sequence of <code class="docutils literal notranslate"><span class="pre">stages</span></code> have been cycled through, the task will just</p>
<p><code class="docutils literal notranslate"><span class="pre">evennia.OnDemandTask.stagefunc_loop</span></code> is an included static-method callable you can use to make the task loop. Heres an example of how to use 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">ON_DEMAND_HANDLER</span><span class="p">,</span> <span class="n">OnDemandTask</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
<span class="s2">&quot;trap_state&quot;</span><span class="p">,</span>
<span class="n">stages</span><span class="o">=</span><span class="p">{</span>
<span class="mi">0</span><span class="p">:</span> <span class="s2">&quot;harmless&quot;</span><span class="p">,</span>
<span class="mi">50</span><span class="p">:</span> <span class="s2">&quot;solvable&quot;</span><span class="p">,</span>
<span class="mi">100</span><span class="p">:</span> <span class="s2">&quot;primed&quot;</span><span class="p">,</span>
<span class="mi">200</span><span class="p">:</span> <span class="s2">&quot;deadly&quot;</span><span class="p">,</span>
<span class="mi">250</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;_reset&quot;</span><span class="p">,</span> <span class="n">OnDemandTask</span><span class="o">.</span><span class="n">stagefunc_loop</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">)</span>
</pre></div>
</div>
<p>This is a trap state that loops through its states depending on timing. Note that the looping helper callable will <em>immediately</em> reset the cycle back to the first stage, so the last stage will never be visible to the player/game system. So its a good (if optional) idea to name it with <code class="docutils literal notranslate"><span class="pre">_*</span></code> to remember this is a virtual stage.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">OnDemandTask</span></code> task instance has a <code class="docutils literal notranslate"><span class="pre">.iterations</span></code> variable that will go up by one for every loop.</p>
<p>If the state is not checked for a long time, the looping function will correctly update the <code class="docutils literal notranslate"><span class="pre">.iterations</span></code> of the task it would have used so far and figure out where in the cycle it is right now.</p>
</section>
<section id="bouncing-back-and-forth">
<h3>Bouncing back and forth<a class="headerlink" href="#bouncing-back-and-forth" title="Permalink to this headline"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">evennia.OnDemandTask.stagefunc_bounce</span></code> is an included static-method callable you can use to bounce the sequence of stages. That is, it will cycle to the end of the cycle and then reverse direction and cycle through the sequence in reverse.</p>
<p>To make this repreat indefinitely, you need to put the callables at both ends of the list:</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">ON_DEMAND_HANDLER</span><span class="p">,</span> <span class="n">OnDemandTask</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
<span class="s2">&quot;cycling reactor&quot;</span><span class="p">,</span>
<span class="s2">&quot;nuclear&quot;</span><span class="p">,</span>
<span class="n">stages</span><span class="o">=</span><span class="p">{</span>
<span class="mi">0</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;cold&quot;</span><span class="p">,</span> <span class="n">OnDemandTask</span><span class="o">.</span><span class="n">stagefunc_bounce</span><span class="p">),</span>
<span class="mi">150</span><span class="p">:</span> <span class="s2">&quot;luke warm&quot;</span><span class="p">,</span>
<span class="mi">300</span><span class="p">:</span> <span class="s2">&quot;warm&quot;</span><span class="p">,</span>
<span class="mi">450</span><span class="p">:</span> <span class="s2">&quot;hot&quot;</span>
<span class="mi">600</span><span class="p">:</span> <span class="p">(</span><span class="s2">&quot;HOT!&quot;</span><span class="p">,</span> <span class="n">OnDemandTask</span><span class="o">.</span><span class="n">stagefunc_bounce</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">)</span>
</pre></div>
</div>
<p>This will cycle</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> cold -&gt; luke warm -&gt; warm -&gt; hot -&gt; HOT!
</pre></div>
</div>
<p>before reversing and go back:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> HOT! -&gt; hot -&gt; warm -&gt; luke warm -&gt; cold
</pre></div>
</div>
<p>Over and over. The <code class="docutils literal notranslate"><span class="pre">OnDemandTask</span></code> instance has an <code class="docutils literal notranslate"><span class="pre">.iterations</span></code> property that will step up by one every time the sequence reverses.</p>
<p>If the state is not checked for a long time, the bounce function will correctly update the <code class="docutils literal notranslate"><span class="pre">.iterations</span></code> property to the amount of iterations it would have done in that time, and figure out where in the cycle it must be right now.</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="TickerHandler.html" title="TickerHandler"
>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 latest</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="">OnDemandHandler</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -18,7 +18,7 @@
<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="MonitorHandler" href="MonitorHandler.html" />
<link rel="prev" title="OnDemandHandler" href="OnDemandHandler.html" />
</head><body>
@ -37,7 +37,7 @@
<a href="Signals.html" title="Signals"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
<a href="OnDemandHandler.html" title="OnDemandHandler"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> &#187;</li>
@ -75,8 +75,8 @@
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="MonitorHandler.html"
title="previous chapter">MonitorHandler</a></p>
<p class="topless"><a href="OnDemandHandler.html"
title="previous chapter">OnDemandHandler</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="Signals.html"
title="next chapter">Signals</a></p>
@ -216,7 +216,7 @@ overload the existing ticker. This identification is also crucial for later remo
<a href="Signals.html" title="Signals"
>next</a> |</li>
<li class="right" >
<a href="MonitorHandler.html" title="MonitorHandler"
<a href="OnDemandHandler.html" title="OnDemandHandler"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> &#187;</li>

View file

@ -69,8 +69,7 @@
<li><a class="reference internal" href="#installation">Installation</a></li>
<li><a class="reference internal" href="#usage">Usage</a></li>
<li><a class="reference internal" href="#known-issues">Known Issues</a></li>
<li><a class="reference internal" href="#godot-3-example">Godot 3 Example</a></li>
<li><a class="reference internal" href="#godot-4-example">Godot 4 Example</a></li>
<li><a class="reference internal" href="#full-example-script">Full Example Script</a></li>
</ul>
</li>
</ul>
@ -145,239 +144,151 @@ to get styled text in a RichTextLabel with bbcode enabled or to handle
the extra data given from Evennia as needed.</p>
<p>This section assumes you have basic knowledge on how to use Godot.
You can read the following url for more details on Godot Websockets
and to implement a minimal client.</p>
and to implement a minimal client or look at the full example at the bottom of this page.</p>
<p><a class="reference external" href="https://docs.godotengine.org/en/stable/tutorials/networking/websocket.html">https://docs.godotengine.org/en/stable/tutorials/networking/websocket.html</a></p>
<p>The rest of this document will be for Godot 3, an example is left at the bottom
of this readme for Godot 4.</p>
<p>At the top of the file you must change the url to point at your mud.</p>
<p>The rest of this document will be for Godot 4.
Note that some of the code shown here is partially taken from official Godot Documentation</p>
<p>A very basic setup in godot would require</p>
<ul class="simple">
<li><p>One RichTextLabel Node to display the Evennia Output, ensure bbcode is enabled on it.</p></li>
<li><p>One Node for your websocket client code with a new Script attached.</p></li>
<li><p>One TextEdit Node to enter commands</p></li>
<li><p>One Button Node to press and send the commands</p></li>
<li><p>Controls for the layout, in this example I have used
Panel
VBoxContainer
RichTextLabel
HBoxContainer
TextEdit
Button</p></li>
</ul>
<p>I will not go over how layout works but the documentation for them is easily accessible in the godot docs.</p>
<p>Open up the script for your client code.</p>
<p>We need to define the url leading to your mud, use the same values you have used in your Evennia Settings.
Next we write some basic code to get a connection going.
This will connect when the Scene is ready, poll and print the data when we receive it and close when the scene exits.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">extends</span> <span class="n">Node</span>
<span class="c1"># The URL we will connect to</span>
<span class="n">export</span> <span class="n">var</span> <span class="n">websocket_url</span> <span class="o">=</span> <span class="s2">&quot;ws://localhost:4008&quot;</span>
<span class="c1"># The URL we will connect to.</span>
<span class="n">var</span> <span class="n">websocket_url</span> <span class="o">=</span> <span class="s2">&quot;ws://localhost:4008&quot;</span>
<span class="n">var</span> <span class="n">socket</span> <span class="o">:=</span> <span class="n">WebSocketPeer</span><span class="o">.</span><span class="n">new</span><span class="p">()</span>
<span class="n">func</span> <span class="n">_ready</span><span class="p">():</span>
<span class="k">if</span> <span class="n">socket</span><span class="o">.</span><span class="n">connect_to_url</span><span class="p">(</span><span class="n">websocket_url</span><span class="p">)</span> <span class="o">!=</span> <span class="n">OK</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Unable to connect.&quot;</span><span class="p">)</span>
<span class="n">set_process</span><span class="p">(</span><span class="n">false</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_process</span><span class="p">(</span><span class="n">_delta</span><span class="p">):</span>
<span class="n">socket</span><span class="o">.</span><span class="n">poll</span><span class="p">()</span>
<span class="k">match</span> <span class="n">socket</span><span class="o">.</span><span class="n">get_ready_state</span><span class="p">():</span>
<span class="n">WebSocketPeer</span><span class="o">.</span><span class="n">STATE_OPEN</span><span class="p">:</span>
<span class="k">while</span> <span class="n">socket</span><span class="o">.</span><span class="n">get_available_packet_count</span><span class="p">():</span>
<span class="nb">print</span><span class="p">(</span><span class="n">socket</span><span class="o">.</span><span class="n">get_packet</span><span class="p">()</span><span class="o">.</span><span class="n">get_string_from_ascii</span><span class="p">())</span>
<span class="n">WebSocketPeer</span><span class="o">.</span><span class="n">STATE_CLOSED</span><span class="p">:</span>
<span class="n">var</span> <span class="n">code</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">get_close_code</span><span class="p">()</span>
<span class="n">var</span> <span class="n">reason</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">get_close_reason</span><span class="p">()</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;WebSocket closed with code: </span><span class="si">%d</span><span class="s2">, reason </span><span class="si">%s</span><span class="s2">. Clean: </span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">[</span><span class="n">code</span><span class="p">,</span> <span class="n">reason</span><span class="p">,</span> <span class="n">code</span> <span class="o">!=</span> <span class="o">-</span><span class="mi">1</span><span class="p">])</span>
<span class="n">set_process</span><span class="p">(</span><span class="n">false</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_exit_tree</span><span class="p">():</span>
<span class="n">socket</span><span class="o">.</span><span class="n">close</span><span class="p">()</span>
</pre></div>
</div>
<p>You must also remove the protocol from the <code class="docutils literal notranslate"><span class="pre">connect_to_url</span></code> call made
within the <code class="docutils literal notranslate"><span class="pre">_ready</span></code> function.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">func</span> <span class="n">_ready</span><span class="p">():</span>
<span class="c1"># ...</span>
<span class="c1"># Change the following line from this</span>
<span class="n">var</span> <span class="n">err</span> <span class="o">=</span> <span class="n">_client</span><span class="o">.</span><span class="n">connect_to_url</span><span class="p">(</span><span class="n">websocket_url</span><span class="p">,</span> <span class="p">[</span><span class="s2">&quot;lws-mirror-protocol&quot;</span><span class="p">])</span>
<span class="c1"># To this</span>
<span class="n">var</span> <span class="n">err</span> <span class="o">=</span> <span class="n">_client</span><span class="o">.</span><span class="n">connect_to_url</span><span class="p">(</span><span class="n">websocket_url</span><span class="p">)</span>
<span class="c1"># ...</span>
</pre></div>
</div>
<p>This will allow you to connect to your mud.
<p>At this point, you can start your evennia server, run godot and it should print a default reply.
After that you need to properly handle the data sent by evennia.
To do this, you should replace your <code class="docutils literal notranslate"><span class="pre">_on_data</span></code> method.
You will need to parse the JSON received to properly act on the data.
Here is an example</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">func</span> <span class="n">_on_data</span><span class="p">():</span>
<span class="c1"># The following two lines will get us the data from Evennia.</span>
<span class="n">var</span> <span class="n">data</span> <span class="o">=</span> <span class="n">_client</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">get_packet</span><span class="p">()</span><span class="o">.</span><span class="n">get_string_from_utf8</span><span class="p">()</span>
<span class="n">var</span> <span class="n">json_data</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">result</span>
<span class="c1"># The json_data is an array</span>
To do this, we will add a new function to dispatch the messages properly.</p>
<p>Here is an example</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">func</span> <span class="n">_handle_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
<span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="c1"># Print for debugging</span>
<span class="n">var</span> <span class="n">data_array</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">parse_string</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="c1"># The first element can be used to see if its text</span>
<span class="k">if</span> <span class="n">data_array</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;text&#39;</span><span class="p">:</span>
<span class="c1"># The second element contains the messages</span>
<span class="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">data_array</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="n">write_to_rtb</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="c1"># The first element informs us this is simple text</span>
<span class="c1"># so we add it to the RichTextlabel</span>
<span class="k">if</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;text&#39;</span><span class="p">:</span>
<span class="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="n">label</span><span class="o">.</span><span class="n">append_bbcode</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="c1"># Always useful to print the data and see what we got.</span>
<span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">func</span> <span class="n">write_to_rtb</span><span class="p">(</span><span class="n">msg</span><span class="p">):</span>
<span class="n">output_label</span><span class="o">.</span><span class="n">append_text</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
</pre></div>
</div>
<p>The first element is the type, it will be <code class="docutils literal notranslate"><span class="pre">text</span></code> if it is a message
It can be anything you would provide to the Evennia <code class="docutils literal notranslate"><span class="pre">msg</span></code> function.
The second element will be the data related to the type of message, in this case it is a list of text to display.
Since it is parsed BBCode, we can add that directly to a RichTextLabel by calling its append_bbcode method.</p>
Since it is parsed BBCode, we can add that directly to a RichTextLabel by calling its append_text method.</p>
<p>If you want anything better than fancy text in Godot, you will have
to leverage Evennias OOB to send extra data.</p>
<p>You can <a class="reference external" href="https://www.evennia.com/docs/latest/OOB.html#oob">read more on OOB here</a>.</p>
<p>In this example, we send coordinates whenever we message our character.</p>
<p>Evennia</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="n">coordinates</span><span class="o">=</span><span class="p">(</span><span class="mi">9</span><span class="p">,</span> <span class="mi">2</span><span class="p">))</span>
<p>Now to send data, we connect the Button pressed Signal to a method,
read the label input and send it via the websocket, then clear the label.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">func</span> <span class="n">_on_button_pressed</span><span class="p">():</span>
<span class="n">var</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">text_edit</span><span class="o">.</span><span class="n">text</span>
<span class="n">var</span> <span class="n">msg_arr</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="p">[</span><span class="n">msg</span><span class="p">],</span> <span class="p">{}]</span>
<span class="n">var</span> <span class="n">msg_str</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">stringify</span><span class="p">(</span><span class="n">msg_arr</span><span class="p">)</span>
<span class="n">socket</span><span class="o">.</span><span class="n">send_text</span><span class="p">(</span><span class="n">msg_str</span><span class="p">)</span>
<span class="n">text_edit</span><span class="o">.</span><span class="n">text</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
</pre></div>
</div>
<p>Godot</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">func</span> <span class="n">_on_data</span><span class="p">():</span>
<span class="o">...</span>
<span class="k">if</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;text&#39;</span><span class="p">:</span>
<span class="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="n">label</span><span class="o">.</span><span class="n">append_bbcode</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="c1"># Notice the first element is the name of the kwarg we used from evennia.</span>
<span class="k">elif</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;coordinates&#39;</span><span class="p">:</span>
<span class="n">var</span> <span class="n">coords_data</span> <span class="o">=</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">2</span><span class="p">]</span>
<span class="n">player</span><span class="o">.</span><span class="n">set_pos</span><span class="p">(</span><span class="n">coords_data</span><span class="p">)</span>
<span class="o">...</span>
</pre></div>
</div>
<p>A good idea would be to set up Godot Signals you can trigger based on the data
you receive, so you can manage the code better.</p>
</section>
<section id="known-issues">
<h2>Known Issues<a class="headerlink" href="#known-issues" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p>Sending SaverDicts and similar objects straight from Evennia .DB will cause issues,
cast them to dict() or list() before doing so.</p></li>
<li><p>Background colors are only supported by Godot 4.</p></li>
</ul>
</section>
<section id="godot-3-example">
<h2>Godot 3 Example<a class="headerlink" href="#godot-3-example" title="Permalink to this headline"></a></h2>
<p>This is an example of a Script to use in Godot 3.
The script can be attached to the root UI node.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">extends</span> <span class="n">Node</span>
<section id="full-example-script">
<h2>Full Example Script<a class="headerlink" href="#full-example-script" title="Permalink to this headline"></a></h2>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>extends Node
<span class="c1"># The URL to connect to, should be your mud.</span>
<span class="n">export</span> <span class="n">var</span> <span class="n">websocket_url</span> <span class="o">=</span> <span class="s2">&quot;ws://127.0.0.1:4008&quot;</span>
# The URL we will connect to.
var websocket_url = &quot;ws://localhost:4008&quot;
var socket := WebSocketPeer.new()
<span class="c1"># These are references to controls in the scene</span>
<span class="n">onready</span> <span class="n">var</span> <span class="n">parent</span> <span class="o">=</span> <span class="n">get_parent</span><span class="p">()</span>
<span class="n">onready</span> <span class="n">var</span> <span class="n">label</span> <span class="o">=</span> <span class="n">parent</span><span class="o">.</span><span class="n">get_node</span><span class="p">(</span><span class="s2">&quot;%ChatLog&quot;</span><span class="p">)</span>
<span class="n">onready</span> <span class="n">var</span> <span class="n">txtEdit</span> <span class="o">=</span> <span class="n">parent</span><span class="o">.</span><span class="n">get_node</span><span class="p">(</span><span class="s2">&quot;%ChatInput&quot;</span><span class="p">)</span>
<span class="n">onready</span> <span class="n">var</span> <span class="n">room</span> <span class="o">=</span> <span class="n">get_node</span><span class="p">(</span><span class="s2">&quot;/root/World/Room&quot;</span><span class="p">)</span>
<span class="c1"># Our WebSocketClient instance</span>
<span class="n">var</span> <span class="n">_client</span> <span class="o">=</span> <span class="n">WebSocketClient</span><span class="o">.</span><span class="n">new</span><span class="p">()</span>
<span class="n">var</span> <span class="n">is_connected</span> <span class="o">=</span> <span class="n">false</span>
<span class="n">func</span> <span class="n">_ready</span><span class="p">():</span>
<span class="c1"># Connect base signals to get notified of connection open, close, errors and messages</span>
<span class="n">_client</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&quot;connection_closed&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="s2">&quot;_closed&quot;</span><span class="p">)</span>
<span class="n">_client</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&quot;connection_error&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="s2">&quot;_closed&quot;</span><span class="p">)</span>
<span class="n">_client</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&quot;connection_established&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="s2">&quot;_connected&quot;</span><span class="p">)</span>
<span class="n">_client</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s2">&quot;data_received&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="p">,</span> <span class="s2">&quot;_on_data&quot;</span><span class="p">)</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Ready&#39;</span><span class="p">)</span>
<span class="c1"># Initiate connection to the given URL.</span>
<span class="n">var</span> <span class="n">err</span> <span class="o">=</span> <span class="n">_client</span><span class="o">.</span><span class="n">connect_to_url</span><span class="p">(</span><span class="n">websocket_url</span><span class="p">)</span>
<span class="k">if</span> <span class="n">err</span> <span class="o">!=</span> <span class="n">OK</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Unable to connect&quot;</span><span class="p">)</span>
<span class="n">set_process</span><span class="p">(</span><span class="n">false</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_closed</span><span class="p">(</span><span class="n">was_clean</span> <span class="o">=</span> <span class="n">false</span><span class="p">):</span>
<span class="c1"># was_clean will tell you if the disconnection was correctly notified</span>
<span class="c1"># by the remote peer before closing the socket.</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Closed, clean: &quot;</span><span class="p">,</span> <span class="n">was_clean</span><span class="p">)</span>
<span class="n">set_process</span><span class="p">(</span><span class="n">false</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_connected</span><span class="p">(</span><span class="n">proto</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span><span class="p">):</span>
<span class="n">is_connected</span> <span class="o">=</span> <span class="n">true</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Connected with protocol: &quot;</span><span class="p">,</span> <span class="n">proto</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_on_data</span><span class="p">():</span>
<span class="c1"># This is called when Godot receives data from evennia</span>
<span class="n">var</span> <span class="n">data</span> <span class="o">=</span> <span class="n">_client</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">get_packet</span><span class="p">()</span><span class="o">.</span><span class="n">get_string_from_utf8</span><span class="p">()</span>
<span class="n">var</span> <span class="n">json_data</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">result</span>
<span class="c1"># Here we have the data from Evennia which is an array.</span>
<span class="c1"># The first element will be text if it is a message</span>
<span class="c1"># and would be the key of the OOB data you passed otherwise.</span>
<span class="k">if</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;text&#39;</span><span class="p">:</span>
<span class="c1"># In this case, we simply append the data as bbcode to our label.</span>
<span class="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="n">label</span><span class="o">.</span><span class="n">append_bbcode</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;coordinates&#39;</span><span class="p">:</span>
<span class="c1"># Dummy signal emitted if we wanted to handle the new coordinates</span>
<span class="c1"># elsewhere in the project.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">emit_signal</span><span class="p">(</span><span class="s1">&#39;updated_coordinates&#39;</span><span class="p">,</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
@onready var output_label = $&quot;../Panel/VBoxContainer/RichTextLabel&quot;
@onready var text_edit = $&quot;../Panel/VBoxContainer/HBoxContainer/TextEdit&quot;
<span class="c1"># We only print this for easier debugging.</span>
<span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
func _ready():
if socket.connect_to_url(websocket_url) != OK:
print(&quot;Unable to connect.&quot;)
set_process(false)
<span class="n">func</span> <span class="n">_process</span><span class="p">(</span><span class="n">delta</span><span class="p">):</span>
<span class="c1"># Required for websocket to properly react</span>
<span class="n">_client</span><span class="o">.</span><span class="n">poll</span><span class="p">()</span>
func _process(_delta):
socket.poll()
match socket.get_ready_state():
WebSocketPeer.STATE_OPEN:
while socket.get_available_packet_count():
var data = socket.get_packet().get_string_from_ascii()
_handle_data(data)
WebSocketPeer.STATE_CLOSED:
var code = socket.get_close_code()
var reason = socket.get_close_reason()
print(&quot;WebSocket closed with code: %d, reason %s. Clean: %s&quot; % [code, reason, code != -1])
set_process(false)
<span class="n">func</span> <span class="n">_on_button_send</span><span class="p">():</span>
<span class="c1"># This is called when we press the button in the scene</span>
<span class="c1"># with a connected signal, it sends the written message to Evennia.</span>
<span class="n">var</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">txtEdit</span><span class="o">.</span><span class="n">text</span>
<span class="n">var</span> <span class="n">msg_arr</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="p">[</span><span class="n">msg</span><span class="p">],</span> <span class="p">{}]</span>
<span class="n">var</span> <span class="n">msg_str</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">print</span><span class="p">(</span><span class="n">msg_arr</span><span class="p">)</span>
<span class="n">_client</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">put_packet</span><span class="p">(</span><span class="n">msg_str</span><span class="o">.</span><span class="n">to_utf8</span><span class="p">())</span>
func _handle_data(data):
print(data) # Print for debugging
var data_array = JSON.parse_string(data)
# The first element can be used to see if its text
if data_array[0] == &#39;text&#39;:
# The second element contains the messages
for msg in data_array[1]: write_to_rtb(msg)
<span class="n">func</span> <span class="n">_notification</span><span class="p">(</span><span class="n">what</span><span class="p">):</span>
<span class="c1"># This is a special method that allows us to notify Evennia we are closing.</span>
<span class="k">if</span> <span class="n">what</span> <span class="o">==</span> <span class="n">MainLoop</span><span class="o">.</span><span class="n">NOTIFICATION_WM_QUIT_REQUEST</span><span class="p">:</span>
<span class="k">if</span> <span class="n">is_connected</span><span class="p">:</span>
<span class="n">var</span> <span class="n">msg_arr</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="p">[</span><span class="s1">&#39;quit&#39;</span><span class="p">],</span> <span class="p">{}]</span>
<span class="n">var</span> <span class="n">msg_str</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">print</span><span class="p">(</span><span class="n">msg_arr</span><span class="p">)</span>
<span class="n">_client</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="o">.</span><span class="n">put_packet</span><span class="p">(</span><span class="n">msg_str</span><span class="o">.</span><span class="n">to_utf8</span><span class="p">())</span>
<span class="n">get_tree</span><span class="p">()</span><span class="o">.</span><span class="n">quit</span><span class="p">()</span> <span class="c1"># default behavior</span>
func write_to_rtb(msg):
output_label.append_text(msg)
</pre></div>
</div>
</section>
<section id="godot-4-example">
<h2>Godot 4 Example<a class="headerlink" href="#godot-4-example" title="Permalink to this headline"></a></h2>
<p>This is an example of a Script to use in Godot 4.
Note that the version is not final so the code may break.
It requires a WebSocketClientNode as a child of the root node.
The script can be attached to the root UI node.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">extends</span> <span class="n">Control</span>
func _on_button_pressed():
var msg = text_edit.text
var msg_arr = [&#39;text&#39;, [msg], {}]
var msg_str = JSON.stringify(msg_arr)
socket.send_text(msg_str)
text_edit.text = &quot;&quot;
<span class="c1"># The URL to connect to, should be your mud.</span>
<span class="n">var</span> <span class="n">websocket_url</span> <span class="o">=</span> <span class="s2">&quot;ws://127.0.0.1:4008&quot;</span>
<span class="c1"># These are references to controls in the scene</span>
<span class="nd">@onready</span>
<span class="n">var</span> <span class="n">label</span><span class="p">:</span> <span class="n">RichTextLabel</span> <span class="o">=</span> <span class="n">get_node</span><span class="p">(</span><span class="s2">&quot;%ChatLog&quot;</span><span class="p">)</span>
<span class="nd">@onready</span>
<span class="n">var</span> <span class="n">txtEdit</span><span class="p">:</span> <span class="n">TextEdit</span> <span class="o">=</span> <span class="n">get_node</span><span class="p">(</span><span class="s2">&quot;%ChatInput&quot;</span><span class="p">)</span>
<span class="nd">@onready</span>
<span class="n">var</span> <span class="n">websocket</span> <span class="o">=</span> <span class="n">get_node</span><span class="p">(</span><span class="s2">&quot;WebSocketClient&quot;</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_ready</span><span class="p">():</span>
<span class="c1"># We connect the various signals</span>
<span class="n">websocket</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">&#39;connected_to_server&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_connected</span><span class="p">)</span>
<span class="n">websocket</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">&#39;connection_closed&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_closed</span><span class="p">)</span>
<span class="n">websocket</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="s1">&#39;message_received&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">_on_data</span><span class="p">)</span>
<span class="c1"># We attempt to connect and print out the error if we have one.</span>
<span class="n">var</span> <span class="n">result</span> <span class="o">=</span> <span class="n">websocket</span><span class="o">.</span><span class="n">connect_to_url</span><span class="p">(</span><span class="n">websocket_url</span><span class="p">)</span>
<span class="k">if</span> <span class="n">result</span> <span class="o">!=</span> <span class="n">OK</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Could not connect:&#39;</span> <span class="o">+</span> <span class="nb">str</span><span class="p">(</span><span class="n">result</span><span class="p">))</span>
<span class="n">func</span> <span class="n">_closed</span><span class="p">():</span>
<span class="c1"># This emits if the connection was closed by the remote host or unexpectedly</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Connection closed.&#39;</span><span class="p">)</span>
<span class="n">set_process</span><span class="p">(</span><span class="n">false</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_connected</span><span class="p">():</span>
<span class="c1"># This emits when the connection succeeds.</span>
<span class="nb">print</span><span class="p">(</span><span class="s1">&#39;Connected!&#39;</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_on_data</span><span class="p">(</span><span class="n">data</span><span class="p">):</span>
<span class="c1"># This is called when Godot receives data from evennia</span>
<span class="n">var</span> <span class="n">json_data</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">parse_string</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="c1"># Here we have the data from Evennia which is an array.</span>
<span class="c1"># The first element will be text if it is a message</span>
<span class="c1"># and would be the key of the OOB data you passed otherwise.</span>
<span class="k">if</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;text&#39;</span><span class="p">:</span>
<span class="c1"># In this case, we simply append the data as bbcode to our label.</span>
<span class="k">for</span> <span class="n">msg</span> <span class="ow">in</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">1</span><span class="p">]:</span> <span class="c1"># Here we include a newline at every message.</span>
<span class="n">label</span><span class="o">.</span><span class="n">append_text</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">msg</span><span class="p">)</span>
<span class="k">elif</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s1">&#39;coordinates&#39;</span><span class="p">:</span>
<span class="c1"># Dummy signal emitted if we wanted to handle the new coordinates</span>
<span class="c1"># elsewhere in the project.</span>
<span class="bp">self</span><span class="o">.</span><span class="n">emit_signal</span><span class="p">(</span><span class="s1">&#39;updated_coordinates&#39;</span><span class="p">,</span> <span class="n">json_data</span><span class="p">[</span><span class="mi">1</span><span class="p">])</span>
<span class="c1"># We only print this for easier debugging.</span>
<span class="nb">print</span><span class="p">(</span><span class="n">data</span><span class="p">)</span>
<span class="n">func</span> <span class="n">_on_button_pressed</span><span class="p">():</span>
<span class="c1"># This is called when we press the button in the scene</span>
<span class="c1"># with a connected signal, it sends the written message to Evennia.</span>
<span class="n">var</span> <span class="n">msg</span> <span class="o">=</span> <span class="n">txtEdit</span><span class="o">.</span><span class="n">text</span>
<span class="n">var</span> <span class="n">msg_arr</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;text&#39;</span><span class="p">,</span> <span class="p">[</span><span class="n">msg</span><span class="p">],</span> <span class="p">{}]</span>
<span class="n">var</span> <span class="n">msg_str</span> <span class="o">=</span> <span class="n">JSON</span><span class="o">.</span><span class="n">stringify</span><span class="p">(</span><span class="n">msg_arr</span><span class="p">)</span>
<span class="n">websocket</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">msg_str</span><span class="p">)</span>
func _exit_tree():
socket.close()
</pre></div>
</div>

View file

@ -68,11 +68,16 @@
<li><a class="reference internal" href="#">Roleplaying base system for Evennia</a><ul>
<li><a class="reference internal" href="#roleplaying-emotes">Roleplaying emotes</a><ul>
<li><a class="reference internal" href="#installation">Installation:</a></li>
<li><a class="reference internal" href="#usage">Usage</a><ul>
<li><a class="reference internal" href="#sdescs">Sdescs</a></li>
<li><a class="reference internal" href="#language-integration">Language integration</a></li>
</ul>
</li>
</ul>
</li>
<li><a class="reference internal" href="#language-and-whisper-obfuscation-system">Language and whisper obfuscation system</a><ul>
<li><a class="reference internal" href="#id1">Installation</a></li>
<li><a class="reference internal" href="#usage">Usage:</a></li>
<li><a class="reference internal" href="#id2">Usage:</a></li>
</ul>
</li>
</ul>
@ -197,7 +202,11 @@ your objects, if you originally created them without this.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; type/reset/force me = typeclasses.characters.Character
</pre></div>
</div>
<p>Examples:</p>
</section>
<section id="usage">
<h3>Usage<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h3>
<section id="sdescs">
<h4>Sdescs<a class="headerlink" href="#sdescs" title="Permalink to this headline"></a></h4>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; look
Tavern
@ -220,6 +229,15 @@ The tavern is full of nice people
</div>
<p>Note that by default, the case of the tag matters, so <code class="docutils literal notranslate"><span class="pre">/tall</span></code> will lead to tall man while <code class="docutils literal notranslate"><span class="pre">/Tall</span></code> will become Tall man and /TALL becomes /TALL MAN. If you dont want this behavior, you can pass case_sensitive=False to the <code class="docutils literal notranslate"><span class="pre">send_emote</span></code> function.</p>
</section>
<section id="language-integration">
<h4>Language integration<a class="headerlink" href="#language-integration" title="Permalink to this headline"></a></h4>
<p>Speech can be identified as a particular language by prefixing it with the language key.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>emote says with a growl, orcish&quot;Hello&quot;.
</pre></div>
</div>
<p>This will identify the speech “Hello” as being spoken in orcish, and then pass that information on to <code class="docutils literal notranslate"><span class="pre">process_language</span></code> on your Character. By default, it doesnt do much, but you can hook in a language system such as the <code class="docutils literal notranslate"><span class="pre">rplanguage</span></code> module below to do more interesting things.</p>
</section>
</section>
</section>
<section id="language-and-whisper-obfuscation-system">
<h2>Language and whisper obfuscation system<a class="headerlink" href="#language-and-whisper-obfuscation-system" title="Permalink to this headline"></a></h2>
@ -232,8 +250,8 @@ The tavern is full of nice people
<h3>Installation<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<p>This module adds no new commands; embed it in your say/emote/whisper commands.</p>
</section>
<section id="usage">
<h3>Usage:<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h3>
<section id="id2">
<h3>Usage:<a class="headerlink" href="#id2" 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.contrib.rpg.rpsystem</span> <span class="kn">import</span> <span class="n">rplanguage</span>
<span class="c1"># need to be done once, here we create the &quot;default&quot; lang</span>

View file

@ -72,8 +72,9 @@
</ul>
</li>
<li><a class="reference internal" href="#using-traits">Using traits</a></li>
<li><a class="reference internal" href="#trait-types">Trait types</a></li>
<li><a class="reference internal" href="#static-trait">Static trait</a><ul>
<li><a class="reference internal" href="#trait-types">Trait types</a><ul>
<li><a class="reference internal" href="#trait">Trait</a></li>
<li><a class="reference internal" href="#static-trait">Static trait</a></li>
<li><a class="reference internal" href="#counter">Counter</a><ul>
<li><a class="reference internal" href="#descs">.descs</a></li>
<li><a class="reference internal" href="#rate">.rate</a></li>
@ -81,7 +82,6 @@
</ul>
</li>
<li><a class="reference internal" href="#gauge">Gauge</a></li>
<li><a class="reference internal" href="#trait">Trait</a></li>
</ul>
</li>
<li><a class="reference internal" href="#expanding-with-your-own-traits">Expanding with your own Traits</a></li>
@ -295,11 +295,31 @@ all sorts of rule-resolution.</p>
<span class="k">if</span> <span class="n">trait1</span> <span class="o">&gt;</span> <span class="n">trait2</span><span class="p">:</span>
<span class="c1"># do stuff</span>
</pre></div>
</div>
<section id="trait">
<h3>Trait<a class="headerlink" href="#trait" title="Permalink to this headline"></a></h3>
<p>A single value of any type.</p>
<p>This is the base Trait, meant to inherit from if you want to invent
trait-types from scratch (most of the time youll probably inherit from some of
the more advanced trait-type classes though).</p>
<p>Unlike other Trait-types, the single <code class="docutils literal notranslate"><span class="pre">.value</span></code> property of the base <code class="docutils literal notranslate"><span class="pre">Trait</span></code> can
be editied. The value can hold any data that can be stored in an Attribute. If
its an integer/float you can do arithmetic with it, but otherwise this acts just
like a glorified Attribute.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;mytrait&quot;</span><span class="p">,</span> <span class="s2">&quot;My Trait&quot;</span><span class="p">,</span> <span class="n">trait_type</span><span class="o">=</span><span class="s2">&quot;trait&quot;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
<span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">mytrait</span><span class="o">.</span><span class="n">value</span>
<span class="mi">30</span>
<span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">mytrait</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="s2">&quot;stringvalue&quot;</span>
<span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">mytrait</span><span class="o">.</span><span class="n">value</span>
<span class="s2">&quot;stringvalue&quot;</span>
</pre></div>
</div>
</section>
<section id="static-trait">
<h2>Static trait<a class="headerlink" href="#static-trait" title="Permalink to this headline"></a></h2>
<h3>Static trait<a class="headerlink" href="#static-trait" title="Permalink to this headline"></a></h3>
<p><code class="docutils literal notranslate"><span class="pre">value</span> <span class="pre">=</span> <span class="pre">base</span> <span class="pre">+</span> <span class="pre">mod</span></code></p>
<p>The static trait has a <code class="docutils literal notranslate"><span class="pre">base</span></code> value and an optional <code class="docutils literal notranslate"><span class="pre">mod</span></code>-ifier. A typical use
of a static trait would be a Strength stat or Skill value. That is, something
@ -319,6 +339,7 @@ that varies slowly or not at all, and which may be modified in-place.</p>
</pre></div>
</div>
</section>
<section id="counter">
<h3>Counter<a class="headerlink" href="#counter" title="Permalink to this headline"></a></h3>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>min/unset base base+mod max/unset
@ -477,27 +498,6 @@ get how filled it is as a percentage etc.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">.rate</span></code> is particularly relevant for gauges - useful for everything
from poison slowly draining your health, to resting gradually increasing it.</p>
</section>
<section id="trait">
<h3>Trait<a class="headerlink" href="#trait" title="Permalink to this headline"></a></h3>
<p>A single value of any type.</p>
<p>This is the base Trait, meant to inherit from if you want to invent
trait-types from scratch (most of the time youll probably inherit from some of
the more advanced trait-type classes though).</p>
<p>Unlike other Trait-types, the single <code class="docutils literal notranslate"><span class="pre">.value</span></code> property of the base <code class="docutils literal notranslate"><span class="pre">Trait</span></code> can
be editied. The value can hold any data that can be stored in an Attribute. If
its an integer/float you can do arithmetic with it, but otherwise this acts just
like a glorified Attribute.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">&quot;mytrait&quot;</span><span class="p">,</span> <span class="s2">&quot;My Trait&quot;</span><span class="p">,</span> <span class="n">trait_type</span><span class="o">=</span><span class="s2">&quot;trait&quot;</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">30</span><span class="p">)</span>
<span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">mytrait</span><span class="o">.</span><span class="n">value</span>
<span class="mi">30</span>
<span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">mytrait</span><span class="o">.</span><span class="n">value</span> <span class="o">=</span> <span class="s2">&quot;stringvalue&quot;</span>
<span class="o">&gt;</span> <span class="n">obj</span><span class="o">.</span><span class="n">traits</span><span class="o">.</span><span class="n">mytrait</span><span class="o">.</span><span class="n">value</span>
<span class="s2">&quot;stringvalue&quot;</span>
</pre></div>
</div>
</section>
</section>
<section id="expanding-with-your-own-traits">
<h2>Expanding with your own Traits<a class="headerlink" href="#expanding-with-your-own-traits" title="Permalink to this headline"></a></h2>

View file

@ -329,8 +329,8 @@ Click here to see the full index of all parts and lessons of the Beginner-Tutori
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html">11. Searching for things</a><ul>
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html#main-search-functions">11.1. Main search functions</a></li>
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html#searching-using-object-search">11.2. Searching using Object.search</a></li>
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html#searching-using-object-search">11.1. Searching using Object.search</a></li>
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html#main-search-functions">11.2. Main search functions</a></li>
<li class="toctree-l4"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html#what-can-be-searched-for">11.3. What can be searched for</a><ul>
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html#search-by-key">11.3.1. Search by key</a></li>
<li class="toctree-l5"><a class="reference internal" href="Part1/Beginner-Tutorial-Searching-Things.html#search-by-aliases">11.3.2. Search by aliases</a></li>

View file

@ -132,9 +132,7 @@ An example is <code class="docutils literal notranslate"><span class="pre">look<
what is in it.</p>
<aside class="sidebar">
<p class="sidebar-title">Commands are not typeclassed</p>
<p>If you just came from the previous lesson, you might want to know that Commands and
CommandSets are not <code class="docutils literal notranslate"><span class="pre">typeclassed</span></code>. That is, instances of them are not saved to the
database. They are “just” normal Python classes.</p>
<p>If you just came from the previous lesson, you might want to know that Commands and CommandSets are not <code class="docutils literal notranslate"><span class="pre">typeclassed</span></code>. That is, instances of them are not saved to the database. They are “just” normal Python classes.</p>
</aside>
<p>In Evennia, a Command is a Python <em>class</em>. If you are unsure about what a class is, review the
<a class="reference internal" href="Beginner-Tutorial-Python-classes-and-objects.html"><span class="doc std std-doc">previous lesson about it</span></a>! A Command inherits from <code class="docutils literal notranslate"><span class="pre">evennia.Command</span></code> or from one of the alternative command- classes, such as <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> which is what most default commands use.</p>
@ -316,8 +314,7 @@ Echo: &#39;Woo Tang!&#39;
<p>You will get the docstring you put in your Command-class!</p>
<section id="making-our-cmdset-persistent">
<h3><span class="section-number">8.1.1. </span>Making our cmdset persistent<a class="headerlink" href="#making-our-cmdset-persistent" title="Permalink to this headline"></a></h3>
<p>Its getting a little annoying to have to re-add our cmdset every time we reload, right? Its simple
enough to make <code class="docutils literal notranslate"><span class="pre">echo</span></code> a <em>persistent</em> change though:</p>
<p>Its getting a little annoying to have to re-add our cmdset every time we reload, right? Its simple enough to make <code class="docutils literal notranslate"><span class="pre">echo</span></code> a <em>persistent</em> change though:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.cmdset.add(&quot;commands.mycommands.MyCmdSet&quot;, persistent=True)
</pre></div>
</div>
@ -431,10 +428,7 @@ You hit Bob with full force!
<li><p><strong>Line 3</strong>: The normal <code class="docutils literal notranslate"><span class="pre">class</span></code> header. We inherit from <code class="docutils literal notranslate"><span class="pre">Command</span></code> which we imported at the top of this file.</p></li>
<li><p><strong>Lines 4-10</strong>: The docstring and help-entry for the command. You could expand on this as much as you wanted.</p></li>
<li><p><strong>Line 11</strong>: We want to write <code class="docutils literal notranslate"><span class="pre">hit</span></code> to use this command.</p></li>
<li><p><strong>Line 14</strong>: We strip the whitespace from the argument like before. Since we dont want to have to do
<code class="docutils literal notranslate"><span class="pre">self.args.strip()</span></code> over and over, we store the stripped version
in a <em>local variable</em> <code class="docutils literal notranslate"><span class="pre">args</span></code>. Note that we dont modify <code class="docutils literal notranslate"><span class="pre">self.args</span></code> by doing this, <code class="docutils literal notranslate"><span class="pre">self.args</span></code> will still
have the whitespace and is not the same as <code class="docutils literal notranslate"><span class="pre">args</span></code> in this example.</p></li>
<li><p><strong>Line 14</strong>: We strip the whitespace from the argument like before. Since we dont want to have to do <code class="docutils literal notranslate"><span class="pre">self.args.strip()</span></code> over and over, we store the stripped version in a <em>local variable</em> <code class="docutils literal notranslate"><span class="pre">args</span></code>. Note that we dont modify <code class="docutils literal notranslate"><span class="pre">self.args</span></code> by doing this, <code class="docutils literal notranslate"><span class="pre">self.args</span></code> will still have the whitespace and is not the same as <code class="docutils literal notranslate"><span class="pre">args</span></code> in this example.</p></li>
</ul>
<aside class="sidebar">
<p class="sidebar-title">if-statements</p>

View file

@ -195,8 +195,7 @@ open it:</p>
<span class="k">pass</span>
</pre></div>
</div>
<p>So we have a class <code class="docutils literal notranslate"><span class="pre">Object</span></code> that <em>inherits</em> from <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> (which is empty) and <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, which we have imported from Evennia. The <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> acts as a place to put code you want all
of your <code class="docutils literal notranslate"><span class="pre">Objects</span></code> to have. Well focus on <code class="docutils literal notranslate"><span class="pre">Object</span></code> and <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> for now.</p>
<p>So we have a class <code class="docutils literal notranslate"><span class="pre">Object</span></code> that <em>inherits</em> from <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> (which is empty) and <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>, which we have imported from Evennia. The <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> acts as a place to put code you want all of your <code class="docutils literal notranslate"><span class="pre">Objects</span></code> to have. Well focus on <code class="docutils literal notranslate"><span class="pre">Object</span></code> and <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> for now.</p>
<p>The class itself doesnt do anything (it just <code class="docutils literal notranslate"><span class="pre">pass</span></code>es) but that doesnt mean its useless. As weve seen, it inherits all the functionality of its parent. Its in fact an <em>exact replica</em> of <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> right now. Once we know what kind of methods and resources are available on <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> we could add our own and change the way it works!</p>
<p>One thing that Evennia classes offers and which you dont get with vanilla Python classes is <em>persistence</em> - they survive a server reload since they are stored in the database.</p>
<p>Go back to <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/monsters.py</span></code>. Change it as follows:</p>
@ -262,8 +261,7 @@ Python Console is closing.
</pre></div>
</div>
<p><em>Hes still there</em>… What we just did was to create a new entry in the database for Smaug. We gave the object its name (key) and set its location to our current location.</p>
<p>To make use of Smaug in code we must first find him in the database. For an object in the current
location we can easily do this in <code class="docutils literal notranslate"><span class="pre">py</span></code> by using <code class="docutils literal notranslate"><span class="pre">me.search()</span></code>:</p>
<p>To make use of Smaug in code we must first find him in the database. For an object in the current location we can easily do this in <code class="docutils literal notranslate"><span class="pre">py</span></code> by using <code class="docutils literal notranslate"><span class="pre">me.search()</span></code>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py smaug = me.search(&quot;Smaug&quot;) ; smaug.firebreath()
Smaug breathes fire!
</pre></div>
@ -271,16 +269,12 @@ Smaug breathes fire!
</section>
<section id="creating-using-create-object">
<h3><span class="section-number">7.1.2. </span>Creating using create_object<a class="headerlink" href="#creating-using-create-object" title="Permalink to this headline"></a></h3>
<p>Creating Smaug like we did above is nice because its similar to how we created non-database
bound Python instances before. But you need to use <code class="docutils literal notranslate"><span class="pre">db_key</span></code> instead of <code class="docutils literal notranslate"><span class="pre">key</span></code> and you also have to
remember to call <code class="docutils literal notranslate"><span class="pre">.save()</span></code> afterwards. Evennia has a helper function that is more common to use,
called <code class="docutils literal notranslate"><span class="pre">create_object</span></code>. Lets recreate Cuddly this time:</p>
<p>Creating Smaug like we did above is nice because its similar to how we created non-database bound Python instances before. But you need to use <code class="docutils literal notranslate"><span class="pre">db_key</span></code> instead of <code class="docutils literal notranslate"><span class="pre">key</span></code> and you also have to remember to call <code class="docutils literal notranslate"><span class="pre">.save()</span></code> afterwards. Evennia has a helper function that is more common to use, called <code class="docutils literal notranslate"><span class="pre">create_object</span></code>. Lets recreate Cuddly this time:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py evennia.create_object(&#39;typeclasses.monsters.Monster&#39;, key=&quot;Cuddly&quot;, location=here)
&gt; look
</pre></div>
</div>
<p>Boom, Cuddly should now be in the room with you, a little less scary than Smaug. You specify the
python-path to the code you want and then set the key and location (if you had the <code class="docutils literal notranslate"><span class="pre">Monster</span></code> class already imported, you could have passed that too). Evennia sets things up and saves for you.</p>
<p>Boom, Cuddly should now be in the room with you, a little less scary than Smaug. You specify the python-path to the code you want and then set the key and location (if you had the <code class="docutils literal notranslate"><span class="pre">Monster</span></code> class already imported, you could have passed that too). Evennia sets things up and saves for you.</p>
<p>If you want to find Cuddly from anywhere (not just in the same room), you can use Evennias <code class="docutils literal notranslate"><span class="pre">search_object</span></code> function:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py cuddly = evennia.search_object(&quot;Cuddly&quot;)[0] ; cuddly.move_around()
Cuddly is moving!
@ -346,8 +340,7 @@ Cuddly is moving!
</tr>
</tbody>
</table>
<p>The child classes under <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/</span></code> are meant for you to conveniently modify and
work with. Every class inheriting (at any distance) from a Evennia base typeclass is also considered a typeclass.</p>
<p>The child classes under <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/</span></code> are meant for you to conveniently modify and work with. Every class inheriting (at any distance) from a Evennia base typeclass is also considered a typeclass.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">somewhere</span> <span class="kn">import</span> <span class="n">Something</span>
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
@ -396,8 +389,7 @@ Persistent attributes:
-------------------------------------------------------------------------------
</pre></div>
</div>
<p>We used the <code class="docutils literal notranslate"><span class="pre">examine</span></code> command briefly in the <a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">lesson about building in-game</span></a>. Now these lines
may be more useful to us:</p>
<p>We used the <code class="docutils literal notranslate"><span class="pre">examine</span></code> command briefly in the <a class="reference internal" href="Beginner-Tutorial-Building-Quickstart.html"><span class="doc std std-doc">lesson about building in-game</span></a>. Now these lines may be more useful to us:</p>
<ul class="simple">
<li><p><strong>Name/key</strong> - The name of this thing. The value <code class="docutils literal notranslate"><span class="pre">(#14)</span></code> is probably different for you. This is the
unique primary key or <em>dbref</em> for this entity in the database.</p></li>
@ -435,8 +427,7 @@ You create a new Object: box.
<p class="sidebar-title">Changing things</p>
<p>While its tempting to change folders around to your liking, this can make it harder to follow tutorials and may confuse if you are asking others for help. So dont overdo it unless you really know what you are doing.</p>
</aside>
<p>So if you wanted the creation commands and methods to default to some other class you could
add your own <code class="docutils literal notranslate"><span class="pre">BASE_OBJECT_TYPECLASS</span></code> line to <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>. The same is true for all the other typeclasseses, like characters, rooms and accounts. This way you can change the layout of your game dir considerably if you wanted. You just need to tell Evennia where everything is.</p>
<p>So if you wanted the creation commands and methods to default to some other class you could add your own <code class="docutils literal notranslate"><span class="pre">BASE_OBJECT_TYPECLASS</span></code> line to <code class="docutils literal notranslate"><span class="pre">mygame/server/conf/settings.py</span></code>. The same is true for all the other typeclasseses, like characters, rooms and accounts. This way you can change the layout of your game dir considerably if you wanted. You just need to tell Evennia where everything is.</p>
</section>
</section>
<section id="modifying-ourselves">
@ -446,15 +437,16 @@ add your own <code class="docutils literal notranslate"><span class="pre">BASE_O
<span class="sd">(module docstring)</span>
<span class="sd">&quot;&quot;&quot;</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">.objects</span> <span class="kn">import</span> <span class="n">ObjectParent</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="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="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> (class docstring)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">pass</span>
</pre></div>
</div>
<p>This looks quite familiar now - an empty class inheriting from the Evennia base typeclass (its even easier than <code class="docutils literal notranslate"><span class="pre">Object</span></code> since there is no equvalent <code class="docutils literal notranslate"><span class="pre">ParentObject</span></code> mixin class here). As you would expect, this is also the default typeclass used for creating Characters if you dont specify it. You can verify it:</p>
<p>This looks quite familiar now - an empty class inheriting from the Evennia base typeclassObjectParent. The <code class="docutils literal notranslate"><span class="pre">ObjectParent</span></code> (empty by default) is also here for adding any functionality shared by all types of Objects. As you would expect, this is also the default typeclass used for creating Characters if you dont specify it. You can verify it:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; examine me
------------------------------------------------------------------------------
Name/key: YourName (#1)
@ -486,16 +478,18 @@ Non-Persistent attributes:
<ul class="simple">
<li><p><strong>Session id(s)</strong>: This identifies the <em>Session</em> (that is, the individual connection to a players game client).</p></li>
<li><p><strong>Account</strong> shows, well the <code class="docutils literal notranslate"><span class="pre">Account</span></code> object associated with this Character and Session.</p></li>
<li><p><strong>Stored/Merged Cmdsets</strong> and <strong>Commands available</strong> is related to which <em>Commands</em> are stored on you. We will get to them in the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">next lesson</span></a>. For now its enough to know these consitute all the
commands available to you at a given moment.</p></li>
<li><p><strong>Stored/Merged Cmdsets</strong> and <strong>Commands available</strong> is related to which <em>Commands</em> are stored on you. We will get to them in the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">next lesson</span></a>. For now its enough to know these consitute all the commands available to you at a given moment.</p></li>
<li><p><strong>Non-Persistent attributes</strong> are Attributes that are only stored temporarily and will go away on next reload.</p></li>
</ul>
<p>Look at the <strong>Typeclass</strong> field and youll find that it points to <code class="docutils literal notranslate"><span class="pre">typeclasses.character.Character</span></code> as expected. So if we modify this class well also modify ourselves.</p>
<section id="a-method-on-ourselves">
<h3><span class="section-number">7.3.1. </span>A method on ourselves<a class="headerlink" href="#a-method-on-ourselves" title="Permalink to this headline"></a></h3>
<p>Lets try something simple first. Back in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/characters.py</span>
<span class="c1"># ...</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="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> (class docstring)</span>
<span class="sd"> &quot;&quot;&quot;</span>
@ -555,8 +549,11 @@ Strength is 10.
<p>After a reload all our changes were forgotten. When we change properties like this, it only changes in memory, not in the database (nor do we modify the python modules code). So when we reloaded, the fresh <code class="docutils literal notranslate"><span class="pre">Character</span></code> class was loaded, and it still has the original stats we wrote in it.</p>
<p>In principle we could change the python code. But we dont want to do that manually every time. And more importantly since we have the stats hardcoded in the class, <em>every</em> character instance in the game will have exactly the same <code class="docutils literal notranslate"><span class="pre">str</span></code>, <code class="docutils literal notranslate"><span class="pre">dex</span></code> and <code class="docutils literal notranslate"><span class="pre">int</span></code> now! This is clearly not what we want.</p>
<p>Evennia offers a special, persistent type of property for this, called an <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>. Rework your <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/characters.py</span></code> like this:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/characters.py</span>
<span class="c1"># ...</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="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> (class docstring)</span>
<span class="sd"> &quot;&quot;&quot;</span>
@ -610,10 +607,12 @@ AttributeError: &#39;Character&#39; object has no attribute &#39;strength&#39;
<h3><span class="section-number">7.3.3. </span>Setting things on new Characters<a class="headerlink" href="#setting-things-on-new-characters" title="Permalink to this headline"></a></h3>
<p>Things are looking better, but one thing remains strange - the stats start out with a value <code class="docutils literal notranslate"><span class="pre">None</span></code> and we have to manually set them to something reasonable. In a later lesson we will investigate character-creation in more detail. For now, lets give every new character some random stats to start with.</p>
<p>We want those stats to be set only once, when the object is first created. For the Character, this method is called <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># up by the other imports</span>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/characters.py</span>
<span class="c1"># ...</span>
<span class="kn">import</span> <span class="nn">random</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="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="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> (class docstring)</span>
<span class="sd"> &quot;&quot;&quot;</span>
@ -630,8 +629,7 @@ AttributeError: &#39;Character&#39; object has no attribute &#39;strength&#39;
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">strength</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">dexterity</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">intelligence</span>
</pre></div>
</div>
<p>We imported a new module, <code class="docutils literal notranslate"><span class="pre">random</span></code>. This is part of Pythons standard library. We used <code class="docutils literal notranslate"><span class="pre">random.randint</span></code> to
set a random value from 3 to 18 to each stat. Simple, but for some classical RPGs this is all you need!</p>
<p>We imported a new module, <code class="docutils literal notranslate"><span class="pre">random</span></code>. This is part of Pythons standard library. We used <code class="docutils literal notranslate"><span class="pre">random.randint</span></code> to set a random value from 3 to 18 to each stat. Simple, but for some classical RPGs this is all you need!</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; reload
&gt; py self.get_stats()
(12, 12, 15)
@ -648,8 +646,7 @@ set a random value from 3 to 18 to each stat. Simple, but for some classical RPG
(5, 4, 8)
</pre></div>
</div>
<p>Lady luck didnt smile on us for this example; maybe youll fare better. Evennia has a helper command
<code class="docutils literal notranslate"><span class="pre">update</span></code> that re-runs the creation hook and also cleans up any other Attributes not re-created by <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>:</p>
<p>Lady luck didnt smile on us for this example; maybe youll fare better. Evennia has a helper command <code class="docutils literal notranslate"><span class="pre">update</span></code> that re-runs the creation hook and also cleans up any other Attributes not re-created by <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; update self
&gt; py self.get_stats()
(8, 16, 14)
@ -683,9 +680,7 @@ foo
<p class="sidebar-title">Database queries</p>
<p><code class="docutils literal notranslate"><span class="pre">Character.objects.all()</span></code> is an example of a database query expressed in Python. This will be converted into a database query under the hood. This syntax is part of <a class="reference external" href="https://docs.djangoproject.com/en/4.1/topics/db/queries/">Djangos query language</a>. You dont need to know Django to use Evennia, but if you ever need more specific database queries, this is always available when you need it. Well get back to database queries in a later lesson.</p>
</aside>
<p>We import the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class and then we use <code class="docutils literal notranslate"><span class="pre">.objects.all()</span></code> to get all <code class="docutils literal notranslate"><span class="pre">Character</span></code> instances. Simplified,
<code class="docutils literal notranslate"><span class="pre">.objects</span></code> is a resource from which one can <em>query</em> for all <code class="docutils literal notranslate"><span class="pre">Characters</span></code>. Using <code class="docutils literal notranslate"><span class="pre">.all()</span></code> gets us a listing
of all of them that we then immediately loop over. Boom, we just updated all Characters, including ourselves:</p>
<p>We import the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class and then we use <code class="docutils literal notranslate"><span class="pre">.objects.all()</span></code> to get all <code class="docutils literal notranslate"><span class="pre">Character</span></code> instances. Simplified, <code class="docutils literal notranslate"><span class="pre">.objects</span></code> is a resource from which one can <em>query</em> for all <code class="docutils literal notranslate"><span class="pre">Characters</span></code>. Using <code class="docutils literal notranslate"><span class="pre">.all()</span></code> gets us a listing of all of them that we then immediately loop over. Boom, we just updated all Characters, including ourselves:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; quit()
Closing the Python console.
&gt; py self.get_stats()
@ -696,8 +691,7 @@ Closing the Python console.
</section>
<section id="extra-credits">
<h2><span class="section-number">7.4. </span>Extra Credits<a class="headerlink" href="#extra-credits" title="Permalink to this headline"></a></h2>
<p>This principle is the same for other typeclasses. So using the tools explored in this lesson, try to expand the default room with an <code class="docutils literal notranslate"><span class="pre">is_dark</span></code> flag. It can be either <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>. Have all new rooms start with <code class="docutils literal notranslate"><span class="pre">is_dark</span> <span class="pre">=</span> <span class="pre">False</span></code> and make it so that once you change it, it survives a reload.
Oh, and if you created any other rooms before, make sure they get the new flag too!</p>
<p>This principle is the same for other typeclasses. So using the tools explored in this lesson, try to expand the default room with an <code class="docutils literal notranslate"><span class="pre">is_dark</span></code> flag. It can be either <code class="docutils literal notranslate"><span class="pre">True</span></code> or <code class="docutils literal notranslate"><span class="pre">False</span></code>. Have all new rooms start with <code class="docutils literal notranslate"><span class="pre">is_dark</span> <span class="pre">=</span> <span class="pre">False</span></code> and make it so that once you change it, it survives a reload. Oh, and if you created any other rooms before, make sure they get the new flag too!</p>
</section>
<section id="conclusions">
<h2><span class="section-number">7.5. </span>Conclusions<a class="headerlink" href="#conclusions" title="Permalink to this headline"></a></h2>

View file

@ -280,8 +280,8 @@ will call <code class="docutils literal notranslate"><span class="pre">character
<section id="sitting-on-or-in">
<h3><span class="section-number">13.2.1. </span>Sitting on or in?<a class="headerlink" href="#sitting-on-or-in" title="Permalink to this headline"></a></h3>
<p>Its fine to sit on a chair. But what if our Sittable is an armchair?</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">py</span> <span class="n">armchair</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="s2">&quot;typeclasses.sittables.Sittable&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;armchair&quot;</span><span class="p">,</span> <span class="n">location</span><span class="o">=</span><span class="n">here</span><span class="p">)</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="n">armchair</span><span class="o">.</span><span class="n">do_sit</span><span class="p">(</span><span class="n">me</span><span class="p">)</span>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">py</span> <span class="n">evennia</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="s2">&quot;typeclasses.sittables.Sittable&quot;</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;armchair&quot;</span><span class="p">,</span> <span class="n">location</span><span class="o">=</span><span class="n">here</span><span class="p">)</span>
<span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s2">&quot;armchair&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">do_sit</span><span class="p">(</span><span class="n">me</span><span class="p">)</span>
<span class="n">You</span> <span class="n">sit</span> <span class="n">on</span> <span class="n">armchair</span><span class="o">.</span>
</pre></div>
</div>
@ -383,7 +383,7 @@ will call <code class="docutils literal notranslate"><span class="pre">character
</pre></div>
</div>
<p>Since we havent added the <code class="docutils literal notranslate"><span class="pre">sit</span></code> command yet, we must still use <code class="docutils literal notranslate"><span class="pre">py</span></code> to test:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">py</span> <span class="n">armchair</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;armchair&quot;</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span><span class="n">armchair</span><span class="o">.</span><span class="n">do_sit</span><span class="p">(</span><span class="n">me</span><span class="p">)</span>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">&gt;</span> <span class="n">py</span> <span class="bp">self</span><span class="o">.</span><span class="n">search</span><span class="p">(</span><span class="s2">&quot;armchair&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">do_sit</span><span class="p">(</span><span class="n">me</span><span class="p">)</span>
<span class="n">You</span> <span class="n">sit</span> <span class="ow">in</span> <span class="n">armchair</span><span class="o">.</span>
</pre></div>
</div>
@ -395,8 +395,8 @@ will call <code class="docutils literal notranslate"><span class="pre">character
</pre></div>
</div>
<p>You can make this happen by tweaking your <code class="docutils literal notranslate"><span class="pre">Sittable</span></code> class having the return messages be replaceable by <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> that you can set on the object you create. You want something like this:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&gt; py
&gt; chair = evennia.create_object(&quot;typeclasses.sittables.Sittable&quot;, key=&quot;pallet&quot;)
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>&gt; py
&gt; chair = evennia.create_object(&quot;typeclasses.sittables.Sittable&quot;, key=&quot;pallet&quot;, location=here)
&gt; chair.do_sit(me)
You sit down on pallet.
&gt; chair.do_stand(me)
@ -406,7 +406,8 @@ You stand up from pallet.
You sit down and a whoopie cushion makes a loud fart noise!
</pre></div>
</div>
<p>That is, if you are not setting the Attribute, you should get a default value. We leave this implementation up to the reader.</p>
<p>That is, if you are not setting the Attribute, you should get a default value.
We leave this implementation up to the reader.</p>
</section>
</section>
<section id="adding-commands">
@ -846,8 +847,7 @@ You stand up from chair.
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># end of mygame/commands/sittables.py</span>
<span class="normal">20</span></pre></div></td><td class="code"><div><pre><span></span><span class="c1"># end of mygame/commands/sittables.py</span>
<span class="k">class</span> <span class="nc">CmdStand2</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
@ -860,15 +860,14 @@ You stand up from chair.
<span class="n">key</span> <span class="o">=</span> <span class="s2">&quot;stand&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">caller</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span>
<span class="c1"># if we are sitting, this should be set on us</span>
<span class="hll"> <span class="n">sittable</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_sitting</span>
</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">sittable</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 are not sitting down.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="hll"> <span class="n">sittable</span><span class="o">.</span><span class="n">do_stand</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span>
</span></pre></div></td></tr></table></div>
<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="c1"># if we are sitting, this should be set on us</span>
<span class="n">sittable</span> <span class="o">=</span> <span class="n">caller</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">is_sitting</span>
<span class="hll"> <span class="k">if</span> <span class="ow">not</span> <span class="n">sittable</span><span class="p">:</span>
</span> <span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">&quot;You are not sitting down.&quot;</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">sittable</span><span class="o">.</span><span class="n">do_stand</span><span class="p">(</span><span class="n">caller</span><span class="p">)</span>
</pre></div></td></tr></table></div>
</div>
<ul class="simple">
<li><p><strong>Line 17</strong>: We didnt need the <code class="docutils literal notranslate"><span class="pre">is_sitting</span></code> Attribute for the first version of these Commands, but we do need it now. Since we have this, we dont need to search and know just which chair we sit on. If we dont have this Attribute set, we are not sitting anywhere.</p></li>

View file

@ -134,8 +134,7 @@
also learn how to add, modify and extend Evennias default commands.</p>
<section id="more-advanced-parsing">
<h2><span class="section-number">9.1. </span>More advanced parsing<a class="headerlink" href="#more-advanced-parsing" title="Permalink to this headline"></a></h2>
<p>In the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">last lesson</span></a> we made a <code class="docutils literal notranslate"><span class="pre">hit</span></code> Command and struck a dragon with it. You should have the code
from that still around.</p>
<p>In the <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">last lesson</span></a> we made a <code class="docutils literal notranslate"><span class="pre">hit</span></code> Command and struck a dragon with it. You should have the code from that still around.</p>
<p>Lets expand our simple <code class="docutils literal notranslate"><span class="pre">hit</span></code> command to accept a little more complex input:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>hit &lt;target&gt; [[with] &lt;weapon&gt;]
</pre></div>
@ -280,29 +279,26 @@ under two conditions (from the example above):</p>
<aside class="sidebar">
<p>Here we create the messages to send to each side of the fight explicitly. Later well find out how to use Evennias <a class="reference internal" href="../../../Components/FuncParser.html"><span class="doc std std-doc">inline functions</span></a> to send a single string that looks different depending on who sees it.</p>
</aside>
<ul>
<ul class="simple">
<li><p><strong>Lines 29 and 35</strong> - We make use of the previously parsed search terms for the target and weapon to find the
respective resource.</p></li>
<li><p><strong>Lines 34-39</strong> - Since the weapon is optional, we need to supply a default (use our fists!) if its not set. We
use this to create a <code class="docutils literal notranslate"><span class="pre">weaponstr</span></code> that is different depending on if we have a weapon or not.</p></li>
<li><p><strong>Lines 41-42</strong> - We merge the <code class="docutils literal notranslate"><span class="pre">weaponstr</span></code> with our attack texts and send it to attacker and target respectively.
Lets try it out!</p>
<blockquote>
<div><p>reload
hit smaug with sword
Could not find sword.
You hit smaug with bare fists!</p>
</div></blockquote>
</li>
<li><p><strong>Lines 41-42</strong> - We merge the <code class="docutils literal notranslate"><span class="pre">weaponstr</span></code> with our attack texts and send it to attacker and target respectively.</p></li>
</ul>
<p>Lets try it out!</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; reload
&gt; hit smaug with sword
Could not find &#39;sword&#39;.
You hit smaug with bare fists!
</pre></div>
</div>
<p>Oops, our <code class="docutils literal notranslate"><span class="pre">self.caller.search(self.weapon)</span></code> is telling us that it found no sword. This is reasonable (we dont have a sword). Since we are not <code class="docutils literal notranslate"><span class="pre">return</span></code>ing when failing to find a weapon in the way we do if we find no <code class="docutils literal notranslate"><span class="pre">target</span></code>, we still continue fighting with our bare hands.</p>
<p>This wont do. Lets make ourselves a sword:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; create sword
</pre></div>
</div>
<p>Since we didnt specify <code class="docutils literal notranslate"><span class="pre">/drop</span></code>, the sword will end up in our inventory and can seen with the <code class="docutils literal notranslate"><span class="pre">i</span></code> or
<code class="docutils literal notranslate"><span class="pre">inventory</span></code> command. The <code class="docutils literal notranslate"><span class="pre">.search</span></code> helper will still find it there. There is no need to reload to see this
change (no code changed, only stuff in the database).</p>
<p>Since we didnt specify <code class="docutils literal notranslate"><span class="pre">/drop</span></code>, the sword will end up in our inventory and can seen with the <code class="docutils literal notranslate"><span class="pre">i</span></code> or <code class="docutils literal notranslate"><span class="pre">inventory</span></code> command. The <code class="docutils literal notranslate"><span class="pre">.search</span></code> helper will still find it there. There is no need to reload to see this change (no code changed, only stuff in the database).</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; hit smaug with sword
You hit smaug with sword!
</pre></div>
@ -341,9 +337,24 @@ Who do you want to hit?
Who do you want to hit?
</pre></div>
</div>
<p>In this case we dont need both command-sets, so lets just keep the one on the sword:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.cmdset.remove(&quot;commands.mycommands.MyCmdSet&quot;)
&gt; hit
<p>In this case we dont need both command-sets, we should drop the version of <code class="docutils literal notranslate"><span class="pre">hit</span></code> sitting on our ourselves.</p>
<p>Go to <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code> and find the line where you added
<code class="docutils literal notranslate"><span class="pre">MyCmdSet</span></code> in the previous lesson. Delete or comment it out:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># mygame/commands/default_cmdsets.py </span>
<span class="c1"># ...</span>
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
<span class="c1"># ... </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"># self.add(MyCmdSet) # &lt;---------</span>
</pre></div>
</div>
<p>Next <code class="docutils literal notranslate"><span class="pre">reload</span></code> and youll only have one <code class="docutils literal notranslate"><span class="pre">hit</span></code> command available:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; hit
Who do you want to hit?
</pre></div>
</div>
@ -387,7 +398,7 @@ Command &#39;hit&#39; is not available. ..
&gt; Who do you want to hit?
</pre></div>
</div>
<p>Finally, we get rid of ours sword so we have a clean slate with no more <code class="docutils literal notranslate"><span class="pre">hit</span></code> commands floating around. We can do that in two ways:</p>
<p>After weve waved the sword around (hit a dragon or two), we will get rid of ours sword so we have a clean slate with no more <code class="docutils literal notranslate"><span class="pre">hit</span></code> commands floating around. We can do that in two ways:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>delete sword
</pre></div>
</div>
@ -456,8 +467,8 @@ Command &#39;hit&#39; is not available. ..
<p class="sidebar-title">super()</p>
<p>The <code class="docutils literal notranslate"><span class="pre">super()</span></code> function refers to the parent of the current class and is commonly used to call same-named methods on the parent.</p>
</aside>
<p><code class="docutils literal notranslate"><span class="pre">evennia.default_cmds</span></code> is a container that holds all of Evennias default commands and cmdsets. In this module we can see that this was imported and then a new child class was made for each cmdset. Each class looks familiar (except the <code class="docutils literal notranslate"><span class="pre">key</span></code>, thats mainly used to easily identify the cmdset in listings). In each <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation</span></code> all we do is call <code class="docutils literal notranslate"><span class="pre">super().at_cmdset_creation</span></code> which means that we call `at_cmdset_creation() on the <em>parent</em> CmdSet.
This is what adds all the default commands to each CmdSet.</p>
<p><code class="docutils literal notranslate"><span class="pre">evennia.default_cmds</span></code> is a container that holds all of Evennias default commands and cmdsets. In this module we can see that this was imported and then a new child class was made for each cmdset. Each class looks familiar (except the <code class="docutils literal notranslate"><span class="pre">key</span></code>, thats mainly used to easily identify the cmdset in listings). In each <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation</span></code> all we do is call <code class="docutils literal notranslate"><span class="pre">super().at_cmdset_creation</span></code> which means that we call `at_cmdset_creation() on the <em>parent</em> CmdSet.</p>
<p>This is what adds all the default commands to each CmdSet.</p>
<p>When the <code class="docutils literal notranslate"><span class="pre">DefaultCharacter</span></code> (or a child of it) is created, youll find that the equivalence of <code class="docutils literal notranslate"><span class="pre">self.cmdset.add(&quot;default_cmdsets.CharacterCmdSet,</span> <span class="pre">persistent=True&quot;)</span></code> gets called. This means that all new Characters get this cmdset. After adding more commands to it, you just need to reload to have all characters see it.</p>
<ul class="simple">
<li><p>Characters (that is you in the gameworld) has the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code>.</p></li>

View file

@ -222,8 +222,8 @@
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html">11. Searching for things</a><ul>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#main-search-functions">11.1. Main search functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#searching-using-object-search">11.2. Searching using Object.search</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#searching-using-object-search">11.1. Searching using Object.search</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#main-search-functions">11.2. Main search functions</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#what-can-be-searched-for">11.3. What can be searched for</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#finding-objects-relative-each-other">11.4. Finding objects relative each other</a></li>
<li class="toctree-l2"><a class="reference internal" href="Beginner-Tutorial-Searching-Things.html#summary">11.5. Summary</a></li>

View file

@ -68,8 +68,8 @@
<h3><a href="../../../index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">11. Searching for things</a><ul>
<li><a class="reference internal" href="#main-search-functions">11.1. Main search functions</a></li>
<li><a class="reference internal" href="#searching-using-object-search">11.2. Searching using Object.search</a></li>
<li><a class="reference internal" href="#searching-using-object-search">11.1. Searching using Object.search</a></li>
<li><a class="reference internal" href="#main-search-functions">11.2. Main search functions</a></li>
<li><a class="reference internal" href="#what-can-be-searched-for">11.3. What can be searched for</a><ul>
<li><a class="reference internal" href="#search-by-key">11.3.1. Search by key</a></li>
<li><a class="reference internal" href="#search-by-aliases">11.3.2. Search by aliases</a></li>
@ -134,52 +134,32 @@
<section class="tex2jax_ignore mathjax_ignore" id="searching-for-things">
<h1><span class="section-number">11. </span>Searching for things<a class="headerlink" href="#searching-for-things" title="Permalink to this headline"></a></h1>
<p>We have gone through how to create the various entities in Evennia. But creating something is of little use if we cannot find and use it afterwards.</p>
<section id="main-search-functions">
<h2><span class="section-number">11.1. </span>Main search functions<a class="headerlink" href="#main-search-functions" title="Permalink to this headline"></a></h2>
<p>The base tools are the <code class="docutils literal notranslate"><span class="pre">evennia.search_*</span></code> functions, such as <code class="docutils literal notranslate"><span class="pre">evennia.search_object</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">roses</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;rose&quot;</span><span class="p">)</span>
<span class="n">accts</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_account</span><span class="p">(</span><span class="s2">&quot;MyAccountName&quot;</span><span class="p">,</span> <span class="n">email</span><span class="o">=</span><span class="s2">&quot;foo@bar.com&quot;</span><span class="p">)</span>
</pre></div>
</div>
<aside class="sidebar">
<p class="sidebar-title">Querysets</p>
<p>What is returned from the main search functions is actually a <code class="docutils literal notranslate"><span class="pre">queryset</span></code>. They can be treated like lists except that they cant modified in-place. Well discuss querysets in the <code class="docutils literal notranslate"><span class="pre">next</span> <span class="pre">lesson</span></code> <Django-queries>`_.</p>
<p class="sidebar-title">Python code vs using the py command</p>
<p>Most of these tools are intended to be used in Python code, as you create your game. We
give examples of how to test things out from the <code class="docutils literal notranslate"><span class="pre">py</span></code> command, but thats just for experimenting and normally not how you code your game.</p>
</aside>
<p>This searches by <code class="docutils literal notranslate"><span class="pre">key</span></code> of the object. Strings are always case-insensitive, so searching for <code class="docutils literal notranslate"><span class="pre">&quot;rose&quot;</span></code>, <code class="docutils literal notranslate"><span class="pre">&quot;Rose&quot;</span></code> or <code class="docutils literal notranslate"><span class="pre">&quot;rOsE&quot;</span></code> give the same results. Its important to remember that what is returned from these search methods is a <em>listing</em> of zero, one or more elements - all the matches to your search. To get the first match:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose = roses[0]
<p>To test out the examples in this tutorial, lets create a few objects we can search for in the current location.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; create/drop Rose
</pre></div>
</div>
<p>Often you really want all matches to the search parameters you specify. In other situations, having zero or more than one match is a sign of a problem and you need to handle this case yourself.</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">the_one_ring</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;The one Ring&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">the_one_ring</span><span class="p">:</span>
<span class="c1"># handle not finding the ring at all</span>
<span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">the_one_ring</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="c1"># handle finding more than one ring</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># ok - exactly one ring found</span>
<span class="n">the_one_ring</span> <span class="o">=</span> <span class="n">the_one_ring</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</pre></div>
</div>
<p>There are equivalent search functions for all the main resources. You can find a listing of them
<a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">in the Search functions section</span></a> of the API frontpage.</p>
</section>
<section id="searching-using-object-search">
<h2><span class="section-number">11.2. </span>Searching using Object.search<a class="headerlink" href="#searching-using-object-search" title="Permalink to this headline"></a></h2>
<p>On the <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is a <code class="docutils literal notranslate"><span class="pre">.search</span></code> method which we have already tried out when we made Commands. For this to be used you must already have an object available:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>obj = evennia.search_object(&quot;My Object&quot;)[0] # assuming this exists
rose = obj.search(&quot;rose&quot;)
<h2><span class="section-number">11.1. </span>Searching using Object.search<a class="headerlink" href="#searching-using-object-search" title="Permalink to this headline"></a></h2>
<p>On the <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is a <code class="docutils literal notranslate"><span class="pre">.search</span></code> method which we have already tried out when we made Commands. For this to be used you must already have an object available, and if you are using <code class="docutils literal notranslate"><span class="pre">py</span></code> you can use yourself:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py self.search(&quot;rose&quot;)
Rose
</pre></div>
</div>
<p>This searches for objects based on <code class="docutils literal notranslate"><span class="pre">key</span></code> or aliases. The <code class="docutils literal notranslate"><span class="pre">.search</span></code> method wraps <code class="docutils literal notranslate"><span class="pre">evennia.search_object</span></code> and handles its output in various ways.</p>
<ul class="simple">
<li><p>This searches by <code class="docutils literal notranslate"><span class="pre">key</span></code> or <code class="docutils literal notranslate"><span class="pre">alias</span></code> of the object. Strings are always case-insensitive, so searching for <code class="docutils literal notranslate"><span class="pre">&quot;rose&quot;</span></code>, <code class="docutils literal notranslate"><span class="pre">&quot;Rose&quot;</span></code> or <code class="docutils literal notranslate"><span class="pre">&quot;rOsE&quot;</span></code> give the same results.</p></li>
<li><p>By default it will always search for objects among those in <code class="docutils literal notranslate"><span class="pre">obj.location.contents</span></code> and <code class="docutils literal notranslate"><span class="pre">obj.contents</span></code> (that is, things in objs inventory or in the same room).</p></li>
<li><p>It will always return exactly one match. If it found zero or more than one match, the return is <code class="docutils literal notranslate"><span class="pre">None</span></code>. This is different from <code class="docutils literal notranslate"><span class="pre">evennia.search</span></code>, which always returns a list.</p></li>
<li><p>It will always return exactly one match. If it found zero or more than one match, the return is <code class="docutils literal notranslate"><span class="pre">None</span></code>. This is different from <code class="docutils literal notranslate"><span class="pre">evennia.search</span></code> (see below), which always returns a list.</p></li>
<li><p>On a no-match or multimatch, <code class="docutils literal notranslate"><span class="pre">.search</span></code> will automatically send an error message to <code class="docutils literal notranslate"><span class="pre">obj</span></code>. So you dont have to worry about reporting messages if the result is <code class="docutils literal notranslate"><span class="pre">None</span></code>.</p></li>
</ul>
<p>So this method handles error messaging for you. A very common way to use it is in commands:</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>
<p>In other words, this method handles error messaging for you. A very common way to use it is in commands:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in for example mygame/commands/command.py</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">CmdQuickFind</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot; </span>
@ -200,31 +180,85 @@ rose = obj.search(&quot;rose&quot;)
<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;Found match for </span><span class="si">{</span><span class="n">query</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">result</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>If you want to test this command out, add it to the default cmdset (see <a class="reference internal" href="Beginner-Tutorial-Adding-Commands.html"><span class="doc std std-doc">the Command tutorial</span></a> for more details) and then reload the server with <code class="docutils literal notranslate"><span class="pre">reload</span></code>:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/commands/default_cmdsets.py</span>
<span class="c1"># ...</span>
<span class="kn">from</span> <span class="nn">commands.command</span> <span class="kn">import</span> <span class="n">CmdQuickFind</span> <span class="c1"># &lt;-------</span>
<span class="k">class</span> <span class="nc">CharacterCmdSet</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">CharacterCmdSet</span><span class="p">):</span>
<span class="c1"># ... </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="c1"># ... </span>
<span class="bp">self</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">CmdQuickFind</span><span class="p">())</span> <span class="c1"># &lt;------</span>
</pre></div>
</div>
<p>Remember, <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> is the one calling the command. This is usually a Character, which
inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code>. So it has <code class="docutils literal notranslate"><span class="pre">.search()</span></code> available on it.</p>
<p>This simple little Command takes its arguments and searches for a match. If it cant find it, <code class="docutils literal notranslate"><span class="pre">result</span></code> will be <code class="docutils literal notranslate"><span class="pre">None</span></code>. The error has already been reported to <code class="docutils literal notranslate"><span class="pre">self.caller</span></code> so we just abort with <code class="docutils literal notranslate"><span class="pre">return</span></code>.</p>
<p>With the <code class="docutils literal notranslate"><span class="pre">global_search</span></code> flag, you can use <code class="docutils literal notranslate"><span class="pre">.search</span></code> to find anything, not just stuff in the same room:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>volcano = self.caller.search(&quot;Vesuvio&quot;, global_search=True)
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">volcano</span> <span class="o">=</span> <span class="bp">self</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="s2">&quot;Vesuvio&quot;</span><span class="p">,</span> <span class="n">global_search</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
</pre></div>
</div>
<p>You can limit your matches to particular typeclasses:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>water_glass = self.caller.search(&quot;glass&quot;, typeclass=&quot;typeclasses.objects.WaterGlass&quot;)
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">water_glass</span> <span class="o">=</span> <span class="bp">self</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="s2">&quot;glass&quot;</span><span class="p">,</span> <span class="n">typeclass</span><span class="o">=</span><span class="s2">&quot;typeclasses.objects.WaterGlass&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>If you only want to search for a specific list of things, you can do so too:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>stone = self.caller.search(&quot;MyStone&quot;, candidates=[obj1, obj2, obj3, obj4])
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">stone</span> <span class="o">=</span> <span class="bp">self</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="s2">&quot;MyStone&quot;</span><span class="p">,</span> <span class="n">candidates</span><span class="o">=</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="n">obj4</span><span class="p">])</span>
</pre></div>
</div>
<p>This will only return a match if “MyStone” is in the room (or in your inventory) <em>and</em> is one of the four provided candidate objects. This is quite powerful, heres how youd find something only in your inventory:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>potion = self.caller.search(&quot;Healing potion&quot;, candidates=self.caller.contents)
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">potion</span> <span class="o">=</span> <span class="bp">self</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="s2">&quot;Healing potion&quot;</span><span class="p">,</span> <span class="n">candidates</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">contents</span><span class="p">)</span>
</pre></div>
</div>
<p>You can also turn off the automatic error handling:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>swords = self.caller.search(&quot;Sword&quot;, quiet=True)
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">swords</span> <span class="o">=</span> <span class="bp">self</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="s2">&quot;Sword&quot;</span><span class="p">,</span> <span class="n">quiet</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># returns a list!</span>
</pre></div>
</div>
<p>With <code class="docutils literal notranslate"><span class="pre">quiet=True</span></code> the user will not be notified on zero or multi-match errors. Instead you are expected to handle this yourself. Furthermore, what is returned is now a list of zero, one or more matches!</p>
</section>
<section id="main-search-functions">
<h2><span class="section-number">11.2. </span>Main search functions<a class="headerlink" href="#main-search-functions" title="Permalink to this headline"></a></h2>
<p>The base search tools of Evennia are the <code class="docutils literal notranslate"><span class="pre">evennia.search_*</span></code> functions, such as <code class="docutils literal notranslate"><span class="pre">evennia.search_object</span></code>. These are normally used in your code, but you can also try them out in-game using <code class="docutils literal notranslate"><span class="pre">py</span></code>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; py evennia.search_object(&quot;rose&quot;)
&lt;Queryset [Rose]&gt;
</pre></div>
</div>
<aside class="sidebar">
<p class="sidebar-title">Querysets</p>
<p>What is returned from the main search functions is actually a <code class="docutils literal notranslate"><span class="pre">queryset</span></code>. They can be treated like lists except that they cant modified in-place. Well discuss querysets in the <a class="reference internal" href="Beginner-Tutorial-Django-queries.html"><span class="doc std std-doc">next lesson</span></a></p>
</aside>
<p>This searches for objects based on <code class="docutils literal notranslate"><span class="pre">key</span></code> or <code class="docutils literal notranslate"><span class="pre">alias</span></code>. The <code class="docutils literal notranslate"><span class="pre">.search</span></code> method we talked about in the previous section in fact wraps <code class="docutils literal notranslate"><span class="pre">evennia.search_object</span></code> and handles its output in various ways. Heres the same example in Python code, for example as part of a command or coded system:</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">roses</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;rose&quot;</span><span class="p">)</span>
<span class="n">accts</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_account</span><span class="p">(</span><span class="s2">&quot;YourName&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>Above we find first the rose and then an Account. You can try both using <code class="docutils literal notranslate"><span class="pre">py</span></code>:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py evennia.search_object(&quot;rose&quot;)[0]
Rose
&gt; py evennia.search_account(&quot;YourName&quot;)[0]
&lt;Player: YourName&gt;
</pre></div>
</div>
<p>In the example above we used <code class="docutils literal notranslate"><span class="pre">[0]</span></code> to only get the first match of the queryset, which in this case gives us the rose and your Account respectively. Note that if you dont find any matches, using <code class="docutils literal notranslate"><span class="pre">[0]</span></code> like this leads to an error, so its mostly useful for debugging.</p>
<p>If you you really want all matches to the search parameters you specify. In other situations, having zero or more than one match is a sign of a problem and you need to handle this case yourself. This is too detailed for testing out just with <code class="docutils literal notranslate"><span class="pre">py</span></code>, but good to know if you want to make your own search methods:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">the_one_ring</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;The one Ring&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">the_one_ring</span><span class="p">:</span>
<span class="c1"># handle not finding the ring at all</span>
<span class="k">elif</span> <span class="nb">len</span><span class="p">(</span><span class="n">the_one_ring</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">1</span><span class="p">:</span>
<span class="c1"># handle finding more than one ring</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># ok - exactly one ring found</span>
<span class="n">the_one_ring</span> <span class="o">=</span> <span class="n">the_one_ring</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</pre></div>
</div>
<p>There are equivalent search functions for all the main resources. You can find a listing of them <a class="reference internal" href="../../../Evennia-API.html"><span class="doc std std-doc">in the Search functions section</span></a> of the API front page.</p>
</section>
<section id="what-can-be-searched-for">
<h2><span class="section-number">11.3. </span>What can be searched for<a class="headerlink" href="#what-can-be-searched-for" title="Permalink to this headline"></a></h2>
<p>These are the main database entities one can search for:</p>
@ -244,51 +278,87 @@ inherits from <code class="docutils literal notranslate"><span class="pre">Defau
</section>
<section id="search-by-aliases">
<h3><span class="section-number">11.3.2. </span>Search by aliases<a class="headerlink" href="#search-by-aliases" title="Permalink to this headline"></a></h3>
<p>Objects and Accounts can have any number of aliases. When searching for <code class="docutils literal notranslate"><span class="pre">key</span></code> these will searched too, you cant easily search only for aliases.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose.aliases.add(&quot;flower&quot;)
<p>Objects and Accounts can have any number of aliases. When searching for <code class="docutils literal notranslate"><span class="pre">key</span></code> these will searched too, you cant easily search only for aliases. Lets add an alias to our rose with the default <code class="docutils literal notranslate"><span class="pre">alias</span></code> command:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; alias rose = flower
</pre></div>
</div>
<p>If the above <code class="docutils literal notranslate"><span class="pre">rose</span></code> has a <code class="docutils literal notranslate"><span class="pre">key</span></code> <code class="docutils literal notranslate"><span class="pre">&quot;Rose&quot;</span></code>, it can now also be found by searching for <code class="docutils literal notranslate"><span class="pre">flower</span></code>. In-game
you can assign new aliases to things with the <code class="docutils literal notranslate"><span class="pre">alias</span></code> command.</p>
<p>Alternatively you can achieve the same thing manually (this is what the <code class="docutils literal notranslate"><span class="pre">alias</span></code> command does for you automatically):</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.search(&quot;rose&quot;).aliases.add(&quot;flower&quot;)
</pre></div>
</div>
<p>If the above example <code class="docutils literal notranslate"><span class="pre">rose</span></code> has a <code class="docutils literal notranslate"><span class="pre">key</span></code> <code class="docutils literal notranslate"><span class="pre">&quot;Rose&quot;</span></code>, it can now also be found by searching for its alias <code class="docutils literal notranslate"><span class="pre">flower</span></code>.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.search(&quot;flower&quot;)
Rose
</pre></div>
</div>
<blockquote>
<div><p>All default commands uses the same search functionality, so you can now do <code class="docutils literal notranslate"><span class="pre">look</span> <span class="pre">flower</span></code> to look at the rose as well.</p>
</div></blockquote>
</section>
<section id="search-by-location">
<h3><span class="section-number">11.3.3. </span>Search by location<a class="headerlink" href="#search-by-location" title="Permalink to this headline"></a></h3>
<p>Only Objects (things inheriting from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultObject</span></code>) has a location. The location is usually a room. The <code class="docutils literal notranslate"><span class="pre">Object.search</span></code> method will automatically limit it search by location, but it also works for the general search function. If we assume <code class="docutils literal notranslate"><span class="pre">room</span></code> is a particular Room instance,</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>chest = evennia.search_object(&quot;Treasure chest&quot;, location=room)
<p>Only Objects (things inheriting from <code class="docutils literal notranslate"><span class="pre">evennia.DefaultObject</span></code>) has a <code class="docutils literal notranslate"><span class="pre">.location</span></code> property.</p>
<p>The <code class="docutils literal notranslate"><span class="pre">Object.search</span></code> method will automatically limit its search by the objects location, so assuming you are in the same room as the rose, this will work:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.search(&quot;rose&quot;)
Rose
</pre></div>
</div>
<p>Lets make another location and move to it - you will no longer find the rose:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; tunnel n = kitchen
north
&gt; py self.search(&quot;rose&quot;)
Could not find &quot;rose&quot;
</pre></div>
</div>
<p>However, using <code class="docutils literal notranslate"><span class="pre">search_object</span></code> will find the rose wherever its located:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span> &gt; py evennia.search_object(&quot;rose&quot;)
&lt;QuerySet [Rose]&gt;
</pre></div>
</div>
<p>However, if you demand that the room is in the current room, it wont be found:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py evennia.search_object(&quot;rose&quot;, location=here)
&lt;QuerySet []&gt;
</pre></div>
</div>
<p>In general, the <code class="docutils literal notranslate"><span class="pre">Object.search</span></code> is a shortcut for doing the very common searches of things in the same location, whereas the <code class="docutils literal notranslate"><span class="pre">search_object</span></code> finds objects anywhere.</p>
</section>
<section id="search-by-tags">
<h3><span class="section-number">11.3.4. </span>Search by Tags<a class="headerlink" href="#search-by-tags" title="Permalink to this headline"></a></h3>
<p>Think of a <a class="reference internal" href="../../../Components/Tags.html"><span class="doc std std-doc">Tag</span></a> as the label the airport puts on your luggage when flying. Everyone going on the same plane gets a tag grouping them together so the airport can know what should go to which plane. Entities in Evennia can be grouped in the same way. Any number of tags can be attached
to each object.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose.tags.add(&quot;flowers&quot;)
rose.tags.add(&quot;thorny&quot;)
daffodil.tags.add(&quot;flowers&quot;)
tulip.tags.add(&quot;flowers&quot;)
cactus.tags.add(&quot;flowers&quot;)
cactus.tags.add(&quot;thorny&quot;)
<p>Think of a <a class="reference internal" href="../../../Components/Tags.html"><span class="doc std std-doc">Tag</span></a> as the label the airport puts on your luggage when flying. Everyone going on the same plane gets a tag, grouping them together so the airport can know what should go to which plane. Entities in Evennia can be grouped in the same way. Any number of tags can be attached to each object.</p>
<p>Go back to the location of your <code class="docutils literal notranslate"><span class="pre">rose</span></code> and lets create a few more plants:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; create/drop Daffodil
&gt; create/drop Tulip
&gt; create/drop Cactus
</pre></div>
</div>
<p>Then lets add the “thorny” and “flowers” tags as ways to group these based on if they are flowers and/or have thorns:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py self.search(&quot;rose&quot;).tags.add(&quot;flowers&quot;)
py self.search(&quot;rose&quot;).tags.add(&quot;thorny&quot;)
py self.search(&quot;daffodil&quot;).tags.add(&quot;flowers&quot;)
py self.search(&quot;tulip&quot;).tags.add(&quot;flowers&quot;)
py self.search(&quot;cactus&quot;).tags.add(&quot;flowers&quot;)
py self.search(&quot;cactus&quot;).tags.add(&quot;thorny&quot;)
</pre></div>
</div>
<p>You can now find all flowers using the <code class="docutils literal notranslate"><span class="pre">search_tag</span></code> function:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_flowers = evennia.search_tag(&quot;flowers&quot;)
roses_and_cactii = evennia.search_tag(&quot;thorny&quot;)
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>py evennia.search_tag(&quot;flowers&quot;)
&lt;QuerySet [Rose, Daffodil, Tulip, Cactus]&gt;
py evennia.search_tag(&quot;thorny&quot;)
&lt;QuerySet [Rose, Cactus]&gt;
</pre></div>
</div>
<p>Tags can also have categories. By default this category is <code class="docutils literal notranslate"><span class="pre">None</span></code> which is also considered a category.</p>
<p>Tags can also have categories. By default this category is <code class="docutils literal notranslate"><span class="pre">None</span></code> , which is considered a category of its own. Here are some examples of using categories in plain Python code (you can also try this out with <code class="docutils literal notranslate"><span class="pre">py</span></code> if you want to create the objects first):</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>silmarillion.tags.add(&quot;fantasy&quot;, category=&quot;books&quot;)
ice_and_fire.tags.add(&quot;fantasy&quot;, category=&quot;books&quot;)
mona_lisa_overdrive.tags.add(&quot;cyberpunk&quot;, category=&quot;books&quot;)
</pre></div>
</div>
<p>Note that if you specify the tag you <em>must</em> also include its category, otherwise that category
will be <code class="docutils literal notranslate"><span class="pre">None</span></code> and find no matches.</p>
<p>Note that if you specify the tag with a category, you <em>must</em> also include its category when searching, otherwise the tag-category of <code class="docutils literal notranslate"><span class="pre">None</span></code> will be searched.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_fantasy_books = evennia.search_tag(&quot;fantasy&quot;) # no matches!
all_fantasy_books = evennia.search_tag(&quot;fantasy&quot;, category=&quot;books&quot;)
</pre></div>
</div>
<p>Only the second line above returns the two fantasy books. If we specify a category however,
we can get all tagged entities within that category:</p>
<p>Only the second line above returns the two fantasy books.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_books = evennia.search_tag(category=&quot;books&quot;)
</pre></div>
</div>
@ -297,34 +367,35 @@ we can get all tagged entities within that category:</p>
<section id="search-by-attribute">
<h3><span class="section-number">11.3.5. </span>Search by Attribute<a class="headerlink" href="#search-by-attribute" title="Permalink to this headline"></a></h3>
<p>We can also search by the <a class="reference internal" href="../../../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> associated with entities.</p>
<p>For example, lets give our rose thorns:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>rose.db.has_thorns = True
wines.db.has_thorns = True
daffodil.db.has_thorns = False
<p>For example, lets say our plants have a growth state that updates as it grows:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py self.search(&quot;rose&quot;).db.growth_state = &quot;blooming&quot;
&gt; py self.search(&quot;daffodil&quot;).db.growth_state = &quot;withering&quot;
</pre></div>
</div>
<p>Now we can find things attribute and the value we want it to have:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>is_ouch = evennia.search_object_attribute(&quot;has_thorns&quot;, True)
<p>Now we can find the things that have a given growth state:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>&gt; py evennia.search_object_attribute(&quot;growth_state&quot;, &quot;withering&quot;)
&lt;QuerySet [Rose]&gt;
</pre></div>
</div>
<p>This returns the rose and the wines.</p>
<blockquote>
<div><p>Searching by Attribute can be very practical. But if you plan to do a search very often, searching
by-tag is generally faster.</p>
<div><p>Searching by Attribute can be very practical. But if you want to group entities or search very often, using Tags and search by Tags is faster and more resource-efficient.</p>
</div></blockquote>
</section>
<section id="search-by-typeclass">
<h3><span class="section-number">11.3.6. </span>Search by Typeclass<a class="headerlink" href="#search-by-typeclass" title="Permalink to this headline"></a></h3>
<p>Sometimes its useful to find all objects of a specific Typeclass. All of Evennias search tools support this.</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_roses = evennia.search_object(typeclass=&quot;typeclasses.flowers.Rose&quot;)
<p>Sometimes its useful to limit your search by which Typeclass they have.</p>
<p>Lets say you for example have two types of flower, <code class="docutils literal notranslate"><span class="pre">CursedFlower</span></code> and <code class="docutils literal notranslate"><span class="pre">BlessedFlower</span></code> defined under <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses.flowers.py</span></code>. Each class contains custom code that grants curses and blessings respectively. You may have two <code class="docutils literal notranslate"><span class="pre">rose</span></code> objects, and the player doesnt know which one is the bad or the good one. To separate them in your search, you can make sure to get the right one like this (in Python code)</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">cursed_roses</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;rose&quot;</span><span class="p">,</span> <span class="n">typeclass</span><span class="o">=</span><span class="s2">&quot;typeclasses.flowers.CursedFlower&quot;</span><span class="p">)</span>
</pre></div>
</div>
<p>If you have the <code class="docutils literal notranslate"><span class="pre">Rose</span></code> class already imported you can also pass it directly:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_roses = evennia.search_object(typeclass=Rose)
<p>If you e.g. have the <code class="docutils literal notranslate"><span class="pre">BlessedRose</span></code> class already imported you can also pass it directly:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typeclasses.flowers</span> <span class="kn">import</span> <span class="n">BlessedFlower</span>
<span class="n">blessed_roses</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="s2">&quot;rose&quot;</span><span class="p">,</span> <span class="n">typeclass</span><span class="o">=</span><span class="n">BlessedFlower</span><span class="p">)</span>
</pre></div>
</div>
<p>You can also search using the typeclass itself:</p>
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>all_roses = Rose.objects.all()
<p>A common use case is finding <em>all</em> items of a given typeclass, no matter what they are named. For this you dont use <code class="docutils literal notranslate"><span class="pre">search_object</span></code>, but search with the typeclass directly:</p>
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">typeclasses.objects.flowers</span> <span class="kn">import</span> <span class="n">Rose</span>
<span class="n">all_roses</span> <span class="o">=</span> <span class="n">Rose</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
</pre></div>
</div>
<p>This last way of searching is a simple form of a Django <em>query</em>. This is a way to express SQL queries using Python. See <a class="reference internal" href="Beginner-Tutorial-Django-queries.html"><span class="doc std std-doc">the next lesson</span></a>, where well explore this way to searching in more detail.</p>
@ -351,7 +422,7 @@ eightball = evennia.search_object(&quot;#8&quot;)
<section id="finding-objects-relative-each-other">
<h2><span class="section-number">11.4. </span>Finding objects relative each other<a class="headerlink" href="#finding-objects-relative-each-other" title="Permalink to this headline"></a></h2>
<p>Its important to understand how objects relate to one another when searching.
Lets consider a <code class="docutils literal notranslate"><span class="pre">chest</span></code> with a <code class="docutils literal notranslate"><span class="pre">coin</span></code> inside it. The chests stand in a room <code class="docutils literal notranslate"><span class="pre">dungeon</span></code>. In the dungeon is also a <code class="docutils literal notranslate"><span class="pre">door</span></code>. This is an exit leading outside.</p>
Lets consider a <code class="docutils literal notranslate"><span class="pre">chest</span></code> with a <code class="docutils literal notranslate"><span class="pre">coin</span></code> inside it. The chest stands in a room <code class="docutils literal notranslate"><span class="pre">dungeon</span></code>. In the dungeon is also a <code class="docutils literal notranslate"><span class="pre">door</span></code>. This is an exit leading outside.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span>┌───────────────────────┐
│dungeon │
│ ┌─────────┐ │
@ -371,7 +442,7 @@ Lets consider a <code class="docutils literal notranslate"><span class="pre">
<li><p><code class="docutils literal notranslate"><span class="pre">door.location</span></code> is <code class="docutils literal notranslate"><span class="pre">dungeon</span></code>.</p></li>
<li><p><code class="docutils literal notranslate"><span class="pre">room.location</span></code> is <code class="docutils literal notranslate"><span class="pre">None</span></code> since its not inside something else.</p></li>
</ul>
<p>One can use this to find what is inside what. For example, <code class="docutils literal notranslate"><span class="pre">coin.location.location</span></code> is the <code class="docutils literal notranslate"><span class="pre">room</span></code>.
<p>One can use this to find what is inside what. For example, <code class="docutils literal notranslate"><span class="pre">coin.location.location</span></code> is the <code class="docutils literal notranslate"><span class="pre">dungeon</span></code>.
We can also find what is inside each object. This is a list of things.</p>
<ul class="simple">
<li><p><code class="docutils literal notranslate"><span class="pre">room.contents</span></code> is <code class="docutils literal notranslate"><span class="pre">[chest,</span> <span class="pre">door]</span></code></p></li>

View file

@ -194,10 +194,17 @@ the <a class="reference external" href="https://django-wiki.readthedocs.io/">Dja
<span class="s1">&#39;wiki.plugins.macros.apps.MacrosConfig&#39;</span><span class="p">,</span>
<span class="p">)</span>
<span class="c1"># Disable wiki handling of login/signup</span>
<span class="c1"># Disable wiki handling of login/signup, so that it uses your Evennia login system instead</span>
<span class="n">WIKI_ACCOUNT_HANDLING</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">WIKI_ACCOUNT_SIGNUP_ALLOWED</span> <span class="o">=</span> <span class="kc">False</span>
<span class="c1"># Enable wikilinks, e.g. [[Getting Started]]</span>
<span class="n">WIKI_MARKDOWN_KWARGS</span> <span class="o">=</span> <span class="p">{</span>
<span class="s1">&#39;extensions&#39;</span><span class="p">:</span> <span class="p">[</span>
<span class="s1">&#39;wikilinks&#39;</span><span class="p">,</span>
<span class="p">]</span>
<span class="p">}</span>
<span class="c1">######################################################################</span>
<span class="c1"># Settings given in secret_settings.py override those in this file.</span>
<span class="c1">######################################################################</span>
@ -268,15 +275,15 @@ system - or, since this is an Evennia site, to define your own custom permission
<span class="c1"># Custom methods to link wiki permissions to game perms</span>
<span class="k">def</span> <span class="nf">is_superuser</span><span class="p">(</span><span class="n">article</span><span class="p">,</span> <span class="n">user</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return True if user is a superuser, False otherwise.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span><span class="p">()</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">is_superuser</span>
<span class="k">return</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">is_superuser</span>
<span class="k">def</span> <span class="nf">is_builder</span><span class="p">(</span><span class="n">article</span><span class="p">,</span> <span class="n">user</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return True if user is a builder, False otherwise.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span><span class="p">()</span> <span class="ow">and</span> <span class="n">user</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="n">user</span><span class="p">,</span> <span class="s2">&quot;perm(Builders)&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s2">&quot;Builder&quot;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">is_player</span><span class="p">(</span><span class="n">article</span><span class="p">,</span> <span class="n">user</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Return True if user is a builder, False otherwise.&quot;&quot;&quot;</span>
<span class="k">return</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span><span class="p">()</span> <span class="ow">and</span> <span class="n">user</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="n">user</span><span class="p">,</span> <span class="s2">&quot;perm(Players)&quot;</span><span class="p">)</span>
<span class="k">return</span> <span class="ow">not</span> <span class="n">user</span><span class="o">.</span><span class="n">is_anonymous</span> <span class="ow">and</span> <span class="n">user</span><span class="o">.</span><span class="n">permissions</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="s2">&quot;Player&quot;</span><span class="p">)</span>
<span class="c1"># Create new users</span>
<span class="n">WIKI_CAN_ADMIN</span> <span class="o">=</span> <span class="n">is_superuser</span>

View file

@ -251,7 +251,6 @@ to change into <code class="docutils literal notranslate"><span class="pre">myga
<span class="c1"># operating between two processes on the same machine. You usually don&#39;t need to</span>
<span class="c1"># change this unless you cannot use the default AMP port/host for</span>
<span class="c1"># whatever reason.</span>
<span class="n">AMP_ENABLED</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">AMP_HOST</span> <span class="o">=</span> <span class="s2">&quot;localhost&quot;</span>
<span class="n">AMP_PORT</span> <span class="o">=</span> <span class="mi">4006</span>
<span class="n">AMP_INTERFACE</span> <span class="o">=</span> <span class="s2">&quot;127.0.0.1&quot;</span>

View file

@ -186,6 +186,7 @@
<span class="n">ANSIString</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">signals</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">FuncParser</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">OnDemandTask</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># Handlers</span>
<span class="n">SESSION_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
@ -194,6 +195,7 @@
<span class="n">TASK_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">TICKER_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">MONITOR_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">ON_DEMAND_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<span class="c1"># Containers</span>
<span class="n">GLOBAL_SCRIPTS</span> <span class="o">=</span> <span class="kc">None</span>
@ -258,11 +260,11 @@
<span class="k">global</span> <span class="n">search_object</span><span class="p">,</span> <span class="n">search_script</span><span class="p">,</span> <span class="n">search_account</span><span class="p">,</span> <span class="n">search_channel</span>
<span class="k">global</span> <span class="n">search_help</span><span class="p">,</span> <span class="n">search_tag</span><span class="p">,</span> <span class="n">search_message</span>
<span class="k">global</span> <span class="n">create_object</span><span class="p">,</span> <span class="n">create_script</span><span class="p">,</span> <span class="n">create_account</span><span class="p">,</span> <span class="n">create_channel</span>
<span class="k">global</span> <span class="n">create_message</span><span class="p">,</span> <span class="n">create_help_entry</span>
<span class="k">global</span> <span class="n">create_message</span><span class="p">,</span> <span class="n">create_help_entry</span><span class="p">,</span> <span class="n">OnDemandTask</span>
<span class="k">global</span> <span class="n">signals</span>
<span class="k">global</span> <span class="n">settings</span><span class="p">,</span> <span class="n">lockfuncs</span><span class="p">,</span> <span class="n">logger</span><span class="p">,</span> <span class="n">utils</span><span class="p">,</span> <span class="n">gametime</span><span class="p">,</span> <span class="n">ansi</span><span class="p">,</span> <span class="n">spawn</span><span class="p">,</span> <span class="n">managers</span>
<span class="k">global</span> <span class="n">contrib</span><span class="p">,</span> <span class="n">TICKER_HANDLER</span><span class="p">,</span> <span class="n">MONITOR_HANDLER</span><span class="p">,</span> <span class="n">SESSION_HANDLER</span><span class="p">,</span> <span class="n">PROCESS_ID</span>
<span class="k">global</span> <span class="n">TASK_HANDLER</span><span class="p">,</span> <span class="n">PORTAL_SESSION_HANDLER</span><span class="p">,</span> <span class="n">SERVER_SESSION_HANDLER</span>
<span class="k">global</span> <span class="n">TASK_HANDLER</span><span class="p">,</span> <span class="n">PORTAL_SESSION_HANDLER</span><span class="p">,</span> <span class="n">SERVER_SESSION_HANDLER</span><span class="p">,</span> <span class="n">ON_DEMAND_HANDLER</span>
<span class="k">global</span> <span class="n">GLOBAL_SCRIPTS</span><span class="p">,</span> <span class="n">OPTION_CLASSES</span><span class="p">,</span> <span class="n">EVENNIA_PORTAL_SERVICE</span><span class="p">,</span> <span class="n">EVENNIA_SERVER_SERVICE</span><span class="p">,</span> <span class="n">TWISTED_APPLICATION</span>
<span class="k">global</span> <span class="n">EvMenu</span><span class="p">,</span> <span class="n">EvTable</span><span class="p">,</span> <span class="n">EvForm</span><span class="p">,</span> <span class="n">EvMore</span><span class="p">,</span> <span class="n">EvEditor</span>
<span class="k">global</span> <span class="n">ANSIString</span><span class="p">,</span> <span class="n">FuncParser</span>
@ -285,15 +287,11 @@
<span class="kn">from</span> <span class="nn">.comms.models</span> <span class="kn">import</span> <span class="n">ChannelDB</span><span class="p">,</span> <span class="n">Msg</span>
<span class="kn">from</span> <span class="nn">.locks</span> <span class="kn">import</span> <span class="n">lockfuncs</span>
<span class="kn">from</span> <span class="nn">.objects.models</span> <span class="kn">import</span> <span class="n">ObjectDB</span>
<span class="kn">from</span> <span class="nn">.objects.objects</span> <span class="kn">import</span> <span class="p">(</span>
<span class="n">DefaultCharacter</span><span class="p">,</span>
<span class="n">DefaultExit</span><span class="p">,</span>
<span class="n">DefaultObject</span><span class="p">,</span>
<span class="n">DefaultRoom</span><span class="p">,</span>
<span class="p">)</span>
<span class="kn">from</span> <span class="nn">.objects.objects</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span><span class="p">,</span> <span class="n">DefaultExit</span><span class="p">,</span> <span class="n">DefaultObject</span><span class="p">,</span> <span class="n">DefaultRoom</span>
<span class="kn">from</span> <span class="nn">.prototypes.spawner</span> <span class="kn">import</span> <span class="n">spawn</span>
<span class="kn">from</span> <span class="nn">.scripts.models</span> <span class="kn">import</span> <span class="n">ScriptDB</span>
<span class="kn">from</span> <span class="nn">.scripts.monitorhandler</span> <span class="kn">import</span> <span class="n">MONITOR_HANDLER</span>
<span class="kn">from</span> <span class="nn">.scripts.ondemandhandler</span> <span class="kn">import</span> <span class="n">ON_DEMAND_HANDLER</span><span class="p">,</span> <span class="n">OnDemandTask</span>
<span class="kn">from</span> <span class="nn">.scripts.scripts</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
<span class="kn">from</span> <span class="nn">.scripts.taskhandler</span> <span class="kn">import</span> <span class="n">TASK_HANDLER</span>
<span class="kn">from</span> <span class="nn">.scripts.tickerhandler</span> <span class="kn">import</span> <span class="n">TICKER_HANDLER</span>

View file

@ -103,10 +103,9 @@
<span class="kn">import</span> <span class="nn">traceback</span>
<span class="kn">import</span> <span class="nn">django</span>
<span class="kn">import</span> <span class="nn">evennia</span>
<span class="kn">import</span> <span class="nn">twisted</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">import</span> <span class="nn">evennia</span>
<span class="kn">from</span> <span class="nn">evennia.accounts.models</span> <span class="kn">import</span> <span class="n">AccountDB</span>
<span class="kn">from</span> <span class="nn">evennia.scripts.taskhandler</span> <span class="kn">import</span> <span class="n">TaskHandlerTask</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">gametime</span><span class="p">,</span> <span class="n">logger</span><span class="p">,</span> <span class="n">search</span><span class="p">,</span> <span class="n">utils</span>
@ -664,7 +663,7 @@
<span class="k">return</span>
<span class="c1"># get all services</span>
<span class="n">service_collection</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">SESSION_HANDLER</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">services</span>
<span class="n">service_collection</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">EVENNIA_SERVER_SERVICE</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">switches</span> <span class="ow">or</span> <span class="n">switches</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">==</span> <span class="s2">&quot;list&quot;</span><span class="p">:</span>
<span class="c1"># Just display the list of installed services and their</span>

View file

@ -0,0 +1,192 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.contrib.base_systems.godotwebsocket.test_webclient &#8212; Evennia latest documentation</title>
<link rel="stylesheet" href="../../../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../../../" src="../../../../../_static/documentation_options.js"></script>
<script src="../../../../../_static/jquery.js"></script>
<script src="../../../../../_static/underscore.js"></script>
<script src="../../../../../_static/doctools.js"></script>
<script src="../../../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../../../genindex.html" />
<link rel="search" title="Search" href="../../../../../search.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../../../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../../../evennia.html" accesskey="U">evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
</ul>
</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>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/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>Doc Versions</h3>
<ul>
<li><a href="test_webclient.html">latest (main branch)</a></li>
<li><a href="../../3.x/index.html">v3.0.0 branch (outdated)</a></li>
<li><a href="../../2.x/index.html">v2.0.0 branch (outdated)</a></li>
<li><a href="../../1.x/index.html">v1.0.0 branch (outdated)</a></li>
<li><a href="../../0.x/index.html">v0.9.5 branch (outdated)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.contrib.base_systems.godotwebsocket.test_webclient</h1><div class="highlight"><pre>
<span></span><span class="kn">from</span> <span class="nn">evennia.contrib.base_systems.godotwebsocket.webclient</span> <span class="kn">import</span> <span class="n">start_plugin_services</span>
<span class="kn">from</span> <span class="nn">evennia.server.portal.amp_server</span> <span class="kn">import</span> <span class="n">AMPServerFactory</span>
<span class="k">try</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">django.utils.unittest</span> <span class="kn">import</span> <span class="n">TestCase</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">TestCase</span>
<span class="k">try</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">unittest</span>
<span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
<span class="kn">import</span> <span class="nn">unittest</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">mock</span>
<span class="kn">from</span> <span class="nn">mock</span> <span class="kn">import</span> <span class="n">MagicMock</span><span class="p">,</span> <span class="n">Mock</span>
<span class="kn">from</span> <span class="nn">twisted.internet.base</span> <span class="kn">import</span> <span class="n">DelayedCall</span>
<span class="kn">from</span> <span class="nn">twisted.test</span> <span class="kn">import</span> <span class="n">proto_helpers</span>
<span class="kn">import</span> <span class="nn">evennia</span>
<span class="kn">from</span> <span class="nn">evennia.server.portal.portalsessionhandler</span> <span class="kn">import</span> <span class="n">PortalSessionHandler</span>
<span class="kn">from</span> <span class="nn">evennia.server.portal.service</span> <span class="kn">import</span> <span class="n">EvenniaPortalService</span>
<span class="kn">from</span> <span class="nn">evennia.utils.test_resources</span> <span class="kn">import</span> <span class="n">BaseEvenniaTest</span>
<span class="kn">from</span> <span class="nn">django.test</span> <span class="kn">import</span> <span class="n">override_settings</span>
<div class="viewcode-block" id="TestGodotWebSocketClient"><a class="viewcode-back" href="../../../../../api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient">[docs]</a><span class="k">class</span> <span class="nc">TestGodotWebSocketClient</span><span class="p">(</span><span class="n">BaseEvenniaTest</span><span class="p">):</span>
<div class="viewcode-block" id="TestGodotWebSocketClient.setUp"><a class="viewcode-back" href="../../../../../api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.setUp">[docs]</a> <span class="nd">@override_settings</span><span class="p">(</span><span class="n">GODOT_CLIENT_WEBSOCKET_CLIENT_INTERFACE</span><span class="o">=</span><span class="s2">&quot;127.0.0.1&quot;</span><span class="p">,</span> <span class="n">GODOT_CLIENT_WEBSOCKET_PORT</span><span class="o">=</span><span class="s1">&#39;8988&#39;</span><span class="p">)</span>
<span class="k">def</span> <span class="nf">setUp</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">setUp</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">portal</span> <span class="o">=</span> <span class="n">EvenniaPortalService</span><span class="p">()</span>
<span class="n">evennia</span><span class="o">.</span><span class="n">EVENNIA_PORTAL_SERVICE</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">portal</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amp_server_factory</span> <span class="o">=</span> <span class="n">AMPServerFactory</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">portal</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">amp_server</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">amp_server_factory</span><span class="o">.</span><span class="n">buildProtocol</span><span class="p">(</span><span class="s2">&quot;127.0.0.1&quot;</span><span class="p">)</span>
<span class="n">start_plugin_services</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">portal</span><span class="p">)</span>
<span class="n">godot_ws_service</span> <span class="o">=</span> <span class="nb">next</span><span class="p">(</span><span class="n">srv</span> <span class="k">for</span> <span class="n">srv</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">portal</span><span class="o">.</span><span class="n">services</span> <span class="k">if</span> <span class="n">srv</span><span class="o">.</span><span class="n">name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s1">&#39;GodotWebSocket&#39;</span><span class="p">))</span>
<span class="n">factory</span> <span class="o">=</span> <span class="n">godot_ws_service</span><span class="o">.</span><span class="n">args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span> <span class="o">=</span> <span class="n">factory</span><span class="o">.</span><span class="n">protocol</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">factory</span> <span class="o">=</span> <span class="n">factory</span>
<span class="n">evennia</span><span class="o">.</span><span class="n">PORTAL_SESSION_HANDLER</span> <span class="o">=</span> <span class="n">PortalSessionHandler</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">sessionhandler</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">PORTAL_SESSION_HANDLER</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">sessionhandler</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">PORTAL_SESSION_HANDLER</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">portal</span> <span class="o">=</span> <span class="n">Mock</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">transport</span> <span class="o">=</span> <span class="n">proto_helpers</span><span class="o">.</span><span class="n">StringTransport</span><span class="p">()</span>
<span class="c1"># self.proto.transport = proto_helpers.FakeDatagramTransport()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">transport</span><span class="o">.</span><span class="n">client</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;localhost&quot;</span><span class="p">]</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">transport</span><span class="o">.</span><span class="n">setTcpKeepAlive</span> <span class="o">=</span> <span class="n">Mock</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">state</span> <span class="o">=</span> <span class="n">MagicMock</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">addCleanup</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">factory</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">disconnect_all</span><span class="p">)</span>
<span class="n">DelayedCall</span><span class="o">.</span><span class="n">debug</span> <span class="o">=</span> <span class="kc">True</span></div>
<div class="viewcode-block" id="TestGodotWebSocketClient.test_data_in"><a class="viewcode-back" href="../../../../../api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_in">[docs]</a> <span class="nd">@mock</span><span class="o">.</span><span class="n">patch</span><span class="p">(</span><span class="s2">&quot;evennia.server.portal.portalsessionhandler.reactor&quot;</span><span class="p">,</span> <span class="n">new</span><span class="o">=</span><span class="n">MagicMock</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">test_data_in</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">proto</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">data_in</span> <span class="o">=</span> <span class="n">MagicMock</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">onOpen</span><span class="p">()</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">([</span><span class="s2">&quot;logged_in&quot;</span><span class="p">,</span> <span class="p">(),</span> <span class="p">{}])</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">onMessage</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">isBinary</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">data_in</span><span class="o">.</span><span class="n">assert_called_with</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="p">,</span> <span class="n">logged_in</span><span class="o">=</span><span class="p">[[],</span> <span class="p">{}])</span>
<span class="n">msg</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">([</span><span class="s2">&quot;text&quot;</span><span class="p">,</span> <span class="p">(</span><span class="s2">&quot;|rRed Text|n&quot;</span><span class="p">,),</span> <span class="p">{}])</span><span class="o">.</span><span class="n">encode</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">onMessage</span><span class="p">(</span><span class="n">msg</span><span class="p">,</span> <span class="n">isBinary</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">data_in</span><span class="o">.</span><span class="n">assert_called_with</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="p">[[</span><span class="s2">&quot;|rRed Text|n&quot;</span><span class="p">],</span> <span class="p">{}])</span></div>
<div class="viewcode-block" id="TestGodotWebSocketClient.test_data_out"><a class="viewcode-back" href="../../../../../api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_out">[docs]</a> <span class="nd">@mock</span><span class="o">.</span><span class="n">patch</span><span class="p">(</span><span class="s2">&quot;evennia.server.portal.portalsessionhandler.reactor&quot;</span><span class="p">,</span> <span class="n">new</span><span class="o">=</span><span class="n">MagicMock</span><span class="p">())</span>
<span class="k">def</span> <span class="nf">test_data_out</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">proto</span><span class="o">.</span><span class="n">onOpen</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">sendLine</span> <span class="o">=</span> <span class="n">MagicMock</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">sessionhandler</span><span class="o">.</span><span class="n">data_out</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="p">,</span> <span class="n">text</span><span class="o">=</span><span class="p">[[</span><span class="s2">&quot;|rRed Text|n&quot;</span><span class="p">],</span> <span class="p">{}])</span>
<span class="bp">self</span><span class="o">.</span><span class="n">proto</span><span class="o">.</span><span class="n">sendLine</span><span class="o">.</span><span class="n">assert_called_with</span><span class="p">(</span><span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">([</span><span class="s2">&quot;text&quot;</span><span class="p">,</span> <span class="p">[</span><span class="s2">&quot;[color=#ff0000]Red Text[/color]&quot;</span><span class="p">],</span> <span class="p">{}]))</span></div></div>
</pre></div>
</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="nav-item nav-item-0"><a href="../../../../../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../../../evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -168,7 +168,7 @@
<span class="n">port</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">GODOT_CLIENT_WEBSOCKET_PORT</span>
<span class="n">websocket_service</span> <span class="o">=</span> <span class="n">internet</span><span class="o">.</span><span class="n">TCPServer</span><span class="p">(</span><span class="n">port</span><span class="p">,</span> <span class="n">factory</span><span class="p">,</span> <span class="n">interface</span><span class="o">=</span><span class="n">interface</span><span class="p">)</span>
<span class="n">websocket_service</span><span class="o">.</span><span class="n">setName</span><span class="p">(</span><span class="s2">&quot;GodotWebSocket</span><span class="si">%s</span><span class="s2">:</span><span class="si">%s</span><span class="s2">&quot;</span> <span class="o">%</span> <span class="p">(</span><span class="n">interface</span><span class="p">,</span> <span class="n">port</span><span class="p">))</span>
<span class="n">portal</span><span class="o">.</span><span class="n">services</span><span class="o">.</span><span class="n">addService</span><span class="p">(</span><span class="n">websocket_service</span><span class="p">)</span></div>
<span class="n">portal</span><span class="o">.</span><span class="n">addService</span><span class="p">(</span><span class="n">websocket_service</span><span class="p">)</span></div>
</pre></div>
</div>

View file

@ -313,7 +313,7 @@
<span class="n">_RE_REF_LANG</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;\{+\##([0-9]+)\}+&quot;</span><span class="p">)</span>
<span class="c1"># language says in the emote are on the form &quot;...&quot; or langname&quot;...&quot; (no spaces).</span>
<span class="c1"># this regex returns in groups (langname, say), where langname can be empty.</span>
<span class="n">_RE_LANGUAGE</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;(?:\((\w+)\))*(</span><span class="se">\&quot;</span><span class="s2">.+?</span><span class="se">\&quot;</span><span class="s2">)&quot;</span><span class="p">)</span>
<span class="n">_RE_LANGUAGE</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="sa">r</span><span class="s2">&quot;(?:(\w+))*(</span><span class="se">\&quot;</span><span class="s2">.+?</span><span class="se">\&quot;</span><span class="s2">)&quot;</span><span class="p">)</span>
<span class="c1"># the emote parser works in two steps:</span>

View file

@ -242,8 +242,17 @@
<span class="s2">&quot;With a flair, /me looks at /first and /colliding sdesc-guy. She says {##0}&quot;</span><span class="p">,</span>
<span class="p">{</span><span class="s2">&quot;##0&quot;</span><span class="p">:</span> <span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="s1">&#39;&quot;This is a test.&quot;&#39;</span><span class="p">)},</span>
<span class="p">),</span>
<span class="p">)</span>
<span class="n">language_emote</span> <span class="o">=</span> <span class="s1">&#39;For a change of pace, /me says, elvish&quot;This is in elvish!&quot;&#39;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">assertEqual</span><span class="p">(</span>
<span class="n">rpsystem</span><span class="o">.</span><span class="n">parse_language</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">speaker</span><span class="p">,</span> <span class="n">language_emote</span><span class="p">),</span>
<span class="p">(</span>
<span class="s1">&#39;For a change of pace, /me says, {##0}&#39;</span><span class="p">,</span>
<span class="p">{</span><span class="s2">&quot;##0&quot;</span><span class="p">:</span> <span class="p">(</span><span class="s1">&#39;elvish&#39;</span><span class="p">,</span> <span class="s1">&#39;&quot;This is in elvish!&quot;&#39;</span><span class="p">)},</span>
<span class="p">),</span>
<span class="p">)</span></div>
<div class="viewcode-block" id="TestRPSystem.test_parse_sdescs_and_recogs"><a class="viewcode-back" href="../../../../../api/evennia.contrib.rpg.rpsystem.tests.html#evennia.contrib.rpg.rpsystem.tests.TestRPSystem.test_parse_sdescs_and_recogs">[docs]</a> <span class="k">def</span> <span class="nf">test_parse_sdescs_and_recogs</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="n">speaker</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">speaker</span>
<span class="n">speaker</span><span class="o">.</span><span class="n">sdesc</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">sdesc0</span><span class="p">)</span>

View file

@ -0,0 +1,663 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>evennia.scripts.ondemandhandler &#8212; Evennia latest documentation</title>
<link rel="stylesheet" href="../../../_static/nature.css" type="text/css" />
<link rel="stylesheet" href="../../../_static/pygments.css" type="text/css" />
<script id="documentation_options" data-url_root="../../../" src="../../../_static/documentation_options.js"></script>
<script src="../../../_static/jquery.js"></script>
<script src="../../../_static/underscore.js"></script>
<script src="../../../_static/doctools.js"></script>
<script src="../../../_static/language_data.js"></script>
<link rel="shortcut icon" href="../../../_static/favicon.ico"/>
<link rel="index" title="Index" href="../../../genindex.html" />
<link rel="search" title="Search" href="../../../search.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="right" style="margin-right: 10px">
<a href="../../../genindex.html" title="General Index"
accesskey="I">index</a></li>
<li class="right" >
<a href="../../../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="nav-item nav-item-0"><a href="../../../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" accesskey="U">evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.scripts.ondemandhandler</a></li>
</ul>
</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>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/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>Doc Versions</h3>
<ul>
<li><a href="ondemandhandler.html">latest (main branch)</a></li>
<li><a href="../../3.x/index.html">v3.0.0 branch (outdated)</a></li>
<li><a href="../../2.x/index.html">v2.0.0 branch (outdated)</a></li>
<li><a href="../../1.x/index.html">v1.0.0 branch (outdated)</a></li>
<li><a href="../../0.x/index.html">v0.9.5 branch (outdated)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<h1>Source code for evennia.scripts.ondemandhandler</h1><div class="highlight"><pre>
<span></span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd">Helper to handle on-demand requests, allowing a system to change state only when a player or system</span>
<span class="sd">actually needs the information. This is a very efficient way to handle gradual changes, requiring</span>
<span class="sd">not computer resources until the state is actually needed.</span>
<span class="sd">For example, consider a flowering system, where a seed sprouts, grows and blooms over a certain time.</span>
<span class="sd">One _could_ implement this with e.g. a Script or a ticker that gradually moves the flower along</span>
<span class="sd">its stages of growth. But what if that flower is in a remote location, and no one is around to see it?</span>
<span class="sd">You are then wasting computational resources on something that no one is looking at.</span>
<span class="sd">The truth is that most of the time, players are not looking at most of the things in the game. They</span>
<span class="sd">_only_ need to know about which state the flower is in when they are actually looking at it, or</span>
<span class="sd">when they are in the same room as it (so it can be incorporated in the room description). This is</span>
<span class="sd">where on-demand handling comes in.</span>
<span class="sd">This is the basic principle, using the flowering system as an example.</span>
<span class="sd">1. Someone plants a seed in a room (could also be automated). The seed is in a &quot;seedling&quot; state.</span>
<span class="sd"> We store the time it was planted (this is the important bit).</span>
<span class="sd">2. A player enters the room or looks at the plant. We check the time it was planted, and calculate</span>
<span class="sd"> how much time has passed since it was planted. If enough time has passed, we change the state to</span>
<span class="sd"> &quot;sprouting&quot; and probably change its description to reflect this.</span>
<span class="sd">3. If a player looks at the plant and not enough time has passed, it keeps the last updated state.</span>
<span class="sd">4. Eventually, it will be bloom time, and the plant will change to a &quot;blooming&quot; state when the</span>
<span class="sd"> player looks.</span>
<span class="sd">5. If no player ever comes around to look at the plant, it will never change state, and if they show</span>
<span class="sd"> up after a long time, it may not show as a &quot;wilted&quot; state or be outright deleted when observed,</span>
<span class="sd"> since too long time has passed and the plant has died.</span>
<span class="sd">With a system like this you could have growing plants all over your world and computing usage would</span>
<span class="sd">only scale by how many players you have exploring your world. The players will not know the difference</span>
<span class="sd">between this and a system that is always running, but your server will thank you.</span>
<span class="sd">There is only one situation where this system is not ideal, and that is when a player should be</span>
<span class="sd">informed of the state change _even if they perform no action_. That is, even if they are just idling</span>
<span class="sd">in the room, they should get a message like &#39;the plant suddenly blooms&#39; (or, more commonly, for</span>
<span class="sd">messages like &#39;you are feeling hungry&#39;). For this you still probably need to use one of Evennia&#39;s</span>
<span class="sd">built-in timers or tickers instead. But most of the time you should really consider using on-demand</span>
<span class="sd">handling instead.</span>
<span class="sd">## Usage</span>
<span class="sd">```python</span>
<span class="sd">from evennia import ON_DEMAND_HANDLER</span>
<span class="sd"># create a new on-demand task</span>
<span class="sd">flower = create_object(Flower, key=&quot;rose&quot;)</span>
<span class="sd">ON_DEMAND_HANDLER.add_task(</span>
<span class="sd"> flower, category=&quot;flowering&quot;,</span>
<span class="sd"> stages={0: &quot;seedling&quot;, 120: &quot;sprouting&quot;,</span>
<span class="sd"> 300: &quot;blooming&quot;, 600: &quot;wilted&quot;, 700: &quot;dead&quot;})</span>
<span class="sd"># later, when we want to check the state of the plant (e.g. in a command),</span>
<span class="sd">state = ON_DEMAND_HANDLER.get_stage(&quot;flowering&quot;, last_checked=plant.planted_time)</span>
<span class="sd">```</span>
<span class="sd">&quot;&quot;&quot;</span>
<span class="kn">from</span> <span class="nn">evennia.server.models</span> <span class="kn">import</span> <span class="n">ServerConfig</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">is_iter</span>
<span class="n">_RUNTIME</span> <span class="o">=</span> <span class="kc">None</span>
<span class="n">ON_DEMAND_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
<div class="viewcode-block" id="OnDemandTask"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask">[docs]</a><span class="k">class</span> <span class="nc">OnDemandTask</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Stores information about an on-demand task.</span>
<span class="sd"> Default property:</span>
<span class="sd"> - `default_stage_function (callable)`: This is called if no stage function is given in the stages dict.</span>
<span class="sd"> This is meant for changing the task itself (such as restarting it). Actual game code should</span>
<span class="sd"> be handled elsewhere, by checking this task. See the `stagefunc_*` static methods for examples</span>
<span class="sd"> of how to manipulate the task when a stage is reached.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="c1"># useful stage-functions. Use with OnDemandTask.endfunc_stop etc</span>
<div class="viewcode-block" id="OnDemandTask.runtime"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.runtime">[docs]</a> <span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">runtime</span><span class="p">():</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Wraps the gametime.runtime() function.</span>
<span class="sd"> Need to import here to avoid circular imports during server reboot.</span>
<span class="sd"> It&#39;s a callable to allow easier unit testing.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">global</span> <span class="n">_RUNTIME</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">_RUNTIME</span><span class="p">:</span>
<span class="kn">from</span> <span class="nn">evennia.utils.gametime</span> <span class="kn">import</span> <span class="n">runtime</span> <span class="k">as</span> <span class="n">_RUNTIME</span>
<span class="k">return</span> <span class="n">_RUNTIME</span><span class="p">()</span></div>
<div class="viewcode-block" id="OnDemandTask.stagefunc_loop"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_loop">[docs]</a> <span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">stagefunc_loop</span><span class="p">(</span><span class="n">task</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Attach this to the last stage to have the task start over from</span>
<span class="sd"> the beginning</span>
<span class="sd"> Example:</span>
<span class="sd"> stages = {0: &quot;seedling&quot;, 120: &quot;flowering&quot;, 300: &quot;dead&quot;, (&quot;_loop&quot;,</span>
<span class="sd"> OnDemandTask.stagefunc_loop)}</span>
<span class="sd"> Note that the &quot;respawn&quot; state will never actually be visible as a state to</span>
<span class="sd"> the user, instead once it reaches this state, it will *immediately* loop</span>
<span class="sd"> and the new looped state will be shown and returned to the user. So it</span>
<span class="sd"> can an idea to mark that end state with a `_` just to indicate this fact.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">now</span> <span class="o">=</span> <span class="n">OnDemandTask</span><span class="o">.</span><span class="n">runtime</span><span class="p">()</span>
<span class="n">original_start_time</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">task</span><span class="o">.</span><span class="n">start_time</span>
<span class="p">)</span> <span class="c1"># this can be set on start or previous call of this func</span>
<span class="n">dts</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">stages</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
<span class="n">total_dt</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">dts</span><span class="p">)</span> <span class="o">-</span> <span class="nb">min</span><span class="p">(</span><span class="n">dts</span><span class="p">)</span>
<span class="c1"># figure out how many times we&#39;ve looped since last start-time was set</span>
<span class="n">task</span><span class="o">.</span><span class="n">iterations</span> <span class="o">+=</span> <span class="p">(</span><span class="n">now</span> <span class="o">-</span> <span class="n">original_start_time</span><span class="p">)</span> <span class="o">//</span> <span class="n">total_dt</span>
<span class="c1"># figure out how far we are into the current loop.</span>
<span class="n">current_loop_time</span> <span class="o">=</span> <span class="p">(</span><span class="n">now</span> <span class="o">-</span> <span class="n">original_start_time</span><span class="p">)</span> <span class="o">%</span> <span class="n">total_dt</span>
<span class="c1"># We need to adjust the start_time to the start of the current loop</span>
<span class="n">task</span><span class="o">.</span><span class="n">start_time</span> <span class="o">=</span> <span class="n">now</span> <span class="o">-</span> <span class="n">current_loop_time</span></div>
<div class="viewcode-block" id="OnDemandTask.stagefunc_bounce"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_bounce">[docs]</a> <span class="nd">@staticmethod</span>
<span class="k">def</span> <span class="nf">stagefunc_bounce</span><span class="p">(</span><span class="n">task</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> This endfunc will have the task reverse direction and go through the stages in</span>
<span class="sd"> reverse order. This stage-function must be placed at both &#39;ends&#39; of the stage sequence</span>
<span class="sd"> for the bounce to continue indefinitely.</span>
<span class="sd"> Example:</span>
<span class="sd"> stages = {0: (&quot;cool&quot;, OnDemandTask.stagefunc_bounce),</span>
<span class="sd"> 50: &quot;lukewarm&quot;,</span>
<span class="sd"> 150: &quot;warm&quot;,</span>
<span class="sd"> 300: &quot;hot&quot;,</span>
<span class="sd"> 300: (&quot;HOT!&quot;, OnDemandTask.stagefunc_bounce)}</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">now</span> <span class="o">=</span> <span class="n">OnDemandTask</span><span class="o">.</span><span class="n">runtime</span><span class="p">()</span>
<span class="n">original_start_time</span> <span class="o">=</span> <span class="p">(</span>
<span class="n">task</span><span class="o">.</span><span class="n">start_time</span>
<span class="p">)</span> <span class="c1"># this can be set on start or previous call of this func</span>
<span class="n">dts</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">stages</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
<span class="n">max_dt</span> <span class="o">=</span> <span class="nb">max</span><span class="p">(</span><span class="n">dts</span><span class="p">)</span>
<span class="n">total_dt</span> <span class="o">=</span> <span class="n">max_dt</span> <span class="o">-</span> <span class="nb">min</span><span class="p">(</span><span class="n">dts</span><span class="p">)</span>
<span class="n">task</span><span class="o">.</span><span class="n">iterations</span> <span class="o">+=</span> <span class="p">(</span><span class="n">now</span> <span class="o">-</span> <span class="n">original_start_time</span><span class="p">)</span> <span class="o">//</span> <span class="n">total_dt</span>
<span class="n">current_loop_time</span> <span class="o">=</span> <span class="p">(</span><span class="n">now</span> <span class="o">-</span> <span class="n">original_start_time</span><span class="p">)</span> <span class="o">%</span> <span class="n">total_dt</span>
<span class="n">task</span><span class="o">.</span><span class="n">start_time</span> <span class="o">=</span> <span class="n">now</span> <span class="o">-</span> <span class="n">current_loop_time</span>
<span class="k">if</span> <span class="n">task</span><span class="o">.</span><span class="n">iterations</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
<span class="c1"># reverse the stages</span>
<span class="n">stages</span> <span class="o">=</span> <span class="n">task</span><span class="o">.</span><span class="n">stages</span>
<span class="n">task</span><span class="o">.</span><span class="n">stages</span> <span class="o">=</span> <span class="p">{</span><span class="nb">abs</span><span class="p">(</span><span class="n">k</span> <span class="o">-</span> <span class="n">max_dt</span><span class="p">):</span> <span class="n">v</span> <span class="k">for</span> <span class="n">k</span><span class="p">,</span> <span class="n">v</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">stages</span><span class="o">.</span><span class="n">items</span><span class="p">())}</span></div>
<span class="c1"># default fallback stage function. This is called if no stage function is given in the stages dict.</span>
<span class="n">default_stage_function</span> <span class="o">=</span> <span class="kc">None</span>
<div class="viewcode-block" id="OnDemandTask.__init__"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.__init__">[docs]</a> <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">key</span><span class="p">,</span> <span class="n">category</span><span class="p">,</span> <span class="n">stages</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">autostart</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str): A unique identifier for the task.</span>
<span class="sd"> stages (dict, optional): A dictionary `{dt: str}` or `{int or float: (str, callable)}`</span>
<span class="sd"> of time-deltas (in seconds) and the stage name they represent. If the value is a</span>
<span class="sd"> tuple, the first element is the name of the stage and the second is a callable</span>
<span class="sd"> that will be called when that stage is *first* reached. Warning: This callable</span>
<span class="sd"> is *only* triggered if the stage is actually checked/retrieved while the task is</span>
<span class="sd"> in that stage checks - it&#39;s _not_ guaranteed to be called, even if the task</span>
<span class="sd"> time-wise goes through all its stages. Each callable must be picklable (so normally</span>
<span class="sd"> it should be a stand-alone function), and takes one argument - this OnDemandTask,</span>
<span class="sd"> which it can be modified in-place as needed. This can be used to loop a task or do</span>
<span class="sd"> other changes to the task.</span>
<span class="sd"> autostart (bool, optional): If `last_checked` is `None`, and this is `False`, then the</span>
<span class="sd"> time will not start counting until the first call of `get_dt` or `get_stage`. If</span>
<span class="sd"> `True`, creating the task will immediately make a hidden check and start the timer.</span>
<span class="sd"> Examples:</span>
<span class="sd"> stages = {0: &quot;seedling&quot;,</span>
<span class="sd"> 120: &quot;sprouting&quot;,</span>
<span class="sd"> 300: &quot;blooming&quot;,</span>
<span class="sd"> 600: &quot;wilted&quot;,</span>
<span class="sd"> 700: &quot;dead&quot;</span>
<span class="sd"> }</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="n">key</span>
<span class="bp">self</span><span class="o">.</span><span class="n">category</span> <span class="o">=</span> <span class="n">category</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start_time</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_stage</span> <span class="o">=</span> <span class="kc">None</span>
<span class="bp">self</span><span class="o">.</span><span class="n">iterations</span> <span class="o">=</span> <span class="mi">0</span> <span class="c1"># only used with looping staging functions</span>
<span class="bp">self</span><span class="o">.</span><span class="n">stages</span> <span class="o">=</span> <span class="kc">None</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">stages</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="c1"># sort the stages by ending time, inserting each state as {dt: (statename, callable)}</span>
<span class="n">_stages</span> <span class="o">=</span> <span class="p">{}</span>
<span class="k">for</span> <span class="n">dt</span><span class="p">,</span> <span class="n">tup</span> <span class="ow">in</span> <span class="n">stages</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">is_iter</span><span class="p">(</span><span class="n">tup</span><span class="p">):</span>
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">tup</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">2</span><span class="p">:</span>
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
<span class="s2">&quot;Each stage must be a tuple (name, callable) or a name-string.&quot;</span>
<span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">callable</span><span class="p">(</span><span class="n">tup</span><span class="p">[</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;The second element of each stage-tuple must be a callable.&quot;</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">tup</span> <span class="o">=</span> <span class="p">(</span><span class="n">tup</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span>
<span class="n">_stages</span><span class="p">[</span><span class="n">dt</span><span class="p">]</span> <span class="o">=</span> <span class="n">tup</span>
<span class="bp">self</span><span class="o">.</span><span class="n">stages</span> <span class="o">=</span> <span class="p">{</span><span class="n">dt</span><span class="p">:</span> <span class="n">tup</span> <span class="k">for</span> <span class="n">dt</span><span class="p">,</span> <span class="n">tup</span> <span class="ow">in</span> <span class="nb">sorted</span><span class="p">(</span><span class="n">_stages</span><span class="o">.</span><span class="n">items</span><span class="p">(),</span> <span class="n">reverse</span><span class="o">=</span><span class="kc">True</span><span class="p">)}</span>
<span class="bp">self</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">autostart</span><span class="o">=</span><span class="n">autostart</span><span class="p">)</span></div>
<span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;Note that we don&#39;t check the state here&quot;&quot;&quot;</span>
<span class="c1"># we visualize stages with ascending key order</span>
<span class="n">dt</span><span class="p">,</span> <span class="n">stage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">check</span><span class="p">(</span><span class="n">autostart</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="k">return</span> <span class="sa">f</span><span class="s2">&quot;OnDemandTask(</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">[</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">category</span><span class="si">}</span><span class="s2">] (dt=</span><span class="si">{</span><span class="n">dt</span><span class="si">}</span><span class="s2">s), stage=</span><span class="si">{</span><span class="n">stage</span><span class="si">}</span><span class="s2">)&quot;</span>
<span class="k">def</span> <span class="fm">__eq__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">other</span><span class="p">):</span>
<span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">other</span><span class="p">,</span> <span class="n">OnDemandTask</span><span class="p">):</span>
<span class="k">return</span> <span class="kc">False</span>
<span class="k">return</span> <span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">category</span><span class="p">)</span> <span class="o">==</span> <span class="p">(</span><span class="n">other</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">other</span><span class="o">.</span><span class="n">category</span><span class="p">)</span>
<div class="viewcode-block" id="OnDemandTask.check"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.check">[docs]</a> <span class="k">def</span> <span class="nf">check</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">autostart</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Check the current stage of the task and return the time-delta to the next stage.</span>
<span class="sd"> Args:</span>
<span class="sd"> autostart (bool, optional): If this is set, and the task has not been started yet,</span>
<span class="sd"> it will be started by this check. This is mainly used internally.</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple: A tuple (dt, stage) where `dt` is the time-delta (in seconds) since the test</span>
<span class="sd"> started (or since it started its latest iteration). and `stage` is the name of the</span>
<span class="sd"> current stage. If no stages are defined, `stage` will always be `None`. Use `get_dt` and</span>
<span class="sd"> `get_stage` to get only one of these values.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">def</span> <span class="nf">_find_stage</span><span class="p">(</span><span class="n">delta_dt</span><span class="p">,</span> <span class="n">_rerun</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="bp">self</span><span class="o">.</span><span class="n">stages</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">None</span>
<span class="k">for</span> <span class="n">dt</span><span class="p">,</span> <span class="p">(</span><span class="n">stage</span><span class="p">,</span> <span class="n">stage_func</span><span class="p">)</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">stages</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
<span class="k">if</span> <span class="n">delta_dt</span> <span class="o">&lt;</span> <span class="n">dt</span><span class="p">:</span>
<span class="k">continue</span>
<span class="k">if</span> <span class="n">autostart</span> <span class="ow">and</span> <span class="n">stage</span> <span class="o">!=</span> <span class="bp">self</span><span class="o">.</span><span class="n">last_stage</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">_rerun</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">last_stage</span> <span class="o">=</span> <span class="n">stage</span>
<span class="k">if</span> <span class="n">stage_func</span><span class="p">:</span>
<span class="k">try</span><span class="p">:</span>
<span class="n">stage_func</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">err</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="sa">f</span><span class="s2">&quot;Error getting stage of on-demand task </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s2"> &quot;</span>
<span class="sa">f</span><span class="s2">&quot;(last_stage: </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">last_stage</span><span class="si">}</span><span class="s2">, trying to call stage-func &quot;</span>
<span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">stage_func</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="n">err</span><span class="si">}</span><span class="s2">&quot;</span>
<span class="p">)</span>
<span class="k">else</span><span class="p">:</span>
<span class="c1"># rerun the check in case the endfunc changed things</span>
<span class="k">return</span> <span class="n">_find_stage</span><span class="p">(</span><span class="n">delta_dt</span><span class="p">,</span> <span class="n">_rerun</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
<span class="k">return</span> <span class="n">stage</span>
<span class="k">def</span> <span class="nf">_find_dt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">autostart</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">start_time</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
<span class="k">if</span> <span class="n">autostart</span><span class="p">:</span>
<span class="c1"># start timer</span>
<span class="bp">self</span><span class="o">.</span><span class="n">start_time</span> <span class="o">=</span> <span class="n">now</span>
<span class="n">dt</span> <span class="o">=</span> <span class="mi">0</span>
<span class="k">else</span><span class="p">:</span>
<span class="n">dt</span> <span class="o">=</span> <span class="n">now</span> <span class="o">-</span> <span class="bp">self</span><span class="o">.</span><span class="n">start_time</span>
<span class="k">return</span> <span class="n">dt</span>
<span class="n">now</span> <span class="o">=</span> <span class="n">OnDemandTask</span><span class="o">.</span><span class="n">runtime</span><span class="p">()</span>
<span class="n">dt</span> <span class="o">=</span> <span class="n">_find_dt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">autostart</span><span class="o">=</span><span class="n">autostart</span><span class="p">)</span>
<span class="c1"># we must always fetch the stage since a stage_func may fire</span>
<span class="n">stage</span> <span class="o">=</span> <span class="n">_find_stage</span><span class="p">(</span><span class="n">dt</span><span class="p">)</span>
<span class="c1"># need to fetch dt again in case stage_func changed it</span>
<span class="n">dt</span> <span class="o">=</span> <span class="n">_find_dt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">autostart</span><span class="o">=</span><span class="n">autostart</span><span class="p">)</span>
<span class="k">return</span> <span class="n">dt</span><span class="p">,</span> <span class="n">stage</span></div>
<div class="viewcode-block" id="OnDemandTask.get_dt"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.get_dt">[docs]</a> <span class="k">def</span> <span class="nf">get_dt</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get the time-delta since last check.</span>
<span class="sd"> Returns:</span>
<span class="sd"> int: The time since the last check, or 0 if this is the first time the task is checked.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">check</span><span class="p">()[</span><span class="mi">0</span><span class="p">]</span></div>
<div class="viewcode-block" id="OnDemandTask.get_stage"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.get_stage">[docs]</a> <span class="k">def</span> <span class="nf">get_stage</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get the current stage of the task. If no stage was given, this will return `None` but</span>
<span class="sd"> still update the last_checked time.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str or None: The current stage of the task, or `None` if no stages are set.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">check</span><span class="p">()[</span><span class="mi">1</span><span class="p">]</span></div></div>
<div class="viewcode-block" id="OnDemandHandler"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler">[docs]</a><span class="k">class</span> <span class="nc">OnDemandHandler</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> A singleton handler for managing on-demand state changes. Its main function is to persistently</span>
<span class="sd"> track the time (in seconds) between a state change and the next. How you make use of this</span>
<span class="sd"> information is up to your particular system.</span>
<span class="sd"> Contrary to just using the `time` module, this will also account for server restarts.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<div class="viewcode-block" id="OnDemandHandler.__init__"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.__init__">[docs]</a> <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="bp">self</span><span class="o">.</span><span class="n">tasks</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">()</span></div>
<div class="viewcode-block" id="OnDemandHandler.load"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.load">[docs]</a> <span class="k">def</span> <span class="nf">load</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Load the on-demand timers from ServerConfig storage.</span>
<span class="sd"> This should be automatically called when Evennia starts.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span> <span class="o">=</span> <span class="n">ServerConfig</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">conf</span><span class="p">(</span><span class="s2">&quot;on_demand_timers&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">dict</span><span class="p">)</span></div>
<div class="viewcode-block" id="OnDemandHandler.save"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.save">[docs]</a> <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Save the on-demand timers to ServerConfig storage. Should be called when Evennia shuts down.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">ServerConfig</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">conf</span><span class="p">(</span><span class="s2">&quot;on_demand_timers&quot;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">)</span></div>
<span class="k">def</span> <span class="nf">_build_key</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Build a unique key for the task.</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str, callable, OnDemandTask or Object): The task key. If callable, it will be</span>
<span class="sd"> called without arguments. If an Object, will be converted to a string. If</span>
<span class="sd"> an `OnDemandTask`, then all other arguments are ignored and the task will be used</span>
<span class="sd"> to build the internal storage key.</span>
<span class="sd"> category (str or callable): The task category. If callable, it will be called without arguments.</span>
<span class="sd"> Returns:</span>
<span class="sd"> tuple (str, str or None): The unique key.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">OnDemandTask</span><span class="p">):</span>
<span class="k">return</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">key</span><span class="o">.</span><span class="n">category</span><span class="p">)</span>
<span class="k">return</span> <span class="p">(</span>
<span class="nb">str</span><span class="p">(</span><span class="n">key</span><span class="p">()</span> <span class="k">if</span> <span class="nb">callable</span><span class="p">(</span><span class="n">key</span><span class="p">)</span> <span class="k">else</span> <span class="n">key</span><span class="p">),</span>
<span class="n">category</span><span class="p">()</span> <span class="k">if</span> <span class="nb">callable</span><span class="p">(</span><span class="n">category</span><span class="p">)</span> <span class="k">else</span> <span class="nb">str</span><span class="p">(</span><span class="n">category</span><span class="p">)</span> <span class="k">if</span> <span class="n">category</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="k">else</span> <span class="kc">None</span><span class="p">,</span>
<span class="p">)</span>
<div class="viewcode-block" id="OnDemandHandler.add"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.add">[docs]</a> <span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">stages</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">autostart</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Add a new on-demand task.</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str, callable, OnDemandTask or Object): A unique identifier for the task. If this</span>
<span class="sd"> is a callable, it will be called without arguments. If a db-Object, it will be</span>
<span class="sd"> converted to a string representation (which will include its (#dbref). If an</span>
<span class="sd"> `OnDemandTask`, then all other arguments are ignored and the task is simply added</span>
<span class="sd"> as-is.</span>
<span class="sd"> category (str or callable, optional): A category to group the task under. If given, it</span>
<span class="sd"> must also be given when checking the task.</span>
<span class="sd"> stages (dict, optional): A dictionary {dt: str}, of time-deltas (in seconds) and the</span>
<span class="sd"> stage which should be entered after that much time has passed. autostart (bool,</span>
<span class="sd"> optional): If `True`, creating the task will immediately make a hidden</span>
<span class="sd"> check and start the timer.</span>
<span class="sd"> Returns:</span>
<span class="sd"> OnDemandTask: The created task (or the same that was added, if given an `OnDemandTask`</span>
<span class="sd"> as a `key`). Use `task.get_dt()` and `task.get_stage()` to get data from it manually.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">OnDemandTask</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_build_key</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">key</span><span class="o">.</span><span class="n">category</span><span class="p">)]</span> <span class="o">=</span> <span class="n">key</span>
<span class="k">return</span> <span class="n">key</span>
<span class="n">task</span> <span class="o">=</span> <span class="n">OnDemandTask</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="p">,</span> <span class="n">stages</span><span class="p">,</span> <span class="n">autostart</span><span class="o">=</span><span class="n">autostart</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_build_key</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="p">)]</span> <span class="o">=</span> <span class="n">task</span>
<span class="k">return</span> <span class="n">task</span></div>
<div class="viewcode-block" id="OnDemandHandler.batch_add"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.batch_add">[docs]</a> <span class="k">def</span> <span class="nf">batch_add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">tasks</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Add multiple on-demand tasks at once.</span>
<span class="sd"> Args:</span>
<span class="sd"> *tasks (OnDemandTask): A set of OnDemandTasks to add.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">task</span> <span class="ow">in</span> <span class="n">tasks</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">_build_key</span><span class="p">(</span><span class="n">task</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">task</span><span class="o">.</span><span class="n">category</span><span class="p">)]</span> <span class="o">=</span> <span class="n">task</span></div>
<div class="viewcode-block" id="OnDemandHandler.remove"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.remove">[docs]</a> <span class="k">def</span> <span class="nf">remove</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Remove an on-demand task.</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str, callable, OnDemandTask or Object): The unique identifier for the task. If a callable, will</span>
<span class="sd"> be called without arguments. If an Object, will be converted to a string. If an `OnDemandTask`,</span>
<span class="sd"> then all other arguments are ignored and the task will be used to identify the task to remove.</span>
<span class="sd"> category (str or callable, optional): The category of the task.</span>
<span class="sd"> Returns:</span>
<span class="sd"> OnDemandTask or None: The removed task, or `None` if no task was found.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_build_key</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="p">),</span> <span class="kc">None</span><span class="p">)</span></div>
<div class="viewcode-block" id="OnDemandHandler.batch_remove"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.batch_remove">[docs]</a> <span class="k">def</span> <span class="nf">batch_remove</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="n">keys</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Remove multiple on-demand tasks at once, potentially within a given category.</span>
<span class="sd"> Args:</span>
<span class="sd"> *keys (str, callable, OnDemandTask or Object): The unique identifiers for the tasks. If</span>
<span class="sd"> a callable, will be called without arguments. If an Object, will be converted to a</span>
<span class="sd"> string. If an `OnDemandTask`, then all other arguments are ignored and the task will</span>
<span class="sd"> be used to identify the task to remove.</span>
<span class="sd"> category (str or callable, optional): The category of the tasks.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">for</span> <span class="n">key</span> <span class="ow">in</span> <span class="n">keys</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="n">category</span><span class="p">)</span></div>
<div class="viewcode-block" id="OnDemandHandler.all"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.all">[docs]</a> <span class="k">def</span> <span class="nf">all</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">all_on_none</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get all on-demand tasks.</span>
<span class="sd"> Args:</span>
<span class="sd"> category (str, optional): The category of the tasks.</span>
<span class="sd"> all_on_none (bool, optional): Determines what to return if `category` is `None`.</span>
<span class="sd"> If `True`, all tasks will be returned. If `False`, only tasks without a category</span>
<span class="sd"> will be returned.</span>
<span class="sd"> Returns:</span>
<span class="sd"> dict: A dictionary of all on-demand task, on the form `{(key, category): task), ...}`.</span>
<span class="sd"> Use `task.get_dt()` or `task.get_stage()` to get the time-delta or stage of each task</span>
<span class="sd"> manually.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">category</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">all_on_none</span><span class="p">:</span>
<span class="c1"># return all</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span>
<span class="c1"># filter by category (treat no-category as its own category)</span>
<span class="k">return</span> <span class="p">{</span><span class="n">keytuple</span><span class="p">:</span> <span class="n">task</span> <span class="k">for</span> <span class="n">keytuple</span><span class="p">,</span> <span class="n">task</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">keytuple</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">==</span> <span class="n">category</span><span class="p">}</span></div>
<div class="viewcode-block" id="OnDemandHandler.clear"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.clear">[docs]</a> <span class="k">def</span> <span class="nf">clear</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">all_on_none</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Clear all on-demand tasks.</span>
<span class="sd"> Args:</span>
<span class="sd"> category (str, optional): The category of the tasks to clear. What `None` means is determined</span>
<span class="sd"> by the `all_on_none` kwarg.</span>
<span class="sd"> all_on_none (bool, optional): Determines what to clear if `category` is `None`. If `True`,</span>
<span class="sd"> clear all tasks, if `False`, only clear tasks with no category.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">if</span> <span class="n">category</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">all_on_none</span><span class="p">:</span>
<span class="c1"># clear all</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span> <span class="o">=</span> <span class="p">{}</span>
<span class="c1"># filter and clear only those matching the category</span>
<span class="bp">self</span><span class="o">.</span><span class="n">tasks</span> <span class="o">=</span> <span class="p">{</span>
<span class="n">keytuple</span><span class="p">:</span> <span class="n">task</span> <span class="k">for</span> <span class="n">keytuple</span><span class="p">,</span> <span class="n">task</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">items</span><span class="p">()</span> <span class="k">if</span> <span class="n">keytuple</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">!=</span> <span class="n">category</span>
<span class="p">}</span></div>
<div class="viewcode-block" id="OnDemandHandler.get"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.get">[docs]</a> <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get an on-demand task. This will _not_ check it.</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str, callable, OnDemandTask or Object): The unique identifier for the task. If a</span>
<span class="sd"> callable, will be called without arguments. If an Object, will be converted to a string.</span>
<span class="sd"> If an `OnDemandTask`, then all other arguments are ignored and the task will be used</span>
<span class="sd"> (only useful to check the task is the same).</span>
<span class="sd"> category (str, optional): The category of the task. If unset, this will only return</span>
<span class="sd"> tasks with no category.</span>
<span class="sd"> Returns:</span>
<span class="sd"> OnDemandTask or None: The task, or `None` if no task was found.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">tasks</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_build_key</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="p">))</span></div>
<div class="viewcode-block" id="OnDemandHandler.get_dt"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.get_dt">[docs]</a> <span class="k">def</span> <span class="nf">get_dt</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get the time-delta since the task started.</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str, callable, OnDemandTask or Object): The unique identifier for the task. If a</span>
<span class="sd"> callable, will be called without arguments. If an Object, will be converted to a string.</span>
<span class="sd"> If an `OnDemandTask`, then all other arguments are ignored and the task will be used</span>
<span class="sd"> to identify the task to get the time-delta from.</span>
<span class="sd"> Returns:</span>
<span class="sd"> int or None: The time since the last check, or `None` if no task was found.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">task</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="p">)</span>
<span class="k">return</span> <span class="n">task</span><span class="o">.</span><span class="n">get_dt</span><span class="p">()</span> <span class="k">if</span> <span class="n">task</span> <span class="k">else</span> <span class="kc">None</span></div>
<div class="viewcode-block" id="OnDemandHandler.get_stage"><a class="viewcode-back" href="../../../api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.get_stage">[docs]</a> <span class="k">def</span> <span class="nf">get_stage</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
<span class="sd"> Get the current stage of an on-demand task.</span>
<span class="sd"> Args:</span>
<span class="sd"> key (str, callable, OnDemandTask or Object): The unique identifier for the task. If a</span>
<span class="sd"> callable, will be called without arguments. If an Object, will be converted to a string.</span>
<span class="sd"> If an `OnDemandTask`, then all other arguments are ignored and the task will be used</span>
<span class="sd"> to identify the task to get the stage from.</span>
<span class="sd"> Returns:</span>
<span class="sd"> str or None: The current stage of the task, or `None` if no task was found.</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">task</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">category</span><span class="p">)</span>
<span class="k">return</span> <span class="n">task</span><span class="o">.</span><span class="n">get_stage</span><span class="p">()</span> <span class="k">if</span> <span class="n">task</span> <span class="k">else</span> <span class="kc">None</span></div></div>
<span class="c1"># Create singleton</span>
<span class="n">ON_DEMAND_HANDLER</span> <span class="o">=</span> <span class="n">OnDemandHandler</span><span class="p">()</span>
</pre></div>
</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="nav-item nav-item-0"><a href="../../../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../../index.html" >Module code</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="../../evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.scripts.ondemandhandler</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -95,13 +95,12 @@
<span class="kn">from</span> <span class="nn">datetime</span> <span class="kn">import</span> <span class="n">datetime</span><span class="p">,</span> <span class="n">timedelta</span>
<span class="kn">from</span> <span class="nn">pickle</span> <span class="kn">import</span> <span class="n">PickleError</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span>
<span class="kn">from</span> <span class="nn">twisted.internet.defer</span> <span class="kn">import</span> <span class="n">CancelledError</span> <span class="k">as</span> <span class="n">DefCancelledError</span>
<span class="kn">from</span> <span class="nn">twisted.internet.task</span> <span class="kn">import</span> <span class="n">deferLater</span>
<span class="kn">from</span> <span class="nn">evennia.server.models</span> <span class="kn">import</span> <span class="n">ServerConfig</span>
<span class="kn">from</span> <span class="nn">evennia.utils.dbserialize</span> <span class="kn">import</span> <span class="n">dbserialize</span><span class="p">,</span> <span class="n">dbunserialize</span>
<span class="kn">from</span> <span class="nn">evennia.utils.logger</span> <span class="kn">import</span> <span class="n">log_err</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span>
<span class="kn">from</span> <span class="nn">twisted.internet.defer</span> <span class="kn">import</span> <span class="n">CancelledError</span> <span class="k">as</span> <span class="n">DefCancelledError</span>
<span class="kn">from</span> <span class="nn">twisted.internet.task</span> <span class="kn">import</span> <span class="n">deferLater</span>
<span class="n">TASK_HANDLER</span> <span class="o">=</span> <span class="kc">None</span>
@ -294,7 +293,7 @@
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">task_id</span></div></div>
<div class="viewcode-block" id="TaskHandler"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler">[docs]</a><span class="k">class</span> <span class="nc">TaskHandler</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
<div class="viewcode-block" id="TaskHandler"><a class="viewcode-back" href="../../../api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler">[docs]</a><span class="k">class</span> <span class="nc">TaskHandler</span><span class="p">:</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;A light singleton wrapper allowing to access permanent tasks.</span>
@ -326,7 +325,7 @@
<span class="sd"> &quot;&quot;&quot;</span>
<span class="n">to_save</span> <span class="o">=</span> <span class="kc">False</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">ServerConfig</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">conf</span><span class="p">(</span><span class="s2">&quot;delayed_tasks&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="p">{})</span>
<span class="n">value</span> <span class="o">=</span> <span class="n">ServerConfig</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">conf</span><span class="p">(</span><span class="s2">&quot;delayed_tasks&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="nb">dict</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="nb">str</span><span class="p">):</span>
<span class="n">tasks</span> <span class="o">=</span> <span class="n">dbunserialize</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
<span class="k">else</span><span class="p">:</span>

View file

@ -202,6 +202,11 @@
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s2">&quot;GAME_DIRECTORY_LISTING&quot;</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">DeprecationWarning</span><span class="p">(</span><span class="n">game_directory_deprecation</span><span class="p">)</span>
<span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">settings</span><span class="p">,</span> <span class="s2">&quot;AMP_ENABLED&quot;</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">DeprecationWarning</span><span class="p">(</span>
<span class="s2">&quot;AMP_ENABLED option is no longer supported. Remove it from your settings.&quot;</span>
<span class="p">)</span>
<span class="n">chan_connectinfo</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">CHANNEL_CONNECTINFO</span>
<span class="k">if</span> <span class="n">chan_connectinfo</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">chan_connectinfo</span><span class="p">,</span> <span class="nb">dict</span><span class="p">):</span>
<span class="k">raise</span> <span class="ne">DeprecationWarning</span><span class="p">(</span>

View file

@ -138,6 +138,9 @@
<span class="k">else</span><span class="p">:</span>
<span class="n">conf</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="n">key</span><span class="p">)</span>
<span class="k">if</span> <span class="ow">not</span> <span class="n">conf</span><span class="p">:</span>
<span class="k">if</span> <span class="nb">callable</span><span class="p">(</span><span class="n">default</span><span class="p">):</span>
<span class="c1"># allows for `dict` to be a default value</span>
<span class="k">return</span> <span class="n">default</span><span class="p">()</span>
<span class="k">return</span> <span class="n">default</span>
<span class="k">return</span> <span class="n">conf</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">value</span>
<span class="k">return</span> <span class="kc">None</span></div></div>

View file

@ -242,8 +242,7 @@
<span class="k">except</span> <span class="n">OperationalError</span><span class="p">:</span>
<span class="nb">print</span><span class="p">(</span><span class="s2">&quot;Server server_starting_mode couldn&#39;t be set - database not set up.&quot;</span><span class="p">)</span>
<span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">AMP_ENABLED</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">register_amp</span><span class="p">()</span>
<span class="bp">self</span><span class="o">.</span><span class="n">register_amp</span><span class="p">()</span>
<span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">WEBSERVER_ENABLED</span><span class="p">:</span>
<span class="bp">self</span><span class="o">.</span><span class="n">register_webserver</span><span class="p">()</span>
@ -573,7 +572,7 @@
<span class="c1"># initialize and start global scripts</span>
<span class="n">evennia</span><span class="o">.</span><span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">start</span><span class="p">()</span></div>
<div class="viewcode-block" id="EvenniaServerService.shutdown"><a class="viewcode-back" href="../../../api/evennia.server.service.html#evennia.server.service.EvenniaServerService.shutdown">[docs]</a> <span class="nd">@defer</span><span class="o">.</span><span class="n">inlineCallbacks</span>
<span class="k">def</span> <span class="nf">shutdown</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">mode</span><span class="o">=</span><span class="s2">&quot;reload&quot;</span><span class="p">,</span> <span class="n">_reactor_stopping</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
<span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
@ -643,6 +642,11 @@
<span class="n">TICKER_HANDLER</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="c1"># on-demand handler state should always be saved.</span>
<span class="kn">from</span> <span class="nn">evennia.scripts.ondemandhandler</span> <span class="kn">import</span> <span class="n">ON_DEMAND_HANDLER</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
<span class="c1"># always called, also for a reload</span>
<span class="bp">self</span><span class="o">.</span><span class="n">at_server_stop</span><span class="p">()</span>
@ -734,6 +738,11 @@
<span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
<span class="n">TASK_HANDLER</span><span class="o">.</span><span class="n">create_delays</span><span class="p">()</span>
<span class="c1"># start the On-demand handler</span>
<span class="kn">from</span> <span class="nn">evennia.scripts.ondemandhandler</span> <span class="kn">import</span> <span class="n">ON_DEMAND_HANDLER</span>
<span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">load</span><span class="p">()</span>
<span class="c1"># create/update channels</span>
<span class="bp">self</span><span class="o">.</span><span class="n">create_default_channels</span><span class="p">()</span>

View file

@ -103,7 +103,6 @@
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
<span class="kn">from</span> <span class="nn">evennia.locks.lockfuncs</span> <span class="kn">import</span> <span class="n">perm</span> <span class="k">as</span> <span class="n">perm_lockfunc</span>
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">make_iter</span><span class="p">,</span> <span class="n">to_str</span>
@ -295,7 +294,7 @@
<span class="sd"> ::</span>
<span class="sd"> class RogueCharacter(DefaultCharacter):</span>
<span class="sd"> guild = TagProperty(&quot;thieves_guild&quot;, &quot;merchant_guild&quot;)</span>
<span class="sd"> guild = TagCategoryProperty(&quot;thieves_guild&quot;, &quot;merchant_guild&quot;)</span>
<span class="sd"> &quot;&quot;&quot;</span>
<span class="bp">self</span><span class="o">.</span><span class="n">_category</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>

View file

@ -118,6 +118,7 @@
<span class="kn">from</span> <span class="nn">string</span> <span class="kn">import</span> <span class="n">punctuation</span>
<span class="kn">from</span> <span class="nn">unicodedata</span> <span class="kn">import</span> <span class="n">east_asian_width</span>
<span class="kn">import</span> <span class="nn">evennia</span>
<span class="kn">from</span> <span class="nn">django.apps</span> <span class="kn">import</span> <span class="n">apps</span>
<span class="kn">from</span> <span class="nn">django.conf</span> <span class="kn">import</span> <span class="n">settings</span>
<span class="kn">from</span> <span class="nn">django.core.exceptions</span> <span class="kn">import</span> <span class="n">ValidationError</span> <span class="k">as</span> <span class="n">DjangoValidationError</span>
@ -125,14 +126,12 @@
<span class="kn">from</span> <span class="nn">django.utils</span> <span class="kn">import</span> <span class="n">timezone</span>
<span class="kn">from</span> <span class="nn">django.utils.html</span> <span class="kn">import</span> <span class="n">strip_tags</span>
<span class="kn">from</span> <span class="nn">django.utils.translation</span> <span class="kn">import</span> <span class="n">gettext</span> <span class="k">as</span> <span class="n">_</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="kn">from</span> <span class="nn">simpleeval</span> <span class="kn">import</span> <span class="n">simple_eval</span>
<span class="kn">from</span> <span class="nn">twisted.internet</span> <span class="kn">import</span> <span class="n">reactor</span><span class="p">,</span> <span class="n">threads</span>
<span class="kn">from</span> <span class="nn">twisted.internet.defer</span> <span class="kn">import</span> <span class="n">returnValue</span> <span class="c1"># noqa - used as import target</span>
<span class="kn">from</span> <span class="nn">twisted.internet.task</span> <span class="kn">import</span> <span class="n">deferLater</span>
<span class="kn">import</span> <span class="nn">evennia</span>
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
<span class="n">_MULTIMATCH_TEMPLATE</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">SEARCH_MULTIMATCH_TEMPLATE</span>
<span class="n">_EVENNIA_DIR</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">EVENNIA_DIR</span>
<span class="n">_GAME_DIR</span> <span class="o">=</span> <span class="n">settings</span><span class="o">.</span><span class="n">GAME_DIR</span>

View file

@ -136,6 +136,7 @@
<li><a href="evennia/contrib/base_systems/email_login/email_login.html">evennia.contrib.base_systems.email_login.email_login</a></li>
<li><a href="evennia/contrib/base_systems/email_login/tests.html">evennia.contrib.base_systems.email_login.tests</a></li>
<li><a href="evennia/contrib/base_systems/godotwebsocket/test_text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></li>
<li><a href="evennia/contrib/base_systems/godotwebsocket/test_webclient.html">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
<li><a href="evennia/contrib/base_systems/godotwebsocket/text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></li>
<li><a href="evennia/contrib/base_systems/godotwebsocket/webclient.html">evennia.contrib.base_systems.godotwebsocket.webclient</a></li>
<li><a href="evennia/contrib/base_systems/ingame_python/callbackhandler.html">evennia.contrib.base_systems.ingame_python.callbackhandler</a></li>
@ -282,6 +283,7 @@
<li><a href="evennia/scripts/manager.html">evennia.scripts.manager</a></li>
<li><a href="evennia/scripts/models.html">evennia.scripts.models</a></li>
<li><a href="evennia/scripts/monitorhandler.html">evennia.scripts.monitorhandler</a></li>
<li><a href="evennia/scripts/ondemandhandler.html">evennia.scripts.ondemandhandler</a></li>
<li><a href="evennia/scripts/scripthandler.html">evennia.scripts.scripthandler</a></li>
<li><a href="evennia/scripts/scripts.html">evennia.scripts.scripts</a></li>
<li><a href="evennia/scripts/taskhandler.html">evennia.scripts.taskhandler</a></li>

View file

@ -1,5 +1,34 @@
# Changelog
## main branch
- [Feature] Add `evennia.ON_DEMAND_HANDLER` for making it easier to implement
timed element with the on-demand approach (Griatch)
- [Fix] Remove `AMP_ENABLED` setting since it services no real purpose and
erroring out on setting it would make it even less useful (Griatch).
- [Fix] `services` command with no args would traceback (regression) (Griatch)
- [Feature][pull3412]: Make it possible to add custom webclient css in
`webclient/css/custom.css`, same as for website (InspectorCaracal)
- Doc fixes (InspectorCaracal, Griatch)
[pull3412]: https://github.com/evennia/evennia/pull/3412
## Evennia 3.1.1
Jan 14, 2024
- [Fix][pull3398]: Fix to make e.g. `elvish"Hello"` work correctly in language rp
contrib (InspectorCaracal)
- [Fix][pull3405]: Fix/update of Godot client contrib to support Godot4 and
latest Evennia portal changes (ChrisLR)
- Updated doc on wiki install (InspectorCaracal)
- Docstring fixes (bradleymarques, Griatch)
- Doc tutorial fixes (Griatch)
[pull3398]: https://github.com/evennia/evennia/pull/3398
[pull3405]: https://github.com/evennia/evennia/pull/3405
## Evennia 3.1.0
Jan 8, 2024
@ -19,7 +48,7 @@ Jan 8, 2024
- [Fix][pull3382]: Make sure global scripts start properly on restart
(InspectorCaracal)
- [Fix][pull3394]: Fix time-of-day issue in ExpandedRoom contrib (jaborsh)
- Doc fixes (homeofpoe, gas-public-wooden-clean, InspectorCaracal)
- Doc fixes (homeofpoe, gas-public-wooden-clean, InspectorCaracal, Griatch)
[pull3373]: https://github.com/evennia/evennia/pull/3373
[pull3375]: https://github.com/evennia/evennia/pull/3375
@ -107,9 +136,9 @@ Dec 20, 2023
other objects than oneself (InspectorCaracal)
- [Fix][pull3361]: Fix of monitoring Attributes with categories (scyfris)
- Docs & docstrings: Lots of Typo and other fixes (iLPdev, InspectorCaracal, jaborsh,
HouseOfPoe etc)
HouseOfPoe, Griatch etc)
- Beginner tutorial: Cleanup and starting earlier with explaining how to add to
the default cmdsets.
the default cmdsets (Griatch).
[pull3267]: https://github.com/evennia/evennia/pull/3267
[pull3270]: https://github.com/evennia/evennia/pull/3270
@ -158,8 +187,8 @@ Sept 3, 2023
- Fix: Traceback when printing CounterTrait contrib objects. (InspectorCaracal)
- Fix: Typo in evadventure twitch combat's call of `create_combathandler`.
- Docs: Fix bug in evadventure equipmenthandler blocking creation of npcs.
in-game.
- Docs: Plenty of typo fixes (iLPDev, moldikins, others)
in-game (Griatch).
- Docs: Plenty of typo fixes (iLPDev, moldikins, Griatch), others)
## Evennia 2.2.0

View file

@ -58,6 +58,7 @@ EvMore.md
EvTable.md
FuncParser.md
MonitorHandler.md
OnDemandHandler.md
TickerHandler.md
Signals.md
```

View file

@ -0,0 +1,174 @@
# OnDemandHandler
This handler offers help for implementing on-demand state changes. On-demand means that the state won't be computed until the player _actually looks for it_. Until they do, nothing happens. This is the most compute-efficient way to handle your systems and you should consider using this style of system whenever you can.
Take for example a gardening system. A player goes to a room and plants a seed. After a certain time, that plant will then move through a set of stages; it will move from "seedling" to 'sprout' to 'flowering' and then on to 'wilting' and eventually 'dead'.
Now, you _could_ use `utils.delay` to track each phase, or use the [TickerHandler](./TickerHandler.md) to tick the flower. You could even use a [Script](./Scripts.md) on the flower.
1. The ticker/task/Script would automatically fire at regular intervals to update the plant through its stages.
2. Whenever a player comes to the room, the state is already updated on the flower, so they just read the state.
This will work fine, but if no one comes back to that room, that's a lot of updating that no one will see. While maybe not a big deal for a single player, what if you have flowers in thousands of rooms, all growing indepedently? Or some even more complex system requiring calculation on every state change. You should avoid spending computing on things that bring nothing extra to your player base.
Using the The on-demand style would instead work like this for the flower:
1. When the player plants the seed, we register a new on-demand task with the `OnDemandHandler` (described below). This registes _the current timestamp_ when the plant starts to grow.
2. When a player enters the room and/or looks at the plant, _then_ (and only then) we call the `OnDemandHandler` to see what state the flower it's in. It will then use the _current time_ to figure out how much time passed and which state the plant is thus in. Until someone looks, the plant is in its previous found state, because no-one needed to know until then. Same thing, if some other system needs to know this - they just figure out the state on the fly.
## A blooming flower using the OnDemandHandler
This handler is found as `evennia.ON_DEMAND_HANDLER`. It is meant to be integrated into your other code. Here's an example of a flower that
```python
# e.g. in mygame/typeclasses/objects.py
from evennia import ON_DEMAND_HANDLER
# ...
class Flower(Object):
def at_object_creation(self):
minute = 60
hour = minute * 60
ON_DEMAND_HANDLER.add(
self,
category="plantgrowth"
stages={
0: "seedling",
10 * minute: "sprout",
5 * hour: "flowering",
10 * hour: "wilting",
12 * hour: "dead"
})
def at_desc(self, looker):
"""
Called whenever someone looks at this object
"""
stage = ON_DEMAND_HANDLER.get_state(self, category="plantgrowth")
match stage:
case "seedling":
return "There's nothing to see. Nothing has grown yet."
case "sprout":
return "A small delicate sprout has emerged!"
case "flowering":
return f"A beautiful {self.name}!"
case "wilting":
return f"This {self.name} has seen better days."
case "dead":
# it's dead and gone. Stop and delete
ON_DEMAND_HANDLER.remove(self, category="plantgrowth")
self.delete()
```
You could now create the rose and it would figure out its state only when you are actually looking at it. It will stay a seedling for 10 minutes (of in-game real time) before it sprouts. Within 12 hours it will be dead again (a very quickly growing rose!).
If you had a `harvest` command in your game, you could equally have it check the stage of bloom and give you different results depending on if you pick the rose at the right time or not.
The on-demand handler's tasks survive a reload and will properly account for downtime.
## More usage examples
The [OnDemandHandler API](evennia.scripts.ondemandhandler.OnDemandHandler) describes how to use the handler in detail. While it's available as `evennia.ON_DEMAND_HANDLER`, its code is located in `evennia.scripts.ondemandhandler.py`.
```python
from evennia import ON_DEMAND_HANDLER
ON_DEMAND_HANDLER.add("key", category=None, stages=None)
time_passed = ON_DEMAND_HANDLER.get_dt("key", category=None)
current_state = ON_DEMAND_HANDLER.get_stage("key", category=None)
# remove things
ON_DEMAND_HANDLER.remove("key", category=None)
ON_DEMAND_HANDLER.clear(cateogory="category") #clear all with category
```
- The `key` can be a string, but also a typeclassed object (its string representation will be used, which normally includes its `#dbref`). You can also pass a `callable` - this will be called without arguments and is expected to return a string to use for the `key`. Finally, you can also pass [OnDemandTask](evennia.scripts.ondemandhandler.OnDemandTask) entities - these are the objects the handler uses under the hood to represent each task.
- The `category` allows you to further categorize your demandhandler tasks to make sure they are unique. Since the handler is global, you need to make sure `key` + `category` is unique. While `category` is optional, if you use it you must also use it to retrieve your state later.
- `stages` is a `dict` `{dt: statename}` or `{dt: (statename, callable}` that represents how much time (in seconds) before next stage begins. In the flower example above, it was 10 hours until the `wilting` state began. If a `callable` is also included, this will be called *the first time* that state is checked for. The callable takes a `evennia.OnDemandTask` as an argument and allows for tweaking the task on the fly. The `dt` can also be a `float` if you desire higher than per-second precision. Having `stages` is optional - sometimes you only want to know how much time has passed.
- `.get_dt()` - get the current time (in seconds) since the task started. This is a `float`.
- `.get_stage()` - get the current state name, such as "flowering" or "seedling". If you didn't specify any `stages`, this will return `None`, and you need to interpret the `dt` yourself to determine which state you are in.
Under the hood, the handler uses [OnDemandTask](evennia.scripts.ondemandhandler.OnDemandTask) objects. It can sometimes be practical to create tasks directly with these, and pass them to the handler in bulk:
```python
from evennia import ON_DEMAND_HANDLER, OnDemandTask
task1 = OnDemandTask("key1", {0: "state1", 100: "state2"})
task2 = OnDemandTask("key2", category)
ON_DEMAND_HANDLER.batch_add(task1, task2)
# get tasks back
task = ON_DEMAND_HANDLER.get("key1")
# batch-delete (deactivate) from handler
ON_DEMAND_HANDLER.batch_remove(task1, task2)
```
### Looping repeatedly
Normally, when a sequence of `stages` have been cycled through, the task will just
`evennia.OnDemandTask.stagefunc_loop` is an included static-method callable you can use to make the task loop. Here's an example of how to use it:
```python
from evennia import ON_DEMAND_HANDLER, OnDemandTask
ON_DEMAND_HANDLER.add(
"trap_state",
stages={
0: "harmless",
50: "solvable",
100: "primed",
200: "deadly",
250: ("_reset", OnDemandTask.stagefunc_loop)
}
)
```
This is a trap state that loops through its states depending on timing. Note that the looping helper callable will _immediately_ reset the cycle back to the first stage, so the last stage will never be visible to the player/game system. So it's a good (if optional) idea to name it with `_*` to remember this is a 'virtual' stage.
The `OnDemandTask` task instance has a `.iterations` variable that will go up by one for every loop.
If the state is not checked for a long time, the looping function will correctly update the `.iterations` of the task it would have used so far and figure out where in the cycle it is right now.
### Bouncing back and forth
`evennia.OnDemandTask.stagefunc_bounce` is an included static-method callable you can use to 'bounce' the sequence of stages. That is, it will cycle to the end of the cycle and then reverse direction and cycle through the sequence in reverse.
To make this repreat indefinitely, you need to put the callables at both ends of the list:
```python
from evennia import ON_DEMAND_HANDLER, OnDemandTask
ON_DEMAND_HANDLER.add(
"cycling reactor",
"nuclear",
stages={
0: ("cold", OnDemandTask.stagefunc_bounce),
150: "luke warm",
300: "warm",
450: "hot"
600: ("HOT!", OnDemandTask.stagefunc_bounce)
}
)
```
This will cycle
cold -> luke warm -> warm -> hot -> HOT!
before reversing and go back:
HOT! -> hot -> warm -> luke warm -> cold
Over and over. The `OnDemandTask` instance has an `.iterations` property that will step up by one every time the sequence reverses.
If the state is not checked for a long time, the bounce function will correctly update the `.iterations` property to the amount of iterations it would have done in that time, and figure out where in the cycle it must be right now.

View file

@ -31,260 +31,168 @@ the extra data given from Evennia as needed.
This section assumes you have basic knowledge on how to use Godot.
You can read the following url for more details on Godot Websockets
and to implement a minimal client.
and to implement a minimal client or look at the full example at the bottom of this page.
https://docs.godotengine.org/en/stable/tutorials/networking/websocket.html
The rest of this document will be for Godot 3, an example is left at the bottom
of this readme for Godot 4.
The rest of this document will be for Godot 4.
Note that some of the code shown here is partially taken from official Godot Documentation
A very basic setup in godot would require
- One RichTextLabel Node to display the Evennia Output, ensure bbcode is enabled on it.
- One Node for your websocket client code with a new Script attached.
- One TextEdit Node to enter commands
- One Button Node to press and send the commands
- Controls for the layout, in this example I have used
Panel
VBoxContainer
RichTextLabel
HBoxContainer
TextEdit
Button
I will not go over how layout works but the documentation for them is easily accessible in the godot docs.
At the top of the file you must change the url to point at your mud.
Open up the script for your client code.
We need to define the url leading to your mud, use the same values you have used in your Evennia Settings.
Next we write some basic code to get a connection going.
This will connect when the Scene is ready, poll and print the data when we receive it and close when the scene exits.
```
extends Node
# The URL we will connect to
export var websocket_url = "ws://localhost:4008"
# The URL we will connect to.
var websocket_url = "ws://localhost:4008"
var socket := WebSocketPeer.new()
```
You must also remove the protocol from the `connect_to_url` call made
within the `_ready` function.
```
func _ready():
# ...
# Change the following line from this
var err = _client.connect_to_url(websocket_url, ["lws-mirror-protocol"])
# To this
var err = _client.connect_to_url(websocket_url)
# ...
if socket.connect_to_url(websocket_url) != OK:
print("Unable to connect.")
set_process(false)
func _process(_delta):
socket.poll()
match socket.get_ready_state():
WebSocketPeer.STATE_OPEN:
while socket.get_available_packet_count():
print(socket.get_packet().get_string_from_ascii())
WebSocketPeer.STATE_CLOSED:
var code = socket.get_close_code()
var reason = socket.get_close_reason()
print("WebSocket closed with code: %d, reason %s. Clean: %s" % [code, reason, code != -1])
set_process(false)
func _exit_tree():
socket.close()
```
This will allow you to connect to your mud.
At this point, you can start your evennia server, run godot and it should print a default reply.
After that you need to properly handle the data sent by evennia.
To do this, you should replace your `_on_data` method.
You will need to parse the JSON received to properly act on the data.
To do this, we will add a new function to dispatch the messages properly.
Here is an example
```
func _on_data():
# The following two lines will get us the data from Evennia.
var data = _client.get_peer(1).get_packet().get_string_from_utf8()
var json_data = JSON.parse(data).result
# The json_data is an array
func _handle_data(data):
print(data) # Print for debugging
var data_array = JSON.parse_string(data)
# The first element can be used to see if its text
if data_array[0] == 'text':
# The second element contains the messages
for msg in data_array[1]: write_to_rtb(msg)
# The first element informs us this is simple text
# so we add it to the RichTextlabel
if json_data[0] == 'text':
for msg in json_data[1]: label.append_bbcode(msg)
# Always useful to print the data and see what we got.
print(data)
func write_to_rtb(msg):
output_label.append_text(msg)
```
The first element is the type, it will be `text` if it is a message
It can be anything you would provide to the Evennia `msg` function.
The second element will be the data related to the type of message, in this case it is a list of text to display.
Since it is parsed BBCode, we can add that directly to a RichTextLabel by calling its append_bbcode method.
Since it is parsed BBCode, we can add that directly to a RichTextLabel by calling its append_text method.
If you want anything better than fancy text in Godot, you will have
to leverage Evennia's OOB to send extra data.
You can [read more on OOB here](https://www.evennia.com/docs/latest/OOB.html#oob).
In this example, we send coordinates whenever we message our character.
Evennia
```python
caller.msg(coordinates=(9, 2))
Now to send data, we connect the Button pressed Signal to a method,
read the label input and send it via the websocket, then clear the label.
```
func _on_button_pressed():
var msg = text_edit.text
var msg_arr = ['text', [msg], {}]
var msg_str = JSON.stringify(msg_arr)
socket.send_text(msg_str)
text_edit.text = ""
```
Godot
```
func _on_data():
...
if json_data[0] == 'text':
for msg in json_data[1]: label.append_bbcode(msg)
# Notice the first element is the name of the kwarg we used from evennia.
elif json_data[0] == 'coordinates':
var coords_data = json_data[2]
player.set_pos(coords_data)
...
```
A good idea would be to set up Godot Signals you can trigger based on the data
you receive, so you can manage the code better.
## Known Issues
- Sending SaverDicts and similar objects straight from Evennia .DB will cause issues,
cast them to dict() or list() before doing so.
- Background colors are only supported by Godot 4.
## Godot 3 Example
This is an example of a Script to use in Godot 3.
The script can be attached to the root UI node.
## Full Example Script
```
extends Node
# The URL to connect to, should be your mud.
export var websocket_url = "ws://127.0.0.1:4008"
# The URL we will connect to.
var websocket_url = "ws://localhost:4008"
var socket := WebSocketPeer.new()
# These are references to controls in the scene
onready var parent = get_parent()
onready var label = parent.get_node("%ChatLog")
onready var txtEdit = parent.get_node("%ChatInput")
@onready var output_label = $"../Panel/VBoxContainer/RichTextLabel"
@onready var text_edit = $"../Panel/VBoxContainer/HBoxContainer/TextEdit"
onready var room = get_node("/root/World/Room")
# Our WebSocketClient instance
var _client = WebSocketClient.new()
var is_connected = false
func _ready():
# Connect base signals to get notified of connection open, close, errors and messages
_client.connect("connection_closed", self, "_closed")
_client.connect("connection_error", self, "_closed")
_client.connect("connection_established", self, "_connected")
_client.connect("data_received", self, "_on_data")
print('Ready')
# Initiate connection to the given URL.
var err = _client.connect_to_url(websocket_url)
if err != OK:
print("Unable to connect")
if socket.connect_to_url(websocket_url) != OK:
print("Unable to connect.")
set_process(false)
func _closed(was_clean = false):
# was_clean will tell you if the disconnection was correctly notified
# by the remote peer before closing the socket.
print("Closed, clean: ", was_clean)
set_process(false)
func _process(_delta):
socket.poll()
match socket.get_ready_state():
WebSocketPeer.STATE_OPEN:
while socket.get_available_packet_count():
var data = socket.get_packet().get_string_from_ascii()
_handle_data(data)
WebSocketPeer.STATE_CLOSED:
var code = socket.get_close_code()
var reason = socket.get_close_reason()
print("WebSocket closed with code: %d, reason %s. Clean: %s" % [code, reason, code != -1])
set_process(false)
func _connected(proto = ""):
is_connected = true
print("Connected with protocol: ", proto)
func _handle_data(data):
print(data) # Print for debugging
var data_array = JSON.parse_string(data)
# The first element can be used to see if its text
if data_array[0] == 'text':
# The second element contains the messages
for msg in data_array[1]: write_to_rtb(msg)
func _on_data():
# This is called when Godot receives data from evennia
var data = _client.get_peer(1).get_packet().get_string_from_utf8()
var json_data = JSON.parse(data).result
# Here we have the data from Evennia which is an array.
# The first element will be text if it is a message
# and would be the key of the OOB data you passed otherwise.
if json_data[0] == 'text':
# In this case, we simply append the data as bbcode to our label.
for msg in json_data[1]: label.append_bbcode(msg)
elif json_data[0] == 'coordinates':
# Dummy signal emitted if we wanted to handle the new coordinates
# elsewhere in the project.
self.emit_signal('updated_coordinates', json_data[1])
# We only print this for easier debugging.
print(data)
func _process(delta):
# Required for websocket to properly react
_client.poll()
func _on_button_send():
# This is called when we press the button in the scene
# with a connected signal, it sends the written message to Evennia.
var msg = txtEdit.text
var msg_arr = ['text', [msg], {}]
var msg_str = JSON.print(msg_arr)
_client.get_peer(1).put_packet(msg_str.to_utf8())
func _notification(what):
# This is a special method that allows us to notify Evennia we are closing.
if what == MainLoop.NOTIFICATION_WM_QUIT_REQUEST:
if is_connected:
var msg_arr = ['text', ['quit'], {}]
var msg_str = JSON.print(msg_arr)
_client.get_peer(1).put_packet(msg_str.to_utf8())
get_tree().quit() # default behavior
```
## Godot 4 Example
This is an example of a Script to use in Godot 4.
Note that the version is not final so the code may break.
It requires a WebSocketClientNode as a child of the root node.
The script can be attached to the root UI node.
```
extends Control
# The URL to connect to, should be your mud.
var websocket_url = "ws://127.0.0.1:4008"
# These are references to controls in the scene
@onready
var label: RichTextLabel = get_node("%ChatLog")
@onready
var txtEdit: TextEdit = get_node("%ChatInput")
@onready
var websocket = get_node("WebSocketClient")
func _ready():
# We connect the various signals
websocket.connect('connected_to_server', self._connected)
websocket.connect('connection_closed', self._closed)
websocket.connect('message_received', self._on_data)
# We attempt to connect and print out the error if we have one.
var result = websocket.connect_to_url(websocket_url)
if result != OK:
print('Could not connect:' + str(result))
func _closed():
# This emits if the connection was closed by the remote host or unexpectedly
print('Connection closed.')
set_process(false)
func _connected():
# This emits when the connection succeeds.
print('Connected!')
func _on_data(data):
# This is called when Godot receives data from evennia
var json_data = JSON.parse_string(data)
# Here we have the data from Evennia which is an array.
# The first element will be text if it is a message
# and would be the key of the OOB data you passed otherwise.
if json_data[0] == 'text':
# In this case, we simply append the data as bbcode to our label.
for msg in json_data[1]: # Here we include a newline at every message.
label.append_text("\n" + msg)
elif json_data[0] == 'coordinates':
# Dummy signal emitted if we wanted to handle the new coordinates
# elsewhere in the project.
self.emit_signal('updated_coordinates', json_data[1])
# We only print this for easier debugging.
print(data)
func write_to_rtb(msg):
output_label.append_text(msg)
func _on_button_pressed():
# This is called when we press the button in the scene
# with a connected signal, it sends the written message to Evennia.
var msg = txtEdit.text
var msg = text_edit.text
var msg_arr = ['text', [msg], {}]
var msg_str = JSON.stringify(msg_arr)
websocket.send(msg_str)
socket.send_text(msg_str)
text_edit.text = ""
func _exit_tree():
socket.close()
```
----
<small>This document page is generated from `evennia/contrib/base_systems/godotwebsocket/README.md`. Changes to this

View file

@ -82,7 +82,9 @@ Example for your character:
> type/reset/force me = typeclasses.characters.Character
Examples:
### Usage
#### Sdescs
> look
@ -105,6 +107,14 @@ Tall man (assuming his name is Tom) sees:
Note that by default, the case of the tag matters, so `/tall` will lead to 'tall man' while `/Tall` will become 'Tall man' and /TALL becomes /TALL MAN. If you don't want this behavior, you can pass case_sensitive=False to the `send_emote` function.
#### Language integration
Speech can be identified as a particular language by prefixing it with the language key.
emote says with a growl, orcish"Hello".
This will identify the speech "Hello" as being spoken in orcish, and then pass that information on to `process_language` on your Character. By default, it doesn't do much, but you can hook in a language system such as the `rplanguage` module below to do more interesting things.
## Language and whisper obfuscation system

View file

@ -171,7 +171,32 @@ if trait1 > trait2:
```
## Static trait
### Trait
A single value of any type.
This is the 'base' Trait, meant to inherit from if you want to invent
trait-types from scratch (most of the time you'll probably inherit from some of
the more advanced trait-type classes though).
Unlike other Trait-types, the single `.value` property of the base `Trait` can
be editied. The value can hold any data that can be stored in an Attribute. If
it's an integer/float you can do arithmetic with it, but otherwise this acts just
like a glorified Attribute.
```python
> obj.traits.add("mytrait", "My Trait", trait_type="trait", value=30)
> obj.traits.mytrait.value
30
> obj.traits.mytrait.value = "stringvalue"
> obj.traits.mytrait.value
"stringvalue"
```
### Static trait
`value = base + mod`
@ -365,31 +390,6 @@ get how filled it is as a percentage etc.
The `.rate` is particularly relevant for gauges - useful for everything
from poison slowly draining your health, to resting gradually increasing it.
### Trait
A single value of any type.
This is the 'base' Trait, meant to inherit from if you want to invent
trait-types from scratch (most of the time you'll probably inherit from some of
the more advanced trait-type classes though).
Unlike other Trait-types, the single `.value` property of the base `Trait` can
be editied. The value can hold any data that can be stored in an Attribute. If
it's an integer/float you can do arithmetic with it, but otherwise this acts just
like a glorified Attribute.
```python
> obj.traits.add("mytrait", "My Trait", trait_type="trait", value=30)
> obj.traits.mytrait.value
30
> obj.traits.mytrait.value = "stringvalue"
> obj.traits.mytrait.value
"stringvalue"
```
## Expanding with your own Traits
A Trait is a class inhering from `evennia.contrib.rpg.traits.Trait` (or from one of

View file

@ -8,9 +8,7 @@ what is in it.
```{sidebar} Commands are not typeclassed
If you just came from the previous lesson, you might want to know that Commands and
CommandSets are not `typeclassed`. That is, instances of them are not saved to the
database. They are "just" normal Python classes.
If you just came from the previous lesson, you might want to know that Commands and CommandSets are not `typeclassed`. That is, instances of them are not saved to the database. They are "just" normal Python classes.
```
In Evennia, a Command is a Python _class_. If you are unsure about what a class is, review the
@ -214,8 +212,7 @@ You will get the docstring you put in your Command-class!
### Making our cmdset persistent
It's getting a little annoying to have to re-add our cmdset every time we reload, right? It's simple
enough to make `echo` a _persistent_ change though:
It's getting a little annoying to have to re-add our cmdset every time we reload, right? It's simple enough to make `echo` a _persistent_ change though:
> py self.cmdset.add("commands.mycommands.MyCmdSet", persistent=True)
@ -335,10 +332,7 @@ A lot of things to dissect here:
- **Line 3**: The normal `class` header. We inherit from `Command` which we imported at the top of this file.
- **Lines 4-10**: The docstring and help-entry for the command. You could expand on this as much as you wanted.
- **Line 11**: We want to write `hit` to use this command.
- **Line 14**: We strip the whitespace from the argument like before. Since we don't want to have to do
`self.args.strip()` over and over, we store the stripped version
in a _local variable_ `args`. Note that we don't modify `self.args` by doing this, `self.args` will still
have the whitespace and is not the same as `args` in this example.
- **Line 14**: We strip the whitespace from the argument like before. Since we don't want to have to do `self.args.strip()` over and over, we store the stripped version in a _local variable_ `args`. Note that we don't modify `self.args` by doing this, `self.args` will still have the whitespace and is not the same as `args` in this example.
```{sidebar} if-statements

View file

@ -63,8 +63,7 @@ class Object(ObjectParent, DefaultObject):
pass
```
So we have a class `Object` that _inherits_ from `ObjectParent` (which is empty) and `DefaultObject`, which we have imported from Evennia. The `ObjectParent` acts as a place to put code you want all
of your `Objects` to have. We'll focus on `Object` and `DefaultObject` for now.
So we have a class `Object` that _inherits_ from `ObjectParent` (which is empty) and `DefaultObject`, which we have imported from Evennia. The `ObjectParent` acts as a place to put code you want all of your `Objects` to have. We'll focus on `Object` and `DefaultObject` for now.
The class itself doesn't do anything (it just `pass`es) but that doesn't mean it's useless. As we've seen, it inherits all the functionality of its parent. It's in fact an _exact replica_ of `DefaultObject` right now. Once we know what kind of methods and resources are available on `DefaultObject` we could add our own and change the way it works!
@ -138,24 +137,19 @@ You should now see that Smaug _is in the room with you_. Woah!
_He's still there_... What we just did was to create a new entry in the database for Smaug. We gave the object its name (key) and set its location to our current location.
To make use of Smaug in code we must first find him in the database. For an object in the current
location we can easily do this in `py` by using `me.search()`:
To make use of Smaug in code we must first find him in the database. For an object in the current location we can easily do this in `py` by using `me.search()`:
> py smaug = me.search("Smaug") ; smaug.firebreath()
Smaug breathes fire!
### Creating using create_object
Creating Smaug like we did above is nice because it's similar to how we created non-database
bound Python instances before. But you need to use `db_key` instead of `key` and you also have to
remember to call `.save()` afterwards. Evennia has a helper function that is more common to use,
called `create_object`. Let's recreate Cuddly this time:
Creating Smaug like we did above is nice because it's similar to how we created non-database bound Python instances before. But you need to use `db_key` instead of `key` and you also have to remember to call `.save()` afterwards. Evennia has a helper function that is more common to use, called `create_object`. Let's recreate Cuddly this time:
> py evennia.create_object('typeclasses.monsters.Monster', key="Cuddly", location=here)
> look
Boom, Cuddly should now be in the room with you, a little less scary than Smaug. You specify the
python-path to the code you want and then set the key and location (if you had the `Monster` class already imported, you could have passed that too). Evennia sets things up and saves for you.
Boom, Cuddly should now be in the room with you, a little less scary than Smaug. You specify the python-path to the code you want and then set the key and location (if you had the `Monster` class already imported, you could have passed that too). Evennia sets things up and saves for you.
If you want to find Cuddly from anywhere (not just in the same room), you can use Evennia's `search_object` function:
@ -194,8 +188,7 @@ The number of typeclasses in Evennia are so few they can be learned by heart:
| `evennia.DefaultChannel` | `typeclasses.channels.Channel` | In-game comms |
| `evennia.DefaultScript` | `typeclasses.scripts.Script` | Entities with no location |
The child classes under `mygame/typeclasses/` are meant for you to conveniently modify and
work with. Every class inheriting (at any distance) from a Evennia base typeclass is also considered a typeclass.
The child classes under `mygame/typeclasses/` are meant for you to conveniently modify and work with. Every class inheriting (at any distance) from a Evennia base typeclass is also considered a typeclass.
```
from somewhere import Something
@ -248,8 +241,7 @@ You are specifying exactly which typeclass you want to use to build the Giantess
desc = You see nothing special.
-------------------------------------------------------------------------------
We used the `examine` command briefly in the [lesson about building in-game](./Beginner-Tutorial-Building-Quickstart.md). Now these lines
may be more useful to us:
We used the `examine` command briefly in the [lesson about building in-game](./Beginner-Tutorial-Building-Quickstart.md). Now these lines may be more useful to us:
- **Name/key** - The name of this thing. The value `(#14)` is probably different for you. This is the
unique 'primary key' or _dbref_ for this entity in the database.
- **Typeclass**: This show the typeclass we specified, and the path to it.
@ -290,8 +282,7 @@ But the reason Evennia knows to fall back to this class is not hard-coded - it's
While it's tempting to change folders around to your liking, this can make it harder to follow tutorials and may confuse if you are asking others for help. So don't overdo it unless you really know what you are doing.
```
So if you wanted the creation commands and methods to default to some other class you could
add your own `BASE_OBJECT_TYPECLASS` line to `mygame/server/conf/settings.py`. The same is true for all the other typeclasseses, like characters, rooms and accounts. This way you can change the layout of your game dir considerably if you wanted. You just need to tell Evennia where everything is.
So if you wanted the creation commands and methods to default to some other class you could add your own `BASE_OBJECT_TYPECLASS` line to `mygame/server/conf/settings.py`. The same is true for all the other typeclasseses, like characters, rooms and accounts. This way you can change the layout of your game dir considerably if you wanted. You just need to tell Evennia where everything is.
## Modifying ourselves
@ -302,15 +293,16 @@ Let's try to modify ourselves a little. Open up `mygame/typeclasses/characters.p
(module docstring)
"""
from evennia import DefaultCharacter
from .objects import ObjectParent
class Character(DefaultCharacter):
class Character(ObjectParent, DefaultCharacter):
"""
(class docstring)
"""
pass
```
This looks quite familiar now - an empty class inheriting from the Evennia base typeclass (it's even easier than `Object` since there is no equvalent `ParentObject` mixin class here). As you would expect, this is also the default typeclass used for creating Characters if you don't specify it. You can verify it:
This looks quite familiar now - an empty class inheriting from the Evennia base typeclassObjectParent. The `ObjectParent` (empty by default) is also here for adding any functionality shared by all types of Objects. As you would expect, this is also the default typeclass used for creating Characters if you don't specify it. You can verify it:
> examine me
@ -343,8 +335,7 @@ Yes, the `examine` command understands `me`. You got a lot longer output this ti
- **Session id(s)**: This identifies the _Session_ (that is, the individual connection to a player's game client).
- **Account** shows, well the `Account` object associated with this Character and Session.
- **Stored/Merged Cmdsets** and **Commands available** is related to which _Commands_ are stored on you. We will get to them in the [next lesson](./Beginner-Tutorial-Adding-Commands.md). For now it's enough to know these consitute all the
commands available to you at a given moment.
- **Stored/Merged Cmdsets** and **Commands available** is related to which _Commands_ are stored on you. We will get to them in the [next lesson](./Beginner-Tutorial-Adding-Commands.md). For now it's enough to know these consitute all the commands available to you at a given moment.
- **Non-Persistent attributes** are Attributes that are only stored temporarily and will go away on next reload.
Look at the **Typeclass** field and you'll find that it points to `typeclasses.character.Character` as expected. So if we modify this class we'll also modify ourselves.
@ -354,8 +345,11 @@ Look at the **Typeclass** field and you'll find that it points to `typeclasses.c
Let's try something simple first. Back in `mygame/typeclasses/characters.py`:
```python
# in mygame/typeclasses/characters.py
class Character(DefaultCharacter):
# ...
class Character(ObjectParent, DefaultCharacter):
"""
(class docstring)
"""
@ -415,8 +409,11 @@ In principle we could change the python code. But we don't want to do that manua
Evennia offers a special, persistent type of property for this, called an `Attribute`. Rework your `mygame/typeclasses/characters.py` like this:
```python
# in mygame/typeclasses/characters.py
class Character(DefaultCharacter):
# ...
class Character(ObjectParent, DefaultCharacter):
"""
(class docstring)
"""
@ -477,10 +474,12 @@ We want those stats to be set only once, when the object is first created. For t
```python
# up by the other imports
# in mygame/typeclasses/characters.py
# ...
import random
class Character(DefaultCharacter):
class Character(ObjectParent, DefaultCharacter):
"""
(class docstring)
"""
@ -497,8 +496,7 @@ class Character(DefaultCharacter):
return self.db.strength, self.db.dexterity, self.db.intelligence
```
We imported a new module, `random`. This is part of Python's standard library. We used `random.randint` to
set a random value from 3 to 18 to each stat. Simple, but for some classical RPGs this is all you need!
We imported a new module, `random`. This is part of Python's standard library. We used `random.randint` to set a random value from 3 to 18 to each stat. Simple, but for some classical RPGs this is all you need!
> reload
> py self.get_stats()
@ -517,8 +515,7 @@ It's simple enough to run it manually though:
> py self.get_stats()
(5, 4, 8)
Lady luck didn't smile on us for this example; maybe you'll fare better. Evennia has a helper command
`update` that re-runs the creation hook and also cleans up any other Attributes not re-created by `at_object_creation`:
Lady luck didn't smile on us for this example; maybe you'll fare better. Evennia has a helper command `update` that re-runs the creation hook and also cleans up any other Attributes not re-created by `at_object_creation`:
> update self
> py self.get_stats()
@ -554,9 +551,7 @@ For our list, we want to loop over all Characters, and want to call `.at_object_
`Character.objects.all()` is an example of a database query expressed in Python. This will be converted into a database query under the hood. This syntax is part of [Django's query language](https://docs.djangoproject.com/en/4.1/topics/db/queries/). You don't need to know Django to use Evennia, but if you ever need more specific database queries, this is always available when you need it. We'll get back to database queries in a later lesson.
```
We import the `Character` class and then we use `.objects.all()` to get all `Character` instances. Simplified,
`.objects` is a resource from which one can _query_ for all `Characters`. Using `.all()` gets us a listing
of all of them that we then immediately loop over. Boom, we just updated all Characters, including ourselves:
We import the `Character` class and then we use `.objects.all()` to get all `Character` instances. Simplified, `.objects` is a resource from which one can _query_ for all `Characters`. Using `.all()` gets us a listing of all of them that we then immediately loop over. Boom, we just updated all Characters, including ourselves:
> quit()
Closing the Python console.
@ -565,8 +560,7 @@ of all of them that we then immediately loop over. Boom, we just updated all Cha
## Extra Credits
This principle is the same for other typeclasses. So using the tools explored in this lesson, try to expand the default room with an `is_dark` flag. It can be either `True` or `False`. Have all new rooms start with `is_dark = False` and make it so that once you change it, it survives a reload.
Oh, and if you created any other rooms before, make sure they get the new flag too!
This principle is the same for other typeclasses. So using the tools explored in this lesson, try to expand the default room with an `is_dark` flag. It can be either `True` or `False`. Have all new rooms start with `is_dark = False` and make it so that once you change it, it survives a reload. Oh, and if you created any other rooms before, make sure they get the new flag too!
## Conclusions

View file

@ -127,8 +127,8 @@ We let the typeclass handle the logic, and also let it do all the return messagi
It's fine to sit 'on' a chair. But what if our Sittable is an armchair?
```
> py armchair = evennia.create_object("typeclasses.sittables.Sittable", key="armchair", location=here)
> py armchair.do_sit(me)
> py evennia.create_object("typeclasses.sittables.Sittable", key="armchair", location=here)
> py self.search("armchair").do_sit(me)
You sit on armchair.
```
@ -197,7 +197,7 @@ class Sittable(Object):
Since we haven't added the `sit` command yet, we must still use `py` to test:
```
> py armchair = evennia.search_object("armchair")[0];armchair.do_sit(me)
> py self.search("armchair").do_sit(me)
You sit in armchair.
```
@ -210,8 +210,8 @@ What if we want some more dramatic flair when you sit down in certain chairs?
You can make this happen by tweaking your `Sittable` class having the return messages be replaceable by `Attributes` that you can set on the object you create. You want something like this:
```
> py
> chair = evennia.create_object("typeclasses.sittables.Sittable", key="pallet")
> py
> chair = evennia.create_object("typeclasses.sittables.Sittable", key="pallet", location=here)
> chair.do_sit(me)
You sit down on pallet.
> chair.do_stand(me)
@ -221,7 +221,8 @@ You stand up from pallet.
You sit down and a whoopie cushion makes a loud fart noise!
```
That is, if you are not setting the Attribute, you should get a default value. We leave this implementation up to the reader.
That is, if you are not setting the Attribute, you should get a default value.
We leave this implementation up to the reader.
## Adding commands
@ -603,14 +604,13 @@ class CmdStand2(Command):
key = "stand"
def func(self):
caller = self.caller
# if we are sitting, this should be set on us
sittable = caller.db.is_sitting
if not sittable:
caller.msg("You are not sitting down.")
else:
sittable.do_stand(caller)
caller = self.caller
# if we are sitting, this should be set on us
sittable = caller.db.is_sitting
if not sittable:
caller.msg("You are not sitting down.")
else:
sittable.do_stand(caller)
```

View file

@ -5,8 +5,7 @@ also learn how to add, modify and extend Evennia's default commands.
## More advanced parsing
In the [last lesson](./Beginner-Tutorial-Adding-Commands.md) we made a `hit` Command and struck a dragon with it. You should have the code
from that still around.
In the [last lesson](./Beginner-Tutorial-Adding-Commands.md) we made a `hit` Command and struck a dragon with it. You should have the code from that still around.
Let's expand our simple `hit` command to accept a little more complex input:
@ -113,6 +112,7 @@ Here we create the messages to send to each side of the fight explicitly. Later
- **Lines 34-39** - Since the weapon is optional, we need to supply a default (use our fists!) if it's not set. We
use this to create a `weaponstr` that is different depending on if we have a weapon or not.
- **Lines 41-42** - We merge the `weaponstr` with our attack texts and send it to attacker and target respectively.
Let's try it out!
> reload
@ -126,9 +126,7 @@ This won't do. Let's make ourselves a sword:
> create sword
Since we didn't specify `/drop`, the sword will end up in our inventory and can seen with the `i` or
`inventory` command. The `.search` helper will still find it there. There is no need to reload to see this
change (no code changed, only stuff in the database).
Since we didn't specify `/drop`, the sword will end up in our inventory and can seen with the `i` or `inventory` command. The `.search` helper will still find it there. There is no need to reload to see this change (no code changed, only stuff in the database).
> hit smaug with sword
You hit smaug with sword!
@ -170,9 +168,27 @@ Woah, that didn't go as planned. Evennia actually found _two_ `hit` commands and
> hit-2
Who do you want to hit?
In this case we don't need both command-sets, so let's just keep the one on the sword:
In this case we don't need both command-sets, we should drop the version of `hit` sitting on our ourselves.
Go to `mygame/commands/default_cmdsets.py` and find the line where you added
`MyCmdSet` in the previous lesson. Delete or comment it out:
```python
# mygame/commands/default_cmdsets.py
# ...
class CharacterCmdSet(default_cmds.CharacterCmdSet):
# ...
def at_object_creation(self):
# self.add(MyCmdSet) # <---------
```
Next `reload` and you'll only have one `hit` command available:
> py self.cmdset.remove("commands.mycommands.MyCmdSet")
> hit
Who do you want to hit?
@ -219,8 +235,8 @@ If the sword lies on the ground, try
> get sword
> hit
> Who do you want to hit?
Finally, we get rid of ours sword so we have a clean slate with no more `hit` commands floating around. We can do that in two ways:
After we've waved the sword around (hit a dragon or two), we will get rid of ours sword so we have a clean slate with no more `hit` commands floating around. We can do that in two ways:
delete sword
@ -293,6 +309,7 @@ class SessionCmdSet(default_cmds.SessionCmdSet):
The `super()` function refers to the parent of the current class and is commonly used to call same-named methods on the parent.
```
`evennia.default_cmds` is a container that holds all of Evennia's default commands and cmdsets. In this module we can see that this was imported and then a new child class was made for each cmdset. Each class looks familiar (except the `key`, that's mainly used to easily identify the cmdset in listings). In each `at_cmdset_creation` all we do is call `super().at_cmdset_creation` which means that we call `at_cmdset_creation() on the _parent_ CmdSet.
This is what adds all the default commands to each CmdSet.
When the `DefaultCharacter` (or a child of it) is created, you'll find that the equivalence of `self.cmdset.add("default_cmdsets.CharacterCmdSet, persistent=True")` gets called. This means that all new Characters get this cmdset. After adding more commands to it, you just need to reload to have all characters see it.

View file

@ -2,58 +2,32 @@
We have gone through how to create the various entities in Evennia. But creating something is of little use if we cannot find and use it afterwards.
## Main search functions
The base tools are the `evennia.search_*` functions, such as `evennia.search_object`.
```python
import evennia
roses = evennia.search_object("rose")
accts = evennia.search_account("MyAccountName", email="foo@bar.com")
```{sidebar} Python code vs using the py command
Most of these tools are intended to be used in Python code, as you create your game. We
give examples of how to test things out from the `py` command, but that's just for experimenting and normally not how you code your game.
```
```{sidebar} Querysets
What is returned from the main search functions is actually a `queryset`. They can be treated like lists except that they can't modified in-place. We'll discuss querysets in the `next lesson` <Django-queries>`_.
```
This searches by `key` of the object. Strings are always case-insensitive, so searching for `"rose"`, `"Rose"` or `"rOsE"` give the same results. It's important to remember that what is returned from these search methods is a _listing_ of zero, one or more elements - all the matches to your search. To get the first match:
rose = roses[0]
Often you really want all matches to the search parameters you specify. In other situations, having zero or more than one match is a sign of a problem and you need to handle this case yourself.
```python
the_one_ring = evennia.search_object("The one Ring")
if not the_one_ring:
# handle not finding the ring at all
elif len(the_one_ring) > 1:
# handle finding more than one ring
else:
# ok - exactly one ring found
the_one_ring = the_one_ring[0]
```
There are equivalent search functions for all the main resources. You can find a listing of them
[in the Search functions section](../../../Evennia-API.md) of the API frontpage.
To test out the examples in this tutorial, let's create a few objects we can search for in the current location.
> create/drop Rose
## Searching using Object.search
On the `DefaultObject` is a `.search` method which we have already tried out when we made Commands. For this to be used you must already have an object available:
On the `DefaultObject` is a `.search` method which we have already tried out when we made Commands. For this to be used you must already have an object available, and if you are using `py` you can use yourself:
obj = evennia.search_object("My Object")[0] # assuming this exists
rose = obj.search("rose")
This searches for objects based on `key` or aliases. The `.search` method wraps `evennia.search_object` and handles its output in various ways.
py self.search("rose")
Rose
- This searches by `key` or `alias` of the object. Strings are always case-insensitive, so searching for `"rose"`, `"Rose"` or `"rOsE"` give the same results.
- By default it will always search for objects among those in `obj.location.contents` and `obj.contents` (that is, things in obj's inventory or in the same room).
- It will always return exactly one match. If it found zero or more than one match, the return is `None`. This is different from `evennia.search`, which always returns a list.
- It will always return exactly one match. If it found zero or more than one match, the return is `None`. This is different from `evennia.search` (see below), which always returns a list.
- On a no-match or multimatch, `.search` will automatically send an error message to `obj`. So you don't have to worry about reporting messages if the result is `None`.
So this method handles error messaging for you. A very common way to use it is in commands:
In other words, this method handles error messaging for you. A very common way to use it is in commands:
```python
# in for example mygame/commands/command.py
from evennia import Command
class CmdQuickFind(Command):
@ -75,6 +49,24 @@ class CmdQuickFind(Command):
self.caller.msg(f"Found match for {query}: {result}")
```
If you want to test this command out, add it to the default cmdset (see [the Command tutorial](./Beginner-Tutorial-Adding-Commands.md) for more details) and then reload the server with `reload`:
```python
# in mygame/commands/default_cmdsets.py
# ...
from commands.command import CmdQuickFind # <-------
class CharacterCmdSet(default_cmds.CharacterCmdSet):
# ...
def at_cmdset_creation(self):
# ...
self.add(CmdQuickFind()) # <------
```
Remember, `self.caller` is the one calling the command. This is usually a Character, which
inherits from `DefaultObject`. So it has `.search()` available on it.
@ -82,25 +74,80 @@ This simple little Command takes its arguments and searches for a match. If it c
With the `global_search` flag, you can use `.search` to find anything, not just stuff in the same room:
volcano = self.caller.search("Vesuvio", global_search=True)
```python
volcano = self.caller.search("Vesuvio", global_search=True)
```
You can limit your matches to particular typeclasses:
water_glass = self.caller.search("glass", typeclass="typeclasses.objects.WaterGlass")
```python
water_glass = self.caller.search("glass", typeclass="typeclasses.objects.WaterGlass")
```
If you only want to search for a specific list of things, you can do so too:
stone = self.caller.search("MyStone", candidates=[obj1, obj2, obj3, obj4])
```python
stone = self.caller.search("MyStone", candidates=[obj1, obj2, obj3, obj4])
```
This will only return a match if "MyStone" is in the room (or in your inventory) _and_ is one of the four provided candidate objects. This is quite powerful, here's how you'd find something only in your inventory:
potion = self.caller.search("Healing potion", candidates=self.caller.contents)
```python
potion = self.caller.search("Healing potion", candidates=self.caller.contents)
```
You can also turn off the automatic error handling:
swords = self.caller.search("Sword", quiet=True)
```python
swords = self.caller.search("Sword", quiet=True) # returns a list!
```
With `quiet=True` the user will not be notified on zero or multi-match errors. Instead you are expected to handle this yourself. Furthermore, what is returned is now a list of zero, one or more matches!
## Main search functions
The base search tools of Evennia are the `evennia.search_*` functions, such as `evennia.search_object`. These are normally used in your code, but you can also try them out in-game using `py`:
> py evennia.search_object("rose")
<Queryset [Rose]>
```{sidebar} Querysets
What is returned from the main search functions is actually a `queryset`. They can be treated like lists except that they can't modified in-place. We'll discuss querysets in the [next lesson](./Beginner-Tutorial-Django-queries.md)
```
This searches for objects based on `key` or `alias`. The `.search` method we talked about in the previous section in fact wraps `evennia.search_object` and handles its output in various ways. Here's the same example in Python code, for example as part of a command or coded system:
```python
import evennia
roses = evennia.search_object("rose")
accts = evennia.search_account("YourName")
```
Above we find first the rose and then an Account. You can try both using `py`:
> py evennia.search_object("rose")[0]
Rose
> py evennia.search_account("YourName")[0]
<Player: YourName>
In the example above we used `[0]` to only get the first match of the queryset, which in this case gives us the rose and your Account respectively. Note that if you don't find any matches, using `[0]` like this leads to an error, so it's mostly useful for debugging.
If you you really want all matches to the search parameters you specify. In other situations, having zero or more than one match is a sign of a problem and you need to handle this case yourself. This is too detailed for testing out just with `py`, but good to know if you want to make your own search methods:
```python
the_one_ring = evennia.search_object("The one Ring")
if not the_one_ring:
# handle not finding the ring at all
elif len(the_one_ring) > 1:
# handle finding more than one ring
else:
# ok - exactly one ring found
the_one_ring = the_one_ring[0]
```
There are equivalent search functions for all the main resources. You can find a listing of them [in the Search functions section](../../../Evennia-API.md) of the API front page.
## What can be searched for
@ -123,50 +170,87 @@ The `key` is the name of the entity. Searching for this is always case-insensiti
### Search by aliases
Objects and Accounts can have any number of aliases. When searching for `key` these will searched too, you can't easily search only for aliases.
Objects and Accounts can have any number of aliases. When searching for `key` these will searched too, you can't easily search only for aliases. Let's add an alias to our rose with the default `alias` command:
rose.aliases.add("flower")
> alias rose = flower
If the above `rose` has a `key` `"Rose"`, it can now also be found by searching for `flower`. In-game
you can assign new aliases to things with the `alias` command.
Alternatively you can achieve the same thing manually (this is what the `alias` command does for you automatically):
> py self.search("rose").aliases.add("flower")
If the above example `rose` has a `key` `"Rose"`, it can now also be found by searching for its alias `flower`.
> py self.search("flower")
Rose
> All default commands uses the same search functionality, so you can now do `look flower` to look at the rose as well.
### Search by location
Only Objects (things inheriting from `evennia.DefaultObject`) has a location. The location is usually a room. The `Object.search` method will automatically limit it search by location, but it also works for the general search function. If we assume `room` is a particular Room instance,
Only Objects (things inheriting from `evennia.DefaultObject`) has a `.location` property.
chest = evennia.search_object("Treasure chest", location=room)
The `Object.search` method will automatically limit its search by the object's location, so assuming you are in the same room as the rose, this will work:
> py self.search("rose")
Rose
Let's make another location and move to it - you will no longer find the rose:
> tunnel n = kitchen
north
> py self.search("rose")
Could not find "rose"
However, using `search_object` will find the rose wherever it's located:
> py evennia.search_object("rose")
<QuerySet [Rose]>
However, if you demand that the room is in the current room, it won't be found:
> py evennia.search_object("rose", location=here)
<QuerySet []>
In general, the `Object.search` is a shortcut for doing the very common searches of things in the same location, whereas the `search_object` finds objects anywhere.
### Search by Tags
Think of a [Tag](../../../Components/Tags.md) as the label the airport puts on your luggage when flying. Everyone going on the same plane gets a tag grouping them together so the airport can know what should go to which plane. Entities in Evennia can be grouped in the same way. Any number of tags can be attached
to each object.
Think of a [Tag](../../../Components/Tags.md) as the label the airport puts on your luggage when flying. Everyone going on the same plane gets a tag, grouping them together so the airport can know what should go to which plane. Entities in Evennia can be grouped in the same way. Any number of tags can be attached to each object.
rose.tags.add("flowers")
rose.tags.add("thorny")
daffodil.tags.add("flowers")
tulip.tags.add("flowers")
cactus.tags.add("flowers")
cactus.tags.add("thorny")
Go back to the location of your `rose` and let's create a few more plants:
> create/drop Daffodil
> create/drop Tulip
> create/drop Cactus
Then let's add the "thorny" and "flowers" tags as ways to group these based on if they are flowers and/or have thorns:
py self.search("rose").tags.add("flowers")
py self.search("rose").tags.add("thorny")
py self.search("daffodil").tags.add("flowers")
py self.search("tulip").tags.add("flowers")
py self.search("cactus").tags.add("flowers")
py self.search("cactus").tags.add("thorny")
You can now find all flowers using the `search_tag` function:
all_flowers = evennia.search_tag("flowers")
roses_and_cactii = evennia.search_tag("thorny")
py evennia.search_tag("flowers")
<QuerySet [Rose, Daffodil, Tulip, Cactus]>
py evennia.search_tag("thorny")
<QuerySet [Rose, Cactus]>
Tags can also have categories. By default this category is `None` which is also considered a category.
Tags can also have categories. By default this category is `None` , which is considered a category of its own. Here are some examples of using categories in plain Python code (you can also try this out with `py` if you want to create the objects first):
silmarillion.tags.add("fantasy", category="books")
ice_and_fire.tags.add("fantasy", category="books")
mona_lisa_overdrive.tags.add("cyberpunk", category="books")
Note that if you specify the tag you _must_ also include its category, otherwise that category
will be `None` and find no matches.
Note that if you specify the tag with a category, you _must_ also include its category when searching, otherwise the tag-category of `None` will be searched.
all_fantasy_books = evennia.search_tag("fantasy") # no matches!
all_fantasy_books = evennia.search_tag("fantasy", category="books")
Only the second line above returns the two fantasy books. If we specify a category however,
we can get all tagged entities within that category:
Only the second line above returns the two fantasy books.
all_books = evennia.search_tag(category="books")
@ -176,35 +260,41 @@ This gets all three books.
We can also search by the [Attributes](../../../Components/Attributes.md) associated with entities.
For example, let's give our rose thorns:
For example, let's say our plants have a 'growth state' that updates as it grows:
rose.db.has_thorns = True
wines.db.has_thorns = True
daffodil.db.has_thorns = False
> py self.search("rose").db.growth_state = "blooming"
> py self.search("daffodil").db.growth_state = "withering"
Now we can find things attribute and the value we want it to have:
Now we can find the things that have a given growth state:
is_ouch = evennia.search_object_attribute("has_thorns", True)
This returns the rose and the wines.
> Searching by Attribute can be very practical. But if you plan to do a search very often, searching
> by-tag is generally faster.
> py evennia.search_object_attribute("growth_state", "withering")
<QuerySet [Rose]>
> Searching by Attribute can be very practical. But if you want to group entities or search very often, using Tags and search by Tags is faster and more resource-efficient.
### Search by Typeclass
Sometimes it's useful to find all objects of a specific Typeclass. All of Evennia's search tools support this.
Sometimes it's useful to limit your search by which Typeclass they have.
all_roses = evennia.search_object(typeclass="typeclasses.flowers.Rose")
Let's say you for example have two types of flower, `CursedFlower` and `BlessedFlower` defined under `mygame/typeclasses.flowers.py`. Each class contains custom code that grants curses and blessings respectively. You may have two `rose` objects, and the player doesn't know which one is the bad or the good one. To separate them in your search, you can make sure to get the right one like this (in Python code)
If you have the `Rose` class already imported you can also pass it directly:
```python
cursed_roses = evennia.search_object("rose", typeclass="typeclasses.flowers.CursedFlower")
```
all_roses = evennia.search_object(typeclass=Rose)
If you e.g. have the `BlessedRose` class already imported you can also pass it directly:
You can also search using the typeclass itself:
```python
from typeclasses.flowers import BlessedFlower
blessed_roses = evennia.search_object("rose", typeclass=BlessedFlower)
```
all_roses = Rose.objects.all()
A common use case is finding _all_ items of a given typeclass, no matter what they are named. For this you don't use `search_object`, but search with the typeclass directly:
```python
from typeclasses.objects.flowers import Rose
all_roses = Rose.objects.all()
```
This last way of searching is a simple form of a Django _query_. This is a way to express SQL queries using Python. See [the next lesson](./Beginner-Tutorial-Django-queries.md), where we'll explore this way to searching in more detail.
@ -230,7 +320,7 @@ In legacy code bases you may be used to relying a lot on #dbrefs to find and tra
## Finding objects relative each other
It's important to understand how objects relate to one another when searching.
Let's consider a `chest` with a `coin` inside it. The chests stand in a room `dungeon`. In the dungeon is also a `door`. This is an exit leading outside.
Let's consider a `chest` with a `coin` inside it. The chest stands in a room `dungeon`. In the dungeon is also a `door`. This is an exit leading outside.
```
┌───────────────────────┐
@ -251,7 +341,7 @@ Let's consider a `chest` with a `coin` inside it. The chests stand in a room `du
- `door.location` is `dungeon`.
- `room.location` is `None` since it's not inside something else.
One can use this to find what is inside what. For example, `coin.location.location` is the `room`.
One can use this to find what is inside what. For example, `coin.location.location` is the `dungeon`.
We can also find what is inside each object. This is a list of things.
- `room.contents` is `[chest, door]`

View file

@ -67,10 +67,17 @@ INSTALLED_APPS += (
'wiki.plugins.macros.apps.MacrosConfig',
)
# Disable wiki handling of login/signup
# Disable wiki handling of login/signup, so that it uses your Evennia login system instead
WIKI_ACCOUNT_HANDLING = False
WIKI_ACCOUNT_SIGNUP_ALLOWED = False
# Enable wikilinks, e.g. [[Getting Started]]
WIKI_MARKDOWN_KWARGS = {
'extensions': [
'wikilinks',
]
}
######################################################################
# Settings given in secret_settings.py override those in this file.
######################################################################
@ -151,15 +158,15 @@ Here's an example of a basic set-up that would go in your `settings.py` file:
# Custom methods to link wiki permissions to game perms
def is_superuser(article, user):
"""Return True if user is a superuser, False otherwise."""
return not user.is_anonymous() and user.is_superuser
return not user.is_anonymous and user.is_superuser
def is_builder(article, user):
"""Return True if user is a builder, False otherwise."""
return not user.is_anonymous() and user.locks.check_lockstring(user, "perm(Builders)")
return not user.is_anonymous and user.permissions.check("Builder")
def is_player(article, user):
"""Return True if user is a builder, False otherwise."""
return not user.is_anonymous() and user.locks.check_lockstring(user, "perm(Players)")
return not user.is_anonymous and user.permissions.check("Player")
# Create new users
WIKI_CAN_ADMIN = is_superuser

View file

@ -147,7 +147,6 @@ EVENNIA_ADMIN = True
# operating between two processes on the same machine. You usually don't need to
# change this unless you cannot use the default AMP port/host for
# whatever reason.
AMP_ENABLED = True
AMP_HOST = "localhost"
AMP_PORT = 4006
AMP_INTERFACE = "127.0.0.1"

View file

@ -13,6 +13,7 @@ evennia.contrib.base\_systems.godotwebsocket
:maxdepth: 6
evennia.contrib.base_systems.godotwebsocket.test_text2bbcode
evennia.contrib.base_systems.godotwebsocket.test_webclient
evennia.contrib.base_systems.godotwebsocket.text2bbcode
evennia.contrib.base_systems.godotwebsocket.webclient

View file

@ -0,0 +1,10 @@
```{eval-rst}
evennia.contrib.base\_systems.godotwebsocket.test\_webclient
===================================================================
.. automodule:: evennia.contrib.base_systems.godotwebsocket.test_webclient
:members:
:undoc-members:
:show-inheritance:
```

View file

@ -15,6 +15,7 @@ evennia.scripts
evennia.scripts.manager
evennia.scripts.models
evennia.scripts.monitorhandler
evennia.scripts.ondemandhandler
evennia.scripts.scripthandler
evennia.scripts.scripts
evennia.scripts.taskhandler

View file

@ -0,0 +1,10 @@
```{eval-rst}
evennia.scripts.ondemandhandler
======================================
.. automodule:: evennia.scripts.ondemandhandler
:members:
:undoc-members:
:show-inheritance:
```

View file

@ -16,7 +16,7 @@ This is the manual of [Evennia](https://www.evennia.com), the open source Python
## Tutorials and Howtos
- [The Beginner Tutorial](Howtos/Howtos-Overview.md#beginner-tutorial) - learn the basics and build a small game (in progress)
- [The Beginner Tutorial](Howtos/Beginner-Tutorial/Beginner-Tutorial-Overview.md) - learn the basics and build a small game (in progress)
- [Tutorials and Howto's](Howtos/Howtos-Overview.md#how-tos) - mixed tutorials and help articles to learn Evennia
- [Coding with Evennia](Coding/Coding-Overview.md) - resources and hints for coding and development

View file

@ -192,6 +192,7 @@
</li>
<li class="toctree-l4"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.html">evennia.contrib.base_systems.godotwebsocket</a><ul>
<li class="toctree-l5"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></li>
<li class="toctree-l5"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
<li class="toctree-l5"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></li>
<li class="toctree-l5"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.webclient.html">evennia.contrib.base_systems.godotwebsocket.webclient</a></li>
</ul>
@ -581,6 +582,10 @@
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.manager.html">evennia.scripts.manager</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.models.html">evennia.scripts.models</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.monitorhandler.html">evennia.scripts.monitorhandler</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.ondemandhandler.html">evennia.scripts.ondemandhandler</a><ul>
<li class="toctree-l4"><a class="reference internal" href="evennia.scripts.ondemandhandler.html#usage">Usage</a></li>
</ul>
</li>
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.scripthandler.html">evennia.scripts.scripthandler</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.scripts.html">evennia.scripts.scripts</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.taskhandler.html">evennia.scripts.taskhandler</a></li>

View file

@ -1409,7 +1409,7 @@ server settings.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.building.CmdTypeclass.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;typeclasses', '&#64;swap', '&#64;type', '&#64;parent', '&#64;update']</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;swap', '&#64;update', '&#64;type', '&#64;typeclasses', '&#64;parent']</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -1440,7 +1440,7 @@ server settings.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.building.CmdTypeclass.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;typeclasses &#64;swap &#64;type &#64;parent &#64;update', 'category': 'building', 'key': '&#64;typeclass', 'no_prefix': 'typeclass typeclasses swap type parent update', 'tags': '', 'text': &quot;\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] &lt;object&gt; [= typeclass.path]\n typeclass/prototype &lt;object&gt; = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n &quot;}</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;swap &#64;update &#64;type &#64;typeclasses &#64;parent', 'category': 'building', 'key': '&#64;typeclass', 'no_prefix': 'typeclass swap update type typeclasses parent', 'tags': '', 'text': &quot;\n set or change an object's typeclass\n\n Usage:\n typeclass[/switch] &lt;object&gt; [= typeclass.path]\n typeclass/prototype &lt;object&gt; = prototype_key\n\n typeclasses or typeclass/list/show [typeclass.path]\n swap - this is a shorthand for using /force/reset flags.\n update - this is a shorthand for using the /force/reload flag.\n\n Switch:\n show, examine - display the current typeclass of object (default) or, if\n given a typeclass path, show the docstring of that typeclass.\n update - *only* re-run at_object_creation on this object\n meaning locks or other properties set later may remain.\n reset - clean out *all* the attributes and properties on the\n object - basically making this a new clean object. This will also\n reset cmdsets!\n force - change to the typeclass also if the object\n already has a typeclass of the same name.\n list - show available typeclasses. Only typeclasses in modules actually\n imported or used from somewhere in the code will show up here\n (those typeclasses are still available if you know the path)\n prototype - clean and overwrite the object with the specified\n prototype key - effectively making a whole new object.\n\n Example:\n type button = examples.red_button.RedButton\n type/prototype button=a red button\n\n If the typeclass_path is not given, the current object's typeclass is\n assumed.\n\n View or set an object's typeclass. If setting, the creation hooks of the\n new typeclass will be run on the object. If you have clashing properties on\n the old class, use /reset. By default you are protected from changing to a\n typeclass of the same name as the one you already have - use /force to\n override this protection.\n\n The given typeclass must be identified by its location using python\n dot-notation pointing to the correct module and class. If no typeclass is\n given (or a wrong typeclass is given). Errors in the path or new typeclass\n will lead to the old typeclass being kept. The location of the typeclass\n module is searched from the default typeclass directory, as defined in the\n server settings.\n\n &quot;}</em><a class="headerlink" href="#evennia.commands.default.building.CmdTypeclass.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -1595,7 +1595,7 @@ If object is not specified, the current location is examined.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.building.CmdExamine.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;exam', '&#64;ex']</em><a class="headerlink" href="#evennia.commands.default.building.CmdExamine.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;ex', '&#64;exam']</em><a class="headerlink" href="#evennia.commands.default.building.CmdExamine.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -1868,7 +1868,7 @@ the cases, see the module doc.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.building.CmdExamine.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;exam &#64;ex', 'category': 'building', 'key': '&#64;examine', 'no_prefix': 'examine exam ex', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [&lt;object&gt;[/attrname]]\n examine [*&lt;account&gt;[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n script - examine a Script\n channel - examine a Channel\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}</em><a class="headerlink" href="#evennia.commands.default.building.CmdExamine.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;ex &#64;exam', 'category': 'building', 'key': '&#64;examine', 'no_prefix': 'examine ex exam', 'tags': '', 'text': '\n get detailed information about an object\n\n Usage:\n examine [&lt;object&gt;[/attrname]]\n examine [*&lt;account&gt;[/attrname]]\n\n Switch:\n account - examine an Account (same as adding *)\n object - examine an Object (useful when OOC)\n script - examine a Script\n channel - examine a Channel\n\n The examine command shows detailed game info about an\n object and optionally a specific attribute on it.\n If object is not specified, the current location is examined.\n\n Append a * before the search string to examine an account.\n\n '}</em><a class="headerlink" href="#evennia.commands.default.building.CmdExamine.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -610,7 +610,7 @@ placing it in their inventory.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.general.CmdSay.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = [&quot;'&quot;, '&quot;']</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['&quot;', &quot;'&quot;]</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -641,7 +641,7 @@ placing it in their inventory.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.general.CmdSay.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '\' &quot;', 'category': 'general', 'key': 'say', 'no_prefix': ' \' &quot;', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say &lt;message&gt;\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&quot; \'', 'category': 'general', 'key': 'say', 'no_prefix': ' &quot; \'', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say &lt;message&gt;\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdSay.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -721,7 +721,7 @@ automatically begin with your name.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.general.CmdPose.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = [':', 'emote']</em><a class="headerlink" href="#evennia.commands.default.general.CmdPose.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['emote', ':']</em><a class="headerlink" href="#evennia.commands.default.general.CmdPose.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -762,7 +762,7 @@ space.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.general.CmdPose.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': ': emote', 'category': 'general', 'key': 'pose', 'no_prefix': ' : emote', 'tags': '', 'text': &quot;\n strike a pose\n\n Usage:\n pose &lt;pose text&gt;\n pose's &lt;pose text&gt;\n\n Example:\n pose is standing by the wall, smiling.\n -&gt; others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n &quot;}</em><a class="headerlink" href="#evennia.commands.default.general.CmdPose.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'emote :', 'category': 'general', 'key': 'pose', 'no_prefix': ' emote :', 'tags': '', 'text': &quot;\n strike a pose\n\n Usage:\n pose &lt;pose text&gt;\n pose's &lt;pose text&gt;\n\n Example:\n pose is standing by the wall, smiling.\n -&gt; others will see:\n Tom is standing by the wall, smiling.\n\n Describe an action being taken. The pose text will\n automatically begin with your name.\n &quot;}</em><a class="headerlink" href="#evennia.commands.default.general.CmdPose.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -785,7 +785,7 @@ which permission groups you are a member of.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.general.CmdAccess.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['hierarchy', 'groups']</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['groups', 'hierarchy']</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -816,7 +816,7 @@ which permission groups you are a member of.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.general.CmdAccess.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hierarchy groups', 'category': 'general', 'key': 'access', 'no_prefix': ' hierarchy groups', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'groups hierarchy', 'category': 'general', 'key': 'access', 'no_prefix': ' groups hierarchy', 'tags': '', 'text': '\n show your current game access\n\n Usage:\n access\n\n This command shows you the permission hierarchy and\n which permission groups you are a member of.\n '}</em><a class="headerlink" href="#evennia.commands.default.general.CmdAccess.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -695,7 +695,7 @@ See <a href="#id11"><span class="problematic" id="id12">|</span></a>luhttps://ww
<dl class="py attribute">
<dt id="evennia.commands.default.system.CmdTasks.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;task', '&#64;delays']</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;delays', '&#64;task']</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -741,7 +741,7 @@ to all the variables defined therein.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.system.CmdTasks.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;task &#64;delays', 'category': 'system', 'key': '&#64;tasks', 'no_prefix': 'tasks task delays', 'tags': '', 'text': &quot;\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n &quot;}</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;delays &#64;task', 'category': 'system', 'key': '&#64;tasks', 'no_prefix': 'tasks delays task', 'tags': '', 'text': &quot;\n Display or terminate active tasks (delays).\n\n Usage:\n tasks[/switch] [task_id or function_name]\n\n Switches:\n pause - Pause the callback of a task.\n unpause - Process all callbacks made since pause() was called.\n do_task - Execute the task (call its callback).\n call - Call the callback of this task.\n remove - Remove a task without executing it.\n cancel - Stop a task from automatically executing.\n\n Notes:\n A task is a single use method of delaying the call of a function. Calls are created\n in code, using `evennia.utils.delay`.\n See |luhttps://www.evennia.com/docs/latest/Command-Duration.html|ltthe docs|le for help.\n\n By default, tasks that are canceled and never called are cleaned up after one minute.\n\n Examples:\n - `tasks/cancel move_callback` - Cancels all movement delays from the slow_exit contrib.\n In this example slow exits creates it's tasks with\n `utils.delay(move_delay, move_callback)`\n - `tasks/cancel 2` - Cancel task id 2.\n\n &quot;}</em><a class="headerlink" href="#evennia.commands.default.system.CmdTasks.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -973,7 +973,7 @@ main test suite started with</p>
<p>Test the batch processor.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.tests.TestBatchProcess.red_button">
<code class="sig-name descname">red_button</code><em class="property"> = &lt;module 'evennia.contrib.tutorials.red_button.red_button' from '/tmp/tmp02ssu5b3/2b7af748f92b82ea879e59645f8b5cde105e13de/evennia/contrib/tutorials/red_button/red_button.py'&gt;</em><a class="headerlink" href="#evennia.commands.default.tests.TestBatchProcess.red_button" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">red_button</code><em class="property"> = &lt;module 'evennia.contrib.tutorials.red_button.red_button' from '/tmp/tmpl5nk3kkg/63072132454093c21c82cd419a789af6528a040e/evennia/contrib/tutorials/red_button/red_button.py'&gt;</em><a class="headerlink" href="#evennia.commands.default.tests.TestBatchProcess.red_button" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">

View file

@ -134,7 +134,7 @@ connect “account name” “pass word”</p>
<dl class="py attribute">
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedConnect.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['conn', 'con', 'co']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedConnect.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['con', 'co', 'conn']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedConnect.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -169,7 +169,7 @@ there is no object yet before the account has logged in)</p>
<dl class="py attribute">
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedConnect.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'conn con co', 'category': 'general', 'key': 'connect', 'no_prefix': ' conn con co', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect &quot;account name&quot; &quot;pass word&quot;\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedConnect.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'con co conn', 'category': 'general', 'key': 'connect', 'no_prefix': ' con co conn', 'tags': '', 'text': '\n connect to the game\n\n Usage (at login screen):\n connect accountname password\n connect &quot;account name&quot; &quot;pass word&quot;\n\n Use the create command to first create an account before logging in.\n\n If you have spaces in your name, enclose it in double quotes.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedConnect.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -193,7 +193,7 @@ create “account name” “pass word”</p>
<dl class="py attribute">
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedCreate.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['cr', 'cre']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['cre', 'cr']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -230,7 +230,7 @@ create “account name” “pass word”</p>
<dl class="py attribute">
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedCreate.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create &lt;accountname&gt; &lt;password&gt;\n create &quot;account name&quot; &quot;pass word&quot;\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'no_prefix': ' cre cr', 'tags': '', 'text': '\n create a new account account\n\n Usage (at login screen):\n create &lt;accountname&gt; &lt;password&gt;\n create &quot;account name&quot; &quot;pass word&quot;\n\n This creates a new account account.\n\n If you have spaces in your name, enclose it in double quotes.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -304,7 +304,7 @@ All it does is display the connect screen.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedLook.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['look', 'l']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['l', 'look']</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -330,7 +330,7 @@ All it does is display the connect screen.</p>
<dl class="py attribute">
<dt id="evennia.commands.default.unloggedin.CmdUnconnectedLook.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n look when in unlogged-in state\n\n Usage:\n look\n\n This is an unconnected version of the look command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.commands.default.unloggedin.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -151,7 +151,7 @@ the module given by settings.CONNECTION_SCREEN_MODULE.</p>
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['conn', 'con', 'co']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['con', 'co', 'conn']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -181,7 +181,7 @@ there is no object yet before the account has logged in)</p>
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'conn con co', 'category': 'general', 'key': 'connect', 'no_prefix': ' conn con co', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect &lt;email&gt; &lt;password&gt;\n\n Use the create command to first create an account before logging in.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'con co conn', 'category': 'general', 'key': 'connect', 'no_prefix': ' con co conn', 'tags': '', 'text': '\n Connect to the game.\n\n Usage (at login screen):\n connect &lt;email&gt; &lt;password&gt;\n\n Use the create command to first create an account before logging in.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedConnect.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -203,7 +203,7 @@ there is no object yet before the account has logged in)</p>
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['cr', 'cre']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['cre', 'cr']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -239,7 +239,7 @@ name enclosed in quotes:</p>
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cr cre', 'category': 'general', 'key': 'create', 'no_prefix': ' cr cre', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create &quot;accountname&quot; &lt;email&gt; &lt;password&gt;\n\n This creates a new account account.\n\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'cre cr', 'category': 'general', 'key': 'create', 'no_prefix': ' cre cr', 'tags': '', 'text': '\n Create a new account.\n\n Usage (at login screen):\n create &quot;accountname&quot; &lt;email&gt; &lt;password&gt;\n\n This creates a new account account.\n\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedCreate.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -303,7 +303,7 @@ All it does is display the connect screen.</p>
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['look', 'l']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['l', 'look']</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -329,7 +329,7 @@ All it does is display the connect screen.</p>
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'look l', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' look l', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'l look', 'category': 'general', 'key': '__unloggedin_look_command', 'no_prefix': ' l look', 'tags': '', 'text': '\n This is an unconnected version of the `look` command for simplicity.\n\n This is called by the server and kicks everything in gear.\n All it does is display the connect screen.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.email_login.email_login.CmdUnconnectedLook.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -124,6 +124,7 @@ You could also pass extra data to this client for advanced functionality.</p>
<div class="toctree-wrapper compound">
<ul>
<li class="toctree-l1"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.webclient.html">evennia.contrib.base_systems.godotwebsocket.webclient</a></li>
</ul>

View file

@ -17,7 +17,7 @@
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="evennia.contrib.base_systems.godotwebsocket.text2bbcode" href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html" />
<link rel="next" title="evennia.contrib.base_systems.godotwebsocket.test_webclient" href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html" />
<link rel="prev" title="evennia.contrib.base_systems.godotwebsocket" href="evennia.contrib.base_systems.godotwebsocket.html" />
</head><body>
@ -34,7 +34,7 @@
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.text2bbcode"
<a href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html" title="evennia.contrib.base_systems.godotwebsocket.test_webclient"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.html" title="evennia.contrib.base_systems.godotwebsocket"
@ -72,8 +72,8 @@
<p class="topless"><a href="evennia.contrib.base_systems.godotwebsocket.html"
title="previous chapter">evennia.contrib.base_systems.godotwebsocket</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html"
title="next chapter">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></p>
<p class="topless"><a href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html"
title="next chapter">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
@ -165,7 +165,7 @@
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.text2bbcode"
<a href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html" title="evennia.contrib.base_systems.godotwebsocket.test_webclient"
>next</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.html" title="evennia.contrib.base_systems.godotwebsocket"

View file

@ -0,0 +1,181 @@
<!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.contrib.base_systems.godotwebsocket.test_webclient &#8212; Evennia latest 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.contrib.base_systems.godotwebsocket.text2bbcode" href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html" />
<link rel="prev" title="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode" href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.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="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.text2bbcode"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="evennia-api.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-4"><a href="evennia.contrib.html" >evennia.contrib</a> &#187;</li>
<li class="nav-item nav-item-5"><a href="evennia.contrib.base_systems.html" >evennia.contrib.base_systems</a> &#187;</li>
<li class="nav-item nav-item-6"><a href="evennia.contrib.base_systems.godotwebsocket.html" accesskey="U">evennia.contrib.base_systems.godotwebsocket</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
</ul>
</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="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html"
title="previous chapter">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html"
title="next chapter">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/api/evennia.contrib.base_systems.godotwebsocket.test_webclient.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/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>Doc Versions</h3>
<ul>
<li><a href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html">latest (main branch)</a></li>
<li><a href="../../3.x/index.html">v3.0.0 branch (outdated)</a></li>
<li><a href="../../2.x/index.html">v2.0.0 branch (outdated)</a></li>
<li><a href="../../1.x/index.html">v1.0.0 branch (outdated)</a></li>
<li><a href="../../0.x/index.html">v0.9.5 branch (outdated)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-evennia.contrib.base_systems.godotwebsocket.test_webclient">
<span id="evennia-contrib-base-systems-godotwebsocket-test-webclient"></span><h1>evennia.contrib.base_systems.godotwebsocket.test_webclient<a class="headerlink" href="#module-evennia.contrib.base_systems.godotwebsocket.test_webclient" title="Permalink to this headline"></a></h1>
<dl class="py class">
<dt id="evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient">
<em class="property">class </em><code class="sig-prename descclassname">evennia.contrib.base_systems.godotwebsocket.test_webclient.</code><code class="sig-name descname">TestGodotWebSocketClient</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">methodName</span><span class="o">=</span><span class="default_value">'runTest'</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/contrib/base_systems/godotwebsocket/test_webclient.html#TestGodotWebSocketClient"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <a class="reference internal" href="evennia.utils.test_resources.html#evennia.utils.test_resources.BaseEvenniaTest" title="evennia.utils.test_resources.BaseEvenniaTest"><code class="xref py py-class docutils literal notranslate"><span class="pre">evennia.utils.test_resources.BaseEvenniaTest</span></code></a></p>
<dl class="py method">
<dt id="evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.setUp">
<code class="sig-name descname">setUp</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/contrib/base_systems/godotwebsocket/test_webclient.html#TestGodotWebSocketClient.setUp"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.setUp" title="Permalink to this definition"></a></dt>
<dd><p>Sets up testing environment</p>
</dd></dl>
<dl class="py method">
<dt id="evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_in">
<code class="sig-name descname">test_data_in</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/contrib/base_systems/godotwebsocket/test_webclient.html#TestGodotWebSocketClient.test_data_in"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_in" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_out">
<code class="sig-name descname">test_data_out</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/contrib/base_systems/godotwebsocket/test_webclient.html#TestGodotWebSocketClient.test_data_out"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_out" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
</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="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.text2bbcode"
>next</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="evennia-api.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-4"><a href="evennia.contrib.html" >evennia.contrib</a> &#187;</li>
<li class="nav-item nav-item-5"><a href="evennia.contrib.base_systems.html" >evennia.contrib.base_systems</a> &#187;</li>
<li class="nav-item nav-item-6"><a href="evennia.contrib.base_systems.godotwebsocket.html" >evennia.contrib.base_systems.godotwebsocket</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -18,7 +18,7 @@
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="evennia.contrib.base_systems.godotwebsocket.webclient" href="evennia.contrib.base_systems.godotwebsocket.webclient.html" />
<link rel="prev" title="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode" href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html" />
<link rel="prev" title="evennia.contrib.base_systems.godotwebsocket.test_webclient" href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html" />
</head><body>
@ -37,7 +37,7 @@
<a href="evennia.contrib.base_systems.godotwebsocket.webclient.html" title="evennia.contrib.base_systems.godotwebsocket.webclient"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode"
<a href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html" title="evennia.contrib.base_systems.godotwebsocket.test_webclient"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>
@ -69,8 +69,8 @@
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html"
title="previous chapter">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></p>
<p class="topless"><a href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html"
title="previous chapter">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="evennia.contrib.base_systems.godotwebsocket.webclient.html"
title="next chapter">evennia.contrib.base_systems.godotwebsocket.webclient</a></p>
@ -484,7 +484,7 @@ into html statements.</p>
<a href="evennia.contrib.base_systems.godotwebsocket.webclient.html" title="evennia.contrib.base_systems.godotwebsocket.webclient"
>next</a> |</li>
<li class="right" >
<a href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html" title="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode"
<a href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html" title="evennia.contrib.base_systems.godotwebsocket.test_webclient"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>

View file

@ -151,6 +151,7 @@
</li>
<li class="toctree-l1"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.html">evennia.contrib.base_systems.godotwebsocket</a><ul>
<li class="toctree-l2"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.webclient.html">evennia.contrib.base_systems.godotwebsocket.webclient</a></li>
</ul>

View file

@ -128,7 +128,7 @@
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.ingame_python.commands.CmdCallback.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;calls', '&#64;callback', '&#64;callbacks']</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;callbacks', '&#64;calls', '&#64;callback']</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -209,7 +209,7 @@ on user permission.</p>
<dl class="py attribute">
<dt id="evennia.contrib.base_systems.ingame_python.commands.CmdCallback.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;calls &#64;callback &#64;callbacks', 'category': 'building', 'key': '&#64;call', 'no_prefix': 'call calls callback callbacks', 'tags': '', 'text': '\n Command to edit callbacks.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;callbacks &#64;calls &#64;callback', 'category': 'building', 'key': '&#64;call', 'no_prefix': 'call callbacks calls callback', 'tags': '', 'text': '\n Command to edit callbacks.\n '}</em><a class="headerlink" href="#evennia.contrib.base_systems.ingame_python.commands.CmdCallback.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -223,7 +223,7 @@ the operation will be general or on the room.</p>
<dl class="py attribute">
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['quit', 'q', 'chicken out', 'abort']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['q', 'quit', 'chicken out', 'abort']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
@ -247,7 +247,7 @@ set in self.parse())</p>
<dl class="py attribute">
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'quit q chicken out abort', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' quit q chicken out abort', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'q quit chicken out abort', 'category': 'evscaperoom', 'key': 'give up', 'no_prefix': ' q quit chicken out abort', 'tags': '', 'text': '\n Give up\n\n Usage:\n give up\n\n Abandons your attempts at escaping and of ever winning the pie-eating contest.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdGiveUp.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -502,7 +502,7 @@ looks and what actions is available.</p>
<dl class="py attribute">
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['e', 'examine', 'unfocus', 'ex']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['e', 'ex', 'examine', 'unfocus']</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -531,7 +531,7 @@ set in self.parse())</p>
<dl class="py attribute">
<dt id="evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'e examine unfocus ex', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' e examine unfocus ex', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus &lt;obj&gt;\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'e ex examine unfocus', 'category': 'evscaperoom', 'key': 'focus', 'no_prefix': ' e ex examine unfocus', 'tags': '', 'text': '\n Focus your attention on a target.\n\n Usage:\n focus &lt;obj&gt;\n\n Once focusing on an object, use look to get more information about how it\n looks and what actions is available.\n\n '}</em><a class="headerlink" href="#evennia.contrib.full_systems.evscaperoom.commands.CmdFocus.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -684,7 +684,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['wait', 'hold']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['hold', 'wait']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -710,7 +710,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_basic.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -579,7 +579,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['wait', 'hold']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['hold', 'wait']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -599,7 +599,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_equip.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -702,7 +702,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_items.CmdPass.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['wait', 'hold']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_items.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['hold', 'wait']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_items.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -722,7 +722,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_items.CmdPass.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_items.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_items.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -481,7 +481,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['wait', 'hold']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['hold', 'wait']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -501,7 +501,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_magic.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -941,7 +941,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_range.CmdPass.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['wait', 'hold']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_range.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['hold', 'wait']</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_range.CmdPass.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -961,7 +961,7 @@ if there are still any actions you can take.</p>
<dl class="py attribute">
<dt id="evennia.contrib.game_systems.turnbattle.tb_range.CmdPass.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'wait hold', 'category': 'combat', 'key': 'pass', 'no_prefix': ' wait hold', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_range.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hold wait', 'category': 'combat', 'key': 'pass', 'no_prefix': ' hold wait', 'tags': '', 'text': '\n Passes on your turn.\n\n Usage:\n pass\n\n When in a fight, you can use this command to end your turn early, even\n if there are still any actions you can take.\n '}</em><a class="headerlink" href="#evennia.contrib.game_systems.turnbattle.tb_range.CmdPass.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -434,7 +434,7 @@ there is no room above/below you, your movement will fail.</p>
<dl class="py attribute">
<dt id="evennia.contrib.grid.xyzgrid.commands.CmdFlyAndDive.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['fly', 'dive']</em><a class="headerlink" href="#evennia.contrib.grid.xyzgrid.commands.CmdFlyAndDive.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['dive', 'fly']</em><a class="headerlink" href="#evennia.contrib.grid.xyzgrid.commands.CmdFlyAndDive.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
@ -457,7 +457,7 @@ to all the variables defined therein.</p>
<dl class="py attribute">
<dt id="evennia.contrib.grid.xyzgrid.commands.CmdFlyAndDive.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'fly dive', 'category': 'general', 'key': 'fly or dive', 'no_prefix': ' fly dive', 'tags': '', 'text': '\n Fly or Dive up and down.\n\n Usage:\n fly\n dive\n\n Will fly up one room or dive down one room at your current position. If\n there is no room above/below you, your movement will fail.\n\n '}</em><a class="headerlink" href="#evennia.contrib.grid.xyzgrid.commands.CmdFlyAndDive.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'dive fly', 'category': 'general', 'key': 'fly or dive', 'no_prefix': ' dive fly', 'tags': '', 'text': '\n Fly or Dive up and down.\n\n Usage:\n fly\n dive\n\n Will fly up one room or dive down one room at your current position. If\n there is no room above/below you, your movement will fail.\n\n '}</em><a class="headerlink" href="#evennia.contrib.grid.xyzgrid.commands.CmdFlyAndDive.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -154,6 +154,7 @@ useful but are deemed too game-specific to go into the core library.</p>
</li>
<li class="toctree-l2"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.html">evennia.contrib.base_systems.godotwebsocket</a><ul>
<li class="toctree-l3"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></li>
<li class="toctree-l3"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.webclient.html">evennia.contrib.base_systems.godotwebsocket.webclient</a></li>
</ul>

View file

@ -338,7 +338,7 @@ everyone but the person rolling.</p>
<dl class="py attribute">
<dt id="evennia.contrib.rpg.dice.dice.CmdDice.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['roll', '&#64;dice']</em><a class="headerlink" href="#evennia.contrib.rpg.dice.dice.CmdDice.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['&#64;dice', 'roll']</em><a class="headerlink" href="#evennia.contrib.rpg.dice.dice.CmdDice.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -364,7 +364,7 @@ everyone but the person rolling.</p>
<dl class="py attribute">
<dt id="evennia.contrib.rpg.dice.dice.CmdDice.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'roll &#64;dice', 'category': 'general', 'key': 'dice', 'no_prefix': ' roll dice', 'tags': '', 'text': &quot;\n roll dice\n\n Usage:\n dice[/switch] &lt;nr&gt;d&lt;sides&gt; [modifier] [success condition]\n\n Switch:\n hidden - tell the room the roll is being done, but don't show the result\n secret - don't inform the room about neither roll nor result\n\n Examples:\n dice 3d6 + 4\n dice 1d100 - 2 &lt; 50\n\n This will roll the given number of dice with given sides and modifiers.\n So e.g. 2d6 + 3 means to 'roll a 6-sided die 2 times and add the result,\n then add 3 to the total'.\n Accepted modifiers are +, -, * and /.\n A success condition is given as normal Python conditionals\n (&lt;,&gt;,&lt;=,&gt;=,==,!=). So e.g. 2d6 + 3 &gt; 10 means that the roll will succeed\n only if the final result is above 8. If a success condition is given, the\n outcome (pass/fail) will be echoed along with how much it succeeded/failed\n with. The hidden/secret switches will hide all or parts of the roll from\n everyone but the person rolling.\n &quot;}</em><a class="headerlink" href="#evennia.contrib.rpg.dice.dice.CmdDice.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&#64;dice roll', 'category': 'general', 'key': 'dice', 'no_prefix': ' dice roll', 'tags': '', 'text': &quot;\n roll dice\n\n Usage:\n dice[/switch] &lt;nr&gt;d&lt;sides&gt; [modifier] [success condition]\n\n Switch:\n hidden - tell the room the roll is being done, but don't show the result\n secret - don't inform the room about neither roll nor result\n\n Examples:\n dice 3d6 + 4\n dice 1d100 - 2 &lt; 50\n\n This will roll the given number of dice with given sides and modifiers.\n So e.g. 2d6 + 3 means to 'roll a 6-sided die 2 times and add the result,\n then add 3 to the total'.\n Accepted modifiers are +, -, * and /.\n A success condition is given as normal Python conditionals\n (&lt;,&gt;,&lt;=,&gt;=,==,!=). So e.g. 2d6 + 3 &gt; 10 means that the roll will succeed\n only if the final result is above 8. If a success condition is given, the\n outcome (pass/fail) will be echoed along with how much it succeeded/failed\n with. The hidden/secret switches will hide all or parts of the roll from\n everyone but the person rolling.\n &quot;}</em><a class="headerlink" href="#evennia.contrib.rpg.dice.dice.CmdDice.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -734,7 +734,7 @@ commands the caller can use.</p>
<dl class="py attribute">
<dt id="evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = [&quot;'&quot;, '&quot;']</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['&quot;', &quot;'&quot;]</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -765,7 +765,7 @@ commands the caller can use.</p>
<dl class="py attribute">
<dt id="evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '\' &quot;', 'category': 'general', 'key': 'say', 'no_prefix': ' \' &quot;', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say &lt;message&gt;\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': '&quot; \'', 'category': 'general', 'key': 'say', 'no_prefix': ' &quot; \'', 'tags': '', 'text': '\n speak as your character\n\n Usage:\n say &lt;message&gt;\n\n Talk to those in your current location.\n '}</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdSay.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -906,7 +906,7 @@ Using the command without arguments will list all current recogs.</p>
<dl class="py attribute">
<dt id="evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['recognize', 'forget']</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['forget', 'recognize']</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
@ -933,7 +933,7 @@ Using the command without arguments will list all current recogs.</p>
<dl class="py attribute">
<dt id="evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'recognize forget', 'category': 'general', 'key': 'recog', 'no_prefix': ' recognize forget', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'forget recognize', 'category': 'general', 'key': 'recog', 'no_prefix': ' forget recognize', 'tags': '', 'text': '\n Recognize another person in the same room.\n\n Usage:\n recog\n recog sdesc as alias\n forget alias\n\n Example:\n recog tall man as Griatch\n forget griatch\n\n This will assign a personal alias for a person, or forget said alias.\n Using the command without arguments will list all current recogs.\n\n '}</em><a class="headerlink" href="#evennia.contrib.rpg.rpsystem.rpsystem.CmdRecog.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -478,7 +478,7 @@ turn of combat, performing everyones actions in random order.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.evadventure.combat_turnbased.CmdTurnAttack.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['turnbased combat', 'hit']</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_turnbased.CmdTurnAttack.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['hit', 'turnbased combat']</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_turnbased.CmdTurnAttack.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -524,7 +524,7 @@ set in self.parse())</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.evadventure.combat_turnbased.CmdTurnAttack.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'turnbased combat hit', 'category': 'general', 'key': 'attack', 'no_prefix': ' turnbased combat hit', 'tags': '', 'text': '\n Start or join combat.\n\n Usage:\n attack [&lt;target&gt;]\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_turnbased.CmdTurnAttack.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'hit turnbased combat', 'category': 'general', 'key': 'attack', 'no_prefix': ' hit turnbased combat', 'tags': '', 'text': '\n Start or join combat.\n\n Usage:\n attack [&lt;target&gt;]\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_turnbased.CmdTurnAttack.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -489,7 +489,7 @@ boost INT Wizard Goblin</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.evadventure.combat_twitch.CmdStunt.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['foil', 'boost']</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_twitch.CmdStunt.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['boost', 'foil']</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_twitch.CmdStunt.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -523,7 +523,7 @@ set in self.parse())</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.evadventure.combat_twitch.CmdStunt.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'foil boost', 'category': 'combat', 'key': 'stunt', 'no_prefix': ' foil boost', 'tags': '', 'text': '\n Perform a combat stunt, that boosts an ally against a target, or\n foils an enemy, giving them disadvantage against an ally.\n\n Usage:\n boost [ability] &lt;recipient&gt; &lt;target&gt;\n foil [ability] &lt;recipient&gt; &lt;target&gt;\n boost [ability] &lt;target&gt; (same as boost me &lt;target&gt;)\n foil [ability] &lt;target&gt; (same as foil &lt;target&gt; me)\n\n Example:\n boost STR me Goblin\n boost DEX Goblin\n foil STR Goblin me\n foil INT Goblin\n boost INT Wizard Goblin\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_twitch.CmdStunt.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'boost foil', 'category': 'combat', 'key': 'stunt', 'no_prefix': ' boost foil', 'tags': '', 'text': '\n Perform a combat stunt, that boosts an ally against a target, or\n foils an enemy, giving them disadvantage against an ally.\n\n Usage:\n boost [ability] &lt;recipient&gt; &lt;target&gt;\n foil [ability] &lt;recipient&gt; &lt;target&gt;\n boost [ability] &lt;target&gt; (same as boost me &lt;target&gt;)\n foil [ability] &lt;target&gt; (same as foil &lt;target&gt; me)\n\n Example:\n boost STR me Goblin\n boost DEX Goblin\n foil STR Goblin me\n foil INT Goblin\n boost INT Wizard Goblin\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.evadventure.combat_twitch.CmdStunt.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -165,7 +165,7 @@ such as when closing the lid and un-blinding a character.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['press', 'push', 'press button']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['press button', 'press', 'push']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -194,7 +194,7 @@ check if the lid is open or closed.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'press push press button', 'category': 'general', 'key': 'push button', 'no_prefix': ' press push press button', 'tags': '', 'text': '\n Push the red button (lid closed)\n\n Usage:\n push button\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'press button press push', 'category': 'general', 'key': 'push button', 'no_prefix': ' press button press push', 'tags': '', 'text': '\n Push the red button (lid closed)\n\n Usage:\n push button\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidClosed.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -391,7 +391,7 @@ be mutually exclusive.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['press', 'push', 'press button']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['press button', 'press', 'push']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -420,7 +420,7 @@ set in self.parse())</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'press push press button', 'category': 'general', 'key': 'push button', 'no_prefix': ' press push press button', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'press button press push', 'category': 'general', 'key': 'push button', 'no_prefix': ' press button press push', 'tags': '', 'text': '\n Push the red button\n\n Usage:\n push button\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdPushLidOpen.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -518,7 +518,7 @@ be mutually exclusive.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['get', 'examine', 'listen', 'ex', 'feel', 'l']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['feel', 'listen', 'examine', 'get', 'l', 'ex']</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -544,7 +544,7 @@ be mutually exclusive.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'get examine listen ex feel l', 'category': 'general', 'key': 'look', 'no_prefix': ' get examine listen ex feel l', 'tags': '', 'text': &quot;\n Looking around in darkness\n\n Usage:\n look &lt;obj&gt;\n\n ... not that there's much to see in the dark.\n\n &quot;}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'feel listen examine get l ex', 'category': 'general', 'key': 'look', 'no_prefix': ' feel listen examine get l ex', 'tags': '', 'text': &quot;\n Looking around in darkness\n\n Usage:\n look &lt;obj&gt;\n\n ... not that there's much to see in the dark.\n\n &quot;}</em><a class="headerlink" href="#evennia.contrib.tutorials.red_button.red_button.CmdBlindLook.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -568,7 +568,7 @@ shift green root up/down</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['move', 'shiftroot', 'push', 'pull']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['pull', 'shiftroot', 'push', 'move']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -604,7 +604,7 @@ yellow/green - horizontal roots</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'move shiftroot push pull', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' move shiftroot push pull', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'pull shiftroot push move', 'category': 'tutorialworld', 'key': 'shift', 'no_prefix': ' pull shiftroot push move', 'tags': '', 'text': '\n Shifts roots around.\n\n Usage:\n shift blue root left/right\n shift red root left/right\n shift yellow root up/down\n shift green root up/down\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdShiftRoot.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -621,7 +621,7 @@ yellow/green - horizontal roots</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['push button', 'button', 'press button']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['button', 'press button', 'push button']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -647,7 +647,7 @@ yellow/green - horizontal roots</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'push button button press button', 'category': 'tutorialworld', 'key': 'press', 'no_prefix': ' push button button press button', 'tags': '', 'text': '\n Presses a button.\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'button press button push button', 'category': 'tutorialworld', 'key': 'press', 'no_prefix': ' button press button push button', 'tags': '', 'text': '\n Presses a button.\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdPressButton.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>
@ -791,7 +791,7 @@ parry - forgoes your attack but will make you harder to hit on next</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['thrust', 'slash', 'defend', 'kill', 'pierce', 'bash', 'hit', 'fight', 'parry', 'chop', 'stab']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['slash', 'fight', 'stab', 'hit', 'pierce', 'bash', 'defend', 'kill', 'parry', 'chop', 'thrust']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -817,7 +817,7 @@ parry - forgoes your attack but will make you harder to hit on next</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'thrust slash defend kill pierce bash hit fight parry chop stab', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' thrust slash defend kill pierce bash hit fight parry chop stab', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab &lt;enemy&gt;\n slash &lt;enemy&gt;\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'slash fight stab hit pierce bash defend kill parry chop thrust', 'category': 'tutorialworld', 'key': 'attack', 'no_prefix': ' slash fight stab hit pierce bash defend kill parry chop thrust', 'tags': '', 'text': '\n Attack the enemy. Commands:\n\n stab &lt;enemy&gt;\n slash &lt;enemy&gt;\n parry\n\n stab - (thrust) makes a lot of damage but is harder to hit with.\n slash - is easier to land, but does not make as much damage.\n parry - forgoes your attack but will make you harder to hit on next\n enemy attack.\n\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.objects.CmdAttack.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -980,7 +980,7 @@ to find something.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['search', 'fiddle', 'feel', 'l', 'feel around']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['l', 'feel', 'search', 'feel around', 'fiddle']</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -1008,7 +1008,7 @@ random chance of eventually finding a light source.</p>
<dl class="py attribute">
<dt id="evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'search fiddle feel l feel around', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' search fiddle feel l feel around', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'l feel search feel around fiddle', 'category': 'tutorialworld', 'key': 'look', 'no_prefix': ' l feel search feel around fiddle', 'tags': '', 'text': '\n Look around in darkness\n\n Usage:\n look\n\n Look around in the darkness, trying\n to find something.\n '}</em><a class="headerlink" href="#evennia.contrib.tutorials.tutorial_world.rooms.CmdLookDark.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -220,7 +220,7 @@ git evennia pull - Pull the latest evennia code.</p>
<dl class="py attribute">
<dt id="evennia.contrib.utils.git_integration.git_integration.CmdGitEvennia.directory">
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmp02ssu5b3/2b7af748f92b82ea879e59645f8b5cde105e13de/evennia'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGitEvennia.directory" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmpl5nk3kkg/63072132454093c21c82cd419a789af6528a040e/evennia'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGitEvennia.directory" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -281,7 +281,7 @@ git pull - Pull the latest code from your current branch.</p>
<dl class="py attribute">
<dt id="evennia.contrib.utils.git_integration.git_integration.CmdGit.directory">
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmp02ssu5b3/2b7af748f92b82ea879e59645f8b5cde105e13de/evennia/game_template'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGit.directory" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">directory</code><em class="property"> = '/tmp/tmpl5nk3kkg/63072132454093c21c82cd419a789af6528a040e/evennia/game_template'</em><a class="headerlink" href="#evennia.contrib.utils.git_integration.git_integration.CmdGit.directory" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">

View file

@ -141,8 +141,10 @@
<li><p>evennia.InterruptCommand</p></li>
<li><p>evennia.MONITOR_HANDLER</p></li>
<li><p>evennia.Msg</p></li>
<li><p>evennia.ON_DEMAND_HANDLER</p></li>
<li><p>evennia.OPTION_CLASSES</p></li>
<li><p>evennia.ObjectDB</p></li>
<li><p>evennia.OnDemandTask</p></li>
<li><p>evennia.PORTAL_MODE</p></li>
<li><p>evennia.PORTAL_SESSION_HANDLER</p></li>
<li><p>evennia.PROCESS_ID</p></li>
@ -302,6 +304,7 @@ with q, remove the break line and restart server when finished.</p></li>
</li>
<li class="toctree-l3"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.html">evennia.contrib.base_systems.godotwebsocket</a><ul>
<li class="toctree-l4"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a></li>
<li class="toctree-l4"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.test_webclient.html">evennia.contrib.base_systems.godotwebsocket.test_webclient</a></li>
<li class="toctree-l4"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.text2bbcode.html">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a></li>
<li class="toctree-l4"><a class="reference internal" href="evennia.contrib.base_systems.godotwebsocket.webclient.html">evennia.contrib.base_systems.godotwebsocket.webclient</a></li>
</ul>
@ -709,6 +712,10 @@ with q, remove the break line and restart server when finished.</p></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.manager.html">evennia.scripts.manager</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.models.html">evennia.scripts.models</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.monitorhandler.html">evennia.scripts.monitorhandler</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.ondemandhandler.html">evennia.scripts.ondemandhandler</a><ul>
<li class="toctree-l3"><a class="reference internal" href="evennia.scripts.ondemandhandler.html#usage">Usage</a></li>
</ul>
</li>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.scripthandler.html">evennia.scripts.scripthandler</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.scripts.html">evennia.scripts.scripts</a></li>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.taskhandler.html">evennia.scripts.taskhandler</a></li>

View file

@ -121,6 +121,10 @@ timed effects.</p>
<li class="toctree-l1"><a class="reference internal" href="evennia.scripts.manager.html">evennia.scripts.manager</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.scripts.models.html">evennia.scripts.models</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.scripts.monitorhandler.html">evennia.scripts.monitorhandler</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.scripts.ondemandhandler.html">evennia.scripts.ondemandhandler</a><ul>
<li class="toctree-l2"><a class="reference internal" href="evennia.scripts.ondemandhandler.html#usage">Usage</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="evennia.scripts.scripthandler.html">evennia.scripts.scripthandler</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.scripts.scripts.html">evennia.scripts.scripts</a></li>
<li class="toctree-l1"><a class="reference internal" href="evennia.scripts.taskhandler.html">evennia.scripts.taskhandler</a></li>

View file

@ -17,7 +17,7 @@
<link rel="shortcut icon" href="../_static/favicon.ico"/>
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="evennia.scripts.scripthandler" href="evennia.scripts.scripthandler.html" />
<link rel="next" title="evennia.scripts.ondemandhandler" href="evennia.scripts.ondemandhandler.html" />
<link rel="prev" title="evennia.scripts.models" href="evennia.scripts.models.html" />
</head><body>
@ -34,7 +34,7 @@
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="evennia.scripts.scripthandler.html" title="evennia.scripts.scripthandler"
<a href="evennia.scripts.ondemandhandler.html" title="evennia.scripts.ondemandhandler"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="evennia.scripts.models.html" title="evennia.scripts.models"
@ -70,8 +70,8 @@
<p class="topless"><a href="evennia.scripts.models.html"
title="previous chapter">evennia.scripts.models</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="evennia.scripts.scripthandler.html"
title="next chapter">evennia.scripts.scripthandler</a></p>
<p class="topless"><a href="evennia.scripts.ondemandhandler.html"
title="next chapter">evennia.scripts.ondemandhandler</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
@ -250,7 +250,7 @@ all kwargs must be possible to pickle!</p></li>
<a href="../py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="evennia.scripts.scripthandler.html" title="evennia.scripts.scripthandler"
<a href="evennia.scripts.ondemandhandler.html" title="evennia.scripts.ondemandhandler"
>next</a> |</li>
<li class="right" >
<a href="evennia.scripts.models.html" title="evennia.scripts.models"

View file

@ -0,0 +1,556 @@
<!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.scripts.ondemandhandler &#8212; Evennia latest 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.scripts.scripthandler" href="evennia.scripts.scripthandler.html" />
<link rel="prev" title="evennia.scripts.monitorhandler" href="evennia.scripts.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="evennia.scripts.scripthandler.html" title="evennia.scripts.scripthandler"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="evennia.scripts.monitorhandler.html" title="evennia.scripts.monitorhandler"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="evennia-api.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-4"><a href="evennia.scripts.html" accesskey="U">evennia.scripts</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.scripts.ondemandhandler</a></li>
</ul>
</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.scripts.ondemandhandler</a><ul>
<li><a class="reference internal" href="#usage">Usage</a></li>
</ul>
</li>
</ul>
<h4>Previous topic</h4>
<p class="topless"><a href="evennia.scripts.monitorhandler.html"
title="previous chapter">evennia.scripts.monitorhandler</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="evennia.scripts.scripthandler.html"
title="next chapter">evennia.scripts.scripthandler</a></p>
<div role="note" aria-label="source link">
<!--h3>This Page</h3-->
<ul class="this-page-menu">
<li><a href="../_sources/api/evennia.scripts.ondemandhandler.md.txt"
rel="nofollow">Show Page Source</a></li>
</ul>
</div><h3>Links</h3>
<ul>
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
<li><a href="https://github.com/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>Doc Versions</h3>
<ul>
<li><a href="evennia.scripts.ondemandhandler.html">latest (main branch)</a></li>
<li><a href="../../3.x/index.html">v3.0.0 branch (outdated)</a></li>
<li><a href="../../2.x/index.html">v2.0.0 branch (outdated)</a></li>
<li><a href="../../1.x/index.html">v1.0.0 branch (outdated)</a></li>
<li><a href="../../0.x/index.html">v0.9.5 branch (outdated)</a></li>
</ul>
</div>
</div>
<div class="bodywrapper">
<div class="body" role="main">
<section id="module-evennia.scripts.ondemandhandler">
<span id="evennia-scripts-ondemandhandler"></span><h1>evennia.scripts.ondemandhandler<a class="headerlink" href="#module-evennia.scripts.ondemandhandler" title="Permalink to this headline"></a></h1>
<p>Helper to handle on-demand requests, allowing a system to change state only when a player or system
actually needs the information. This is a very efficient way to handle gradual changes, requiring
not computer resources until the state is actually needed.</p>
<p>For example, consider a flowering system, where a seed sprouts, grows and blooms over a certain time.
One _could_ implement this with e.g. a Script or a ticker that gradually moves the flower along
its stages of growth. But what if that flower is in a remote location, and no one is around to see it?
You are then wasting computational resources on something that no one is looking at.</p>
<p>The truth is that most of the time, players are not looking at most of the things in the game. They
_only_ need to know about which state the flower is in when they are actually looking at it, or
when they are in the same room as it (so it can be incorporated in the room description). This is
where on-demand handling comes in.</p>
<p>This is the basic principle, using the flowering system as an example.</p>
<ol class="arabic simple">
<li><dl class="simple">
<dt>Someone plants a seed in a room (could also be automated). The seed is in a “seedling” state.</dt><dd><p>We store the time it was planted (this is the important bit).</p>
</dd>
</dl>
</li>
<li><p>A player enters the room or looks at the plant. We check the time it was planted, and calculate</p></li>
</ol>
<blockquote>
<div><p>how much time has passed since it was planted. If enough time has passed, we change the state to
“sprouting” and probably change its description to reflect this.</p>
</div></blockquote>
<ol class="arabic simple" start="3">
<li><p>If a player looks at the plant and not enough time has passed, it keeps the last updated state.</p></li>
<li><p>Eventually, it will be bloom time, and the plant will change to a “blooming” state when the
player looks.</p></li>
<li><p>If no player ever comes around to look at the plant, it will never change state, and if they show
up after a long time, it may not show as a “wilted” state or be outright deleted when observed,
since too long time has passed and the plant has died.</p></li>
</ol>
<p>With a system like this you could have growing plants all over your world and computing usage would
only scale by how many players you have exploring your world. The players will not know the difference
between this and a system that is always running, but your server will thank you.</p>
<p>There is only one situation where this system is not ideal, and that is when a player should be
informed of the state change _even if they perform no <a href="#id1"><span class="problematic" id="id2">action_</span></a>. That is, even if they are just idling
in the room, they should get a message like the plant suddenly blooms (or, more commonly, for
messages like you are feeling hungry). For this you still probably need to use one of Evennias
built-in timers or tickers instead. But most of the time you should really consider using on-demand
handling instead.</p>
<section id="usage">
<h2>Usage<a class="headerlink" href="#usage" title="Permalink to this headline"></a></h2>
<div class="highlight-default 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">ON_DEMAND_HANDLER</span>
<span class="c1"># create a new on-demand task</span>
<span class="n">flower</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">Flower</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="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">add_task</span><span class="p">(</span>
<span class="n">flower</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">&quot;flowering&quot;</span><span class="p">,</span>
<span class="n">stages</span><span class="o">=</span><span class="p">{</span><span class="mi">0</span><span class="p">:</span> <span class="s2">&quot;seedling&quot;</span><span class="p">,</span> <span class="mi">120</span><span class="p">:</span> <span class="s2">&quot;sprouting&quot;</span><span class="p">,</span>
<span class="mi">300</span><span class="p">:</span> <span class="s2">&quot;blooming&quot;</span><span class="p">,</span> <span class="mi">600</span><span class="p">:</span> <span class="s2">&quot;wilted&quot;</span><span class="p">,</span> <span class="mi">700</span><span class="p">:</span> <span class="s2">&quot;dead&quot;</span><span class="p">})</span>
<span class="c1"># later, when we want to check the state of the plant (e.g. in a command),</span>
<span class="n">state</span> <span class="o">=</span> <span class="n">ON_DEMAND_HANDLER</span><span class="o">.</span><span class="n">get_stage</span><span class="p">(</span><span class="s2">&quot;flowering&quot;</span><span class="p">,</span> <span class="n">last_checked</span><span class="o">=</span><span class="n">plant</span><span class="o">.</span><span class="n">planted_time</span><span class="p">)</span>
</pre></div>
</div>
<dl class="py class">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask">
<em class="property">class </em><code class="sig-prename descclassname">evennia.scripts.ondemandhandler.</code><code class="sig-name descname">OnDemandTask</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">key</span></em>, <em class="sig-param"><span class="n">category</span></em>, <em class="sig-param"><span class="n">stages</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">autostart</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></p>
<p>Stores information about an on-demand task.</p>
<p>Default property:
- <strong>default_stage_function (callable)</strong>: This is called if no stage function is given in the stages dict.</p>
<blockquote>
<div><p>This is meant for changing the task itself (such as restarting it). Actual game code should
be handled elsewhere, by checking this task. See the <strong>stagefunc_*</strong> static methods for examples
of how to manipulate the task when a stage is reached.</p>
</div></blockquote>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.runtime">
<em class="property">static </em><code class="sig-name descname">runtime</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask.runtime"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.runtime" title="Permalink to this definition"></a></dt>
<dd><p>Wraps the gametime.runtime() function.</p>
<p>Need to import here to avoid circular imports during server reboot.
Its a callable to allow easier unit testing.</p>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_loop">
<em class="property">static </em><code class="sig-name descname">stagefunc_loop</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">task</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask.stagefunc_loop"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_loop" title="Permalink to this definition"></a></dt>
<dd><p>Attach this to the last stage to have the task start over from
the beginning</p>
<p class="rubric">Example</p>
<p>stages = {0: “seedling”, 120: “flowering”, 300: “dead”, (“_loop”,
OnDemandTask.stagefunc_loop)}</p>
<p>Note that the “respawn” state will never actually be visible as a state to
the user, instead once it reaches this state, it will <em>immediately</em> loop
and the new looped state will be shown and returned to the user. So it
can an idea to mark that end state with a <strong>_</strong> just to indicate this fact.</p>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_bounce">
<em class="property">static </em><code class="sig-name descname">stagefunc_bounce</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">task</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask.stagefunc_bounce"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_bounce" title="Permalink to this definition"></a></dt>
<dd><p>This endfunc will have the task reverse direction and go through the stages in
reverse order. This stage-function must be placed at both ends of the stage sequence
for the bounce to continue indefinitely.</p>
<p class="rubric">Example</p>
<dl class="simple">
<dt>stages = {0: (“cool”, OnDemandTask.stagefunc_bounce),</dt><dd><p>50: “lukewarm”,
150: “warm”,
300: “hot”,
300: (“HOT!”, OnDemandTask.stagefunc_bounce)}</p>
</dd>
</dl>
</dd></dl>
<dl class="py attribute">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.default_stage_function">
<code class="sig-name descname">default_stage_function</code><em class="property"> = None</em><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.default_stage_function" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.__init__">
<code class="sig-name descname">__init__</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">key</span></em>, <em class="sig-param"><span class="n">category</span></em>, <em class="sig-param"><span class="n">stages</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">autostart</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask.__init__"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.__init__" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>key</strong> (<em>str</em>) A unique identifier for the task.</p></li>
<li><p><strong>stages</strong> (<em>dict</em><em>, </em><em>optional</em>) A dictionary <strong>{dt: str}</strong> or <strong>{int or float: (str, callable)}</strong>
of time-deltas (in seconds) and the stage name they represent. If the value is a
tuple, the first element is the name of the stage and the second is a callable
that will be called when that stage is <em>first</em> reached. Warning: This callable
is <em>only</em> triggered if the stage is actually checked/retrieved while the task is
in that stage checks - its _not_ guaranteed to be called, even if the task
time-wise goes through all its stages. Each callable must be picklable (so normally
it should be a stand-alone function), and takes one argument - this OnDemandTask,
which it can be modified in-place as needed. This can be used to loop a task or do
other changes to the task.</p></li>
<li><p><strong>autostart</strong> (<em>bool</em><em>, </em><em>optional</em>) If <strong>last_checked</strong> is <strong>None</strong>, and this is <strong>False</strong>, then the
time will not start counting until the first call of <strong>get_dt</strong> or <strong>get_stage</strong>. If
<strong>True</strong>, creating the task will immediately make a hidden check and start the timer.</p></li>
</ul>
</dd>
</dl>
<p class="rubric">Examples</p>
<dl>
<dt>stages = {0: “seedling”,</dt><dd><blockquote>
<div><p>120: “sprouting”,
300: “blooming”,
600: “wilted”,
700: “dead”</p>
</div></blockquote>
<p>}</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.check">
<code class="sig-name descname">check</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">autostart</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask.check"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.check" title="Permalink to this definition"></a></dt>
<dd><p>Check the current stage of the task and return the time-delta to the next stage.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>autostart</strong> (<em>bool</em><em>, </em><em>optional</em>) If this is set, and the task has not been started yet,
it will be started by this check. This is mainly used internally.</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><em>tuple</em> A tuple (dt, stage) where <strong>dt</strong> is the time-delta (in seconds) since the test
started (or since it started its latest iteration). and <strong>stage</strong> is the name of the
current stage. If no stages are defined, <strong>stage</strong> will always be <strong>None</strong>. Use <strong>get_dt</strong> and
<strong>get_stage</strong> to get only one of these values.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.get_dt">
<code class="sig-name descname">get_dt</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask.get_dt"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.get_dt" title="Permalink to this definition"></a></dt>
<dd><p>Get the time-delta since last check.</p>
<dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p><em>int</em> The time since the last check, or 0 if this is the first time the task is checked.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandTask.get_stage">
<code class="sig-name descname">get_stage</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandTask.get_stage"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandTask.get_stage" title="Permalink to this definition"></a></dt>
<dd><p>Get the current stage of the task. If no stage was given, this will return <strong>None</strong> but
still update the last_checked time.</p>
<dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p><em>str or None</em> The current stage of the task, or <strong>None</strong> if no stages are set.</p>
</dd>
</dl>
</dd></dl>
</dd></dl>
<dl class="py class">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler">
<em class="property">class </em><code class="sig-prename descclassname">evennia.scripts.ondemandhandler.</code><code class="sig-name descname">OnDemandHandler</code><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></p>
<p>A singleton handler for managing on-demand state changes. Its main function is to persistently
track the time (in seconds) between a state change and the next. How you make use of this
information is up to your particular system.</p>
<p>Contrary to just using the <strong>time</strong> module, this will also account for server restarts.</p>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.__init__">
<code class="sig-name descname">__init__</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.__init__"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.__init__" title="Permalink to this definition"></a></dt>
<dd><p>Initialize self. See help(type(self)) for accurate signature.</p>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.load">
<code class="sig-name descname">load</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.load"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.load" title="Permalink to this definition"></a></dt>
<dd><p>Load the on-demand timers from ServerConfig storage.</p>
<p>This should be automatically called when Evennia starts.</p>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.save">
<code class="sig-name descname">save</code><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.save"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.save" title="Permalink to this definition"></a></dt>
<dd><p>Save the on-demand timers to ServerConfig storage. Should be called when Evennia shuts down.</p>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.add">
<code class="sig-name descname">add</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">key</span></em>, <em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">stages</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">autostart</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.add"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.add" title="Permalink to this definition"></a></dt>
<dd><p>Add a new on-demand task.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>key</strong> (<em>str</em><em>, </em><em>callable</em><em>, </em><a class="reference internal" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><em>OnDemandTask</em></a><em> or </em><em>Object</em>) A unique identifier for the task. If this
is a callable, it will be called without arguments. If a db-Object, it will be
converted to a string representation (which will include its (#dbref). If an
<strong>OnDemandTask</strong>, then all other arguments are ignored and the task is simply added
as-is.</p></li>
<li><p><strong>category</strong> (<em>str</em><em> or </em><em>callable</em><em>, </em><em>optional</em>) A category to group the task under. If given, it
must also be given when checking the task.</p></li>
<li><p><strong>stages</strong> (<em>dict</em><em>, </em><em>optional</em>) A dictionary {dt: str}, of time-deltas (in seconds) and the
stage which should be entered after that much time has passed. autostart (bool,</p></li>
<li><p><strong>optional</strong><strong>)</strong> If <strong>True</strong>, creating the task will immediately make a hidden
check and start the timer.</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><p><em>OnDemandTask</em> </p>
<dl class="simple">
<dt>The created task (or the same that was added, if given an <strong>OnDemandTask</strong></dt><dd><p>as a <strong>key</strong>). Use <strong>task.get_dt()</strong> and <strong>task.get_stage()</strong> to get data from it manually.</p>
</dd>
</dl>
</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.batch_add">
<code class="sig-name descname">batch_add</code><span class="sig-paren">(</span><em class="sig-param"><span class="o">*</span><span class="n">tasks</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.batch_add"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.batch_add" title="Permalink to this definition"></a></dt>
<dd><p>Add multiple on-demand tasks at once.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>*tasks</strong> (<a class="reference internal" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><em>OnDemandTask</em></a>) A set of OnDemandTasks to add.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.remove">
<code class="sig-name descname">remove</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">key</span></em>, <em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.remove"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.remove" title="Permalink to this definition"></a></dt>
<dd><p>Remove an on-demand task.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>key</strong> (<em>str</em><em>, </em><em>callable</em><em>, </em><a class="reference internal" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><em>OnDemandTask</em></a><em> or </em><em>Object</em>) The unique identifier for the task. If a callable, will
be called without arguments. If an Object, will be converted to a string. If an <strong>OnDemandTask</strong>,
then all other arguments are ignored and the task will be used to identify the task to remove.</p></li>
<li><p><strong>category</strong> (<em>str</em><em> or </em><em>callable</em><em>, </em><em>optional</em>) The category of the task.</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><em>OnDemandTask or None</em> The removed task, or <strong>None</strong> if no task was found.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.batch_remove">
<code class="sig-name descname">batch_remove</code><span class="sig-paren">(</span><em class="sig-param"><span class="o">*</span><span class="n">keys</span></em>, <em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.batch_remove"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.batch_remove" title="Permalink to this definition"></a></dt>
<dd><p>Remove multiple on-demand tasks at once, potentially within a given category.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>*keys</strong> (<em>str</em><em>, </em><em>callable</em><em>, </em><a class="reference internal" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><em>OnDemandTask</em></a><em> or </em><em>Object</em>) The unique identifiers for the tasks. If
a callable, will be called without arguments. If an Object, will be converted to a
string. If an <strong>OnDemandTask</strong>, then all other arguments are ignored and the task will
be used to identify the task to remove.</p></li>
<li><p><strong>category</strong> (<em>str</em><em> or </em><em>callable</em><em>, </em><em>optional</em>) The category of the tasks.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.all">
<code class="sig-name descname">all</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">all_on_none</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.all"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.all" title="Permalink to this definition"></a></dt>
<dd><p>Get all on-demand tasks.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>category</strong> (<em>str</em><em>, </em><em>optional</em>) The category of the tasks.</p></li>
<li><p><strong>all_on_none</strong> (<em>bool</em><em>, </em><em>optional</em>) Determines what to return if <strong>category</strong> is <strong>None</strong>.
If <strong>True</strong>, all tasks will be returned. If <strong>False</strong>, only tasks without a category
will be returned.</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><em>dict</em> A dictionary of all on-demand task, on the form <strong>{(key, category): task), …}</strong>.
Use <strong>task.get_dt()</strong> or <strong>task.get_stage()</strong> to get the time-delta or stage of each task
manually.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.clear">
<code class="sig-name descname">clear</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em>, <em class="sig-param"><span class="n">all_on_none</span><span class="o">=</span><span class="default_value">True</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.clear"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.clear" title="Permalink to this definition"></a></dt>
<dd><p>Clear all on-demand tasks.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>category</strong> (<em>str</em><em>, </em><em>optional</em>) The category of the tasks to clear. What <strong>None</strong> means is determined
by the <strong>all_on_none</strong> kwarg.</p></li>
<li><p><strong>all_on_none</strong> (<em>bool</em><em>, </em><em>optional</em>) Determines what to clear if <strong>category</strong> is <strong>None</strong>. If <strong>True</strong>,
clear all tasks, if <strong>False</strong>, only clear tasks with no category.</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.get">
<code class="sig-name descname">get</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">key</span></em>, <em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.get"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.get" title="Permalink to this definition"></a></dt>
<dd><p>Get an on-demand task. This will _not_ check it.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>key</strong> (<em>str</em><em>, </em><em>callable</em><em>, </em><a class="reference internal" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><em>OnDemandTask</em></a><em> or </em><em>Object</em>) The unique identifier for the task. If a
callable, will be called without arguments. If an Object, will be converted to a string.
If an <strong>OnDemandTask</strong>, then all other arguments are ignored and the task will be used
(only useful to check the task is the same).</p></li>
<li><p><strong>category</strong> (<em>str</em><em>, </em><em>optional</em>) The category of the task. If unset, this will only return
tasks with no category.</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><em>OnDemandTask or None</em> The task, or <strong>None</strong> if no task was found.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.get_dt">
<code class="sig-name descname">get_dt</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">key</span></em>, <em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.get_dt"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.get_dt" title="Permalink to this definition"></a></dt>
<dd><p>Get the time-delta since the task started.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>key</strong> (<em>str</em><em>, </em><em>callable</em><em>, </em><a class="reference internal" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><em>OnDemandTask</em></a><em> or </em><em>Object</em>) The unique identifier for the task. If a
callable, will be called without arguments. If an Object, will be converted to a string.
If an <strong>OnDemandTask</strong>, then all other arguments are ignored and the task will be used
to identify the task to get the time-delta from.</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><em>int or None</em> The time since the last check, or <strong>None</strong> if no task was found.</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt id="evennia.scripts.ondemandhandler.OnDemandHandler.get_stage">
<code class="sig-name descname">get_stage</code><span class="sig-paren">(</span><em class="sig-param"><span class="n">key</span></em>, <em class="sig-param"><span class="n">category</span><span class="o">=</span><span class="default_value">None</span></em><span class="sig-paren">)</span><a class="reference internal" href="../_modules/evennia/scripts/ondemandhandler.html#OnDemandHandler.get_stage"><span class="viewcode-link">[source]</span></a><a class="headerlink" href="#evennia.scripts.ondemandhandler.OnDemandHandler.get_stage" title="Permalink to this definition"></a></dt>
<dd><p>Get the current stage of an on-demand task.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>key</strong> (<em>str</em><em>, </em><em>callable</em><em>, </em><a class="reference internal" href="#evennia.scripts.ondemandhandler.OnDemandTask" title="evennia.scripts.ondemandhandler.OnDemandTask"><em>OnDemandTask</em></a><em> or </em><em>Object</em>) The unique identifier for the task. If a
callable, will be called without arguments. If an Object, will be converted to a string.
If an <strong>OnDemandTask</strong>, then all other arguments are ignored and the task will be used
to identify the task to get the stage from.</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p><em>str or None</em> The current stage of the task, or <strong>None</strong> if no task was found.</p>
</dd>
</dl>
</dd></dl>
</dd></dl>
</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="evennia.scripts.scripthandler.html" title="evennia.scripts.scripthandler"
>next</a> |</li>
<li class="right" >
<a href="evennia.scripts.monitorhandler.html" title="evennia.scripts.monitorhandler"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>
<li class="nav-item nav-item-2"><a href="evennia-api.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-3"><a href="evennia.html" >evennia</a> &#187;</li>
<li class="nav-item nav-item-4"><a href="evennia.scripts.html" >evennia.scripts</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">evennia.scripts.ondemandhandler</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
&#169; Copyright 2023, The Evennia developer community.
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
</div>
</body>
</html>

View file

@ -18,7 +18,7 @@
<link rel="index" title="Index" href="../genindex.html" />
<link rel="search" title="Search" href="../search.html" />
<link rel="next" title="evennia.scripts.scripts" href="evennia.scripts.scripts.html" />
<link rel="prev" title="evennia.scripts.monitorhandler" href="evennia.scripts.monitorhandler.html" />
<link rel="prev" title="evennia.scripts.ondemandhandler" href="evennia.scripts.ondemandhandler.html" />
</head><body>
@ -37,7 +37,7 @@
<a href="evennia.scripts.scripts.html" title="evennia.scripts.scripts"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="evennia.scripts.monitorhandler.html" title="evennia.scripts.monitorhandler"
<a href="evennia.scripts.ondemandhandler.html" title="evennia.scripts.ondemandhandler"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>
@ -67,8 +67,8 @@
</div>
<script>$('#searchbox').show(0);</script>
<h4>Previous topic</h4>
<p class="topless"><a href="evennia.scripts.monitorhandler.html"
title="previous chapter">evennia.scripts.monitorhandler</a></p>
<p class="topless"><a href="evennia.scripts.ondemandhandler.html"
title="previous chapter">evennia.scripts.ondemandhandler</a></p>
<h4>Next topic</h4>
<p class="topless"><a href="evennia.scripts.scripts.html"
title="next chapter">evennia.scripts.scripts</a></p>
@ -265,7 +265,7 @@ If no key is given, delete <em>all</em> scripts on the object!</p>
<a href="evennia.scripts.scripts.html" title="evennia.scripts.scripts"
>next</a> |</li>
<li class="right" >
<a href="evennia.scripts.monitorhandler.html" title="evennia.scripts.monitorhandler"
<a href="evennia.scripts.ondemandhandler.html" title="evennia.scripts.ondemandhandler"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="../index.html">Evennia latest</a> &#187;</li>
<li class="nav-item nav-item-1"><a href="../Evennia-API.html" >API Summary</a> &#187;</li>

View file

@ -365,7 +365,7 @@ Taghandler directly for that). Tag keys are not case sensitive.</p>
use <strong>obj.tags.add()</strong> instead.</p>
<p>Example:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">RogueCharacter</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
<span class="n">guild</span> <span class="o">=</span> <span class="n">TagProperty</span><span class="p">(</span><span class="s2">&quot;thieves_guild&quot;</span><span class="p">,</span> <span class="s2">&quot;merchant_guild&quot;</span><span class="p">)</span>
<span class="n">guild</span> <span class="o">=</span> <span class="n">TagCategoryProperty</span><span class="p">(</span><span class="s2">&quot;thieves_guild&quot;</span><span class="p">,</span> <span class="s2">&quot;merchant_guild&quot;</span><span class="p">)</span>
</pre></div>
</div>
</dd></dl>

View file

@ -348,7 +348,7 @@ indentation.</p>
<dl class="py attribute">
<dt id="evennia.utils.eveditor.CmdEditorGroup.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = [':w', ':&gt;', ':I', ':&lt;', ':DD', ':r', ':wq', ':fd', ':x', ':=', ':', ':dd', ':q', ':echo', ':q!', '::', ':s', ':h', ':y', ':fi', ':i', ':A', ':::', ':p', ':dw', ':f', ':j', ':uu', ':S', ':!', ':u', ':UU']</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = [':r', ':q!', ':&gt;', ':wq', ':u', ':p', '::', ':&lt;', ':fd', ':w', ':A', ':!', ':i', ':f', ':=', ':', ':UU', ':dw', ':I', ':uu', ':y', ':h', ':x', ':::', ':s', ':DD', ':q', ':j', ':dd', ':echo', ':S', ':fi']</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -376,7 +376,7 @@ efficient presentation.</p>
<dl class="py attribute">
<dt id="evennia.utils.eveditor.CmdEditorGroup.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': ':w :&gt; :I :&lt; :DD :r :wq :fd :x := : :dd :q :echo :q! :: :s :h :y :fi :i :A ::: :p :dw :f :j :uu :S :! :u :UU', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :w :&gt; :I :&lt; :DD :r :wq :fd :x := : :dd :q :echo :q! :: :s :h :y :fi :i :A ::: :p :dw :f :j :uu :S :! :u :UU', 'tags': '', 'text': '\n Commands for the editor\n '}</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': ':r :q! :&gt; :wq :u :p :: :&lt; :fd :w :A :! :i :f := : :UU :dw :I :uu :y :h :x ::: :s :DD :q :j :dd :echo :S :fi', 'category': 'general', 'key': ':editor_command_group', 'no_prefix': ' :r :q! :&gt; :wq :u :p :: :&lt; :fd :w :A :! :i :f := : :UU :dw :I :uu :y :h :x ::: :s :DD :q :j :dd :echo :S :fi', 'tags': '', 'text': '\n Commands for the editor\n '}</em><a class="headerlink" href="#evennia.utils.eveditor.CmdEditorGroup.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -951,7 +951,7 @@ single question.</p>
<dl class="py attribute">
<dt id="evennia.utils.evmenu.CmdYesNoQuestion.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['a', '__nomatch_command', 'yes', 'y', 'abort', 'no', 'n']</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['a', 'no', 'n', 'abort', '__nomatch_command', 'y', 'yes']</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -977,7 +977,7 @@ single question.</p>
<dl class="py attribute">
<dt id="evennia.utils.evmenu.CmdYesNoQuestion.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'a __nomatch_command yes y abort no n', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' a __nomatch_command yes y abort no n', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'a no n abort __nomatch_command y yes', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' a no n abort __nomatch_command y yes', 'tags': '', 'text': '\n Handle a prompt for yes or no. Press [return] for the default choice.\n\n '}</em><a class="headerlink" href="#evennia.utils.evmenu.CmdYesNoQuestion.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -149,7 +149,7 @@ the <strong>caller.msg()</strong> construct every time the page is updated.</p>
<dl class="py attribute">
<dt id="evennia.utils.evmore.CmdMore.aliases">
<code class="sig-name descname">aliases</code><em class="property"> = ['a', 'p', 'quit', 'end', 'e', 'q', 'previous', 'abort', 'next', 't', 'top', 'n']</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.aliases" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">aliases</code><em class="property"> = ['a', 'q', 'quit', 'next', 'p', 'top', 'n', 'abort', 'previous', 'end', 'e', 't']</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.aliases" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py attribute">
@ -175,7 +175,7 @@ the <strong>caller.msg()</strong> construct every time the page is updated.</p>
<dl class="py attribute">
<dt id="evennia.utils.evmore.CmdMore.search_index_entry">
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'a p quit end e q previous abort next t top n', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' a p quit end e q previous abort next t top n', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.search_index_entry" title="Permalink to this definition"></a></dt>
<code class="sig-name descname">search_index_entry</code><em class="property"> = {'aliases': 'a q quit next p top n abort previous end e t', 'category': 'general', 'key': '__noinput_command', 'no_prefix': ' a q quit next p top n abort previous end e t', 'tags': '', 'text': '\n Manipulate the text paging. Catch no-input with aliases.\n '}</em><a class="headerlink" href="#evennia.utils.evmore.CmdMore.search_index_entry" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
</dd></dl>

View file

@ -255,6 +255,10 @@
<li><a href="api/evennia.prototypes.prototypes.html#evennia.prototypes.prototypes.PrototypeEvMore.__init__">(evennia.prototypes.prototypes.PrototypeEvMore method)</a>
</li>
<li><a href="api/evennia.scripts.monitorhandler.html#evennia.scripts.monitorhandler.MonitorHandler.__init__">(evennia.scripts.monitorhandler.MonitorHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.__init__">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.__init__">(evennia.scripts.ondemandhandler.OnDemandTask method)</a>
</li>
<li><a href="api/evennia.scripts.scripthandler.html#evennia.scripts.scripthandler.ScriptHandler.__init__">(evennia.scripts.scripthandler.ScriptHandler method)</a>
</li>
@ -697,6 +701,8 @@
<li><a href="api/evennia.prototypes.prototypes.html#evennia.prototypes.prototypes.DBPrototypeCache.add">(evennia.prototypes.prototypes.DBPrototypeCache method)</a>
</li>
<li><a href="api/evennia.scripts.monitorhandler.html#evennia.scripts.monitorhandler.MonitorHandler.add">(evennia.scripts.monitorhandler.MonitorHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.add">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.scripthandler.html#evennia.scripts.scripthandler.ScriptHandler.add">(evennia.scripts.scripthandler.ScriptHandler method)</a>
</li>
@ -1431,6 +1437,8 @@
<li><a href="api/evennia.objects.objects.html#evennia.objects.objects.ObjectSessionHandler.all">(evennia.objects.objects.ObjectSessionHandler method)</a>
</li>
<li><a href="api/evennia.scripts.monitorhandler.html#evennia.scripts.monitorhandler.MonitorHandler.all">(evennia.scripts.monitorhandler.MonitorHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.all">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.scripthandler.html#evennia.scripts.scripthandler.ScriptHandler.all">(evennia.scripts.scripthandler.ScriptHandler method)</a>
</li>
@ -1590,11 +1598,11 @@
<li><a href="api/evennia.server.portal.telnet.html#evennia.server.portal.telnet.TelnetProtocol.applicationDataReceived">applicationDataReceived() (evennia.server.portal.telnet.TelnetProtocol method)</a>
</li>
<li><a href="api/evennia.contrib.tutorials.evadventure.chargen.html#evennia.contrib.tutorials.evadventure.chargen.TemporaryCharacterSheet.apply">apply() (evennia.contrib.tutorials.evadventure.chargen.TemporaryCharacterSheet method)</a>
</li>
<li><a href="api/evennia.contrib.game_systems.turnbattle.tb_basic.html#evennia.contrib.game_systems.turnbattle.tb_basic.BasicCombatRules.apply_damage">apply_damage() (evennia.contrib.game_systems.turnbattle.tb_basic.BasicCombatRules method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api/evennia.contrib.game_systems.turnbattle.tb_basic.html#evennia.contrib.game_systems.turnbattle.tb_basic.BasicCombatRules.apply_damage">apply_damage() (evennia.contrib.game_systems.turnbattle.tb_basic.BasicCombatRules method)</a>
</li>
<li><a href="api/evennia.contrib.game_systems.turnbattle.tb_items.html#evennia.contrib.game_systems.turnbattle.tb_items.TBItemsCharacter.apply_turn_conditions">apply_turn_conditions() (evennia.contrib.game_systems.turnbattle.tb_items.TBItemsCharacter method)</a>
</li>
<li><a href="api/evennia.contrib.game_systems.turnbattle.tb_range.html#evennia.contrib.game_systems.turnbattle.tb_range.RangedCombatRules.approach">approach() (evennia.contrib.game_systems.turnbattle.tb_range.RangedCombatRules method)</a>
@ -3011,13 +3019,15 @@
</li>
<li><a href="api/evennia.contrib.game_systems.turnbattle.tb_basic.html#evennia.contrib.game_systems.turnbattle.tb_basic.BasicCombatRules">BasicCombatRules (class in evennia.contrib.game_systems.turnbattle.tb_basic)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api/evennia.contrib.grid.xyzgrid.xymap_legend.html#evennia.contrib.grid.xyzgrid.xymap_legend.BasicMapNode">BasicMapNode (class in evennia.contrib.grid.xyzgrid.xymap_legend)</a>
</li>
<li><a href="api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler.batch_add">batch_add() (evennia.typeclasses.attributes.AttributeHandler method)</a>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.batch_add">batch_add() (evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
<ul>
<li><a href="api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler.batch_add">(evennia.typeclasses.attributes.AttributeHandler method)</a>
</li>
<li><a href="api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.IAttributeBackend.batch_add">(evennia.typeclasses.attributes.IAttributeBackend method)</a>
</li>
<li><a href="api/evennia.typeclasses.tags.html#evennia.typeclasses.tags.TagHandler.batch_add">(evennia.typeclasses.tags.TagHandler method)</a>
@ -3025,8 +3035,12 @@
</ul></li>
<li><a href="api/evennia.prototypes.spawner.html#evennia.prototypes.spawner.batch_create_object">batch_create_object() (in module evennia.prototypes.spawner)</a>
</li>
<li><a href="api/evennia.typeclasses.tags.html#evennia.typeclasses.tags.TagHandler.batch_remove">batch_remove() (evennia.typeclasses.tags.TagHandler method)</a>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.batch_remove">batch_remove() (evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
<ul>
<li><a href="api/evennia.typeclasses.tags.html#evennia.typeclasses.tags.TagHandler.batch_remove">(evennia.typeclasses.tags.TagHandler method)</a>
</li>
</ul></li>
<li><a href="api/evennia.prototypes.spawner.html#evennia.prototypes.spawner.batch_update_objects_with_prototype">batch_update_objects_with_prototype() (in module evennia.prototypes.spawner)</a>
</li>
<li><a href="api/evennia.utils.batchprocessors.html#evennia.utils.batchprocessors.BatchCodeProcessor">BatchCodeProcessor (class in evennia.utils.batchprocessors)</a>
@ -3461,6 +3475,8 @@
<ul>
<li><a href="api/evennia.locks.lockhandler.html#evennia.locks.lockhandler.LockHandler.check">(evennia.locks.lockhandler.LockHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.check">(evennia.scripts.ondemandhandler.OnDemandTask method)</a>
</li>
<li><a href="api/evennia.server.throttle.html#evennia.server.throttle.Throttle.check">(evennia.server.throttle.Throttle method)</a>
</li>
@ -3613,6 +3629,8 @@
<li><a href="api/evennia.prototypes.prototypes.html#evennia.prototypes.prototypes.DBPrototypeCache.clear">(evennia.prototypes.prototypes.DBPrototypeCache method)</a>
</li>
<li><a href="api/evennia.scripts.monitorhandler.html#evennia.scripts.monitorhandler.MonitorHandler.clear">(evennia.scripts.monitorhandler.MonitorHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.clear">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.clear">(evennia.scripts.taskhandler.TaskHandler method)</a>
</li>
@ -4026,11 +4044,11 @@
<li><a href="api/evennia.commands.default.building.html#evennia.commands.default.building.CmdObjects">CmdObjects (class in evennia.commands.default.building)</a>
</li>
<li><a href="api/evennia.contrib.game_systems.barter.barter.html#evennia.contrib.game_systems.barter.barter.CmdOffer">CmdOffer (class in evennia.contrib.game_systems.barter.barter)</a>
</li>
<li><a href="api/evennia.commands.default.account.html#evennia.commands.default.account.CmdOOC">CmdOOC (class in evennia.commands.default.account)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api/evennia.commands.default.account.html#evennia.commands.default.account.CmdOOC">CmdOOC (class in evennia.commands.default.account)</a>
</li>
<li><a href="api/evennia.commands.default.account.html#evennia.commands.default.account.CmdOOCLook">CmdOOCLook (class in evennia.commands.default.account)</a>
</li>
<li><a href="api/evennia.commands.default.building.html#evennia.commands.default.building.CmdOpen">CmdOpen (class in evennia.commands.default.building)</a>
@ -5388,6 +5406,8 @@
<li><a href="api/evennia.contrib.base_systems.components.tests.html#evennia.contrib.base_systems.components.tests.ComponentTestB.default_single_tag">default_single_tag (evennia.contrib.base_systems.components.tests.ComponentTestB attribute)</a>
</li>
<li><a href="api/evennia.web.utils.adminsite.html#evennia.web.utils.adminsite.EvenniaAdminApp.default_site">default_site (evennia.web.utils.adminsite.EvenniaAdminApp attribute)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.default_stage_function">default_stage_function (evennia.scripts.ondemandhandler.OnDemandTask attribute)</a>
</li>
<li><a href="api/evennia.contrib.base_systems.components.tests.html#evennia.contrib.base_systems.components.tests.ComponentTestB.default_tag">default_tag (evennia.contrib.base_systems.components.tests.ComponentTestB attribute)</a>
</li>
@ -5436,11 +5456,11 @@
<li><a href="api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom">DefaultRoom (class in evennia.objects.objects)</a>
</li>
<li><a href="api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom.DoesNotExist">DefaultRoom.DoesNotExist</a>
</li>
<li><a href="api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom.MultipleObjectsReturned">DefaultRoom.MultipleObjectsReturned</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api/evennia.objects.objects.html#evennia.objects.objects.DefaultRoom.MultipleObjectsReturned">DefaultRoom.MultipleObjectsReturned</a>
</li>
<li><a href="api/evennia.scripts.scripts.html#evennia.scripts.scripts.DefaultScript">DefaultScript (class in evennia.scripts.scripts)</a>
</li>
<li><a href="api/evennia.scripts.scripts.html#evennia.scripts.scripts.DefaultScript.DoesNotExist">DefaultScript.DoesNotExist</a>
@ -6686,6 +6706,13 @@
<ul>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html#module-evennia.contrib.base_systems.godotwebsocket.test_text2bbcode">module</a>
</li>
</ul></li>
<li>
evennia.contrib.base_systems.godotwebsocket.test_webclient
<ul>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#module-evennia.contrib.base_systems.godotwebsocket.test_webclient">module</a>
</li>
</ul></li>
<li>
@ -8095,6 +8122,13 @@
<ul>
<li><a href="api/evennia.scripts.monitorhandler.html#module-evennia.scripts.monitorhandler">module</a>
</li>
</ul></li>
<li>
evennia.scripts.ondemandhandler
<ul>
<li><a href="api/evennia.scripts.ondemandhandler.html#module-evennia.scripts.ondemandhandler">module</a>
</li>
</ul></li>
<li>
@ -10336,6 +10370,8 @@
<li><a href="api/evennia.objects.objects.html#evennia.objects.objects.ObjectSessionHandler.get">(evennia.objects.objects.ObjectSessionHandler method)</a>
</li>
<li><a href="api/evennia.prototypes.prototypes.html#evennia.prototypes.prototypes.DBPrototypeCache.get">(evennia.prototypes.prototypes.DBPrototypeCache method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.get">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.scripthandler.html#evennia.scripts.scripthandler.ScriptHandler.get">(evennia.scripts.scripthandler.ScriptHandler method)</a>
</li>
@ -10706,6 +10742,12 @@
<li><a href="api/evennia.contrib.rpg.rpsystem.rpsystem.html#evennia.contrib.rpg.rpsystem.rpsystem.ContribRPObject.get_display_things">(evennia.contrib.rpg.rpsystem.rpsystem.ContribRPObject method)</a>
</li>
<li><a href="api/evennia.objects.objects.html#evennia.objects.objects.DefaultObject.get_display_things">(evennia.objects.objects.DefaultObject method)</a>
</li>
</ul></li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.get_dt">get_dt() (evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
<ul>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.get_dt">(evennia.scripts.ondemandhandler.OnDemandTask method)</a>
</li>
</ul></li>
<li><a href="api/evennia.utils.utils.html#evennia.utils.utils.get_evennia_pids">get_evennia_pids() (in module evennia.utils.utils)</a>
@ -11018,6 +11060,12 @@
<ul>
<li><a href="api/evennia.contrib.grid.xyzgrid.xymap_legend.html#evennia.contrib.grid.xyzgrid.xymap_legend.TransitionMapNode.get_spawn_xyz">(evennia.contrib.grid.xyzgrid.xymap_legend.TransitionMapNode method)</a>
</li>
</ul></li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.get_stage">get_stage() (evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
<ul>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.get_stage">(evennia.scripts.ondemandhandler.OnDemandTask method)</a>
</li>
</ul></li>
<li><a href="api/evennia.contrib.grid.extended_room.extended_room.html#evennia.contrib.grid.extended_room.extended_room.ExtendedRoom.get_stateful_desc">get_stateful_desc() (evennia.contrib.grid.extended_room.extended_room.ExtendedRoom method)</a>
@ -13332,6 +13380,8 @@
<li><a href="api/evennia.help.filehelp.html#evennia.help.filehelp.FileHelpStorageHandler.load">(evennia.help.filehelp.FileHelpStorageHandler method)</a>
</li>
<li><a href="api/evennia.objects.models.html#evennia.objects.models.ContentsHandler.load">(evennia.objects.models.ContentsHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.load">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.load">(evennia.scripts.taskhandler.TaskHandler method)</a>
</li>
@ -15037,6 +15087,8 @@
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.html#module-evennia.contrib.base_systems.godotwebsocket">evennia.contrib.base_systems.godotwebsocket</a>
</li>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html#module-evennia.contrib.base_systems.godotwebsocket.test_text2bbcode">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</a>
</li>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#module-evennia.contrib.base_systems.godotwebsocket.test_webclient">evennia.contrib.base_systems.godotwebsocket.test_webclient</a>
</li>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.text2bbcode.html#module-evennia.contrib.base_systems.godotwebsocket.text2bbcode">evennia.contrib.base_systems.godotwebsocket.text2bbcode</a>
</li>
@ -15439,6 +15491,8 @@
<li><a href="api/evennia.scripts.models.html#module-evennia.scripts.models">evennia.scripts.models</a>
</li>
<li><a href="api/evennia.scripts.monitorhandler.html#module-evennia.scripts.monitorhandler">evennia.scripts.monitorhandler</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#module-evennia.scripts.ondemandhandler">evennia.scripts.ondemandhandler</a>
</li>
<li><a href="api/evennia.scripts.scripthandler.html#module-evennia.scripts.scripthandler">evennia.scripts.scripthandler</a>
</li>
@ -16561,6 +16615,10 @@
<li><a href="api/evennia.server.portal.webclient.html#evennia.server.portal.webclient.WebSocketClient.onClose">(evennia.server.portal.webclient.WebSocketClient method)</a>
</li>
</ul></li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler">OnDemandHandler (class in evennia.scripts.ondemandhandler)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask">OnDemandTask (class in evennia.scripts.ondemandhandler)</a>
</li>
<li><a href="api/evennia.contrib.full_systems.evscaperoom.objects.html#evennia.contrib.full_systems.evscaperoom.objects.BaseConsumable.one_consume_only">one_consume_only (evennia.contrib.full_systems.evscaperoom.objects.BaseConsumable attribute)</a>
</li>
<li><a href="api/evennia.comms.models.html#evennia.comms.models.SubscriptionHandler.online">online() (evennia.comms.models.SubscriptionHandler method)</a>
@ -18097,6 +18155,8 @@
<li><a href="api/evennia.prototypes.prototypes.html#evennia.prototypes.prototypes.DBPrototypeCache.remove">(evennia.prototypes.prototypes.DBPrototypeCache method)</a>
</li>
<li><a href="api/evennia.scripts.monitorhandler.html#evennia.scripts.monitorhandler.MonitorHandler.remove">(evennia.scripts.monitorhandler.MonitorHandler method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.remove">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.scripthandler.html#evennia.scripts.scripthandler.ScriptHandler.remove">(evennia.scripts.scripthandler.ScriptHandler method)</a>
</li>
@ -18573,8 +18633,12 @@
</li>
<li><a href="api/evennia.contrib.full_systems.evscaperoom.menu.html#evennia.contrib.full_systems.evscaperoom.menu.run_option_menu">run_option_menu() (in module evennia.contrib.full_systems.evscaperoom.menu)</a>
</li>
<li><a href="api/evennia.utils.gametime.html#evennia.utils.gametime.runtime">runtime() (in module evennia.utils.gametime)</a>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.runtime">runtime() (evennia.scripts.ondemandhandler.OnDemandTask static method)</a>
<ul>
<li><a href="api/evennia.utils.gametime.html#evennia.utils.gametime.runtime">(in module evennia.utils.gametime)</a>
</li>
</ul></li>
<li><a href="api/evennia.contrib.base_systems.components.tests.html#evennia.contrib.base_systems.components.tests.RuntimeComponentTestC">RuntimeComponentTestC (class in evennia.contrib.base_systems.components.tests)</a>
</li>
</ul></td>
@ -18594,6 +18658,8 @@
<li><a href="api/evennia.scripts.monitorhandler.html#evennia.scripts.monitorhandler.MonitorHandler.save">save() (evennia.scripts.monitorhandler.MonitorHandler method)</a>
<ul>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandHandler.save">(evennia.scripts.ondemandhandler.OnDemandHandler method)</a>
</li>
<li><a href="api/evennia.scripts.taskhandler.html#evennia.scripts.taskhandler.TaskHandler.save">(evennia.scripts.taskhandler.TaskHandler method)</a>
</li>
<li><a href="api/evennia.scripts.tickerhandler.html#evennia.scripts.tickerhandler.TickerHandler.save">(evennia.scripts.tickerhandler.TickerHandler method)</a>
@ -19741,6 +19807,8 @@
<li><a href="api/evennia.contrib.base_systems.building_menu.tests.html#evennia.contrib.base_systems.building_menu.tests.TestBuildingMenu.setUp">(evennia.contrib.base_systems.building_menu.tests.TestBuildingMenu method)</a>
</li>
<li><a href="api/evennia.contrib.base_systems.components.tests.html#evennia.contrib.base_systems.components.tests.TestComponentSignals.setUp">(evennia.contrib.base_systems.components.tests.TestComponentSignals method)</a>
</li>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.setUp">(evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient method)</a>
</li>
<li><a href="api/evennia.contrib.base_systems.ingame_python.tests.html#evennia.contrib.base_systems.ingame_python.tests.TestCmdCallback.setUp">(evennia.contrib.base_systems.ingame_python.tests.TestCmdCallback method)</a>
</li>
@ -20084,6 +20152,10 @@
<li><a href="api/evennia.contrib.rpg.buffs.buff.html#evennia.contrib.rpg.buffs.buff.BaseBuff.stacking">stacking() (evennia.contrib.rpg.buffs.buff.BaseBuff property)</a>
</li>
<li><a href="api/evennia.contrib.rpg.buffs.buff.html#evennia.contrib.rpg.buffs.buff.BaseBuff.stacks">stacks (evennia.contrib.rpg.buffs.buff.BaseBuff attribute)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_bounce">stagefunc_bounce() (evennia.scripts.ondemandhandler.OnDemandTask static method)</a>
</li>
<li><a href="api/evennia.scripts.ondemandhandler.html#evennia.scripts.ondemandhandler.OnDemandTask.stagefunc_loop">stagefunc_loop() (evennia.scripts.ondemandhandler.OnDemandTask static method)</a>
</li>
<li><a href="api/evennia.contrib.rpg.buffs.buff.html#evennia.contrib.rpg.buffs.buff.BaseBuff.start">start (evennia.contrib.rpg.buffs.buff.BaseBuff attribute)</a>
</li>
@ -21359,10 +21431,18 @@
</li>
<li><a href="api/evennia.contrib.tutorials.tutorial_world.tests.html#evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldRooms.test_darkroom">test_darkroom() (evennia.contrib.tutorials.tutorial_world.tests.TestTutorialWorldRooms method)</a>
</li>
<li><a href="api/evennia.server.portal.tests.html#evennia.server.portal.tests.TestWebSocket.test_data_in">test_data_in() (evennia.server.portal.tests.TestWebSocket method)</a>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_in">test_data_in() (evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient method)</a>
<ul>
<li><a href="api/evennia.server.portal.tests.html#evennia.server.portal.tests.TestWebSocket.test_data_in">(evennia.server.portal.tests.TestWebSocket method)</a>
</li>
<li><a href="api/evennia.server.portal.tests.html#evennia.server.portal.tests.TestWebSocket.test_data_out">test_data_out() (evennia.server.portal.tests.TestWebSocket method)</a>
</ul></li>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient.test_data_out">test_data_out() (evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient method)</a>
<ul>
<li><a href="api/evennia.server.portal.tests.html#evennia.server.portal.tests.TestWebSocket.test_data_out">(evennia.server.portal.tests.TestWebSocket method)</a>
</li>
</ul></li>
<li><a href="api/evennia.utils.verb_conjugation.tests.html#evennia.utils.verb_conjugation.tests.TestPronounMapping.test_default_mapping">test_default_mapping (evennia.utils.verb_conjugation.tests.TestPronounMapping attribute)</a>
</li>
<li><a href="api/evennia.utils.verb_conjugation.tests.html#evennia.utils.verb_conjugation.tests.TestPronounMapping.test_default_mapping_00_you">test_default_mapping_00_you() (evennia.utils.verb_conjugation.tests.TestPronounMapping method)</a>
@ -23120,6 +23200,8 @@
<li><a href="api/evennia.web.utils.tests.html#evennia.web.utils.tests.TestGeneralContext">TestGeneralContext (class in evennia.web.utils.tests)</a>
</li>
<li><a href="api/evennia.contrib.utils.git_integration.tests.html#evennia.contrib.utils.git_integration.tests.TestGitIntegration">TestGitIntegration (class in evennia.contrib.utils.git_integration.tests)</a>
</li>
<li><a href="api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#evennia.contrib.base_systems.godotwebsocket.test_webclient.TestGodotWebSocketClient">TestGodotWebSocketClient (class in evennia.contrib.base_systems.godotwebsocket.test_webclient)</a>
</li>
<li><a href="api/evennia.contrib.rpg.health_bar.tests.html#evennia.contrib.rpg.health_bar.tests.TestHealthBar">TestHealthBar (class in evennia.contrib.rpg.health_bar.tests)</a>
</li>

View file

@ -135,7 +135,7 @@
<section id="tutorials-and-howtos">
<h2>Tutorials and Howtos<a class="headerlink" href="#tutorials-and-howtos" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p><a class="reference internal" href="Howtos/Howtos-Overview.html#beginner-tutorial"><span class="std std-doc">The Beginner Tutorial</span></a> - learn the basics and build a small game (in progress)</p></li>
<li><p><a class="reference internal" href="Howtos/Beginner-Tutorial/Beginner-Tutorial-Overview.html"><span class="doc std std-doc">The Beginner Tutorial</span></a> - learn the basics and build a small game (in progress)</p></li>
<li><p><a class="reference internal" href="Howtos/Howtos-Overview.html#how-tos"><span class="std std-doc">Tutorials and Howtos</span></a> - mixed tutorials and help articles to learn Evennia</p></li>
<li><p><a class="reference internal" href="Coding/Coding-Overview.html"><span class="doc std std-doc">Coding with Evennia</span></a> - resources and hints for coding and development</p></li>
</ul>
@ -365,6 +365,7 @@
<li class="toctree-l3"><a class="reference internal" href="Components/EvTable.html">EvTable</a></li>
<li class="toctree-l3"><a class="reference internal" href="Components/FuncParser.html">FuncParser inline text parsing</a></li>
<li class="toctree-l3"><a class="reference internal" href="Components/MonitorHandler.html">MonitorHandler</a></li>
<li class="toctree-l3"><a class="reference internal" href="Components/OnDemandHandler.html">OnDemandHandler</a></li>
<li class="toctree-l3"><a class="reference internal" href="Components/TickerHandler.html">TickerHandler</a></li>
<li class="toctree-l3"><a class="reference internal" href="Components/Signals.html">Signals</a></li>
</ul>

Binary file not shown.

View file

@ -385,6 +385,11 @@
<td>&#160;&#160;&#160;
<a href="api/evennia.contrib.base_systems.godotwebsocket.test_text2bbcode.html#module-evennia.contrib.base_systems.godotwebsocket.test_text2bbcode"><code class="xref">evennia.contrib.base_systems.godotwebsocket.test_text2bbcode</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="api/evennia.contrib.base_systems.godotwebsocket.test_webclient.html#module-evennia.contrib.base_systems.godotwebsocket.test_webclient"><code class="xref">evennia.contrib.base_systems.godotwebsocket.test_webclient</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
@ -1390,6 +1395,11 @@
<td>&#160;&#160;&#160;
<a href="api/evennia.scripts.monitorhandler.html#module-evennia.scripts.monitorhandler"><code class="xref">evennia.scripts.monitorhandler</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;
<a href="api/evennia.scripts.ondemandhandler.html#module-evennia.scripts.ondemandhandler"><code class="xref">evennia.scripts.ondemandhandler</code></a></td><td>
<em></em></td></tr>
<tr class="cg-1">
<td></td>
<td>&#160;&#160;&#160;

File diff suppressed because one or more lines are too long