mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
328 lines
No EOL
26 KiB
HTML
328 lines
No EOL
26 KiB
HTML
|
||
<!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>Async Process — Evennia 0.9.5 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>
|
||
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"processClass": "tex2jax_process|mathjax_process|math|output_area"}})</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 0.9.5</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Async Process</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="async-process">
|
||
<h1>Async Process<a class="headerlink" href="#async-process" title="Permalink to this headline">¶</a></h1>
|
||
<p><em>This is considered an advanced topic.</em></p>
|
||
<section id="synchronous-versus-asynchronous">
|
||
<h2>Synchronous versus Asynchronous<a class="headerlink" href="#synchronous-versus-asynchronous" title="Permalink to this headline">¶</a></h2>
|
||
<p>Most program code operates <em>synchronously</em>. This means that each statement in your code gets
|
||
processed and finishes before the next can begin. This makes for easy-to-understand code. It is also
|
||
a <em>requirement</em> in many cases - a subsequent piece of code often depend on something calculated or
|
||
defined in a previous statement.</p>
|
||
<p>Consider this piece of code in a traditional Python program:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="nb">print</span><span class="p">(</span><span class="s2">"before call ..."</span><span class="p">)</span>
|
||
<span class="n">long_running_function</span><span class="p">()</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"after call ..."</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>When run, this will print <code class="docutils literal notranslate"><span class="pre">"before</span> <span class="pre">call</span> <span class="pre">..."</span></code>, after which the <code class="docutils literal notranslate"><span class="pre">long_running_function</span></code> gets to work
|
||
for however long time. Only once that is done, the system prints <code class="docutils literal notranslate"><span class="pre">"after</span> <span class="pre">call</span> <span class="pre">..."</span></code>. Easy and
|
||
logical to follow. Most of Evennia work in this way and often it’s important that commands get
|
||
executed in the same strict order they were coded.</p>
|
||
<p>Evennia, via Twisted, is a single-process multi-user server. In simple terms this means that it
|
||
swiftly switches between dealing with player input so quickly that each player feels like they do
|
||
things at the same time. This is a clever illusion however: If one user, say, runs a command
|
||
containing that <code class="docutils literal notranslate"><span class="pre">long_running_function</span></code>, <em>all</em> other players are effectively forced to wait until it
|
||
finishes.</p>
|
||
<p>Now, it should be said that on a modern computer system this is rarely an issue. Very few commands
|
||
run so long that other users notice it. And as mentioned, most of the time you <em>want</em> to enforce
|
||
all commands to occur in strict sequence.</p>
|
||
<p>When delays do become noticeable and you don’t care in which order the command actually completes,
|
||
you can run it <em>asynchronously</em>. This makes use of the <code class="docutils literal notranslate"><span class="pre">run_async()</span></code> function in
|
||
<code class="docutils literal notranslate"><span class="pre">src/utils/utils.py</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">run_async</span><span class="p">(</span><span class="n">function</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Where <code class="docutils literal notranslate"><span class="pre">function</span></code> will be called asynchronously with <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code>. Example:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">utils</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"before call ..."</span><span class="p">)</span>
|
||
<span class="n">utils</span><span class="o">.</span><span class="n">run_async</span><span class="p">(</span><span class="n">long_running_function</span><span class="p">)</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"after call ..."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Now, when running this you will find that the program will not wait around for
|
||
<code class="docutils literal notranslate"><span class="pre">long_running_function</span></code> to finish. In fact you will see <code class="docutils literal notranslate"><span class="pre">"before</span> <span class="pre">call</span> <span class="pre">..."</span></code> and <code class="docutils literal notranslate"><span class="pre">"after</span> <span class="pre">call</span> <span class="pre">..."</span></code>
|
||
printed out right away. The long-running function will run in the background and you (and other
|
||
users) can go on as normal.</p>
|
||
</section>
|
||
<section id="customizing-asynchronous-operation">
|
||
<h2>Customizing asynchronous operation<a class="headerlink" href="#customizing-asynchronous-operation" title="Permalink to this headline">¶</a></h2>
|
||
<p>A complication with using asynchronous calls is what to do with the result from that call. What if
|
||
<code class="docutils literal notranslate"><span class="pre">long_running_function</span></code> returns a value that you need? It makes no real sense to put any lines of
|
||
code after the call to try to deal with the result from <code class="docutils literal notranslate"><span class="pre">long_running_function</span></code> above - as we saw
|
||
the <code class="docutils literal notranslate"><span class="pre">"after</span> <span class="pre">call</span> <span class="pre">..."</span></code> got printed long before <code class="docutils literal notranslate"><span class="pre">long_running_function</span></code> was finished, making that
|
||
line quite pointless for processing any data from the function. Instead one has to use <em>callbacks</em>.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">utils.run_async</span></code> takes reserved kwargs that won’t be passed into the long-running function:</p>
|
||
<ul>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_return(r)</span></code> (the <em>callback</em>) is called when the asynchronous function (<code class="docutils literal notranslate"><span class="pre">long_running_function</span></code>
|
||
above) finishes successfully. The argument <code class="docutils literal notranslate"><span class="pre">r</span></code> will then be the return value of that function (or
|
||
<code class="docutils literal notranslate"><span class="pre">None</span></code>).</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">at_return</span><span class="p">(</span><span class="n">r</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">r</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_return_kwargs</span></code> - an optional dictionary that will be fed as keyword arguments to the
|
||
<code class="docutils literal notranslate"><span class="pre">at_return</span></code> callback.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_err(e)</span></code> (the <em>errback</em>) is called if the asynchronous function fails and raises an exception.
|
||
This exception is passed to the errback wrapped in a <em>Failure</em> object <code class="docutils literal notranslate"><span class="pre">e</span></code>. If you do not supply an
|
||
errback of your own, Evennia will automatically add one that silently writes errors to the evennia
|
||
log. An example of an errback is found below:</p></li>
|
||
</ul>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">at_err</span><span class="p">(</span><span class="n">e</span><span class="p">):</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"There was an error:"</span><span class="p">,</span> <span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_err_kwargs</span></code> - an optional dictionary that will be fed as keyword arguments to the <code class="docutils literal notranslate"><span class="pre">at_err</span></code>
|
||
errback.</p></li>
|
||
</ul>
|
||
<p>An example of making an asynchronous call from inside a <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Command</span></a> definition:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">utils</span><span class="p">,</span> <span class="n">Command</span>
|
||
|
||
<span class="k">class</span> <span class="nc">CmdAsync</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"asynccommand"</span>
|
||
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">long_running_function</span><span class="p">():</span>
|
||
<span class="c1">#[... lots of time-consuming code ...]</span>
|
||
<span class="k">return</span> <span class="n">final_value</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_return_function</span><span class="p">(</span><span class="n">r</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"The final value is </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">r</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_err_function</span><span class="p">(</span><span class="n">e</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"There was an error: </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="n">e</span><span class="p">)</span>
|
||
|
||
<span class="c1"># do the async call, setting all callbacks</span>
|
||
<span class="n">utils</span><span class="o">.</span><span class="n">run_async</span><span class="p">(</span><span class="n">long_running_function</span><span class="p">,</span> <span class="n">at_return</span><span class="o">=</span><span class="n">at_return_function</span><span class="p">,</span>
|
||
<span class="n">at_err</span><span class="o">=</span><span class="n">at_err_function</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>That’s it - from here on we can forget about <code class="docutils literal notranslate"><span class="pre">long_running_function</span></code> and go on with what else need
|
||
to be done. <em>Whenever</em> it finishes, the <code class="docutils literal notranslate"><span class="pre">at_return_function</span></code> function will be called and the final
|
||
value will
|
||
pop up for us to see. If not we will see an error message.</p>
|
||
</section>
|
||
<section id="delay">
|
||
<h2>delay<a class="headerlink" href="#delay" title="Permalink to this headline">¶</a></h2>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">delay</span></code> function is a much simpler sibling to <code class="docutils literal notranslate"><span class="pre">run_async</span></code>. It is in fact just a way to delay the
|
||
execution of a command until a future time. This is equivalent to something like <code class="docutils literal notranslate"><span class="pre">time.sleep()</span></code>
|
||
except delay is asynchronous while <code class="docutils literal notranslate"><span class="pre">sleep</span></code> would lock the entire server for the duration of the
|
||
sleep.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">delay</span>
|
||
|
||
<span class="c1"># [...]</span>
|
||
<span class="c1"># e.g. inside a Command, where `self.caller` is available</span>
|
||
<span class="k">def</span> <span class="nf">callback</span><span class="p">(</span><span class="n">obj</span><span class="p">):</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Returning!"</span><span class="p">)</span>
|
||
<span class="n">delay</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This will delay the execution of the callback for 10 seconds. This function is explored much more in
|
||
the <a class="reference internal" href="Command-Duration.html"><span class="doc std std-doc">Command Duration Tutorial</span></a>.</p>
|
||
<p>You can also try the following snippet just see how it works:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>@py from evennia.utils import delay; delay(10, lambda who: who.msg("Test!"), self)
|
||
</pre></div>
|
||
</div>
|
||
<p>Wait 10 seconds and ‘Test!’ should be echoed back to you.</p>
|
||
</section>
|
||
<section id="the-interactive-decorator">
|
||
<h2>The @interactive decorator<a class="headerlink" href="#the-interactive-decorator" title="Permalink to this headline">¶</a></h2>
|
||
<p>As of Evennia 0.9, the <code class="docutils literal notranslate"><span class="pre">@interactive</span></code> <a class="reference external" href="https://realpython.com/primer-on-python-decorators/">decorator</a>
|
||
is available. This makes any function or method possible to ‘pause’ and/or await player input
|
||
in an interactive way.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">interactive</span>
|
||
|
||
<span class="nd">@interactive</span>
|
||
<span class="k">def</span> <span class="nf">myfunc</span><span class="p">(</span><span class="n">caller</span><span class="p">):</span>
|
||
|
||
<span class="k">while</span> <span class="kc">True</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">"Getting ready to wait ..."</span><span class="p">)</span>
|
||
<span class="k">yield</span><span class="p">(</span><span class="mi">5</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">"Now 5 seconds have passed."</span><span class="p">)</span>
|
||
|
||
<span class="n">response</span> <span class="o">=</span> <span class="k">yield</span><span class="p">(</span><span class="s2">"Do you want to wait another 5 secs?"</span><span class="p">)</span>
|
||
|
||
<span class="k">if</span> <span class="n">response</span><span class="o">.</span><span class="n">lower</span><span class="p">()</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"yes"</span><span class="p">,</span> <span class="s2">"y"</span><span class="p">):</span>
|
||
<span class="k">break</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">@interactive</span></code> decorator gives the function the ability to pause. The use
|
||
of <code class="docutils literal notranslate"><span class="pre">yield(seconds)</span></code> will do just that - it will asynchronously pause for the
|
||
number of seconds given before continuing. This is technically equivalent to
|
||
using <code class="docutils literal notranslate"><span class="pre">call_async</span></code> with a callback that continues after 5 secs. But the code
|
||
with <code class="docutils literal notranslate"><span class="pre">@interactive</span></code> is a little easier to follow.</p>
|
||
<p>Within the <code class="docutils literal notranslate"><span class="pre">@interactive</span></code> function, the <code class="docutils literal notranslate"><span class="pre">response</span> <span class="pre">=</span> <span class="pre">yield("question")</span></code> question
|
||
allows you to ask the user for input. You can then process the input, just like
|
||
you would if you used the Python <code class="docutils literal notranslate"><span class="pre">input</span></code> function. There is one caveat to this
|
||
functionality though - <em>it will only work if the function/method has an
|
||
argument named exactly <code class="docutils literal notranslate"><span class="pre">caller</span></code></em>. This is because internally Evennia will look
|
||
for the <code class="docutils literal notranslate"><span class="pre">caller</span></code> argument and treat that as the source of input.</p>
|
||
<p>All of this makes the <code class="docutils literal notranslate"><span class="pre">@interactive</span></code> decorator very useful. But it comes with a
|
||
few caveats. Notably, decorating a function/method with <code class="docutils literal notranslate"><span class="pre">@interactive</span></code> turns it
|
||
into a Python <a class="reference external" href="https://wiki.python.org/moin/Generators">generator</a>. The most
|
||
common issue is that you cannot use <code class="docutils literal notranslate"><span class="pre">return</span> <span class="pre"><value></span></code> from a generator (just an
|
||
empty <code class="docutils literal notranslate"><span class="pre">return</span></code> works). To return a value from a function/method you have decorated
|
||
with <code class="docutils literal notranslate"><span class="pre">@interactive</span></code>, you must instead use a special Twisted function
|
||
<code class="docutils literal notranslate"><span class="pre">twisted.internet.defer.returnValue</span></code>. Evennia also makes this function
|
||
conveniently available from <code class="docutils literal notranslate"><span class="pre">evennia.utils</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">interactive</span><span class="p">,</span> <span class="n">returnValue</span>
|
||
|
||
<span class="nd">@interactive</span>
|
||
<span class="k">def</span> <span class="nf">myfunc</span><span class="p">():</span>
|
||
|
||
<span class="c1"># ...</span>
|
||
<span class="n">result</span> <span class="o">=</span> <span class="mi">10</span>
|
||
|
||
<span class="c1"># this must be used instead of `return result`</span>
|
||
<span class="n">returnValue</span><span class="p">(</span><span class="n">result</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="assorted-notes">
|
||
<h2>Assorted notes<a class="headerlink" href="#assorted-notes" title="Permalink to this headline">¶</a></h2>
|
||
<p>Overall, be careful with choosing when to use asynchronous calls. It is mainly useful for large
|
||
administration operations that have no direct influence on the game world (imports and backup
|
||
operations come to mind). Since there is no telling exactly when an asynchronous call actually ends,
|
||
using them for in-game commands is to potentially invite confusion and inconsistencies (and very
|
||
hard-to-reproduce bugs).</p>
|
||
<p>The very first synchronous example above is not <em>really</em> correct in the case of Twisted, which is
|
||
inherently an asynchronous server. Notably you might find that you will <em>not</em> see the first <code class="docutils literal notranslate"><span class="pre">before</span> <span class="pre">call</span> <span class="pre">...</span></code> text being printed out right away. Instead all texts could end up being delayed until
|
||
after the long-running process finishes. So all commands will retain their relative order as
|
||
expected, but they may appear with delays or in groups.</p>
|
||
</section>
|
||
<section id="further-reading">
|
||
<h2>Further reading<a class="headerlink" href="#further-reading" title="Permalink to this headline">¶</a></h2>
|
||
<p>Technically, <code class="docutils literal notranslate"><span class="pre">run_async</span></code> is just a very thin and simplified wrapper around a
|
||
<a class="reference external" href="http://twistedmatrix.com/documents/9.0.0/core/howto/defer.html">Twisted Deferred</a> object; the
|
||
wrapper sets
|
||
up a default errback also if none is supplied. If you know what you are doing there is nothing
|
||
stopping you from bypassing the utility function, building a more sophisticated callback chain after
|
||
your own liking.</p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="index.html">
|
||
<img class="logo" src="_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<p><h3><a href="index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Async Process</a><ul>
|
||
<li><a class="reference internal" href="#synchronous-versus-asynchronous">Synchronous versus Asynchronous</a></li>
|
||
<li><a class="reference internal" href="#customizing-asynchronous-operation">Customizing asynchronous operation</a></li>
|
||
<li><a class="reference internal" href="#delay">delay</a></li>
|
||
<li><a class="reference internal" href="#the-interactive-decorator">The @interactive decorator</a></li>
|
||
<li><a class="reference internal" href="#assorted-notes">Assorted notes</a></li>
|
||
<li><a class="reference internal" href="#further-reading">Further reading</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="_sources/Async-Process.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
|
||
<a href="https://discord.gg/NecFePw">Discord</a> -
|
||
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
|
||
</li>
|
||
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
|
||
</ul>
|
||
<h3>Versions</h3>
|
||
<ul>
|
||
<li><a href="../1.0-dev/index.html">1.0-dev (develop branch)</a></li>
|
||
<li><a href="Async-Process.html">0.9.5 (v0.9.5 branch)</a></li>
|
||
</ul>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Async Process</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2020, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |