mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
552 lines
No EOL
48 KiB
HTML
552 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 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>
|
||
<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="Objects" href="Objects.html" />
|
||
</head><body>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Channels.html" title="Channels"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Objects.html" title="Objects"
|
||
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="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Scripts</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="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 previus 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="in-game-command-examples">
|
||
<h2>In-game command examples<a class="headerlink" href="#in-game-command-examples" 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>
|
||
<section id="code-examples">
|
||
<h2>Code examples<a class="headerlink" href="#code-examples" title="Permalink to this headline">¶</a></h2>
|
||
<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">
|
||
<h2>Defining new Scripts<a class="headerlink" href="#defining-new-scripts" title="Permalink to this headline">¶</a></h2>
|
||
<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">
|
||
<h3>Simple storage script<a class="headerlink" href="#simple-storage-script" title="Permalink to this headline">¶</a></h3>
|
||
<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="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>
|
||
<section id="timed-scripts">
|
||
<h2>Timed Scripts<a class="headerlink" href="#timed-scripts" title="Permalink to this headline">¶</a></h2>
|
||
<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 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>
|
||
<section id="script-attached-to-another-object">
|
||
<h2>Script attached to another object<a class="headerlink" href="#script-attached-to-another-object" title="Permalink to this headline">¶</a></h2>
|
||
<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="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">
|
||
<h2>Other Script methods<a class="headerlink" href="#other-script-methods" title="Permalink to this headline">¶</a></h2>
|
||
<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-scripts"><span class="std std-doc">Timed Script</span></a> above.</p>
|
||
</section>
|
||
<section id="the-global-scripts-container">
|
||
<h2>The GLOBAL_SCRIPTS container<a class="headerlink" href="#the-global-scripts-container" 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>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>Note that global scripts appear as properties on `GLOBAL_SCRIPTS` based on their `key`.
|
||
If you were to create two global scripts with the same `key` (even with different typeclasses),
|
||
the `GLOBAL_SCRIPTS` 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
|
||
`evennia.search_scripts` to get exactly the script you want.
|
||
</pre></div>
|
||
</div>
|
||
</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">"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>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>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 `DefaultScript` type.
|
||
</pre></div>
|
||
</div>
|
||
</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 id="hints-dealing-with-script-errors">
|
||
<h2>Hints: Dealing with Script Errors<a class="headerlink" href="#hints-dealing-with-script-errors" title="Permalink to this headline">¶</a></h2>
|
||
<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>
|
||
|
||
|
||
<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="#">Scripts</a><ul>
|
||
<li><a class="reference internal" href="#in-game-command-examples">In-game command examples</a></li>
|
||
<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>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#timed-scripts">Timed Scripts</a><ul>
|
||
<li><a class="reference internal" href="#script-timers-vs-delay-repeat">Script timers vs delay/repeat</a></li>
|
||
</ul>
|
||
</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="#the-global-scripts-container">The GLOBAL_SCRIPTS container</a></li>
|
||
<li><a class="reference internal" href="#hints-dealing-with-script-errors">Hints: Dealing with Script Errors</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Objects.html"
|
||
title="previous chapter">Objects</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">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="Scripts.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="right" >
|
||
<a href="Channels.html" title="Channels"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Objects.html" title="Objects"
|
||
>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="Components-Overview.html" >Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Scripts</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> |