mirror of
https://github.com/evennia/evennia.git
synced 2026-03-17 13:26:30 +01:00
632 lines
No EOL
81 KiB
HTML
632 lines
No EOL
81 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>Attributes — Evennia 3.x documentation</title>
|
||
<link rel="stylesheet" href="../_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="../" src="../_static/documentation_options.js"></script>
|
||
<script src="../_static/jquery.js"></script>
|
||
<script src="../_static/underscore.js"></script>
|
||
<script src="../_static/doctools.js"></script>
|
||
<script src="../_static/language_data.js"></script>
|
||
<link rel="shortcut icon" href="../_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="../genindex.html" />
|
||
<link rel="search" title="Search" href="../search.html" />
|
||
<link rel="next" title="Nicks" href="Nicks.html" />
|
||
<link rel="prev" title="Msg" href="Msg.html" />
|
||
</head><body>
|
||
|
||
|
||
<div class="admonition important">
|
||
<p class="first admonition-title">Note</p>
|
||
<p class="last">You are reading an old version of the Evennia documentation. <a href="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
|
||
</div>
|
||
|
||
|
||
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="../genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="../py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="right" >
|
||
<a href="Nicks.html" title="Nicks"
|
||
accesskey="N">next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Msg.html" title="Msg"
|
||
accesskey="P">previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 3.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" accesskey="U">Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Attributes</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="#">Attributes</a><ul>
|
||
<li><a class="reference internal" href="#working-with-attributes">Working with Attributes</a><ul>
|
||
<li><a class="reference internal" href="#using-db">Using .db</a></li>
|
||
<li><a class="reference internal" href="#using-attributes">Using .attributes</a></li>
|
||
<li><a class="reference internal" href="#using-attributeproperty">Using AttributeProperty</a></li>
|
||
<li><a class="reference internal" href="#properties-of-attributes">Properties of Attributes</a></li>
|
||
<li><a class="reference internal" href="#managing-attributes-in-game">Managing Attributes in-game</a></li>
|
||
<li><a class="reference internal" href="#locking-and-checking-attributes">Locking and checking Attributes</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute">What types of data can I save in an Attribute?</a><ul>
|
||
<li><a class="reference internal" href="#storing-single-objects">Storing single objects</a></li>
|
||
<li><a class="reference internal" href="#storing-multiple-objects">Storing multiple objects</a></li>
|
||
<li><a class="reference internal" href="#retrieving-mutable-objects">Retrieving Mutable objects</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#in-memory-attributes-nattributes">In-memory Attributes (NAttributes)</a><ul>
|
||
<li><a class="reference internal" href="#persistent-vs-non-persistent">Persistent vs non-persistent</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<h4>Previous topic</h4>
|
||
<p class="topless"><a href="Msg.html"
|
||
title="previous chapter">Msg</a></p>
|
||
<h4>Next topic</h4>
|
||
<p class="topless"><a href="Nicks.html"
|
||
title="next chapter">Nicks</a></p>
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="../_sources/Components/Attributes.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com/docs/latest/index.html">Documentation Top</a> </li>
|
||
<li><a href="https://www.evennia.com">Evennia Home</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li>
|
||
<a href="https://discord.gg/AJJpcRUhtF">Discord</a> -
|
||
<a href="https://github.com/evennia/evennia/discussions">Discussions</a> -
|
||
<a href="https://evennia.blogspot.com/">Blog</a>
|
||
</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="attributes">
|
||
<h1>Attributes<a class="headerlink" href="#attributes" title="Permalink to this headline">¶</a></h1>
|
||
<div class="literal-block-wrapper docutils container" id="id1">
|
||
<div class="code-block-caption"><span class="caption-text">In-game</span><a class="headerlink" href="#id1" title="Permalink to this code">¶</a></div>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="o">></span> <span class="nb">set</span> <span class="n">obj</span><span class="o">/</span><span class="n">myattr</span> <span class="o">=</span> <span class="s2">"test"</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="literal-block-wrapper docutils container" id="id2">
|
||
<div class="code-block-caption"><span class="caption-text">In-code, using the .db wrapper</span><a class="headerlink" href="#id2" title="Permalink to this code">¶</a></div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">obj</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="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">"bar"</span><span class="p">]</span>
|
||
<span class="n">value</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="literal-block-wrapper docutils container" id="id3">
|
||
<div class="code-block-caption"><span class="caption-text">In-code, using the .attributes handler</span><a class="headerlink" href="#id3" title="Permalink to this code">¶</a></div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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">"myattr"</span><span class="p">,</span> <span class="mi">1234</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"bar"</span><span class="p">)</span>
|
||
<span class="n">value</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">"myattr"</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"bar"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<div class="literal-block-wrapper docutils container" id="id4">
|
||
<div class="code-block-caption"><span class="caption-text">In-code, using <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> at class level</span><a class="headerlink" href="#id4" title="Permalink to this code">¶</a></div>
|
||
<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="kn">from</span> <span class="nn">evennia</span> <span class="kn">import</span> <span class="n">AttributeProperty</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="n">foo</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">"bar"</span><span class="p">])</span>
|
||
<span class="n">myattr</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">100</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">'bar'</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<p><em>Attributes</em> allow you to to store arbitrary data on objects and make sure the data survives a server reboot. An Attribute can store pretty much any Python data structure and data type, like numbers, strings, lists, dicts etc. You can also store (references to) database objects like characters and rooms.</p>
|
||
<section id="working-with-attributes">
|
||
<h2>Working with Attributes<a class="headerlink" href="#working-with-attributes" title="Permalink to this headline">¶</a></h2>
|
||
<p>Attributes are usually handled in code. All <a class="reference internal" href="Typeclasses.html"><span class="doc std std-doc">Typeclassed</span></a> entities (<a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a>, <a class="reference internal" href="Objects.html"><span class="doc std std-doc">Objects</span></a>, <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Scripts</span></a> and <a class="reference internal" href="Channels.html"><span class="doc std std-doc">Channels</span></a>) can (and usually do) have Attributes associated with them. There are three ways to manage Attributes, all of which can be mixed.</p>
|
||
<section id="using-db">
|
||
<h3>Using .db<a class="headerlink" href="#using-db" title="Permalink to this headline">¶</a></h3>
|
||
<p>The simplest way to get/set Attributes is to use the <code class="docutils literal notranslate"><span class="pre">.db</span></code> shortcut. This allows for setting and getting Attributes that lack a <em>category</em> (having category <code class="docutils literal notranslate"><span class="pre">None</span></code>)</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="kn">import</span> <span class="nn">evennia</span>
|
||
|
||
<span class="n">obj</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">create_object</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">"Foo"</span><span class="p">)</span>
|
||
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo1</span> <span class="o">=</span> <span class="mi">1234</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo2</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">weapon</span> <span class="o">=</span> <span class="s2">"sword"</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">self_reference</span> <span class="o">=</span> <span class="n">obj</span> <span class="c1"># stores a reference to the obj</span>
|
||
|
||
<span class="c1"># (let's assume a rose exists in-game)</span>
|
||
<span class="n">rose</span> <span class="o">=</span> <span class="n">evennia</span><span class="o">.</span><span class="n">search_object</span><span class="p">(</span><span class="n">key</span><span class="o">=</span><span class="s2">"rose"</span><span class="p">)[</span><span class="mi">0</span><span class="p">]</span> <span class="c1"># returns a list, grab 0th element</span>
|
||
<span class="n">rose</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">has_thorns</span> <span class="o">=</span> <span class="kc">True</span>
|
||
|
||
<span class="c1"># retrieving</span>
|
||
<span class="n">val1</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo1</span>
|
||
<span class="n">val2</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo2</span>
|
||
<span class="n">weap</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">weapon</span>
|
||
<span class="n">myself</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">self_reference</span> <span class="c1"># retrieve reference from db, get object back</span>
|
||
|
||
<span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">has_thorns</span>
|
||
|
||
<span class="c1"># this will return None, not AttributeError!</span>
|
||
<span class="n">not_found</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">jiwjpowiwwerw</span>
|
||
|
||
<span class="c1"># returns all Attributes on the object</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">all</span>
|
||
|
||
<span class="c1"># delete an Attribute</span>
|
||
<span class="k">del</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">foo2</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Trying to access a non-existing Attribute will never lead to an <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code>. Instead you will get <code class="docutils literal notranslate"><span class="pre">None</span></code> back. The special <code class="docutils literal notranslate"><span class="pre">.db.all</span></code> will return a list of all Attributes on the object. You can replace this with your own Attribute <code class="docutils literal notranslate"><span class="pre">all</span></code> if you want, it will replace the default <code class="docutils literal notranslate"><span class="pre">all</span></code> functionality until you delete it again.</p>
|
||
</section>
|
||
<section id="using-attributes">
|
||
<h3>Using .attributes<a class="headerlink" href="#using-attributes" title="Permalink to this headline">¶</a></h3>
|
||
<p>If you want to group your Attribute in a category, or don’t know the name of the Attribute beforehand, you can make use of the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler" title="evennia.typeclasses.attributes.AttributeHandler"><span class="xref myst py py-class">AttributeHandler</span></a>, available as <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> on all typeclassed entities. With no extra keywords, this is identical to using the <code class="docutils literal notranslate"><span class="pre">.db</span></code> shortcut (<code class="docutils literal notranslate"><span class="pre">.db</span></code> is actually using the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> internally):</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</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">"has_thorns"</span><span class="p">)</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">"helmet"</span><span class="p">,</span> <span class="s2">"Knight's helmet"</span><span class="p">)</span>
|
||
<span class="n">helmet</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">"helmet"</span><span class="p">)</span>
|
||
|
||
<span class="c1"># you can give space-separated Attribute-names (can't do that with .db)</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">"my game log"</span><span class="p">,</span> <span class="s2">"long text about ..."</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>By using a category you can separate same-named Attributes on the same object to help organization.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># store (let's say we have gold_necklace and ringmail_armor from before)</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">"neck"</span><span class="p">,</span> <span class="n">gold_necklace</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"clothing"</span><span class="p">)</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">"neck"</span><span class="p">,</span> <span class="n">ringmail_armor</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"armor"</span><span class="p">)</span>
|
||
|
||
<span class="c1"># retrieve later - we'll get back gold_necklace and ringmail_armor</span>
|
||
<span class="n">neck_clothing</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">"neck"</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"clothing"</span><span class="p">)</span>
|
||
<span class="n">neck_armor</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">"neck"</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"armor"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If you don’t specify a category, the Attribute’s <code class="docutils literal notranslate"><span class="pre">category</span></code> will be <code class="docutils literal notranslate"><span class="pre">None</span></code> and can thus also be found via <code class="docutils literal notranslate"><span class="pre">.db</span></code>. <code class="docutils literal notranslate"><span class="pre">None</span></code> is considered a category of its own, so you won’t find <code class="docutils literal notranslate"><span class="pre">None</span></code>-category Attributes mixed with Attributes having categories.</p>
|
||
<p>Here are the methods of the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code>. See the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeHandler" title="evennia.typeclasses.attributes.AttributeHandler"><span class="xref myst py py-class">AttributeHandler API</span></a> for more details.</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">has(...)</span></code> - this checks if the object has an Attribute with this key. This is equivalent to doing <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span></code> except you can also check for a specific `category.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">get(...)</span></code> - this retrieves the given Attribute. You can also provide a <code class="docutils literal notranslate"><span class="pre">default</span></code> value to return if the Attribute is not defined (instead of None). By supplying an <code class="docutils literal notranslate"><span class="pre">accessing_object</span></code> to the call one can also make sure to check permissions before modifying anything. The <code class="docutils literal notranslate"><span class="pre">raise_exception</span></code> kwarg allows you to raise an <code class="docutils literal notranslate"><span class="pre">AttributeError</span></code> instead of returning <code class="docutils literal notranslate"><span class="pre">None</span></code> when you access a non-existing <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>. The <code class="docutils literal notranslate"><span class="pre">strattr</span></code> kwarg tells the system to store the Attribute as a raw string rather than to pickle it. While an optimization this should usually not be used unless the Attribute is used for some particular, limited purpose.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">add(...)</span></code> - this adds a new Attribute to the object. An optional <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lockstring</span></a> can be supplied here to restrict future access and also the call itself may be checked against locks.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">remove(...)</span></code> - Remove the given Attribute. This can optionally be made to check for permission before performing the deletion. - <code class="docutils literal notranslate"><span class="pre">clear(...)</span></code> - removes all Attributes from object.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">all(category=None)</span></code> - returns all Attributes (of the given category) attached to this object.</p></li>
|
||
</ul>
|
||
<p>Examples:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="k">try</span><span class="p">:</span>
|
||
<span class="c1"># raise error if Attribute foo does not exist</span>
|
||
<span class="n">val</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">"foo"</span><span class="p">,</span> <span class="n">raise_exception</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
|
||
<span class="k">except</span> <span class="ne">AttributeError</span><span class="p">:</span>
|
||
<span class="c1"># ...</span>
|
||
|
||
<span class="c1"># return default value if foo2 doesn't exist</span>
|
||
<span class="n">val2</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">"foo2"</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="s2">"bar"</span><span class="p">])</span>
|
||
|
||
<span class="c1"># delete foo if it exists (will silently fail if unset, unless</span>
|
||
<span class="c1"># raise_exception is set)</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">attributes</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="s2">"foo"</span><span class="p">)</span>
|
||
|
||
<span class="c1"># view all clothes on obj</span>
|
||
<span class="n">all_clothes</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">all</span><span class="p">(</span><span class="n">category</span><span class="o">=</span><span class="s2">"clothes"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
</section>
|
||
<section id="using-attributeproperty">
|
||
<h3>Using AttributeProperty<a class="headerlink" href="#using-attributeproperty" title="Permalink to this headline">¶</a></h3>
|
||
<p>The third way to set up an Attribute is to use an <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>. This is done on the <em>class level</em> of your typeclass and allows you to treat Attributes a bit like Django database Fields. Unlike using <code class="docutils literal notranslate"><span class="pre">.db</span></code> and <code class="docutils literal notranslate"><span class="pre">.attributes</span></code>, an <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> can’t be created on the fly, you must assign it in the class code.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># 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.typeclasses.attributes</span> <span class="kn">import</span> <span class="n">AttributeProperty</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="n">strength</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">10</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">'stat'</span><span class="p">)</span>
|
||
<span class="n">constitution</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">11</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">'stat'</span><span class="p">)</span>
|
||
<span class="n">agility</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">12</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">'stat'</span><span class="p">)</span>
|
||
<span class="n">magic</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="mi">13</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s1">'stat'</span><span class="p">)</span>
|
||
|
||
<span class="n">sleepy</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="kc">False</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||
<span class="n">poisoned</span> <span class="o">=</span> <span class="n">AttributeProperty</span><span class="p">(</span><span class="kc">False</span><span class="p">,</span> <span class="n">autocreate</span><span class="o">=</span><span class="kc">False</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="c1"># ...</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When a new instance of the class is created, new <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> will be created with the value and category given.</p>
|
||
<p>With <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>’s set up like this, one can access the underlying <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> like a regular property on the created object:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">char</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">Character</span><span class="p">)</span>
|
||
|
||
<span class="n">char</span><span class="o">.</span><span class="n">strength</span> <span class="c1"># returns 10</span>
|
||
<span class="n">char</span><span class="o">.</span><span class="n">agility</span> <span class="o">=</span> <span class="mi">15</span> <span class="c1"># assign a new value (category remains 'stat')</span>
|
||
|
||
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">magic</span> <span class="c1"># returns None (wrong category)</span>
|
||
<span class="n">char</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">"agility"</span><span class="p">,</span> <span class="n">category</span><span class="o">=</span><span class="s2">"stat"</span><span class="p">)</span> <span class="c1"># returns 15</span>
|
||
|
||
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># returns None because autocreate=False (see below)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>Be careful to not assign AttributeProperty’s to names of properties and methods already existing on the class, like ‘key’ or ‘at_object_creation’. That could lead to very confusing errors.</p>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">autocreate=False</span></code> (default is <code class="docutils literal notranslate"><span class="pre">True</span></code>) used for <code class="docutils literal notranslate"><span class="pre">sleepy</span></code> and <code class="docutils literal notranslate"><span class="pre">poisoned</span></code> is worth a closer explanation. When <code class="docutils literal notranslate"><span class="pre">False</span></code>, <em>no</em> Attribute will be auto-created for these AttributProperties unless they are <em>explicitly</em> set.</p>
|
||
<p>The advantage of not creating an Attribute is that the default value given to <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> is returned with no database access unless you change it. This also means that if you want to change the default later, all entities previously create will inherit the new default.</p>
|
||
<p>The drawback is that without a database precense you can’t find the Attribute via <code class="docutils literal notranslate"><span class="pre">.db</span></code> and <code class="docutils literal notranslate"><span class="pre">.attributes.get</span></code> (or by querying for it in other ways in the database):</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">char</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># returns False, no db access</span>
|
||
|
||
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># returns None - no Attribute exists</span>
|
||
<span class="n">char</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">"sleepy"</span><span class="p">)</span> <span class="c1"># returns None too</span>
|
||
|
||
<span class="n">char</span><span class="o">.</span><span class="n">sleepy</span> <span class="o">=</span> <span class="kc">True</span> <span class="c1"># now an Attribute is created</span>
|
||
<span class="n">char</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># now returns True!</span>
|
||
<span class="n">char</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">"sleepy"</span><span class="p">)</span> <span class="c1"># now returns True</span>
|
||
|
||
<span class="n">char</span><span class="o">.</span><span class="n">sleepy</span> <span class="c1"># now returns True, involves db access</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>You can e.g. <code class="docutils literal notranslate"><span class="pre">del</span> <span class="pre">char.strength</span></code> to set the value back to the default (the value defined in the <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>).</p>
|
||
<p>See the <a class="reference internal" href="../api/evennia.typeclasses.attributes.html#evennia.typeclasses.attributes.AttributeProperty" title="evennia.typeclasses.attributes.AttributeProperty"><span class="xref myst py py-class">AttributeProperty API</span></a> for more details on how to create it with special options, like giving access-restrictions.</p>
|
||
<div class="admonition warning">
|
||
<p class="admonition-title">Warning</p>
|
||
<p>While the <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> uses the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> (<code class="docutils literal notranslate"><span class="pre">.attributes</span></code>) under the hood, the reverse is <em>not</em> true. The <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> has helper methods, like <code class="docutils literal notranslate"><span class="pre">at_get</span></code> and <code class="docutils literal notranslate"><span class="pre">at_set</span></code>. These will <em>only</em> be called if you access the Attribute using the property.</p>
|
||
<p>That is, if you do <code class="docutils literal notranslate"><span class="pre">obj.yourattribute</span> <span class="pre">=</span> <span class="pre">1</span></code>, the <code class="docutils literal notranslate"><span class="pre">AttributeProperty.at_set</span></code> will be called. But while doing <code class="docutils literal notranslate"><span class="pre">obj.db.yourattribute</span> <span class="pre">=</span> <span class="pre">1</span></code>, will lead to the same Attribute being saved, this is ‘bypassing’ the <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> and using the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> directly. So in this case the <code class="docutils literal notranslate"><span class="pre">AttributeProperty.at_set</span></code> will <em>not</em> be called. If you added some special functionality in <code class="docutils literal notranslate"><span class="pre">at_get</span></code> this may be confusing.</p>
|
||
<p>To avoid confusion, you should aim to be consistent in how you access your Attributes - if you use a <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code> to define it, use that also to access and modify the Attribute later.</p>
|
||
</div>
|
||
</section>
|
||
<section id="properties-of-attributes">
|
||
<h3>Properties of Attributes<a class="headerlink" href="#properties-of-attributes" title="Permalink to this headline">¶</a></h3>
|
||
<p>An <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object is stored in the database. It has the following properties:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> - the name of the Attribute. When doing e.g. <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, this property is set to <code class="docutils literal notranslate"><span class="pre">attrname</span></code>.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">value</span></code> - this is the value of the Attribute. This value can be anything which can be pickled - objects, lists, numbers or what have you (see <a class="reference internal" href="#what-types-of-data-can-i-save-in-an-attribute"><span class="std std-doc">this section</span></a> for more info). In the example
|
||
<code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code>, the <code class="docutils literal notranslate"><span class="pre">value</span></code> is stored here.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">category</span></code> - this is an optional property that is set to None for most Attributes. Setting this allows to use Attributes for different functionality. This is usually not needed unless you want to use Attributes for very different functionality (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> is an example of using
|
||
Attributes in this way). To modify this property you need to use the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a></p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">strvalue</span></code> - this is a separate value field that only accepts strings. This severely limits the data possible to store, but allows for easier database lookups. This property is usually not used except when re-using Attributes for some other purpose (<a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a> use it). It is only accessible via the <a class="reference internal" href="#attributes"><span class="std std-doc">Attribute Handler</span></a>.</p></li>
|
||
</ul>
|
||
<p>There are also two special properties:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">attrtype</span></code> - this is used internally by Evennia to separate <a class="reference internal" href="Nicks.html"><span class="doc std std-doc">Nicks</span></a>, from Attributes (Nicks use Attributes behind the scenes).</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">model</span></code> - this is a <em>natural-key</em> describing the model this Attribute is attached to. This is on the form <em>appname.modelclass</em>, like <code class="docutils literal notranslate"><span class="pre">objects.objectdb</span></code>. It is used by the Attribute and NickHandler to quickly sort matches in the database. Neither this nor <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> should normally need to be modified.</p></li>
|
||
</ul>
|
||
<p>Non-database attributes are not stored in the database and have no equivalence to <code class="docutils literal notranslate"><span class="pre">category</span></code> nor <code class="docutils literal notranslate"><span class="pre">strvalue</span></code>, <code class="docutils literal notranslate"><span class="pre">attrtype</span></code> or <code class="docutils literal notranslate"><span class="pre">model</span></code>.</p>
|
||
</section>
|
||
<section id="managing-attributes-in-game">
|
||
<h3>Managing Attributes in-game<a class="headerlink" href="#managing-attributes-in-game" title="Permalink to this headline">¶</a></h3>
|
||
<p>Attributes are mainly used by code. But one can also allow the builder to use Attributes to ‘turn knobs’ in-game. For example a builder could want to manually tweak the “level” Attribute of an enemy NPC to lower its difficuly.</p>
|
||
<p>When setting Attributes this way, you are severely limited in what can be stored - this is because giving players (even builders) the ability to store arbitrary Python would be a severe security problem.</p>
|
||
<p>In game you can set an Attribute like this:</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>set myobj/foo = "bar"
|
||
</pre></div>
|
||
</div>
|
||
<p>To view, do</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>set myobj/foo
|
||
</pre></div>
|
||
</div>
|
||
<p>or see them together with all object-info with</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>examine myobj
|
||
</pre></div>
|
||
</div>
|
||
<p>The first <code class="docutils literal notranslate"><span class="pre">set</span></code>-example will store a new Attribute <code class="docutils literal notranslate"><span class="pre">foo</span></code> on the object <code class="docutils literal notranslate"><span class="pre">myobj</span></code> and give it the value “bar”. You can store numbers, booleans, strings, tuples, lists and dicts this way. But if you store a list/tuple/dict they must be proper Python structures and may <em>only</em> contain strings
|
||
or numbers. If you try to insert an unsupported structure, the input will be converted to a
|
||
string.</p>
|
||
<div class="highlight-none notranslate"><div class="highlight"><pre><span></span>set myobj/mybool = True
|
||
set myobj/mybool = True
|
||
set myobj/mytuple = (1, 2, 3, "foo")
|
||
set myobj/mylist = ["foo", "bar", 2]
|
||
set myobj/mydict = {"a": 1, "b": 2, 3: 4}
|
||
set mypobj/mystring = [1, 2, foo] # foo is invalid Python (no quotes)
|
||
</pre></div>
|
||
</div>
|
||
<p>For the last line you’ll get a warning and the value instead will be saved as a string <code class="docutils literal notranslate"><span class="pre">"[1,</span> <span class="pre">2,</span> <span class="pre">foo]"</span></code>.</p>
|
||
</section>
|
||
<section id="locking-and-checking-attributes">
|
||
<h3>Locking and checking Attributes<a class="headerlink" href="#locking-and-checking-attributes" title="Permalink to this headline">¶</a></h3>
|
||
<p>While the <code class="docutils literal notranslate"><span class="pre">set</span></code> command is limited to builders, individual Attributes are usually not locked down. You may want to lock certain sensitive Attributes, in particular for games where you allow player building. You can add such limitations by adding a <a class="reference internal" href="Locks.html"><span class="doc std std-doc">lock string</span></a> to your Attribute. A NAttribute have no locks.</p>
|
||
<p>The relevant lock types are</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">attrread</span></code> - limits who may read the value of the Attribute</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">attredit</span></code> - limits who may set/change this Attribute</p></li>
|
||
</ul>
|
||
<p>You must use the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> to assign the lockstring to the Attribute:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">lockstring</span> <span class="o">=</span> <span class="s2">"attread:all();attredit:perm(Admins)"</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">"myattr"</span><span class="p">,</span> <span class="s2">"bar"</span><span class="p">,</span> <span class="n">lockstring</span><span class="o">=</span><span class="n">lockstring</span><span class="p">)</span><span class="s2">"</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>If you already have an Attribute and want to add a lock in-place you can do so by having the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> return the <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object itself (rather than its value) and then assign the lock to it directly:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">lockstring</span> <span class="o">=</span> <span class="s2">"attread:all();attredit:perm(Admins)"</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">"myattr"</span><span class="p">,</span> <span class="n">return_obj</span><span class="o">=</span><span class="kc">True</span><span class="p">)</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="n">lockstring</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note the <code class="docutils literal notranslate"><span class="pre">return_obj</span></code> keyword which makes sure to return the <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> object so its LockHandler could be accessed.</p>
|
||
<p>A lock is no good if nothing checks it – and by default Evennia does not check locks on Attributes. To check the <code class="docutils literal notranslate"><span class="pre">lockstring</span></code> you provided, make sure you include <code class="docutils literal notranslate"><span class="pre">accessing_obj</span></code> and set <code class="docutils literal notranslate"><span class="pre">default_access=False</span></code> as you make a <code class="docutils literal notranslate"><span class="pre">get</span></code> call.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="c1"># in some command code where we want to limit</span>
|
||
<span class="c1"># setting of a given attribute name on an object</span>
|
||
<span class="n">attr</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="n">attrname</span><span class="p">,</span>
|
||
<span class="n">return_obj</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
|
||
<span class="n">accessing_obj</span><span class="o">=</span><span class="n">caller</span><span class="p">,</span>
|
||
<span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||
<span class="n">default_access</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">attr</span><span class="p">:</span>
|
||
<span class="n">caller</span><span class="o">.</span><span class="n">msg</span><span class="p">(</span><span class="s2">"You cannot edit that Attribute!"</span><span class="p">)</span>
|
||
<span class="k">return</span>
|
||
<span class="c1"># edit the Attribute here</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The same keywords are available to use with <code class="docutils literal notranslate"><span class="pre">obj.attributes.set()</span></code> and <code class="docutils literal notranslate"><span class="pre">obj.attributes.remove()</span></code>, those will check for the <code class="docutils literal notranslate"><span class="pre">attredit</span></code> lock type.</p>
|
||
</section>
|
||
</section>
|
||
<section id="what-types-of-data-can-i-save-in-an-attribute">
|
||
<h2>What types of data can I save in an Attribute?<a class="headerlink" href="#what-types-of-data-can-i-save-in-an-attribute" title="Permalink to this headline">¶</a></h2>
|
||
<p>The database doesn’t know anything about Python objects, so Evennia must <em>serialize</em> Attribute values into a string representation before storing it to the database. This is done using the <a class="reference external" href="https://docs.python.org/library/pickle.html">pickle</a> module of Python.</p>
|
||
<blockquote>
|
||
<div><p>The only exception is if you use the <code class="docutils literal notranslate"><span class="pre">strattr</span></code> keyword of the <code class="docutils literal notranslate"><span class="pre">AttributeHandler</span></code> to save to the <code class="docutils literal notranslate"><span class="pre">strvalue</span></code> field of the Attribute. In that case you can <em>only</em> save <em>strings</em> and those will not be pickled).</p>
|
||
</div></blockquote>
|
||
<section id="storing-single-objects">
|
||
<h3>Storing single objects<a class="headerlink" href="#storing-single-objects" title="Permalink to this headline">¶</a></h3>
|
||
<p>With a single object, we mean anything that is <em>not iterable</em>, like numbers, strings or custom class instances without the <code class="docutils literal notranslate"><span class="pre">__iter__</span></code> method.</p>
|
||
<ul class="simple">
|
||
<li><p>You can generally store any non-iterable Python entity that can be <em>pickled</em>.</p></li>
|
||
<li><p>Single database objects/typeclasses can be stored, despite them normally not being possible to pickle. Evennia will convert them to an internal representation using theihr classname, database-id and creation-date with a microsecond precision. When retrieving, the object instance will be re-fetched from the database using this information.</p></li>
|
||
<li><p>If you ‘hide’ a db-obj as a property on a custom class, Evennia will not be able to find it to serialize it. For that you need to help it out (see below).</p></li>
|
||
</ul>
|
||
<div class="literal-block-wrapper docutils container" id="id5">
|
||
<div class="code-block-caption"><span class="caption-text">Valid assignments</span><a class="headerlink" href="#id5" title="Permalink to this code">¶</a></div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Examples of valid single-value attribute data:</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test1</span> <span class="o">=</span> <span class="mi">23</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test1</span> <span class="o">=</span> <span class="kc">False</span>
|
||
<span class="c1"># a database object (will be stored as an internal representation)</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test2</span> <span class="o">=</span> <span class="n">myobj</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<p>As mentioned, Evennia will not be able to automatically serialize db-objects ‘hidden’ in arbitrary properties on an object. This will lead to an error when saving the Attribute.</p>
|
||
<div class="literal-block-wrapper docutils container" id="id6">
|
||
<div class="code-block-caption"><span class="caption-text">Invalid, ‘hidden’ dbobject</span><a class="headerlink" href="#id6" title="Permalink to this code">¶</a></div>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># example of storing an invalid, "hidden" dbobject in Attribute</span>
|
||
<span class="k">class</span> <span class="nc">Container</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">mydbobj</span><span class="p">):</span>
|
||
<span class="c1"># no way for Evennia to know this is a database object!</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span> <span class="o">=</span> <span class="n">mydbobj</span>
|
||
|
||
<span class="c1"># let's assume myobj is a db-object</span>
|
||
<span class="n">container</span> <span class="o">=</span> <span class="n">Container</span><span class="p">(</span><span class="n">myobj</span><span class="p">)</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mydata</span> <span class="o">=</span> <span class="n">container</span> <span class="c1"># will raise error!</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<p>By adding two methods <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> to the object you want to save, you can pre-serialize and post-deserialize all ‘hidden’ objects before Evennia’s main serializer gets to work. Inside these methods, use Evennia’s <a class="reference internal" href="../api/evennia.utils.dbserialize.html#evennia.utils.dbserialize.dbserialize" title="evennia.utils.dbserialize.dbserialize"><span class="xref myst py py-func">evennia.utils.dbserialize.dbserialize</span></a> and <a class="reference internal" href="../api/evennia.utils.dbserialize.html#evennia.utils.dbserialize.dbunserialize" title="evennia.utils.dbserialize.dbunserialize"><span class="xref myst py py-func">dbunserialize</span></a> functions to safely serialize the db-objects you want to store.</p>
|
||
<div class="literal-block-wrapper docutils container" id="id7">
|
||
<div class="code-block-caption"><span class="caption-text">Fixing an invalid ‘hidden’ dbobj for storing in Attribute</span><a class="headerlink" href="#id7" title="Permalink to this code">¶</a></div>
|
||
<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="c1"># important</span>
|
||
|
||
<span class="k">class</span> <span class="nc">Container</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">mydbobj</span><span class="p">):</span>
|
||
<span class="c1"># A 'hidden' db-object</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</span> <span class="o">=</span> <span class="n">mydbobj</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="w"> </span><span class="sd">"""This is called before serialization and allows</span>
|
||
<span class="sd"> us to custom-handle those 'hidden' dbobjs"""</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</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">mydbobj</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="w"> </span><span class="sd">"""This is called after deserialization and allows you to</span>
|
||
<span class="sd"> restore the 'hidden' dbobjs you serialized before"""</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">mydbobj</span><span class="p">,</span> <span class="nb">bytes</span><span class="p">):</span>
|
||
<span class="c1"># make sure to check if it's bytes before trying dbunserialize</span>
|
||
<span class="bp">self</span><span class="o">.</span><span class="n">mydbobj</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">mydbobj</span><span class="p">)</span>
|
||
|
||
<span class="c1"># let's assume myobj is a db-object</span>
|
||
<span class="n">container</span> <span class="o">=</span> <span class="n">Container</span><span class="p">(</span><span class="n">myobj</span><span class="p">)</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mydata</span> <span class="o">=</span> <span class="n">container</span> <span class="c1"># will now work fine!</span>
|
||
</pre></div>
|
||
</div>
|
||
</div>
|
||
<blockquote>
|
||
<div><p>Note the extra check in <code class="docutils literal notranslate"><span class="pre">__deserialize_dbobjs__</span></code> to make sure the thing you are deserializing is a <code class="docutils literal notranslate"><span class="pre">bytes</span></code> object. This is needed because the Attribute’s cache reruns deserializations in some situations when the data was already once deserialized. If you see errors in the log saying <code class="docutils literal notranslate"><span class="pre">Could</span> <span class="pre">not</span> <span class="pre">unpickle</span> <span class="pre">data</span> <span class="pre">for</span> <span class="pre">storage:</span> <span class="pre">...</span></code>, the reason is likely that you forgot to add this check.</p>
|
||
</div></blockquote>
|
||
</section>
|
||
<section id="storing-multiple-objects">
|
||
<h3>Storing multiple objects<a class="headerlink" href="#storing-multiple-objects" title="Permalink to this headline">¶</a></h3>
|
||
<p>This means storing objects in a collection of some kind and are examples of <em>iterables</em>, pickle-able entities you can loop over in a for-loop. Attribute-saving supports the following iterables:</p>
|
||
<ul class="simple">
|
||
<li><p><a class="reference external" href="https://docs.python.org/3/library/functions.html#tuple">Tuples</a>, like <code class="docutils literal notranslate"><span class="pre">(1,2,"test",</span> <span class="pre"><dbobj>)</span></code>.</p></li>
|
||
<li><p><a class="reference external" href="https://docs.python.org/3/tutorial/datastructures.html#more-on-lists">Lists</a>, like <code class="docutils literal notranslate"><span class="pre">[1,2,"test",</span> <span class="pre"><dbobj>]</span></code>.</p></li>
|
||
<li><p><a class="reference external" href="https://docs.python.org/3/tutorial/datastructures.html#dictionaries">Dicts</a>, like <code class="docutils literal notranslate"><span class="pre">{1:2,</span> <span class="pre">"test":<dbobj>]</span></code>.</p></li>
|
||
<li><p><a class="reference external" href="https://docs.python.org/2/tutorial/datastructures.html#sets">Sets</a>, like <code class="docutils literal notranslate"><span class="pre">{1,2,"test",<dbobj>}</span></code>.</p></li>
|
||
<li><p><a class="reference external" href="https://docs.python.org/3/library/collections.html#collections.OrderedDict">collections.OrderedDict</a>,
|
||
like <code class="docutils literal notranslate"><span class="pre">OrderedDict((1,2),</span> <span class="pre">("test",</span> <span class="pre"><dbobj>))</span></code>.</p></li>
|
||
<li><p><a class="reference external" href="https://docs.python.org/3/library/collections.html#collections.deque">collections.Deque</a>, like <code class="docutils literal notranslate"><span class="pre">deque((1,2,"test",<dbobj>))</span></code>.</p></li>
|
||
<li><p><a class="reference external" href="https://docs.python.org/3/library/collections.html#collections.defaultdict">collections.DefaultDict</a> like <code class="docutils literal notranslate"><span class="pre">defaultdict(list)</span></code>.</p></li>
|
||
<li><p><em>Nestings</em> of any combinations of the above, like lists in dicts or an OrderedDict of tuples, each containing dicts, etc.</p></li>
|
||
<li><p>All other iterables (i.e. entities with the <code class="docutils literal notranslate"><span class="pre">__iter__</span></code> method) will be converted to a <em>list</em>. Since you can use any combination of the above iterables, this is generally not much of a limitation.</p></li>
|
||
</ul>
|
||
<p>Any entity listed in the <a class="reference internal" href="#storing-single-objects"><span class="std std-doc">Single object</span></a> section above can be stored in the iterable.</p>
|
||
<blockquote>
|
||
<div><p>As mentioned in the previous section, database entities (aka typeclasses) are not possible to pickle. So when storing an iterable, Evennia must recursively traverse the iterable <em>and all its nested sub-iterables</em> in order to find eventual database objects to convert. This is a very fast process but for efficiency you may want to avoid too deeply nested structures if you can.</p>
|
||
</div></blockquote>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># examples of valid iterables to store</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test3</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj1</span><span class="p">,</span> <span class="mi">45</span><span class="p">,</span> <span class="n">obj2</span><span class="p">,</span> <span class="mi">67</span><span class="p">]</span>
|
||
<span class="c1"># a dictionary</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test4</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'str'</span><span class="p">:</span><span class="mi">34</span><span class="p">,</span> <span class="s1">'dex'</span><span class="p">:</span><span class="mi">56</span><span class="p">,</span> <span class="s1">'agi'</span><span class="p">:</span><span class="mi">22</span><span class="p">,</span> <span class="s1">'int'</span><span class="p">:</span><span class="mi">77</span><span class="p">}</span>
|
||
<span class="c1"># a mixed dictionary/list</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test5</span> <span class="o">=</span> <span class="p">{</span><span class="s1">'members'</span><span class="p">:</span> <span class="p">[</span><span class="n">obj1</span><span class="p">,</span><span class="n">obj2</span><span class="p">,</span><span class="n">obj3</span><span class="p">],</span> <span class="s1">'enemies'</span><span class="p">:[</span><span class="n">obj4</span><span class="p">,</span><span class="n">obj5</span><span class="p">]}</span>
|
||
<span class="c1"># a tuple with a list in it</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test6</span> <span class="o">=</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">8</span><span class="p">,</span> <span class="p">[</span><span class="s2">"test"</span><span class="p">,</span> <span class="s2">"test2"</span><span class="p">],</span> <span class="mi">9</span><span class="p">)</span>
|
||
<span class="c1"># a set</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test7</span> <span class="o">=</span> <span class="nb">set</span><span class="p">([</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">])</span>
|
||
<span class="c1"># in-situ manipulation</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test8</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="p">{</span><span class="s2">"test"</span><span class="p">:</span><span class="mi">1</span><span class="p">}]</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test8</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">4</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">test8</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="s2">"test"</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span>
|
||
<span class="c1"># test8 is now [4,2,{"test":5}]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Note that if make some advanced iterable object, and store an db-object on it in a way such that it is <em>not</em> returned by iterating over it, you have created a ‘hidden’ db-object. See <a class="reference internal" href="#storing-single-objects"><span class="std std-doc">the previous section</span></a> for how to tell Evennia how to serialize such hidden objects safely.</p>
|
||
</section>
|
||
<section id="retrieving-mutable-objects">
|
||
<h3>Retrieving Mutable objects<a class="headerlink" href="#retrieving-mutable-objects" title="Permalink to this headline">¶</a></h3>
|
||
<p>A side effect of the way Evennia stores Attributes is that <em>mutable</em> iterables (iterables that can be modified in-place after they were created, which is everything except tuples) are handled by custom objects called <code class="docutils literal notranslate"><span class="pre">_SaverList</span></code>, <code class="docutils literal notranslate"><span class="pre">_SaverDict</span></code> etc. These <code class="docutils literal notranslate"><span class="pre">_Saver...</span></code> classes behave just like the normal variant except that they are aware of the database and saves to it whenever new data gets assigned to them. This is what allows you to do things like <code class="docutils literal notranslate"><span class="pre">self.db.mylist[7]</span> <span class="pre">=</span> <span class="pre">val</span></code> and be sure that the new version of list is saved. Without this you would have to load the list into a temporary variable, change it and then re-assign it to the Attribute in order for it to save.</p>
|
||
<p>There is however an important thing to remember. If you retrieve your mutable iterable into another variable, e.g. <code class="docutils literal notranslate"><span class="pre">mylist2</span> <span class="pre">=</span> <span class="pre">obj.db.mylist</span></code>, your new variable (<code class="docutils literal notranslate"><span class="pre">mylist2</span></code>) will <em>still</em> be a <code class="docutils literal notranslate"><span class="pre">_SaverList</span></code>. This means it will continue to save itself to the database whenever it is updated!</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
|
||
<span class="n">mylist</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span>
|
||
|
||
<span class="n">mylist</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span> <span class="c1"># this will also update database</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># this is now [1, 2, 3, 5]</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># now also [1, 2, 3, 5]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When you extract your mutable Attribute data into a variable like <code class="docutils literal notranslate"><span class="pre">mylist</span></code>, think of it as getting a <em>snapshot</em> of the variable. If you update the snapshot, it will save to the database, but this change <em>will not propagate to any other snapshots you may have done previously</em>.</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">]</span>
|
||
<span class="n">mylist1</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span>
|
||
<span class="n">mylist2</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span>
|
||
<span class="n">mylist1</span><span class="p">[</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">5</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">mylist1</span><span class="p">)</span> <span class="c1"># this is now [1, 2, 3, 5]</span>
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span><span class="p">)</span> <span class="c1"># also updated to [1, 2, 3, 5]</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">mylist2</span><span class="p">)</span> <span class="c1"># still [1, 2, 3, 4] !</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<aside class="sidebar">
|
||
<p>Remember, the complexities of this section only relate to <em>mutable</em> iterables - things you can update
|
||
in-place, like lists and dicts. <a class="reference external" href="https://en.wikipedia.org/wiki/Immutable">Immutable</a> objects (strings,
|
||
numbers, tuples etc) are already disconnected from the database from the onset.</p>
|
||
</aside>
|
||
<p>To avoid confusion with mutable Attributes, only work with one variable (snapshot) at a time and save back the results as needed.</p>
|
||
<p>You can also choose to “disconnect” the Attribute entirely from the
|
||
database with the help of the <code class="docutils literal notranslate"><span class="pre">.deserialize()</span></code> method:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span> <span class="o">=</span> <span class="p">[</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">,</span> <span class="mi">4</span><span class="p">,</span> <span class="p">{</span><span class="mi">1</span><span class="p">:</span> <span class="mi">2</span><span class="p">}]</span>
|
||
<span class="n">mylist</span> <span class="o">=</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">mylist</span><span class="o">.</span><span class="n">deserialize</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The result of this operation will be a structure only consisting of normal Python mutables (<code class="docutils literal notranslate"><span class="pre">list</span></code> instead of <code class="docutils literal notranslate"><span class="pre">_SaverList</span></code>, <code class="docutils literal notranslate"><span class="pre">dict</span></code> instead of <code class="docutils literal notranslate"><span class="pre">_SaverDict</span></code> and so on). If you update it, you need to explicitly save it back to the Attribute for it to save.</p>
|
||
</section>
|
||
</section>
|
||
<section id="in-memory-attributes-nattributes">
|
||
<h2>In-memory Attributes (NAttributes)<a class="headerlink" href="#in-memory-attributes-nattributes" title="Permalink to this headline">¶</a></h2>
|
||
<p><em>NAttributes</em> (short of Non-database Attributes) mimic Attributes in most things except they
|
||
are <strong>non-persistent</strong> - they will <em>not</em> survive a server reload.</p>
|
||
<ul class="simple">
|
||
<li><p>Instead of <code class="docutils literal notranslate"><span class="pre">.db</span></code> use <code class="docutils literal notranslate"><span class="pre">.ndb</span></code>.</p></li>
|
||
<li><p>Instead of <code class="docutils literal notranslate"><span class="pre">.attributes</span></code> use <code class="docutils literal notranslate"><span class="pre">.nattributes</span></code></p></li>
|
||
<li><p>Instead of <code class="docutils literal notranslate"><span class="pre">AttributeProperty</span></code>, use <code class="docutils literal notranslate"><span class="pre">NAttributeProperty</span></code>.</p></li>
|
||
</ul>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span> <span class="n">rose</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">has_thorns</span> <span class="o">=</span> <span class="kc">True</span>
|
||
<span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">ndb</span><span class="o">.</span><span class="n">has_thorns</span>
|
||
|
||
<span class="n">rose</span><span class="o">.</span><span class="n">nattributes</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="s2">"has_thorns"</span><span class="p">,</span> <span class="kc">True</span><span class="p">)</span>
|
||
<span class="n">is_ouch</span> <span class="o">=</span> <span class="n">rose</span><span class="o">.</span><span class="n">nattributes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"has_thorns"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>Differences between <code class="docutils literal notranslate"><span class="pre">Attributes</span></code> and <code class="docutils literal notranslate"><span class="pre">NAttributes</span></code>:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">NAttribute</span></code>s are always wiped on a server reload.</p></li>
|
||
<li><p>They only exist in memory and never involve the database at all, making them faster to
|
||
access and edit than <code class="docutils literal notranslate"><span class="pre">Attribute</span></code>s.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">NAttribute</span></code>s can store <em>any</em> Python structure (and database object) without limit. However, if you were to <em>delete</em> a database object you previously stored in an <code class="docutils literal notranslate"><span class="pre">NAttribute</span></code>, the <code class="docutils literal notranslate"><span class="pre">NAttribute</span></code> will not know about this and may give you a python object without a matching database entry. In comparison, an <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> always checks this). If this is a concern, use an <code class="docutils literal notranslate"><span class="pre">Attribute</span></code> or check that the object’s <code class="docutils literal notranslate"><span class="pre">.pk</span></code> property is not <code class="docutils literal notranslate"><span class="pre">None</span></code> before saving it.</p></li>
|
||
<li><p>They can <em>not</em> be set with the standard <code class="docutils literal notranslate"><span class="pre">set</span></code> command (but they are visible with <code class="docutils literal notranslate"><span class="pre">examine</span></code>)</p></li>
|
||
</ul>
|
||
<p>There are some important reasons we recommend using <code class="docutils literal notranslate"><span class="pre">ndb</span></code> to store temporary data rather than the simple alternative of just storing a variable directly on an object:
|
||
<span class="xref myst"></span></p>
|
||
<ul class="simple">
|
||
<li><p>NAttributes are tracked by Evennia and will not be purged in various cache-cleanup operations the server may do. So using them guarantees that they’ll remain available at least as long as the server lives.</p></li>
|
||
<li><p>It’s a consistent style - <code class="docutils literal notranslate"><span class="pre">.db/.attributes</span></code> and <code class="docutils literal notranslate"><span class="pre">.ndb/.nattributes</span></code> makes for clean-looking code where it’s clear how long-lived (or not) your data is to be.</p></li>
|
||
</ul>
|
||
<section id="persistent-vs-non-persistent">
|
||
<h3>Persistent vs non-persistent<a class="headerlink" href="#persistent-vs-non-persistent" title="Permalink to this headline">¶</a></h3>
|
||
<p>So <em>persistent</em> data means that your data will survive a server reboot, whereas with
|
||
<em>non-persistent</em> data it will not …</p>
|
||
<p>… So why would you ever want to use non-persistent data? The answer is, you don’t have to. Most of
|
||
the time you really want to save as much as you possibly can. Non-persistent data is potentially
|
||
useful in a few situations though.</p>
|
||
<ul class="simple">
|
||
<li><p>You are worried about database performance. Since Evennia caches Attributes very aggressively, this is not an issue unless you are reading <em>and</em> writing to your Attribute very often (like many times per second). Reading from an already cached Attribute is as fast as reading any Python property. But even then this is not likely something to worry about: Apart from Evennia’s own caching, modern database systems themselves also cache data very efficiently for speed. Our default database even runs completely in RAM if possible, alleviating much of the need to write to disk during heavy loads.</p></li>
|
||
<li><p>A more valid reason for using non-persistent data is if you <em>want</em> to lose your state when logging off. Maybe you are storing throw-away data that are re-initialized at server startup. Maybe you are implementing some caching of your own. Or maybe you are testing a buggy <a class="reference internal" href="Scripts.html"><span class="doc std std-doc">Script</span></a> that does potentially harmful stuff to your character object. With non-persistent storage you can be sure that whatever is messed up, it’s nothing a server reboot can’t clear up.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">NAttribute</span></code>s have no restrictions at all on what they can store, since they don’t need to worry about being saved to the database - they work very well for temporary storage.</p></li>
|
||
<li><p>You want to implement a fully or partly <em>non-persistent world</em>. Who are we to argue with your grand vision!</p></li>
|
||
</ul>
|
||
</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="Nicks.html" title="Nicks"
|
||
>next</a> |</li>
|
||
<li class="right" >
|
||
<a href="Msg.html" title="Msg"
|
||
>previous</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="../index.html">Evennia 3.x</a> »</li>
|
||
<li class="nav-item nav-item-1"><a href="Components-Overview.html" >Core Components</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Attributes</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
|
||
<div class="admonition important">
|
||
<p class="first admonition-title">Note</p>
|
||
<p class="last">You are reading an old version of the Evennia documentation. <a href="https://www.evennia.com/docs/latest/index.html">The latest version is here</a></p>.
|
||
</div>
|
||
|
||
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2023, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |