mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 22:06:30 +01:00
234 lines
No EOL
18 KiB
HTML
234 lines
No EOL
18 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>TickerHandler — Evennia 1.0-dev documentation</title>
|
||
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||
<script src="../_static/jquery.js"></script>
|
||
<script src="../_static/underscore.js"></script>
|
||
<script src="../_static/doctools.js"></script>
|
||
<script src="../_static/language_data.js"></script>
|
||
<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 1.0-dev</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">TickerHandler</a></li>
|
||
</ul>
|
||
<div class="develop">develop branch</div>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="tickerhandler">
|
||
<h1>TickerHandler<a class="headerlink" href="#tickerhandler" title="Permalink to this headline">¶</a></h1>
|
||
<p>One way to implement a dynamic MUD is by using “tickers”, also known as “heartbeats”. A ticker is a
|
||
timer that fires (“ticks”) at a given interval. The tick triggers updates in various game systems.</p>
|
||
<section id="about-tickers">
|
||
<h2>About Tickers<a class="headerlink" href="#about-tickers" title="Permalink to this headline">¶</a></h2>
|
||
<p>Tickers are very common or even unavoidable in other mud code bases. Certain code bases are even
|
||
hard-coded to rely on the concept of the global ‘tick’. Evennia has no such notion - the decision to
|
||
use tickers is very much up to the need of your game and which requirements you have. The “ticker
|
||
recipe” is just one way of cranking the wheels.</p>
|
||
<p>The most fine-grained way to manage the flow of time is of course to use <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a>. Many
|
||
types of operations (weather being the classic example) are however done on multiple objects in the
|
||
same way at regular intervals, and for this, storing separate Scripts on each object is inefficient.
|
||
The way to do this is to use a ticker with a “subscription model” - let objects sign up to be
|
||
triggered at the same interval, unsubscribing when the updating is no longer desired.</p>
|
||
<p>Evennia offers an optimized implementation of the subscription model - the <em>TickerHandler</em>. This is
|
||
a singleton global handler reachable from <code class="docutils literal notranslate"><span class="pre">evennia.TICKER_HANDLER</span></code>. You can assign any <em>callable</em> (a
|
||
function or, more commonly, a method on a database object) to this handler. The TickerHandler will
|
||
then call this callable at an interval you specify, and with the arguments you supply when adding
|
||
it. This continues until the callable un-subscribes from the ticker. The handler survives a reboot
|
||
and is highly optimized in resource usage.</p>
|
||
<p>Here is an example of importing <code class="docutils literal notranslate"><span class="pre">TICKER_HANDLER</span></code> and using it:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># we assume that obj has a hook "at_tick" defined on itself</span>
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">TICKER_HANDLER</span> <span class="k">as</span> <span class="n">tickerhandler</span>
|
||
|
||
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">at_tick</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>That’s it - from now on, <code class="docutils literal notranslate"><span class="pre">obj.at_tick()</span></code> will be called every 20 seconds.</p>
|
||
<p>You can also import function and tick that:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">TICKER_HANDLER</span> <span class="k">as</span> <span class="n">tickerhandler</span>
|
||
<span class="kn">from</span> <span class="nn">mymodule</span> <span class="kn">import</span> <span class="n">myfunc</span>
|
||
|
||
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">myfunc</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Removing (stopping) the ticker works as expected:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">20</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">at_tick</span><span class="p">)</span>
|
||
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">30</span><span class="p">,</span> <span class="n">myfunc</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that you have to also supply <code class="docutils literal notranslate"><span class="pre">interval</span></code> to identify which subscription to remove. This is
|
||
because the TickerHandler maintains a pool of tickers and a given callable can subscribe to be
|
||
ticked at any number of different intervals.</p>
|
||
<p>The full definition of the <code class="docutils literal notranslate"><span class="pre">tickerhandler.add</span></code> method is</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">interval</span><span class="p">,</span> <span class="n">callback</span><span class="p">,</span>
|
||
<span class="n">idstring</span><span class="o">=</span><span class="s2">""</span><span class="p">,</span> <span class="n">persistent</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Here <code class="docutils literal notranslate"><span class="pre">*args</span></code> and <code class="docutils literal notranslate"><span class="pre">**kwargs</span></code> will be passed to <code class="docutils literal notranslate"><span class="pre">callback</span></code> every <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds. If <code class="docutils literal notranslate"><span class="pre">persistent</span></code>
|
||
is <code class="docutils literal notranslate"><span class="pre">False</span></code>, this subscription will not survive a server reload.</p>
|
||
<p>Tickers are identified and stored by making a key of the callable itself, the ticker-interval, the
|
||
<code class="docutils literal notranslate"><span class="pre">persistent</span></code> flag and the <code class="docutils literal notranslate"><span class="pre">idstring</span></code> (the latter being an empty string when not given explicitly).</p>
|
||
<p>Since the arguments are not included in the ticker’s identification, the <code class="docutils literal notranslate"><span class="pre">idstring</span></code> must be used to
|
||
have a specific callback triggered multiple times on the same interval but with different arguments:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="s2">"ticker1"</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">)</span>
|
||
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="s2">"ticker2"</span><span class="p">,</span> <span class="kc">True</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<blockquote>
|
||
<div><p>Note that, when we want to send arguments to our callback within a ticker handler, we need to
|
||
specify <code class="docutils literal notranslate"><span class="pre">idstring</span></code> and <code class="docutils literal notranslate"><span class="pre">persistent</span></code> before, unless we call our arguments as keywords, which would
|
||
often be more readable:</p>
|
||
</div></blockquote>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="n">caller</span><span class="o">=</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="o">=</span><span class="mi">118</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If you add a ticker with exactly the same combination of callback, interval and idstring, it will
|
||
overload the existing ticker. This identification is also crucial for later removing (stopping) the
|
||
subscription:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="s2">"ticker1"</span><span class="p">)</span>
|
||
<span class="n">tickerhandler</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">obj</span><span class="o">.</span><span class="n">update</span><span class="p">,</span> <span class="n">idstring</span><span class="o">=</span><span class="s2">"ticker2"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">callable</span></code> can be on any form as long as it accepts the arguments you give to send to it in
|
||
<code class="docutils literal notranslate"><span class="pre">TickerHandler.add</span></code>.</p>
|
||
<blockquote>
|
||
<div><p>Note that everything you supply to the TickerHandler will need to be pickled at some point to be
|
||
saved into the database. Most of the time the handler will correctly store things like database
|
||
objects, but the same restrictions as for <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> apply to what the TickerHandler
|
||
may store.</p>
|
||
</div></blockquote>
|
||
<p>When testing, you can stop all tickers in the entire game with <code class="docutils literal notranslate"><span class="pre">tickerhandler.clear()</span></code>. You can also
|
||
view the currently subscribed objects with <code class="docutils literal notranslate"><span class="pre">tickerhandler.all()</span></code>.</p>
|
||
<p>See the <a class="reference internal" href="../Howto/Weather-Tutorial.html"><span class="doc std std-doc">Weather Tutorial</span></a> for an example of using the TickerHandler.</p>
|
||
<section id="when-not-to-use-tickerhandler">
|
||
<h3>When <em>not</em> to use TickerHandler<a class="headerlink" href="#when-not-to-use-tickerhandler" title="Permalink to this headline">¶</a></h3>
|
||
<p>Using the TickerHandler may sound very useful but it is important to consider when not to use it.
|
||
Even if you are used to habitually relying on tickers for everything in other code bases, stop and
|
||
think about what you really need it for. This is the main point:</p>
|
||
<blockquote>
|
||
<div><p>You should <em>never</em> use a ticker to catch <em>changes</em>.</p>
|
||
</div></blockquote>
|
||
<p>Think about it - you might have to run the ticker every second to react to the change fast enough.
|
||
Most likely nothing will have changed at a given moment. So you are doing pointless calls (since
|
||
skipping the call gives the same result as doing it). Making sure nothing’s changed might even be
|
||
computationally expensive depending on the complexity of your system. Not to mention that you might
|
||
need to run the check <em>on every object in the database</em>. Every second. Just to maintain status quo
|
||
…</p>
|
||
<p>Rather than checking over and over on the off-chance that something changed, consider a more
|
||
proactive approach. Could you implement your rarely changing system to <em>itself</em> report when its
|
||
status changes? It’s almost always much cheaper/efficient if you can do things “on demand”. Evennia
|
||
itself uses hook methods for this very reason.</p>
|
||
<p>So, if you consider a ticker that will fire very often but which you expect to have no effect 99% of
|
||
the time, consider handling things things some other way. A self-reporting on-demand solution is
|
||
usually cheaper also for fast-updating properties. Also remember that some things may not need to be
|
||
updated until someone actually is examining or using them - any interim changes happening up to that
|
||
moment are pointless waste of computing time.</p>
|
||
<p>The main reason for needing a ticker is when you want things to happen to multiple objects at the
|
||
same time without input from something else.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="../index.html">
|
||
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="../search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<p><h3><a href="../index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">TickerHandler</a><ul>
|
||
<li><a class="reference internal" href="#about-tickers">About Tickers</a><ul>
|
||
<li><a class="reference internal" href="#when-not-to-use-tickerhandler">When <em>not</em> to use TickerHandler</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../_sources/Components/TickerHandler.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li>
|
||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||
</li>
|
||
</ul>
|
||
<h3>Versions</h3>
|
||
<ul>
|
||
<li><a href="TickerHandler.html">1.0-dev (develop branch)</a></li>
|
||
<li><a href="../../0.9.5/index.html">0.9.5 (v0.9.5 branch)</a></li>
|
||
</ul>
|
||
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 1.0-dev</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">TickerHandler</a></li>
|
||
</ul>
|
||
<div class="develop">develop branch</div>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2020, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |