mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
371 lines
No EOL
30 KiB
HTML
371 lines
No EOL
30 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>Making a Persistent object Handler — Evennia 2.x documentation</title>
|
||
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||
<script src="../_static/jquery.js"></script>
|
||
<script src="../_static/underscore.js"></script>
|
||
<script src="../_static/doctools.js"></script>
|
||
<script src="../_static/language_data.js"></script>
|
||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="../genindex.html" />
|
||
<link rel="search" title="Search" href="../search.html" />
|
||
<link rel="next" title="Changing game calendar and time speed" href="Howto-Game-Time.html" />
|
||
<link rel="prev" title="Building a train that moves" href="Tutorial-Building-a-Train.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="Howto-Game-Time.html" title="Changing game calendar and time speed"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Tutorial-Building-a-Train.html" title="Building a train that moves"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" accesskey="U">Tutorials and Howto’s</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Making a Persistent object Handler</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
|
||
<div class="documentwrapper">
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="../index.html">
|
||
<img class="logo" src="../_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="../search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<h3><a href="../index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Making a Persistent object Handler</a><ul>
|
||
<li><a class="reference internal" href="#base-handler-example">Base Handler example</a></li>
|
||
<li><a class="reference internal" href="#persistent-storage-of-data-in-handler">Persistent storage of data in handler</a><ul>
|
||
<li><a class="reference internal" href="#handler-with-save-load-capability">Handler with save/load capability</a></li>
|
||
<li><a class="reference internal" href="#make-quests-storable">Make quests storable</a></li>
|
||
<li><a class="reference internal" href="#tying-it-all-together">Tying it all together</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Tutorial-Building-a-Train.html"
|
||
title="previous chapter">Building a train that moves</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Howto-Game-Time.html"
|
||
title="next chapter">Changing game calendar and time speed</a></p>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../_sources/Howtos/Tutorial-Persistent-Handler.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
|
||
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li>
|
||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||
</li>
|
||
</ul>
|
||
<h3>Doc Versions</h3>
|
||
<ul>
|
||
|
||
<li><a href="Tutorial-Persistent-Handler.html">2.x (main branch)</a></li>
|
||
<ul>
|
||
<li><a href="../1.3.0/index.html">1.3.0 (v1.3.0 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="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="making-a-persistent-object-handler">
|
||
<h1>Making a Persistent object Handler<a class="headerlink" href="#making-a-persistent-object-handler" title="Permalink to this headline">¶</a></h1>
|
||
<p>A <em>handler</em> is a convenient way to group functionality on an object. This allows you to logically
|
||
group all actions related to that thing in one place. This tutorial expemplifies how to make your
|
||
own handlers and make sure data you store in them survives a reload.</p>
|
||
<p>For example, when you do <code class="docutils literal notranslate"><span class="pre">obj.attributes.get("key")</span></code> or <code class="docutils literal notranslate"><span class="pre">obj.tags.add('tagname')</span></code> you are evoking
|
||
handlers stored as <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> and <code class="docutils literal notranslate"><span class="pre">tags</span></code> on the <code class="docutils literal notranslate"><span class="pre">obj</span></code>. On these handlers are methods (<code class="docutils literal notranslate"><span class="pre">get()</span></code>
|
||
and <code class="docutils literal notranslate"><span class="pre">add()</span></code> in this example).</p>
|
||
<section id="base-handler-example">
|
||
<h2>Base Handler example<a class="headerlink" href="#base-handler-example" title="Permalink to this headline">¶</a></h2>
|
||
<p>Here is a base way to set up an on-object handler:</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">DefaultObject</span><span class="p">,</span> <span class="n">create_object</span>
|
||
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">lazy_property</span>
|
||
|
||
<span class="k">class</span> <span class="nc">NameChanger</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">obj</span>
|
||
|
||
<span class="k">def</span> <span class="nf">add_to_key</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">suffix</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">"self.obj.key_</span><span class="si">{</span><span class="n">suffix</span><span class="si">}</span><span class="s2">"</span>
|
||
|
||
<span class="c1"># make a test object</span>
|
||
<span class="k">class</span> <span class="nc">MyObject</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||
<span class="nd">@lazy_property</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="nf">namechange</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">NameChanger</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
||
|
||
|
||
<span class="n">obj</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">MyObject</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"test"</span><span class="p">)</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
|
||
<span class="o">>>></span> <span class="s2">"test"</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">namechange</span><span class="o">.</span><span class="n">add_to_key</span><span class="p">(</span><span class="s2">"extra"</span><span class="p">)</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
|
||
<span class="o">>>></span> <span class="s2">"test_extra"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>What happens here is that we make a new class <code class="docutils literal notranslate"><span class="pre">NameChanger</span></code>. We use the
|
||
<code class="docutils literal notranslate"><span class="pre">@lazy_property</span></code> decorator to set it up - this means the handler will not be
|
||
actually created until someone really wants to use it, by accessing
|
||
<code class="docutils literal notranslate"><span class="pre">obj.namechange</span></code> later. The decorated <code class="docutils literal notranslate"><span class="pre">namechange</span></code> method returns the handler
|
||
and makes sure to initialize it with <code class="docutils literal notranslate"><span class="pre">self</span></code> - this becomes the <code class="docutils literal notranslate"><span class="pre">obj</span></code> inside the
|
||
handler!</p>
|
||
<p>We then make a silly method <code class="docutils literal notranslate"><span class="pre">add_to_key</span></code> that uses the handler to manipulate the
|
||
key of the object. In this example, the handler is pretty pointless, but
|
||
grouping functionality this way can both make for an easy-to-remember API and
|
||
can also allow you cache data for easy access - this is how the
|
||
<code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> (<code class="docutils literal notranslate"><span class="pre">.attributes</span></code>) and <code class="docutils literal notranslate"><span class="pre">TagHandler</span></code> (<code class="docutils literal notranslate"><span class="pre">.tags</span></code>) works.</p>
|
||
</section>
|
||
<section id="persistent-storage-of-data-in-handler">
|
||
<h2>Persistent storage of data in handler<a class="headerlink" href="#persistent-storage-of-data-in-handler" title="Permalink to this headline">¶</a></h2>
|
||
<p>Let’s say we want to track ‘quests’ in our handler. A ‘quest’ is a regular class
|
||
that represents the quest. Let’s make it simple as an example:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># for example in mygame/world/quests.py</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">Quest</span><span class="p">:</span>
|
||
|
||
<span class="n">key</span> <span class="o">=</span> <span class="s2">"The quest for the red key"</span>
|
||
|
||
<span class="k">def</span> <span class="fm">__init__</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">current_step</span> <span class="o">=</span> <span class="s2">"start"</span>
|
||
|
||
<span class="k">def</span> <span class="nf">check_progress</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># uses self.current_step to check</span>
|
||
<span class="c1"># progress of this quest</span>
|
||
<span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="sa">f</span><span class="s2">"step_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">current_step</span><span class="si">}</span><span class="s2">"</span><span class="p">)()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">step_start</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># check here if quest-step is complete</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">current_step</span> <span class="o">=</span> <span class="s2">"find_the_red_key"</span>
|
||
<span class="k">def</span> <span class="nf">step_find_the_red_key</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># check if step is complete</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">current_step</span> <span class="o">=</span> <span class="s2">"hand_in_quest"</span>
|
||
<span class="k">def</span> <span class="nf">step_hand_in_quest</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="c1"># check if handed in quest to quest giver</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">current_step</span> <span class="o">=</span> <span class="kc">None</span> <span class="c1"># finished</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>We expect the dev to make subclasses of this to implement different quests. Exactly how this works
|
||
doesn’t matter, the key is that we want to track <code class="docutils literal notranslate"><span class="pre">self.current_step</span></code> - a property that <em>should
|
||
survive a server reload</em>. But so far there is no way for <code class="docutils literal notranslate"><span class="pre">Quest</span></code> to accomplish this, it’s just a
|
||
normal Python class with no connection to the database.</p>
|
||
<section id="handler-with-save-load-capability">
|
||
<h3>Handler with save/load capability<a class="headerlink" href="#handler-with-save-load-capability" title="Permalink to this headline">¶</a></h3>
|
||
<p>Let’s make a <code class="docutils literal notranslate"><span class="pre">QuestHandler</span></code> that manages a character’s quests.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># for example in the same mygame/world/quests.py</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">QuestHandler</span><span class="p">:</span>
|
||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">obj</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">do_save</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_load</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">_load</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">storage</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span>
|
||
<span class="s2">"quest_storage"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="p">{},</span> <span class="n">category</span><span class="o">=</span><span class="s2">"quests"</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">_save</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">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span>
|
||
<span class="s2">"quest_storage"</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">storage</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"quests"</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_load</span><span class="p">()</span> <span class="c1"># important</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">do_save</span> <span class="o">=</span> <span class="kc">False</span>
|
||
|
||
<span class="k">def</span> <span class="nf">add</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">questclass</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">storage</span><span class="p">[</span><span class="n">questclass</span><span class="o">.</span><span class="n">key</span><span class="p">]</span> <span class="o">=</span> <span class="n">questclass</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
|
||
|
||
<span class="k">def</span> <span class="nf">check_progress</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="n">quest</span><span class="o">.</span><span class="n">check_progress</span><span class="p">()</span>
|
||
<span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">do_save</span><span class="p">:</span>
|
||
<span class="c1"># .do_save is set on handler by Quest if it wants to save progress</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_save</span><span class="p">()</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>The handler is just a normal Python class and has no database-storage on its own. But it has a link
|
||
to <code class="docutils literal notranslate"><span class="pre">.obj</span></code>, which is assumed to be a full typeclased entity, on which we can create
|
||
persistent <a class="reference internal" href="../Components/Attributes.html"><span class="doc std std-doc">Attributes</span></a> to store things however we like!</p>
|
||
<p>We make two helper methods <code class="docutils literal notranslate"><span class="pre">_load</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">_save</span></code> that handles local fetches and saves <code class="docutils literal notranslate"><span class="pre">storage</span></code> to an Attribute on the object. To avoid
|
||
saving more than necessary, we have a property <code class="docutils literal notranslate"><span class="pre">do_save</span></code>. This we will set in <code class="docutils literal notranslate"><span class="pre">Quest</span></code> below.</p>
|
||
<blockquote>
|
||
<div><p>Note that once we <code class="docutils literal notranslate"><span class="pre">_save</span></code> the data, we need to call <code class="docutils literal notranslate"><span class="pre">_load</span></code> again. This is to make sure the version we store on the handler is properly de-serialized. If you get an error about data being <code class="docutils literal notranslate"><span class="pre">bytes</span></code>, you probably missed this step.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="make-quests-storable">
|
||
<h3>Make quests storable<a class="headerlink" href="#make-quests-storable" title="Permalink to this headline">¶</a></h3>
|
||
<p>The handler will save all <code class="docutils literal notranslate"><span class="pre">Quest</span></code> objects as a <code class="docutils literal notranslate"><span class="pre">dict</span></code> in an Attribute on <code class="docutils literal notranslate"><span class="pre">obj</span></code>. We are not done yet
|
||
though, the <code class="docutils literal notranslate"><span class="pre">Quest</span></code> object needs access to the <code class="docutils literal notranslate"><span class="pre">obj</span></code> too - not only will this is important to figure
|
||
out if the quest is complete (the <code class="docutils literal notranslate"><span class="pre">Quest</span></code> must be able to check the quester’s inventory to see if
|
||
they have the red key, for example), it also allows the <code class="docutils literal notranslate"><span class="pre">Quest</span></code> to tell the handler when its state
|
||
changed and it should be saved.</p>
|
||
<p>We change the <code class="docutils literal notranslate"><span class="pre">Quest</span></code> such:</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">dbserialize</span>
|
||
|
||
|
||
<span class="k">class</span> <span class="nc">Quest</span><span class="p">:</span>
|
||
|
||
<span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">obj</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_current_step</span> <span class="o">=</span> <span class="s2">"start"</span>
|
||
|
||
<span class="k">def</span> <span class="nf">__serialize_dbobjs__</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">obj</span> <span class="o">=</span> <span class="n">dbserialize</span><span class="o">.</span><span class="n">dbserialize</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span>
|
||
|
||
<span class="k">def</span> <span class="nf">__deserialize_dbobjs__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">obj</span> <span class="o">=</span> <span class="n">dbserialize</span><span class="o">.</span><span class="n">dbunserialize</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="p">)</span>
|
||
|
||
<span class="nd">@property</span>
|
||
<span class="k">def</span> <span class="nf">questhandler</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj</span><span class="o">.</span><span class="n">quests</span>
|
||
|
||
<span class="nd">@property</span>
|
||
<span class="k">def</span> <span class="nf">current_step</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_current_step</span>
|
||
|
||
<span class="nd">@current_step</span><span class="o">.</span><span class="n">setter</span>
|
||
<span class="k">def</span> <span class="nf">current_step</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">_current_step</span> <span class="o">=</span> <span class="n">value</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">questhandler</span><span class="o">.</span><span class="n">do_save</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># this triggers save in handler!</span>
|
||
|
||
<span class="c1"># [same as before]</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">Quest.__init__</span></code> now takes <code class="docutils literal notranslate"><span class="pre">obj</span></code> as argument, to match what we pass to it in
|
||
<code class="docutils literal notranslate"><span class="pre">QuestHandler.add</span></code>. We want to monitor the changing of <code class="docutils literal notranslate"><span class="pre">current_step</span></code>, so we
|
||
make it into a <code class="docutils literal notranslate"><span class="pre">property</span></code>. When we edit that value, we set the <code class="docutils literal notranslate"><span class="pre">do_save</span></code> flag on
|
||
the handler, which means it will save the status to database once it has checked
|
||
progress on all its quests. The <code class="docutils literal notranslate"><span class="pre">Quest.questhandler</span></code> property allows to easily
|
||
get back to the handler (and the object on which it sits).</p>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">__serialize__dbobjs__</span></code> and <code class="docutils literal notranslate"><span class="pre">__deserialize_dbobjs__</span></code> methods are needed
|
||
because <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> can’t store ‘hidden’ database objects (the <code class="docutils literal notranslate"><span class="pre">Quest.obj</span></code>
|
||
property. The methods help Evennia serialize/deserialize <code class="docutils literal notranslate"><span class="pre">Quest</span></code> propertly when
|
||
the handler saves it. For more information, see <a class="reference internal" href="../Components/Attributes.html#storing-single-objects"><span class="std std-doc">Storing Single
|
||
objects</span></a> in the Attributes</p>
|
||
</section>
|
||
<section id="tying-it-all-together">
|
||
<h3>Tying it all together<a class="headerlink" href="#tying-it-all-together" title="Permalink to this headline">¶</a></h3>
|
||
<p>The final thing we need to do is to add the quest-handler to the character:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># in mygame/typeclasses/characters.py</span>
|
||
|
||
<span class="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">DefaultCharacter</span>
|
||
<span class="kn">from</span> <span class="nn">evennia.utils.utils</span> <span class="kn">import</span> <span class="n">lazy_property</span>
|
||
<span class="kn">from</span> <span class="nn">.world.quests</span> <span class="kn">import</span> <span class="n">QuestHandler</span> <span class="c1"># as an example</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="c1"># ...</span>
|
||
<span class="nd">@lazy_property</span>
|
||
<span class="k">def</span> <span class="nf">quests</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
|
||
<span class="k">return</span> <span class="n">QuestHandler</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>You can now make your Quest classes to describe your quests and add them to
|
||
characters with</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">character</span><span class="o">.</span><span class="n">quests</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">FindTheRedKey</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>and can later do</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">character</span><span class="o">.</span><span class="n">quests</span><span class="o">.</span><span class="n">check_progress</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>and be sure that quest data is not lost between reloads.</p>
|
||
<p>You can find a full-fledged quest-handler example as <a class="reference internal" href="../api/evennia.contrib.tutorials.evadventure.quests.html#evennia-contrib-tutorials-evadventure-quests"><span class="std std-ref">EvAdventure
|
||
quests</span></a> contrib in the Evennia
|
||
repository.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Howto-Game-Time.html" title="Changing game calendar and time speed"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Tutorial-Building-a-Train.html" title="Building a train that moves"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 2.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Howtos-Overview.html" >Tutorials and Howto’s</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Making a Persistent object Handler</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
|
||
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2023, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |