mirror of
https://github.com/evennia/evennia.git
synced 2026-03-17 13:26:30 +01:00
504 lines
No EOL
48 KiB
HTML
504 lines
No EOL
48 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>Scripts — Evennia 3.x documentation</title>
|
||
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||
<script src="../_static/jquery.js"></script>
|
||
<script src="../_static/underscore.js"></script>
|
||
<script src="../_static/doctools.js"></script>
|
||
<script src="../_static/language_data.js"></script>
|
||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="../genindex.html" />
|
||
<link rel="search" title="Search" href="../search.html" />
|
||
<link rel="next" title="Channels" href="Channels.html" />
|
||
<link rel="prev" title="Exits" href="Exits.html" />
|
||
</head><body>
|
||
|
||
|
||
<div class="admonition important">
|
||
<p class="first admonition-title">Note</p>
|
||
<p class="last">You are reading an old version of the Evennia documentation. <a href="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
|
||
</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"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Channels.html" title="Channels"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Exits.html" title="Exits"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 3.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Scripts</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="#">Scripts</a><ul>
|
||
<li><a class="reference internal" href="#working-with-scripts">Working with Scripts</a><ul>
|
||
<li><a class="reference internal" href="#code-examples">Code examples</a></li>
|
||
<li><a class="reference internal" href="#defining-new-scripts">Defining new Scripts</a><ul>
|
||
<li><a class="reference internal" href="#simple-storage-script">Simple storage script</a></li>
|
||
<li><a class="reference internal" href="#timed-script">Timed Script</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#script-timers-vs-delay-repeat">Script timers vs delay/repeat</a></li>
|
||
<li><a class="reference internal" href="#script-attached-to-another-object">Script attached to another object</a></li>
|
||
<li><a class="reference internal" href="#other-script-methods">Other Script methods</a></li>
|
||
<li><a class="reference internal" href="#dealing-with-script-errors">Dealing with Script Errors</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#using-global-scripts">Using GLOBAL_SCRIPTS</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Exits.html"
|
||
title="previous chapter">Exits</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Channels.html"
|
||
title="next chapter">Channels</a></p>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../_sources/Components/Scripts.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com/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>
|
||
</div>
|
||
</div>
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="scripts">
|
||
<h1>Scripts<a class="headerlink" href="#scripts" title="Permalink to this headline">¶</a></h1>
|
||
<p><a class="reference internal" href="../api/evennia.scripts.scripts.html#evennia-scripts-scripts"><span class="std std-ref">Script API reference</span></a></p>
|
||
<p><em>Scripts</em> are the out-of-character siblings to the in-character <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>. Scripts are so flexible that the name “Script” is a bit limiting in itself - but we had to pick <em>something</em> to name them. Other possible names (depending on what you’d use them for) would be <code class="docutils literal notranslate"><span class="pre">OOBObjects</span></code>, <code class="docutils literal notranslate"><span class="pre">StorageContainers</span></code> or <code class="docutils literal notranslate"><span class="pre">TimerObjects</span></code>.</p>
|
||
<p>If you ever consider creating an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a> with a <code class="docutils literal notranslate"><span class="pre">None</span></code>-location just to store some game data, you should really be using a Script instead.</p>
|
||
<ul class="simple">
|
||
<li><p>Scripts are full <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities - they have <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and can be modified in the same way. But they have <em>no in-game existence</em>, so no location or command-execution like <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a> and no connection to a particular player/session like <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>. This means they are perfectly suitable for acting as database-storage backends for game <em>systems</em>: Storing the current state of the economy, who is involved in the current fight, tracking an ongoing barter and so on. They are great as persistent system handlers.</p></li>
|
||
<li><p>Scripts have an optional <em>timer component</em>. This means that you can set up the script to tick the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook on the Script at a certain interval. The timer can be controlled independently of the rest of the script as needed. This component is optional and complementary to other timing functions in Evennia, like <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a>.</p></li>
|
||
<li><p>Scripts can <em>attach</em> to Objects and Accounts via e.g. <code class="docutils literal notranslate"><span class="pre">obj.scripts.add/remove</span></code>. In the script you can then access the object/account as <code class="docutils literal notranslate"><span class="pre">self.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">self.account</span></code>. This can be used to dynamically extend other typeclasses but also to use the timer component to affect the parent object in various ways. For historical reasons, a Script <em>not</em> attached to an object is referred to as a <em>Global</em> Script.</p></li>
|
||
</ul>
|
||
<div class="versionchanged">
|
||
<p><span class="versionmodified changed">Changed in version 1.0: </span>In previous Evennia versions, stopping the Script’s timer also meant deleting the Script object.
|
||
Starting with this version, the timer can be start/stopped separately and <code class="docutils literal notranslate"><span class="pre">.delete()</span></code> must be called
|
||
on the Script explicitly to delete it.</p>
|
||
</div>
|
||
<section id="working-with-scripts">
|
||
<h2>Working with Scripts<a class="headerlink" href="#working-with-scripts" title="Permalink to this headline">¶</a></h2>
|
||
<p>There are two main commands controlling scripts in the default cmdset:</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">addscript</span></code> command is used for attaching scripts to existing objects:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> addscript obj = bodyfunctions.BodyFunctions
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">scripts</span></code> command is used to view all scripts and perform operations on them:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>> scripts
|
||
> scripts/stop bodyfunctions.BodyFunctions
|
||
> scripts/start #244
|
||
> scripts/pause #11
|
||
> scripts/delete #566
|
||
</pre></div>
|
||
</div>
|
||
<div class="versionchanged">
|
||
<p><span class="versionmodified changed">Changed in version 1.0: </span>The <code class="docutils literal notranslate"><span class="pre">addscript</span></code> command used to be only <code class="docutils literal notranslate"><span class="pre">script</span></code> which was easy to confuse with <code class="docutils literal notranslate"><span class="pre">scripts</span></code>.</p>
|
||
</div>
|
||
<section id="code-examples">
|
||
<h3>Code examples<a class="headerlink" href="#code-examples" title="Permalink to this headline">¶</a></h3>
|
||
<p>Here are some examples of working with Scripts in-code (more details to follow in later
|
||
sections).</p>
|
||
<p>Create a new script:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">new_script</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">"myscript"</span><span class="p">,</span> <span class="n">typeclass</span><span class="o">=...</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Create script with timer component:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># (note that this will call `timed_script.at_repeat` which is empty by default)</span>
|
||
<span class="n">timed_script</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">"Timed script"</span><span class="p">,</span>
|
||
<span class="n">interval</span><span class="o">=</span><span class="mi">34</span><span class="p">,</span> <span class="c1"># seconds <=0 means off</span>
|
||
<span class="n">start_delay</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="c1"># wait interval before first call</span>
|
||
<span class="n">autostart</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="c1"># start timer (else needing .start() )</span>
|
||
|
||
<span class="c1"># manipulate the script's timer</span>
|
||
<span class="n">timed_script</span><span class="o">.</span><span class="n">stop</span><span class="p">()</span>
|
||
<span class="n">timed_script</span><span class="o">.</span><span class="n">start</span><span class="p">()</span>
|
||
<span class="n">timed_script</span><span class="o">.</span><span class="n">pause</span><span class="p">()</span>
|
||
<span class="n">timed_script</span><span class="o">.</span><span class="n">unpause</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Attach script to another object:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">myobj</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">new_script</span><span class="p">)</span>
|
||
<span class="n">myobj</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">evennia</span><span class="o">.</span><span class="n">DefaultScript</span><span class="p">)</span>
|
||
<span class="n">all_scripts_on_obj</span> <span class="o">=</span> <span class="n">myobj</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Search/find scripts in various ways:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># regular search (this is always a list, also if there is only one match)</span>
|
||
<span class="n">list_of_myscripts</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_script</span><span class="p">(</span><span class="s2">"myscript"</span><span class="p">)</span>
|
||
|
||
<span class="c1"># search through Evennia's GLOBAL_SCRIPTS container (based on</span>
|
||
<span class="c1"># script's key only)</span>
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
|
||
|
||
<span class="n">myscript</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">myscript</span>
|
||
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"Timed script"</span><span class="p">)</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span> <span class="o">=</span> <span class="s2">"bar"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Delete the Script (this will also stop its timer):</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">new_script</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
|
||
<span class="n">timed_script</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="defining-new-scripts">
|
||
<h3>Defining new Scripts<a class="headerlink" href="#defining-new-scripts" title="Permalink to this headline">¶</a></h3>
|
||
<p>A Script is defined as a class and is created in the same way as other
|
||
<a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">typeclassed</span></a> entities. The parent class is <code class="docutils literal notranslate"><span class="pre">evennia.DefaultScript</span></code>.</p>
|
||
<section id="simple-storage-script">
|
||
<h4>Simple storage script<a class="headerlink" href="#simple-storage-script" title="Permalink to this headline">¶</a></h4>
|
||
<p>In <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/scripts.py</span></code> is an empty <code class="docutils literal notranslate"><span class="pre">Script</span></code> class already set up. You
|
||
can use this as a base for your own scripts.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultScript</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Script</span><span class="p">(</span><span class="n">DefaultScript</span><span class="p">):</span>
|
||
<span class="c1"># stuff common for all your scripts goes here</span>
|
||
|
||
<span class="k">class</span> <span class="nc">MyScript</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
|
||
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""Called once, when script is first created"""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">"myscript"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span> <span class="o">=</span> <span class="s2">"bar"</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Once created, this simple Script could act as a global storage:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="s1">'typeclasses.scripts.MyScript'</span><span class="p">)</span>
|
||
|
||
<span class="c1"># from somewhere else</span>
|
||
|
||
<span class="n">myscript</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_script</span><span class="p">(</span><span class="s2">"myscript"</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
|
||
<span class="n">bar</span> <span class="o">=</span> <span class="n">myscript</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span>
|
||
<span class="n">myscript</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">something_else</span> <span class="o">=</span> <span class="mi">1000</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that if you give keyword arguments to <code class="docutils literal notranslate"><span class="pre">create_script</span></code> you can override the values
|
||
you set in your <code class="docutils literal notranslate"><span class="pre">at_script_creation</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="n">evennia</span><span class="o">.</span><span class="n">create_script</span><span class="p">(</span><span class="s1">'typeclasses.scripts.MyScript'</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"another name"</span><span class="p">,</span>
|
||
<span class="n">attributes</span><span class="o">=</span><span class="p">[(</span><span class="s2">"foo"</span><span class="p">,</span> <span class="s2">"bar-alternative"</span><span class="p">)])</span>
|
||
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>See the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">create_script</span></a> and <a class="reference internal" href="../api/evennia.utils.search.html#evennia.utils.search.search_script" title="evennia.utils.search.search_script"><span class="xref myst py py-func">search_script</span></a> API documentation for more options on creating and finding Scripts.</p>
|
||
</section>
|
||
<section id="timed-script">
|
||
<h4>Timed Script<a class="headerlink" href="#timed-script" title="Permalink to this headline">¶</a></h4>
|
||
<p>There are several properties one can set on the Script to control its timer component.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/scripts.py</span>
|
||
|
||
<span class="k">class</span> <span class="nc">TimerScript</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">"myscript"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">"An example script"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">60</span> <span class="c1"># 1 min repeat</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># do stuff every minute</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>This example will call <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> every minute. The <code class="docutils literal notranslate"><span class="pre">create_script</span></code> function has an <code class="docutils literal notranslate"><span class="pre">autostart=True</span></code> keyword
|
||
set by default - this means the script’s timer component will be started automatically. Otherwise
|
||
<code class="docutils literal notranslate"><span class="pre">.start()</span></code> must be called separately.</p>
|
||
<p>Supported properties are:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (str): The name of the script. This makes it easier to search for it later. If it’s a script
|
||
attached to another object one can also get all scripts off that object and get the script that way.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">desc</span></code> (str): Note - not <code class="docutils literal notranslate"><span class="pre">.db.desc</span></code>! This is a database field on the Script shown in script listings
|
||
to help identifying what does what.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">interval</span></code> (int): The amount of time (in seconds) between every ‘tick’ of the timer. Note that
|
||
it’s generally bad practice to use sub-second timers for anything in a text-game - the player will
|
||
not be able to appreciate the precision (and if you print it, it will just spam the screen). For
|
||
calculations you can pretty much always do them on-demand, or at a much slower interval without the player being the wiser.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">start_delay</span></code> (bool): If timer should start right away or wait <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds first.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">repeats</span></code> (int): If >0, the timer will only run this many times before stopping. Otherwise the
|
||
number of repeats are infinite. If set to 1, the Script mimics a <code class="docutils literal notranslate"><span class="pre">delay</span></code> action.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">persistent</span></code> (bool): This defaults to <code class="docutils literal notranslate"><span class="pre">True</span></code> and means the timer will survive a server reload/reboot.
|
||
If not, a reload will have the timer come back in a stopped state. Setting this to <code class="docutils literal notranslate"><span class="pre">False</span></code> will <em>not</em>
|
||
delete the Script object itself (use <code class="docutils literal notranslate"><span class="pre">.delete()</span></code> for this).</p></li>
|
||
</ul>
|
||
<p>The timer component is controlled with methods on the Script class:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.at_repeat()</span></code> - this method is called every <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds while the timer is
|
||
active.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.is_valid()</span></code> - this method is called by the timer just before <code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code>. If it returns <code class="docutils literal notranslate"><span class="pre">False</span></code>
|
||
the timer is immediately stopped.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.start()</span></code> - start/update the timer. If keyword arguments are given, they can be used to
|
||
change <code class="docutils literal notranslate"><span class="pre">interval</span></code>, <code class="docutils literal notranslate"><span class="pre">start_delay</span></code> etc on the fly. This calls the <code class="docutils literal notranslate"><span class="pre">.at_start()</span></code> hook.
|
||
This is also called after a server reload assuming the timer was not previously stopped.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.update()</span></code> - legacy alias for <code class="docutils literal notranslate"><span class="pre">.start</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.stop()</span></code> - stops and resets the timer. This calls the <code class="docutils literal notranslate"><span class="pre">.at_stop()</span></code> hook.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.pause()</span></code> - pauses the timer where it is, storing its current position. This calls
|
||
the <code class="docutils literal notranslate"><span class="pre">.at_pause(manual_pause=True)</span></code> hook. This is also called on a server reload/reboot,
|
||
at which time the <code class="docutils literal notranslate"><span class="pre">manual_pause</span></code> will be <code class="docutils literal notranslate"><span class="pre">False</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.unpause()</span></code> - unpause a previously paused script. This will call the <code class="docutils literal notranslate"><span class="pre">at_start</span></code> hook.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.time_until_next_repeat()</span></code> - get the time until next time the timer fires.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.remaining_repeats()</span></code> - get the number of repeats remaining, or <code class="docutils literal notranslate"><span class="pre">None</span></code> if repeats are infinite.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.reset_callcount()</span></code> - this resets the repeat counter to start over from 0. Only useful if <code class="docutils literal notranslate"><span class="pre">repeats>0</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">.force_repeat()</span></code> - this prematurely forces <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> to be called right away. Doing so will reset the countdown so that next call will again happen after <code class="docutils literal notranslate"><span class="pre">interval</span></code> seconds.</p></li>
|
||
</ul>
|
||
</section>
|
||
</section>
|
||
<section id="script-timers-vs-delay-repeat">
|
||
<h3>Script timers vs delay/repeat<a class="headerlink" href="#script-timers-vs-delay-repeat" title="Permalink to this headline">¶</a></h3>
|
||
<p>If the <em>only</em> goal is to get a repeat/delay effect, the <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.delay" title="evennia.utils.utils.delay"><span class="xref myst py py-func">evennia.utils.delay</span></a> and <a class="reference internal" href="../api/evennia.utils.utils.html#evennia.utils.utils.repeat" title="evennia.utils.utils.repeat"><span class="xref myst py py-func">evennia.utils.repeat</span></a> functions should generally be considered first. A Script is a lot ‘heavier’ to create/delete on the fly. In fact, for making a single delayed call (<code class="docutils literal notranslate"><span class="pre">script.repeats==1</span></code>), the <code class="docutils literal notranslate"><span class="pre">utils.delay</span></code> call is probably always the better choice.</p>
|
||
<p>For repeating tasks, the <code class="docutils literal notranslate"><span class="pre">utils.repeat</span></code> is optimized for quick repeating of a large number of objects. It uses the TickerHandler under the hood. Its subscription-based model makes it very efficient to start/stop the repeating action for an object. The side effect is however that all objects set to tick at a given interval will <em>all do so at the same time</em>. This may or may not look strange in-game depending on the situation. By contrast the Script uses its own ticker that will operate independently from the tickers of all other Scripts.</p>
|
||
<p>It’s also worth noting that once the script object has <em>already been created</em>, starting/stopping/pausing/unpausing the timer has very little overhead. The pause/unpause and update methods of the script also offers a bit more fine-control than using <code class="docutils literal notranslate"><span class="pre">utils.delays/repeat</span></code>.</p>
|
||
</section>
|
||
<section id="script-attached-to-another-object">
|
||
<h3>Script attached to another object<a class="headerlink" href="#script-attached-to-another-object" title="Permalink to this headline">¶</a></h3>
|
||
<p>Scripts can be attached to an <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Account</span></a> or (more commonly) an <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Object</span></a>.
|
||
If so, the ‘parent object’ will be available to the script as either <code class="docutils literal notranslate"><span class="pre">.obj</span></code> or <code class="docutils literal notranslate"><span class="pre">.account</span></code>.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># mygame/typeclasses/scripts.py</span>
|
||
<span class="c1"># Script class is defined at the top of this module</span>
|
||
|
||
<span class="kn">import</span> <span class="nn">random</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
|
||
<span class="w"> </span><span class="sd">"""</span>
|
||
<span class="sd"> A timer script that displays weather info. Meant to</span>
|
||
<span class="sd"> be attached to a room.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
<span class="k">def</span> <span class="nf">at_script_creation</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">"weather_script"</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">desc</span> <span class="o">=</span> <span class="s2">"Gives random weather messages."</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">interval</span> <span class="o">=</span> <span class="mi">60</span> <span class="o">*</span> <span class="mi">5</span> <span class="c1"># every 5 minutes</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="s2">"called every self.interval seconds."</span>
|
||
<span class="n">rand</span> <span class="o">=</span> <span class="n">random</span><span class="o">.</span><span class="n">random</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="n">rand</span> <span class="o"><</span> <span class="mf">0.5</span><span class="p">:</span>
|
||
<span class="n">weather</span> <span class="o">=</span> <span class="s2">"A faint breeze is felt."</span>
|
||
<span class="k">elif</span> <span class="n">rand</span> <span class="o"><</span> <span class="mf">0.7</span><span class="p">:</span>
|
||
<span class="n">weather</span> <span class="o">=</span> <span class="s2">"Clouds sweep across the sky."</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">weather</span> <span class="o">=</span> <span class="s2">"There is a light drizzle of rain."</span>
|
||
<span class="c1"># send this message to everyone inside the object this</span>
|
||
<span class="c1"># script is attached to (likely a room)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">msg_contents</span><span class="p">(</span><span class="n">weather</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If attached to a room, this Script will randomly report some weather
|
||
to everyone in the room every 5 minutes.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">myroom</span><span class="o">.</span><span class="n">scripts</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">scripts</span><span class="o">.</span><span class="n">Weather</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<blockquote>
|
||
<div><p>Note that <code class="docutils literal notranslate"><span class="pre">typeclasses</span></code> in your game dir is added to the setting <code class="docutils literal notranslate"><span class="pre">TYPECLASS_PATHS</span></code>.
|
||
Therefore we don’t need to give the full path (<code class="docutils literal notranslate"><span class="pre">typeclasses.scripts.Weather</span></code>
|
||
but only <code class="docutils literal notranslate"><span class="pre">scripts.Weather</span></code> above.</p>
|
||
</div></blockquote>
|
||
<p>You can also attach the script as part of creating it:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">create_script</span><span class="p">(</span><span class="s1">'typeclasses.weather.Weather'</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="n">myroom</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="other-script-methods">
|
||
<h3>Other Script methods<a class="headerlink" href="#other-script-methods" title="Permalink to this headline">¶</a></h3>
|
||
<p>A Script has all the properties of a typeclassed object, such as <code class="docutils literal notranslate"><span class="pre">db</span></code> and <code class="docutils literal notranslate"><span class="pre">ndb</span></code>(see
|
||
<a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclasses</span></a>). Setting <code class="docutils literal notranslate"><span class="pre">key</span></code> is useful in order to manage scripts (delete them by name
|
||
etc). These are usually set up in the Script’s typeclass, but can also be assigned on the fly as
|
||
keyword arguments to <code class="docutils literal notranslate"><span class="pre">evennia.create_script</span></code>.</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_script_creation()</span></code> - this is only called once - when the script is first created.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_reload()</span></code> - this is called whenever the server is warm-rebooted (e.g. with the <code class="docutils literal notranslate"><span class="pre">reload</span></code> command). It’s a good place to save non-persistent data you might want to survive a reload.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_shutdown()</span></code> - this is called when a system reset or systems shutdown is invoked.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_server_start()</span></code> - this is called when the server comes back (from reload/shutdown/reboot). It can be usuful for initializations and caching of non-persistent data when starting up a script’s functionality.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_repeat()</span></code></p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_start()</span></code></p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_pause()</span></code></p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">at_stop()</span></code></p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">delete()</span></code> - same as for other typeclassed entities, this will delete the Script. Of note is that
|
||
it will also stop the timer (if it runs), leading to the <code class="docutils literal notranslate"><span class="pre">at_stop</span></code> hook being called.</p></li>
|
||
</ul>
|
||
<p>In addition, Scripts support <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> and <a class="reference internal" href="Locks.html"><span class="doc std std-doc">Locks</span></a> etc like other Typeclassed entities.</p>
|
||
<p>See also the methods involved in controlling a <a class="reference internal" href="#timed-script"><span class="std std-doc">Timed Script</span></a> above.</p>
|
||
</section>
|
||
<section id="dealing-with-script-errors">
|
||
<h3>Dealing with Script Errors<a class="headerlink" href="#dealing-with-script-errors" title="Permalink to this headline">¶</a></h3>
|
||
<p>Errors inside a timed, executing script can sometimes be rather terse or point to parts of the execution mechanism that is hard to interpret. One way to make it easier to debug scripts is to import Evennia’s native logger and wrap your functions in a try/catch block. Evennia’s logger can show you where the traceback occurred in your script.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span>
|
||
<span class="kn">from</span> <span class="nn">evennia.utils</span> <span class="kn">import</span> <span class="n">logger</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Weather</span><span class="p">(</span><span class="n">Script</span><span class="p">):</span>
|
||
|
||
<span class="c1"># [...]</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_repeat</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
|
||
<span class="k">try</span><span class="p">:</span>
|
||
<span class="c1"># [...]</span>
|
||
<span class="k">except</span> <span class="ne">Exception</span><span class="p">:</span>
|
||
<span class="n">logger</span><span class="o">.</span><span class="n">log_trace</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
</section>
|
||
<section id="using-global-scripts">
|
||
<h2>Using GLOBAL_SCRIPTS<a class="headerlink" href="#using-global-scripts" title="Permalink to this headline">¶</a></h2>
|
||
<p>A Script not attached to another entity is commonly referred to as a <em>Global</em> script since it’t available
|
||
to access from anywhere. This means they need to be searched for in order to be used.</p>
|
||
<p>Evennia supplies a convenient “container” <code class="docutils literal notranslate"><span class="pre">evennia.GLOBAL_SCRIPTS</span></code> to help organize your global
|
||
scripts. All you need is the Script’s <code class="docutils literal notranslate"><span class="pre">key</span></code>.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
|
||
|
||
<span class="c1"># access as a property on the container, named the same as the key</span>
|
||
<span class="n">my_script</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">my_script</span>
|
||
<span class="c1"># needed if there are spaces in name or name determined on the fly</span>
|
||
<span class="n">another_script</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"another script"</span><span class="p">)</span>
|
||
<span class="c1"># get all global scripts (this returns a Django Queryset)</span>
|
||
<span class="n">all_scripts</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
|
||
<span class="c1"># you can operate directly on the script</span>
|
||
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">weather</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">current_weather</span> <span class="o">=</span> <span class="s2">"Cloudy"</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Note that global scripts appear as properties on <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> based on their <code class="docutils literal notranslate"><span class="pre">key</span></code>. If you were to create two global scripts with the same <code class="docutils literal notranslate"><span class="pre">key</span></code> (even with different typeclasses), the <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> container will only return one of them (which one depends on order in the database). Best is to organize your scripts so that this does not happen. Otherwise, use <code class="docutils literal notranslate"><span class="pre">evennia.search_script</span></code> to get exactly the script you want.</p>
|
||
</div>
|
||
<p>There are two ways to make a script appear as a property on <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>:</p>
|
||
<ol class="simple">
|
||
<li><p>Manually create a new global script with a <code class="docutils literal notranslate"><span class="pre">key</span></code> using <code class="docutils literal notranslate"><span class="pre">create_script</span></code>.</p></li>
|
||
<li><p>Define the script’s properties in the <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code> settings variable. This tells Evennia
|
||
that it should check if a script with that <code class="docutils literal notranslate"><span class="pre">key</span></code> exists and if not, create it for you.
|
||
This is very useful for scripts that must always exist and/or should be auto-created
|
||
when your server restarts. If you use this method, you must make sure all
|
||
script keys are globally unique.</p></li>
|
||
</ol>
|
||
<p>Here’s how to tell Evennia to manage the script in settings:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/server/conf/settings.py</span>
|
||
|
||
<span class="n">GLOBAL_SCRIPTS</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="s2">"my_script"</span><span class="p">:</span> <span class="p">{</span>
|
||
<span class="s2">"typeclass"</span><span class="p">:</span> <span class="s2">"typeclasses.scripts.Weather"</span><span class="p">,</span>
|
||
<span class="s2">"repeats"</span><span class="p">:</span> <span class="o">-</span><span class="mi">1</span><span class="p">,</span>
|
||
<span class="s2">"interval"</span><span class="p">:</span> <span class="mi">50</span><span class="p">,</span>
|
||
<span class="s2">"desc"</span><span class="p">:</span> <span class="s2">"Weather script"</span>
|
||
<span class="p">},</span>
|
||
<span class="s2">"storagescript"</span><span class="p">:</span> <span class="p">{}</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Above we add two scripts with keys <code class="docutils literal notranslate"><span class="pre">myscript</span></code> and <code class="docutils literal notranslate"><span class="pre">storagescript</span></code>respectively. The following dict can be empty - the <code class="docutils literal notranslate"><span class="pre">settings.BASE_SCRIPT_TYPECLASS</span></code> will then be used. Under the hood, the provided dict (along with the <code class="docutils literal notranslate"><span class="pre">key</span></code>) will be passed into <code class="docutils literal notranslate"><span class="pre">create_script</span></code> automatically, so all the <a class="reference internal" href="../api/evennia.utils.create.html#evennia.utils.create.create_script" title="evennia.utils.create.create_script"><span class="xref myst py py-func">same keyword arguments as for create_script</span></a> are supported here.</p>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Before setting up Evennia to manage your script like this, make sure that your Script typeclass does not have any critical errors (test it separately). If there are, you’ll see errors in your log and your Script will temporarily fall back to being a <code class="docutils literal notranslate"><span class="pre">DefaultScript</span></code> type.</p>
|
||
</div>
|
||
<p>Moreover, a script defined this way is <em>guaranteed</em> to exist when you try to access it:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">GLOBAL_SCRIPTS</span>
|
||
<span class="c1"># Delete the script</span>
|
||
<span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">storagescript</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
|
||
<span class="c1"># running the `scripts` command now will show no storagescript</span>
|
||
<span class="c1"># but below it's automatically recreated again!</span>
|
||
<span class="n">storage</span> <span class="o">=</span> <span class="n">GLOBAL_SCRIPTS</span><span class="o">.</span><span class="n">storagescript</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>That is, if the script is deleted, next time you get it from <code class="docutils literal notranslate"><span class="pre">GLOBAL_SCRIPTS</span></code>, Evennia will use the
|
||
information in settings to recreate it for you on the fly.</p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Channels.html" title="Channels"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Exits.html" title="Exits"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 3.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Scripts</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
|
||
<div class="admonition important">
|
||
<p class="first admonition-title">Note</p>
|
||
<p class="last">You are reading an old version of the Evennia documentation. <a href="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
|
||
</div>
|
||
|
||
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2023, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |