mirror of
https://github.com/evennia/evennia.git
synced 2026-04-03 22:47:16 +02:00
Updated HTML docs.
This commit is contained in:
parent
6ba9b7c23f
commit
41ca2163d3
114 changed files with 1905 additions and 3331 deletions
|
|
@ -17,8 +17,8 @@
|
|||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||||
<link rel="index" title="Index" href="../genindex.html" />
|
||||
<link rel="search" title="Search" href="../search.html" />
|
||||
<link rel="next" title="Soft Code" href="Soft-Code.html" />
|
||||
<link rel="prev" title="Core Concepts" href="Concepts-Overview.html" />
|
||||
<link rel="next" title="In-text tags parsed by Evennia" href="Tags-Parsed-By-Evennia.html" />
|
||||
<link rel="prev" title="Out-of-Band messaging" href="OOB.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
<h3>Navigation</h3>
|
||||
|
|
@ -30,10 +30,10 @@
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Soft-Code.html" title="Soft Code"
|
||||
<a href="Tags-Parsed-By-Evennia.html" title="In-text tags parsed by Evennia"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Concepts-Overview.html" title="Core Concepts"
|
||||
<a href="OOB.html" title="Out-of-Band messaging"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Concepts-Overview.html" accesskey="U">Core Concepts</a> »</li>
|
||||
|
|
@ -64,21 +64,19 @@
|
|||
<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>
|
||||
<li><a class="reference internal" href="#utils-delay"><code class="docutils literal notranslate"><span class="pre">utils.delay</span></code></a></li>
|
||||
<li><a class="reference internal" href="#utils-interactive-decorator"><code class="docutils literal notranslate"><span class="pre">@utils.interactive</span></code> decorator</a></li>
|
||||
<li><a class="reference internal" href="#utils-run-async"><code class="docutils literal notranslate"><span class="pre">utils.run_async</span></code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Previous topic</h4>
|
||||
<p class="topless"><a href="Concepts-Overview.html"
|
||||
title="previous chapter">Core Concepts</a></p>
|
||||
<p class="topless"><a href="OOB.html"
|
||||
title="previous chapter">Out-of-Band messaging</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="Soft-Code.html"
|
||||
title="next chapter">Soft Code</a></p>
|
||||
<p class="topless"><a href="Tags-Parsed-By-Evennia.html"
|
||||
title="next chapter">In-text tags parsed by Evennia</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<!--h3>This Page</h3-->
|
||||
<ul class="this-page-menu">
|
||||
|
|
@ -111,35 +109,101 @@
|
|||
|
||||
<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>
|
||||
<div class="admonition important">
|
||||
<p class="admonition-title">Important</p>
|
||||
<p>This is considered an advanced topic.</p>
|
||||
</div>
|
||||
<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>
|
||||
<aside class="sidebar">
|
||||
<p>This is also explored in the <a class="reference internal" href="../Howtos/Howto-Command-Duration.html"><span class="doc std std-doc">Command Duration Tutorial</span></a>.</p>
|
||||
</aside>
|
||||
<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
|
||||
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>
|
||||
<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>
|
||||
</section>
|
||||
<section id="utils-delay">
|
||||
<h2><code class="docutils literal notranslate"><span class="pre">utils.delay</span></code><a class="headerlink" href="#utils-delay" title="Permalink to this headline">¶</a></h2>
|
||||
<aside class="sidebar">
|
||||
<p class="sidebar-title">delay() vs time.sleep()</p>
|
||||
<p>This is equivalent to something like <code class="docutils literal notranslate"><span class="pre">time.sleep()</span></code> except <code class="docutils literal notranslate"><span class="pre">delay</span></code> 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>
|
||||
</aside>
|
||||
<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.</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. Provide <code class="docutils literal notranslate"><span class="pre">persistent=True</span></code> to make the delay survive a server <code class="docutils literal notranslate"><span class="pre">reload</span></code>. While waiting, you can input commands normally.</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="utils-interactive-decorator">
|
||||
<h2><code class="docutils literal notranslate"><span class="pre">@utils.interactive</span></code> decorator<a class="headerlink" href="#utils-interactive-decorator" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">@interactive</span></code> [decorator](<a class="reference external" href="https://realpython.com/primer-on-python-">https://realpython.com/primer-on-python-</a> decorators/) 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.</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.</p>
|
||||
<ul>
|
||||
<li><p>The decorated function/method/callable must have an argument named exactly <code class="docutils literal notranslate"><span class="pre">caller</span></code>. Evennia will look for an argument with this name and treat it as the source of input.</p></li>
|
||||
<li><p>Decorating a function this way turns it turns it into a Python <a class="reference external" href="https://wiki.python.org/moin/Generators">generator</a>. This means</p>
|
||||
<ul class="simple">
|
||||
<li><p>You can’t 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></li>
|
||||
</ul>
|
||||
<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>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section id="utils-run-async">
|
||||
<h2><code class="docutils literal notranslate"><span class="pre">utils.run_async</span></code><a class="headerlink" href="#utils-run-async" title="Permalink to this headline">¶</a></h2>
|
||||
<div class="admonition warning">
|
||||
<p class="admonition-title">Warning</p>
|
||||
<p>Unless you have a very clear purpose in mind, you are unlikely to get an expected result from <code class="docutils literal notranslate"><span class="pre">run_async</span></code>. Notably, it will still run your long-running function <em>in the same thread</em> as the rest of the server. So while it does run async, a very heavy and CPU-heavy operation will still block the server. So don’t consider this as a way to offload heavy operations without affecting the rest of the server.</p>
|
||||
</div>
|
||||
<p>When 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>
|
||||
|
|
@ -150,13 +214,7 @@ you can run it <em>asynchronously</em>. This makes use of the <code class="docut
|
|||
<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>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>
|
||||
<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
|
||||
|
|
@ -172,8 +230,7 @@ above) finishes successfully. The argument <code class="docutils literal notrans
|
|||
</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_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
|
||||
|
|
@ -211,109 +268,10 @@ errback.</p></li>
|
|||
<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="../Howtos/Howto-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> [decorator](<a class="reference external" href="https://realpython.com/primer-on-python-">https://realpython.com/primer-on-python-</a>
|
||||
decorators/)
|
||||
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="https://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>
|
||||
<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>
|
||||
<blockquote>
|
||||
<div><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="https://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>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
|
|
@ -333,10 +291,10 @@ your own liking.</p>
|
|||
<a href="../py-modindex.html" title="Python Module Index"
|
||||
>modules</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Soft-Code.html" title="Soft Code"
|
||||
<a href="Tags-Parsed-By-Evennia.html" title="In-text tags parsed by Evennia"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="Concepts-Overview.html" title="Core Concepts"
|
||||
<a href="OOB.html" title="Out-of-Band messaging"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||||
<li class="nav-item nav-item-1"><a href="Concepts-Overview.html" >Core Concepts</a> »</li>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue