mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 05:46:31 +01:00
494 lines
No EOL
46 KiB
HTML
494 lines
No EOL
46 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>Coding FAQ — Evennia 0.9.5 documentation</title>
|
||
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||
<script src="_static/jquery.js"></script>
|
||
<script src="_static/underscore.js"></script>
|
||
<script src="_static/doctools.js"></script>
|
||
<script src="_static/language_data.js"></script>
|
||
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"processClass": "tex2jax_process|mathjax_process|math|output_area"}})</script>
|
||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
</head><body>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Coding FAQ</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="coding-faq">
|
||
<h1>Coding FAQ<a class="headerlink" href="#coding-faq" title="Permalink to this headline">¶</a></h1>
|
||
<p><em>This FAQ page is for users to share their solutions to coding problems. Keep it brief and link to
|
||
the docs if you can rather than too lengthy explanations. Don’t forget to check if an answer already
|
||
exists before answering - maybe you can clarify that answer rather than to make a new Q&A section.</em></p>
|
||
<section id="table-of-contents">
|
||
<h2>Table of Contents<a class="headerlink" href="#table-of-contents" title="Permalink to this headline">¶</a></h2>
|
||
<ul class="simple">
|
||
<li><p><a class="reference internal" href="#will-i-run-out-of-dbrefs"><span class="std std-doc">Will I run out of dbrefs?</span></a></p></li>
|
||
<li><p><a class="reference internal" href="#removing-default-commands"><span class="std std-doc">Removing default commands</span></a></p></li>
|
||
<li><p>[Preventing character from moving based on a condition](./Coding-FAQ.md#preventing-character-from-
|
||
moving-based-on-a-condition)</p></li>
|
||
<li><p>[Reference initiating object in an EvMenu command](./Coding-FAQ.md#reference-initiating-object-in-an-
|
||
evmenu-command)</p></li>
|
||
<li><p><a class="reference internal" href="#adding-color-to-default-evennia-channels"><span class="std std-doc">Adding color to default Evennia Channels</span></a></p></li>
|
||
<li><p><a class="reference internal" href="#selectively-turn-off-commands-in-a-room"><span class="std std-doc">Selectively turn off commands in a room</span></a></p></li>
|
||
<li><p><a class="reference internal" href="#select-command-based-on-a-condition"><span class="std std-doc">Select Command based on a condition</span></a></p></li>
|
||
<li><p>[Automatically updating code when reloading](./Coding-FAQ.md#automatically-updating-code-when-
|
||
reloading)</p></li>
|
||
<li><p><a class="reference internal" href="#changing-all-exit-messages"><span class="std std-doc">Changing all exit messages</span></a></p></li>
|
||
<li><p><a class="reference internal" href="#add-parsing-with-the-to-delimiter"><span class="std std-doc">Add parsing with the “to” delimiter</span></a></p></li>
|
||
<li><p><a class="reference internal" href="#store-last-used-session-ip-address"><span class="std std-doc">Store last used session IP address</span></a></p></li>
|
||
<li><p><a class="reference internal" href="#non-latin-characters-in-evtable"><span class="std std-doc">Use wide characters with EvTable</span></a></p></li>
|
||
</ul>
|
||
</section>
|
||
<section id="will-i-run-out-of-dbrefs">
|
||
<h2>Will I run out of dbrefs?<a class="headerlink" href="#will-i-run-out-of-dbrefs" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> The <code class="docutils literal notranslate"><span class="pre">#dbref</span></code> of a database object is ever-increasing. Evennia doesn’t allow you to change or
|
||
reuse them. Will not a big/old game run out of dbref integers eventually?</p>
|
||
<p><strong>A:</strong> No. For example, the default sqlite3 database’s max dbref is <code class="docutils literal notranslate"><span class="pre">2**64</span></code>. If you created <code class="docutils literal notranslate"><span class="pre">10</span> <span class="pre">000</span></code>
|
||
objects every second every minute and every day of the year it would take ~60 million years for you
|
||
to run out of dbref numbers. That’s a database of 140 TeraBytes, if every row was empty. If you are
|
||
still using Evennia at that point and has this concern, get back to us and we can discuss adding
|
||
dbref reuse then.</p>
|
||
</section>
|
||
<section id="removing-default-commands">
|
||
<h2>Removing default commands<a class="headerlink" href="#removing-default-commands" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> How does one <em>remove</em> (not replace) e.g. the default <code class="docutils literal notranslate"><span class="pre">get</span></code> <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Command</span></a> from the
|
||
Character <a class="reference internal" href="Command-Sets.html"><span class="doc std std-doc">Command Set</span></a>?</p>
|
||
<p><strong>A:</strong> Go to <code class="docutils literal notranslate"><span class="pre">mygame/commands/default_cmdsets.py</span></code>. Find the <code class="docutils literal notranslate"><span class="pre">CharacterCmdSet</span></code> class. It has one
|
||
method named <code class="docutils literal notranslate"><span class="pre">at_cmdset_creation</span></code>. At the end of that method, add the following line:
|
||
<code class="docutils literal notranslate"><span class="pre">self.remove(default_cmds.CmdGet())</span></code>. See the <a class="reference internal" href="Adding-Command-Tutorial.html"><span class="doc std std-doc">Adding Commands Tutorial</span></a>
|
||
for more info.</p>
|
||
</section>
|
||
<section id="preventing-character-from-moving-based-on-a-condition">
|
||
<h2>Preventing character from moving based on a condition<a class="headerlink" href="#preventing-character-from-moving-based-on-a-condition" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> How does one keep a character from using any exit, if they meet a certain condition? (I.E. in
|
||
combat, immobilized, etc.)</p>
|
||
<p><strong>A:</strong> The <code class="docutils literal notranslate"><span class="pre">at_before_move</span></code> hook is called by Evennia just before performing any move. If it returns
|
||
<code class="docutils literal notranslate"><span class="pre">False</span></code>, the move is aborted. Let’s say we want to check for an <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attribute</span></a> <code class="docutils literal notranslate"><span class="pre">cantmove</span></code>.
|
||
Add the following code to the <code class="docutils literal notranslate"><span class="pre">Character</span></code> class:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">def</span> <span class="nf">at_before_move</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">):</span>
|
||
<span class="s2">"Called just before trying to move"</span>
|
||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">cantmove</span><span class="p">:</span> <span class="c1"># replace with condition you want to test</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"Something is preventing you from moving!"</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="kc">False</span>
|
||
<span class="k">return</span> <span class="kc">True</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="reference-initiating-object-in-an-evmenu-command">
|
||
<h2>Reference initiating object in an EvMenu command.<a class="headerlink" href="#reference-initiating-object-in-an-evmenu-command" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> An object has a Command on it starts up an EvMenu instance. How do I capture a reference to
|
||
that object for use in the menu?</p>
|
||
<p><strong>A:</strong> When an <a class="reference internal" href="EvMenu.html"><span class="doc std std-doc">EvMenu</span></a> is started, the menu object is stored as <code class="docutils literal notranslate"><span class="pre">caller.ndb._menutree</span></code>.
|
||
This is a good place to store menu-specific things since it will clean itself up when the menu
|
||
closes. When initiating the menu, any additional keywords you give will be available for you as
|
||
properties on this menu object:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">class</span> <span class="nc">MyObjectCommand</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||
<span class="c1"># A Command stored on an object (the object is always accessible from</span>
|
||
<span class="c1"># the Command as self.obj)</span>
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># add the object as the stored_obj menu property</span>
|
||
<span class="n">EvMenu</span><span class="p">(</span><span class="n">caller</span><span class="p">,</span> <span class="o">...</span><span class="p">,</span> <span class="n">stored_obj</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>Inside the menu you can now access the object through <code class="docutils literal notranslate"><span class="pre">caller.ndb._menutree.stored_obj</span></code>.</p>
|
||
</section>
|
||
<section id="adding-color-to-default-evennia-channels">
|
||
<h2>Adding color to default Evennia Channels<a class="headerlink" href="#adding-color-to-default-evennia-channels" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> How do I add colors to the names of Evennia channels?</p>
|
||
<p><strong>A:</strong> The Channel typeclass’ <code class="docutils literal notranslate"><span class="pre">channel_prefix</span></code> method decides what is shown at the beginning of a
|
||
channel send. Edit <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/channels.py</span></code> (and then <code class="docutils literal notranslate"><span class="pre">@reload</span></code>):</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># define our custom color names</span>
|
||
<span class="n">CHANNEL_COLORS</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'public'</span><span class="p">:</span> <span class="s1">'|015Public|n'</span><span class="p">,</span>
|
||
<span class="s1">'newbie'</span><span class="p">:</span> <span class="s1">'|550N|n|551e|n|552w|n|553b|n|554i|n|555e|n'</span><span class="p">,</span>
|
||
<span class="s1">'staff'</span><span class="p">:</span> <span class="s1">'|010S|n|020t|n|030a|n|040f|n|050f|n'</span><span class="p">}</span>
|
||
|
||
<span class="c1"># Add to the Channel class</span>
|
||
<span class="c1"># ...</span>
|
||
<span class="k">def</span> <span class="nf">channel_prefix</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">msg</span><span class="p">,</span> <span class="n">emit</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
|
||
<span class="n">prefix_string</span> <span class="o">=</span> <span class="s2">""</span>
|
||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">key</span> <span class="ow">in</span> <span class="n">COLORS</span><span class="p">:</span>
|
||
<span class="n">prefix_string</span> <span class="o">=</span> <span class="s2">"[</span><span class="si">%s</span><span class="s2">] "</span> <span class="o">%</span> <span class="n">CHANNEL_COLORS</span><span class="o">.</span><span class="n">get</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="n">lower</span><span class="p">())</span>
|
||
<span class="k">else</span><span class="p">:</span>
|
||
<span class="n">prefix_string</span> <span class="o">=</span> <span class="s2">"[</span><span class="si">%s</span><span class="s2">] "</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">key</span><span class="o">.</span><span class="n">capitalize</span><span class="p">()</span>
|
||
<span class="k">return</span> <span class="n">prefix_string</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Additional hint: To make colors easier to change from one place you could instead put the
|
||
<code class="docutils literal notranslate"><span class="pre">CHANNEL_COLORS</span></code> dict in your settings file and import it as <code class="docutils literal notranslate"><span class="pre">from</span> <span class="pre">django.conf.settings</span> <span class="pre">import</span> <span class="pre">CHANNEL_COLORS</span></code>.</p>
|
||
</section>
|
||
<section id="selectively-turn-off-commands-in-a-room">
|
||
<h2>Selectively turn off commands in a room<a class="headerlink" href="#selectively-turn-off-commands-in-a-room" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> I want certain commands to turn off in a given room. They should still work normally for
|
||
staff.</p>
|
||
<p><strong>A:</strong> This is done using a custom cmdset on a room <a class="reference internal" href="Locks.html"><span class="doc std std-doc">locked with the ‘call’ lock type</span></a>. Only
|
||
if this lock is passed will the commands on the room be made available to an object inside it. Here
|
||
is an example of a room where certain commands are disabled for non-staff:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/rooms.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_commands</span><span class="p">,</span> <span class="n">CmdSet</span>
|
||
|
||
<span class="k">class</span> <span class="nc">CmdBlocking</span><span class="p">(</span><span class="n">default_commands</span><span class="o">.</span><span class="n">MuxCommand</span><span class="p">):</span>
|
||
<span class="c1"># block commands give, get, inventory and drop</span>
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"give"</span>
|
||
<span class="n">aliases</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"get"</span><span class="p">,</span> <span class="s2">"inventory"</span><span class="p">,</span> <span class="s2">"drop"</span><span class="p">]</span>
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"You cannot do that in this room."</span><span class="p">)</span>
|
||
|
||
<span class="k">class</span> <span class="nc">BlockingCmdSet</span><span class="p">(</span><span class="n">CmdSet</span><span class="p">):</span>
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"blocking_cmdset"</span>
|
||
<span class="c1"># default commands have prio 0</span>
|
||
<span class="n">priority</span> <span class="o">=</span> <span class="mi">1</span>
|
||
<span class="k">def</span> <span class="nf">at_cmdset_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">add</span><span class="p">(</span><span class="n">CmdBlocking</span><span class="p">())</span>
|
||
|
||
<span class="k">class</span> <span class="nc">BlockingRoom</span><span class="p">(</span><span class="n">Room</span><span class="p">):</span>
|
||
<span class="k">def</span> <span class="nf">at_object_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">cmdset</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">BlockingCmdSet</span><span class="p">,</span> <span class="n">permanent</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
|
||
<span class="c1"># only share commands with players in the room that</span>
|
||
<span class="c1"># are NOT Builders or higher</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">locks</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">"call:not perm(Builders)"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>After <code class="docutils literal notranslate"><span class="pre">@reload</span></code>, make some <code class="docutils literal notranslate"><span class="pre">BlockingRooms</span></code> (or switch a room to it with <code class="docutils literal notranslate"><span class="pre">@typeclass</span></code>). Entering one
|
||
will now replace the given commands for anyone that does not have the <code class="docutils literal notranslate"><span class="pre">Builders</span></code> or higher
|
||
permission. Note that the ‘call’ lock is special in that even the superuser will be affected by it
|
||
(otherwise superusers would always see other player’s cmdsets and a game would be unplayable for
|
||
superusers).</p>
|
||
</section>
|
||
<section id="select-command-based-on-a-condition">
|
||
<h2>Select Command based on a condition<a class="headerlink" href="#select-command-based-on-a-condition" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> I want a command to be available only based on a condition. For example I want the “werewolf”
|
||
command to only be available on a full moon, from midnight to three in-game time.</p>
|
||
<p><strong>A:</strong> This is easiest accomplished by putting the “werewolf” command on the Character as normal,
|
||
but to <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock</span></a> it with the “cmd” type lock. Only if the “cmd” lock type is passed will the
|
||
command be available.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/commands/command.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">Command</span>
|
||
|
||
<span class="k">class</span> <span class="nc">CmdWerewolf</span><span class="p">(</span><span class="n">Command</span><span class="p">):</span>
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"werewolf"</span>
|
||
<span class="c1"># lock full moon, between 00:00 (midnight) and 03:00.</span>
|
||
<span class="n">locks</span> <span class="o">=</span> <span class="s2">"cmd:is_full_moon(0, 3)"</span>
|
||
<span class="k">def</span> <span class="nf">func</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># ...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Add this to the <a class="reference internal" href="Adding-Command-Tutorial.html"><span class="doc std std-doc">default cmdset as usual</span></a>. The <code class="docutils literal notranslate"><span class="pre">is_full_moon</span></code> <a class="reference internal" href="Locks.html#lock-functions"><span class="std std-doc">lock
|
||
function</span></a> does not yet exist. We must create that:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/server/conf/lockfuncs.py</span>
|
||
|
||
<span class="k">def</span> <span class="nf">is_full_moon</span><span class="p">(</span><span class="n">accessing_obj</span><span class="p">,</span> <span class="n">accessed_obj</span><span class="p">,</span>
|
||
<span class="n">starthour</span><span class="p">,</span> <span class="n">endhour</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="c1"># calculate if the moon is full here and</span>
|
||
<span class="c1"># if current game time is between starthour and endhour</span>
|
||
<span class="c1"># return True or False</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>After a <code class="docutils literal notranslate"><span class="pre">@reload</span></code>, the <code class="docutils literal notranslate"><span class="pre">werewolf</span></code> command will be available only at the right time, that is when the
|
||
<code class="docutils literal notranslate"><span class="pre">is_full_moon</span></code> lock function returns True.</p>
|
||
</section>
|
||
<section id="automatically-updating-code-when-reloading">
|
||
<h2>Automatically updating code when reloading<a class="headerlink" href="#automatically-updating-code-when-reloading" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> I have a development server running Evennia. Can I have the server update its code-base when
|
||
I reload?</p>
|
||
<p><strong>A:</strong> Having a development server that pulls updated code whenever you reload it can be really
|
||
useful if you have limited shell access to your server, or want to have it done automatically. If
|
||
you have your project in a configured Git environment, it’s a matter of automatically calling <code class="docutils literal notranslate"><span class="pre">git</span> <span class="pre">pull</span></code> when you reload. And that’s pretty straightforward:</p>
|
||
<p>In <code class="docutils literal notranslate"><span class="pre">/server/conf/at_server_startstop.py</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">subprocess</span>
|
||
|
||
<span class="c1"># ... other hooks ...</span>
|
||
|
||
<span class="k">def</span> <span class="nf">at_server_reload_stop</span><span class="p">():</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> This is called only time the server stops before a reload.</span>
|
||
<span class="sd"> """</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="s2">"Pulling from the game repository..."</span><span class="p">)</span>
|
||
<span class="n">process</span> <span class="o">=</span> <span class="n">subprocess</span><span class="o">.</span><span class="n">call</span><span class="p">([</span><span class="s2">"git"</span><span class="p">,</span> <span class="s2">"pull"</span><span class="p">],</span> <span class="n">shell</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>That’s all. We call <code class="docutils literal notranslate"><span class="pre">subprocess</span></code> to execute a shell command (that code works on Windows and Linux,
|
||
assuming the current directory is your game directory, which is probably the case when you run
|
||
Evennia). <code class="docutils literal notranslate"><span class="pre">call</span></code> waits for the process to complete, because otherwise, Evennia would reload on
|
||
partially-modified code, which would be problematic.</p>
|
||
<p>Now, when you enter <code class="docutils literal notranslate"><span class="pre">@reload</span></code> on your development server, the game repository is updated from the
|
||
configured remote repository (Github, for instance). Your development cycle could resemble
|
||
something like:</p>
|
||
<ol class="simple">
|
||
<li><p>Coding on the local machine.</p></li>
|
||
<li><p>Testing modifications.</p></li>
|
||
<li><p>Committing once, twice or more (being sure the code is still working, unittests are pretty useful
|
||
here).</p></li>
|
||
<li><p>When the time comes, login to the development server and run <code class="docutils literal notranslate"><span class="pre">@reload</span></code>.</p></li>
|
||
</ol>
|
||
<p>The reloading might take one or two additional seconds, since Evennia will pull from your remote Git
|
||
repository. But it will reload on it and you will have your modifications ready, without needing
|
||
connecting to your server using SSH or something similar.</p>
|
||
</section>
|
||
<section id="changing-all-exit-messages">
|
||
<h2>Changing all exit messages<a class="headerlink" href="#changing-all-exit-messages" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> How can I change the default exit messages to something like “XXX leaves east” or “XXX
|
||
arrives from the west”?</p>
|
||
<p><strong>A:</strong> the default exit messages are stored in two hooks, namely <code class="docutils literal notranslate"><span class="pre">announce_move_from</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">announce_move_to</span></code>, on the <code class="docutils literal notranslate"><span class="pre">Character</span></code> typeclass (if what you want to change is the message other
|
||
characters will see when a character exits).</p>
|
||
<p>These two hooks provide some useful features to easily update the message to be displayed. They
|
||
take both the default message and mapping as argument. You can easily call the parent hook with
|
||
these information:</p>
|
||
<ul class="simple">
|
||
<li><p>The message represents the string of characters sent to characters in the room when a character
|
||
leaves.</p></li>
|
||
<li><p>The mapping is a dictionary containing additional mappings (you will probably not need it for
|
||
simple customization).</p></li>
|
||
</ul>
|
||
<p>It is advisable to look in the <a class="reference external" href="https://github.com/evennia/evennia/tree/master/evennia/objects/objects.py">code of both
|
||
hooks</a>, and read the
|
||
hooks’ documentation. The explanations on how to quickly update the message are shown below:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># In typeclasses/characters.py</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd">Characters</span>
|
||
|
||
<span class="sd">"""</span>
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Character</span><span class="p">(</span><span class="n">DefaultCharacter</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> The default character class.</span>
|
||
|
||
<span class="sd"> ...</span>
|
||
<span class="sd"> """</span>
|
||
|
||
<span class="k">def</span> <span class="nf">announce_move_from</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">destination</span><span class="p">,</span> <span class="n">msg</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">mapping</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> Called if the move is to be announced. This is</span>
|
||
<span class="sd"> called while we are still standing in the old</span>
|
||
<span class="sd"> location.</span>
|
||
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> destination (Object): The place we are going to.</span>
|
||
<span class="sd"> msg (str, optional): a replacement message.</span>
|
||
<span class="sd"> mapping (dict, optional): additional mapping objects.</span>
|
||
|
||
<span class="sd"> You can override this method and call its parent with a</span>
|
||
<span class="sd"> message to simply change the default message. In the string,</span>
|
||
<span class="sd"> you can use the following as mappings (between braces):</span>
|
||
<span class="sd"> object: the object which is moving.</span>
|
||
<span class="sd"> exit: the exit from which the object is moving (if found).</span>
|
||
<span class="sd"> origin: the location of the object before the move.</span>
|
||
<span class="sd"> destination: the location of the object after moving.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">announce_move_from</span><span class="p">(</span><span class="n">destination</span><span class="p">,</span> <span class="n">msg</span><span class="o">=</span><span class="s2">"</span><span class="si">{object}</span><span class="s2"> leaves </span><span class="si">{exit}</span><span class="s2">."</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">announce_move_to</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">source_location</span><span class="p">,</span> <span class="n">msg</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">mapping</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
|
||
<span class="sd">"""</span>
|
||
<span class="sd"> Called after the move if the move was not quiet. At this point</span>
|
||
<span class="sd"> we are standing in the new location.</span>
|
||
|
||
<span class="sd"> Args:</span>
|
||
<span class="sd"> source_location (Object): The place we came from</span>
|
||
<span class="sd"> msg (str, optional): the replacement message if location.</span>
|
||
<span class="sd"> mapping (dict, optional): additional mapping objects.</span>
|
||
|
||
<span class="sd"> You can override this method and call its parent with a</span>
|
||
<span class="sd"> message to simply change the default message. In the string,</span>
|
||
<span class="sd"> you can use the following as mappings (between braces):</span>
|
||
<span class="sd"> object: the object which is moving.</span>
|
||
<span class="sd"> exit: the exit from which the object is moving (if found).</span>
|
||
<span class="sd"> origin: the location of the object before the move.</span>
|
||
<span class="sd"> destination: the location of the object after moving.</span>
|
||
|
||
<span class="sd"> """</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">announce_move_to</span><span class="p">(</span><span class="n">source_location</span><span class="p">,</span> <span class="n">msg</span><span class="o">=</span><span class="s2">"</span><span class="si">{object}</span><span class="s2"> arrives from the </span><span class="si">{exit}</span><span class="s2">."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>We override both hooks, but call the parent hook to display a different message. If you read the
|
||
provided docstrings, you will better understand why and how we use mappings (information between
|
||
braces). You can provide additional mappings as well, if you want to set a verb to move, for
|
||
instance, or other, extra information.</p>
|
||
</section>
|
||
<section id="add-parsing-with-the-to-delimiter">
|
||
<h2>Add parsing with the “to” delimiter<a class="headerlink" href="#add-parsing-with-the-to-delimiter" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> How do I change commands to undestand say <code class="docutils literal notranslate"><span class="pre">give</span> <span class="pre">obj</span> <span class="pre">to</span> <span class="pre">target</span></code> as well as the default <code class="docutils literal notranslate"><span class="pre">give</span> <span class="pre">obj</span> <span class="pre">=</span> <span class="pre">target</span></code>?</p>
|
||
<p><strong>A:</strong> You can make change the default <code class="docutils literal notranslate"><span class="pre">MuxCommand</span></code> parent with your own class making a small change
|
||
in its <code class="docutils literal notranslate"><span class="pre">parse</span></code> method:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># in mygame/commands/command.py</span>
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">default_cmds</span>
|
||
<span class="k">class</span> <span class="nc">MuxCommand</span><span class="p">(</span><span class="n">default_cmds</span><span class="o">.</span><span class="n">MuxCommand</span><span class="p">):</span>
|
||
<span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="sd">"""Implement an additional parsing of 'to'"""</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">parse</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="s2">" to "</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">lhs</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">rhs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">args</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">" to "</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Next you change the parent of the default commands in settings:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">COMMAND_DEFAULT_CLASS</span> <span class="o">=</span> <span class="s2">"commands.command.MuxCommand"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Do a <code class="docutils literal notranslate"><span class="pre">@reload</span></code> and all default commands will now use your new tweaked parent class. A copy of the
|
||
MuxCommand class is also found commented-out in the <code class="docutils literal notranslate"><span class="pre">mygame/commands/command.py</span></code> file.</p>
|
||
</section>
|
||
<section id="store-last-used-session-ip-address">
|
||
<h2>Store last used session IP address<a class="headerlink" href="#store-last-used-session-ip-address" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> If a user has already logged out of an Evennia account, their IP is no longer visible to
|
||
staff that wants to ban-by-ip (instead of the user) with <code class="docutils literal notranslate"><span class="pre">@ban/ip</span></code>?</p>
|
||
<p><strong>A:</strong> One approach is to write the IP from the last session onto the “account” account object.</p>
|
||
<p><code class="docutils literal notranslate"><span class="pre">typeclasses/accounts.py</span></code></p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">at_post_login</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_post_login</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">lastsite</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="o">.</span><span class="n">all</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span><span class="o">.</span><span class="n">address</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Adding timestamp for login time and appending to a list to keep the last N login IP addresses and
|
||
timestamps is possible, also. Additionally, if you don’t want the list to grow beyond a
|
||
<code class="docutils literal notranslate"><span class="pre">do_not_exceed</span></code> length, conditionally pop a value after you’ve added it, if the length has grown too
|
||
long.</p>
|
||
<p><strong>NOTE:</strong> You’ll need to add <code class="docutils literal notranslate"><span class="pre">import</span> <span class="pre">time</span></code> to generate the login timestamp.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="k">def</span> <span class="nf">at_post_login</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">session</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">at_post_login</span><span class="p">(</span><span class="n">session</span><span class="o">=</span><span class="n">session</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
<span class="n">do_not_exceed</span> <span class="o">=</span> <span class="mi">24</span> <span class="c1"># Keep the last two dozen entries</span>
|
||
<span class="n">session</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">sessions</span><span class="o">.</span><span class="n">all</span><span class="p">()[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># Most recent session</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">lastsite</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">lastsite</span> <span class="o">=</span> <span class="p">[]</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">lastsite</span><span class="o">.</span><span class="n">insert</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="p">(</span><span class="n">session</span><span class="o">.</span><span class="n">address</span><span class="p">,</span> <span class="nb">int</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">time</span><span class="p">())))</span>
|
||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">lastsite</span><span class="p">)</span> <span class="o">></span> <span class="n">do_not_exceed</span><span class="p">:</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">lastsite</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>This only stores the data. You may want to interface the <code class="docutils literal notranslate"><span class="pre">@ban</span></code> command or make a menu-driven viewer
|
||
for staff to browse the list and display how long ago the login occurred.</p>
|
||
</section>
|
||
<section id="non-latin-characters-in-evtable">
|
||
<h2>Non-latin characters in EvTable<a class="headerlink" href="#non-latin-characters-in-evtable" title="Permalink to this headline">¶</a></h2>
|
||
<p><strong>Q:</strong> When using e.g. Chinese characters in EvTable, some lines appear to be too wide, for example</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">+------+------+</span>
|
||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="o">|</span> <span class="n">测试</span> <span class="o">|</span> <span class="n">测试</span> <span class="o">|</span>
|
||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="o">+~~~~~~+~~~~~~+</span>
|
||
</pre></div>
|
||
</div>
|
||
<p><strong>A:</strong> The reason for this is because certain non-latin characters are <em>visually</em> much wider than
|
||
their len() suggests. There is little Evennia can (reliably) do about this. If you are using such
|
||
characters, you need to make sure to use a suitable mono-spaced font where are width are equal. You
|
||
can set this in your web client and need to recommend it for telnet-client users. See <a class="reference external" href="https://github.com/evennia/evennia/issues/1522">this
|
||
discussion</a> where some suitable fonts are suggested.</p>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="index.html">
|
||
<img class="logo" src="_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<p><h3><a href="index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Coding FAQ</a><ul>
|
||
<li><a class="reference internal" href="#table-of-contents">Table of Contents</a></li>
|
||
<li><a class="reference internal" href="#will-i-run-out-of-dbrefs">Will I run out of dbrefs?</a></li>
|
||
<li><a class="reference internal" href="#removing-default-commands">Removing default commands</a></li>
|
||
<li><a class="reference internal" href="#preventing-character-from-moving-based-on-a-condition">Preventing character from moving based on a condition</a></li>
|
||
<li><a class="reference internal" href="#reference-initiating-object-in-an-evmenu-command">Reference initiating object in an EvMenu command.</a></li>
|
||
<li><a class="reference internal" href="#adding-color-to-default-evennia-channels">Adding color to default Evennia Channels</a></li>
|
||
<li><a class="reference internal" href="#selectively-turn-off-commands-in-a-room">Selectively turn off commands in a room</a></li>
|
||
<li><a class="reference internal" href="#select-command-based-on-a-condition">Select Command based on a condition</a></li>
|
||
<li><a class="reference internal" href="#automatically-updating-code-when-reloading">Automatically updating code when reloading</a></li>
|
||
<li><a class="reference internal" href="#changing-all-exit-messages">Changing all exit messages</a></li>
|
||
<li><a class="reference internal" href="#add-parsing-with-the-to-delimiter">Add parsing with the “to” delimiter</a></li>
|
||
<li><a class="reference internal" href="#store-last-used-session-ip-address">Store last used session IP address</a></li>
|
||
<li><a class="reference internal" href="#non-latin-characters-in-evtable">Non-latin characters in EvTable</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="_sources/Coding-FAQ.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
|
||
<a href="https://discord.gg/NecFePw">Discord</a> -
|
||
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
|
||
</li>
|
||
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
|
||
</ul>
|
||
<h3>Versions</h3>
|
||
<ul>
|
||
<li><a href="../1.0-dev/index.html">1.0-dev (develop branch)</a></li>
|
||
<li><a href="Coding-FAQ.html">0.9.5 (v0.9.5 branch)</a></li>
|
||
</ul>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Coding FAQ</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2020, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |