mirror of
https://github.com/evennia/evennia.git
synced 2026-03-18 13:56:30 +01:00
441 lines
No EOL
42 KiB
HTML
441 lines
No EOL
42 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>Typeclasses — Evennia 0.9.5 documentation</title>
|
||
<link rel="stylesheet" href="_static/nature.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
|
||
<script id="documentation_options" data-url_root="./" src="_static/documentation_options.js"></script>
|
||
<script src="_static/jquery.js"></script>
|
||
<script src="_static/underscore.js"></script>
|
||
<script src="_static/doctools.js"></script>
|
||
<script src="_static/language_data.js"></script>
|
||
<script async="async" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/latest.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||
<script type="text/x-mathjax-config">MathJax.Hub.Config({"tex2jax": {"processClass": "tex2jax_process|mathjax_process|math|output_area"}})</script>
|
||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
</head><body>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
accesskey="I">index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Typeclasses</a></li>
|
||
</ul>
|
||
</div>
|
||
|
||
<div class="document">
|
||
<div class="documentwrapper">
|
||
<div class="bodywrapper">
|
||
<div class="body" role="main">
|
||
|
||
<section class="tex2jax_ignore mathjax_ignore" id="typeclasses">
|
||
<h1>Typeclasses<a class="headerlink" href="#typeclasses" title="Permalink to this headline">¶</a></h1>
|
||
<p><em>Typeclasses</em> form the core of Evennia data storage. It allows Evennia to represent any number of
|
||
different game entities as Python classes, without having to modify the database schema for every
|
||
new type.</p>
|
||
<p>In Evennia the most important game 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="Communications.html#channels"><span class="std std-doc">Channels</span></a> are all Python classes inheriting, at
|
||
varying distance, from <code class="docutils literal notranslate"><span class="pre">evennia.typeclasses.models.TypedObject</span></code>. In the documentation we refer to
|
||
these objects as being “typeclassed” or even “being a typeclass”.</p>
|
||
<p>This is how the inheritance looks for the typeclasses in Evennia:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span> <span class="n">TypedObject</span>
|
||
<span class="n">_________________</span><span class="o">|</span><span class="n">_________________________________</span>
|
||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="mi">1</span><span class="p">:</span> <span class="n">AccountDB</span> <span class="n">ObjectDB</span> <span class="n">ScriptDB</span> <span class="n">ChannelDB</span>
|
||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="mi">2</span><span class="p">:</span> <span class="n">DefaultAccount</span> <span class="n">DefaultObject</span> <span class="n">DefaultScript</span> <span class="n">DefaultChannel</span>
|
||
<span class="o">|</span> <span class="n">DefaultCharacter</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="o">|</span> <span class="n">DefaultRoom</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="o">|</span> <span class="n">DefaultExit</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="o">|</span> <span class="o">|</span> <span class="o">|</span> <span class="o">|</span>
|
||
<span class="mi">3</span><span class="p">:</span> <span class="n">Account</span> <span class="n">Object</span> <span class="n">Script</span> <span class="n">Channel</span>
|
||
<span class="n">Character</span>
|
||
<span class="n">Room</span>
|
||
<span class="n">Exit</span>
|
||
</pre></div>
|
||
</div>
|
||
<ul class="simple">
|
||
<li><p><strong>Level 1</strong> above is the “database model” level. This describes the database tables and fields
|
||
(this is technically a <a class="reference external" href="https://docs.djangoproject.com/en/2.2/topics/db/models/">Django model</a>).</p></li>
|
||
<li><p><strong>Level 2</strong> is where we find Evennia’s default implementations of the various game entities, on
|
||
top of the database. These classes define all the hook methods that Evennia calls in various
|
||
situations. <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is a little special since it’s the parent for <code class="docutils literal notranslate"><span class="pre">DefaultCharacter</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code> and <code class="docutils literal notranslate"><span class="pre">DefaultExit</span></code>. They are all grouped under level 2 because they all represents
|
||
defaults to build from.</p></li>
|
||
<li><p><strong>Level 3</strong>, finally, holds empty template classes created in your game directory. This is the
|
||
level you are meant to modify and tweak as you please, overloading the defaults as befits your game.
|
||
The templates inherit directly from their defaults, so <code class="docutils literal notranslate"><span class="pre">Object</span></code> inherits from <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> and
|
||
<code class="docutils literal notranslate"><span class="pre">Room</span></code> inherits from <code class="docutils literal notranslate"><span class="pre">DefaultRoom</span></code>.</p></li>
|
||
</ul>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">typeclass/list</span></code> command will provide a list of all typeclasses known to
|
||
Evennia. This can be useful for getting a feel for what is available. Note
|
||
however that if you add a new module with a class in it but do not import that
|
||
module from anywhere, the <code class="docutils literal notranslate"><span class="pre">typeclass/list</span></code> will not find it. To make it known
|
||
to Evennia you must import that module from somewhere.</p>
|
||
<section id="difference-between-typeclasses-and-classes">
|
||
<h2>Difference between typeclasses and classes<a class="headerlink" href="#difference-between-typeclasses-and-classes" title="Permalink to this headline">¶</a></h2>
|
||
<p>All Evennia classes inheriting from class in the table above share one important feature and two
|
||
important limitations. This is why we don’t simply call them “classes” but “typeclasses”.</p>
|
||
<ol>
|
||
<li><p>A typeclass can save itself to the database. This means that some properties (actually not that
|
||
many) on the class actually represents database fields and can only hold very specific data types.
|
||
This is detailed <a class="reference internal" href="#about-typeclass-properties"><span class="std std-doc">below</span></a>.</p></li>
|
||
<li><p>Due to its connection to the database, the typeclass’ name must be <em>unique</em> across the <em>entire</em>
|
||
server namespace. That is, there must never be two same-named classes defined anywhere. So the below
|
||
code would give an error (since <code class="docutils literal notranslate"><span class="pre">DefaultObject</span></code> is now globally found both in this module and in the
|
||
default library):</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="k">as</span> <span class="n">BaseObject</span>
|
||
<span class="k">class</span> <span class="nc">DefaultObject</span><span class="p">(</span><span class="n">BaseObject</span><span class="p">):</span>
|
||
<span class="k">pass</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
<li><p>A typeclass’ <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method should normally not be overloaded. This has mostly to do with the
|
||
fact that the <code class="docutils literal notranslate"><span class="pre">__init__</span></code> method is not called in a predictable way. Instead Evennia suggest you use
|
||
the <code class="docutils literal notranslate"><span class="pre">at_*_creation</span></code> hooks (like <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> for Objects) for setting things the very first
|
||
time the typeclass is saved to the database or the <code class="docutils literal notranslate"><span class="pre">at_init</span></code> hook which is called every time the
|
||
object is cached to memory. If you know what you are doing and want to use <code class="docutils literal notranslate"><span class="pre">__init__</span></code>, it <em>must</em>
|
||
both accept arbitrary keyword arguments and use <code class="docutils literal notranslate"><span class="pre">super</span></code> to call its parent::</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></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="o">**</span><span class="n">kwargs</span><span class="p">):</span>
|
||
<span class="c1"># my content</span>
|
||
<span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span><span class="o">**</span><span class="n">kwargs</span><span class="p">)</span>
|
||
<span class="c1"># my content</span>
|
||
</pre></div>
|
||
</div>
|
||
</li>
|
||
</ol>
|
||
<p>Apart from this, a typeclass works like any normal Python class and you can
|
||
treat it as such.</p>
|
||
</section>
|
||
<section id="creating-a-new-typeclass">
|
||
<h2>Creating a new typeclass<a class="headerlink" href="#creating-a-new-typeclass" title="Permalink to this headline">¶</a></h2>
|
||
<p>It’s easy to work with Typeclasses. Either you use an existing typeclass or you create a new Python
|
||
class inheriting from an existing typeclass. Here is an example of creating a new type of Object:</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="k">class</span> <span class="nc">Furniture</span><span class="p">(</span><span class="n">DefaultObject</span><span class="p">):</span>
|
||
<span class="c1"># this defines what 'furniture' is, like</span>
|
||
<span class="c1"># storing who sits on it or something.</span>
|
||
<span class="k">pass</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>You can now create a new <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> object in two ways. First (and usually not the most
|
||
convenient) way is to create an instance of the class and then save it manually to the database:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">chair</span> <span class="o">=</span> <span class="n">Furniture</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">"Chair"</span><span class="p">)</span>
|
||
<span class="n">chair</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>To use this you must give the database field names as keywords to the call. Which are available
|
||
depends on the entity you are creating, but all start with <code class="docutils literal notranslate"><span class="pre">db_*</span></code> in Evennia. This is a method you
|
||
may be familiar with if you know Django from before.</p>
|
||
<p>It is recommended that you instead use the <code class="docutils literal notranslate"><span class="pre">create_*</span></code> functions to create typeclassed entities:</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">create_object</span>
|
||
|
||
<span class="n">chair</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="n">Furniture</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"Chair"</span><span class="p">)</span>
|
||
<span class="c1"># or (if your typeclass is in a module furniture.py)</span>
|
||
<span class="n">chair</span> <span class="o">=</span> <span class="n">create_object</span><span class="p">(</span><span class="s2">"furniture.Furniture"</span><span class="p">,</span> <span class="n">key</span><span class="o">=</span><span class="s2">"Chair"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">create_object</span></code> (<code class="docutils literal notranslate"><span class="pre">create_account</span></code>, <code class="docutils literal notranslate"><span class="pre">create_script</span></code> etc) takes the typeclass as its first
|
||
argument; this can both be the actual class or the python path to the typeclass as found under your
|
||
game directory. So if your <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> typeclass sits in <code class="docutils literal notranslate"><span class="pre">mygame/typeclasses/furniture.py</span></code>, you
|
||
could point to it as <code class="docutils literal notranslate"><span class="pre">typeclasses.furniture.Furniture</span></code>. Since Evennia will itself look in
|
||
<code class="docutils literal notranslate"><span class="pre">mygame/typeclasses</span></code>, you can shorten this even further to just <code class="docutils literal notranslate"><span class="pre">furniture.Furniture</span></code>. The create-
|
||
functions take a lot of extra keywords allowing you to set things like <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and
|
||
<a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> all in one go. These keywords don’t use the <code class="docutils literal notranslate"><span class="pre">db_*</span></code> prefix. This will also automatically
|
||
save the new instance to the database, so you don’t need to call <code class="docutils literal notranslate"><span class="pre">save()</span></code> explicitly.</p>
|
||
<section id="about-typeclass-properties">
|
||
<h3>About typeclass properties<a class="headerlink" href="#about-typeclass-properties" title="Permalink to this headline">¶</a></h3>
|
||
<p>An example of a database field is <code class="docutils literal notranslate"><span class="pre">db_key</span></code>. This stores the “name” of the entity you are modifying
|
||
and can thus only hold a string. This is one way of making sure to update the <code class="docutils literal notranslate"><span class="pre">db_key</span></code>:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">chair</span><span class="o">.</span><span class="n">db_key</span> <span class="o">=</span> <span class="s2">"Table"</span>
|
||
<span class="n">chair</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">chair</span><span class="o">.</span><span class="n">db_key</span><span class="p">)</span>
|
||
<span class="o"><<<</span> <span class="n">Table</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>That is, we change the chair object to have the <code class="docutils literal notranslate"><span class="pre">db_key</span></code> “Table”, then save this to the database.
|
||
However, you almost never do things this way; Evennia defines property wrappers for all the database
|
||
fields. These are named the same as the field, but without the <code class="docutils literal notranslate"><span class="pre">db_</span></code> part:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">chair</span><span class="o">.</span><span class="n">key</span> <span class="o">=</span> <span class="s2">"Table"</span>
|
||
|
||
<span class="nb">print</span><span class="p">(</span><span class="n">chair</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
|
||
<span class="o"><<<</span> <span class="n">Table</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">key</span></code> wrapper is not only shorter to write, it will make sure to save the field for you, and
|
||
does so more efficiently by levering sql update mechanics under the hood. So whereas it is good to
|
||
be aware that the field is named <code class="docutils literal notranslate"><span class="pre">db_key</span></code> you should use <code class="docutils literal notranslate"><span class="pre">key</span></code> as much as you can.</p>
|
||
<p>Each typeclass entity has some unique fields relevant to that type. But all also share the
|
||
following fields (the wrapper name without <code class="docutils literal notranslate"><span class="pre">db_</span></code> is given):</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">key</span></code> (str): The main identifier for the entity, like “Rose”, “myscript” or “Paul”. <code class="docutils literal notranslate"><span class="pre">name</span></code> is an
|
||
alias.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">date_created</span></code> (datetime): Time stamp when this object was created.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">typeclass_path</span></code> (str): A python path pointing to the location of this (type)class</p></li>
|
||
</ul>
|
||
<p>There is one special field that doesn’t use the <code class="docutils literal notranslate"><span class="pre">db_</span></code> prefix (it’s defined by Django):</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">id</span></code> (int): the database id (database ref) of the object. This is an ever-increasing, unique
|
||
integer. It can also be accessed as <code class="docutils literal notranslate"><span class="pre">dbid</span></code> (database ID) or <code class="docutils literal notranslate"><span class="pre">pk</span></code> (primary key). The <code class="docutils literal notranslate"><span class="pre">dbref</span></code> property
|
||
returns the string form “#id”.</p></li>
|
||
</ul>
|
||
<p>The typeclassed entity has several common handlers:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">tags</span></code> - the <a class="reference internal" href="Tags.html"><span class="doc std std-doc">TagHandler</span></a> that handles tagging. Use <code class="docutils literal notranslate"><span class="pre">tags.add()</span></code> , <code class="docutils literal notranslate"><span class="pre">tags.get()</span></code> etc.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">locks</span></code> - the <a class="reference internal" href="Locks.html"><span class="doc std std-doc">LockHandler</span></a> that manages access restrictions. Use <code class="docutils literal notranslate"><span class="pre">locks.add()</span></code>,
|
||
<code class="docutils literal notranslate"><span class="pre">locks.get()</span></code> etc.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">attributes</span></code> - the <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">AttributeHandler</span></a> that manages Attributes on the object. Use
|
||
<code class="docutils literal notranslate"><span class="pre">attributes.add()</span></code>
|
||
etc.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">db</span></code> (DataBase) - a shortcut property to the AttributeHandler; allowing <code class="docutils literal notranslate"><span class="pre">obj.db.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code></p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">nattributes</span></code> - the <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Non-persistent AttributeHandler</span></a> for attributes not saved in the
|
||
database.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">ndb</span></code> (NotDataBase) - a shortcut property to the Non-peristent AttributeHandler. Allows
|
||
<code class="docutils literal notranslate"><span class="pre">obj.ndb.attrname</span> <span class="pre">=</span> <span class="pre">value</span></code></p></li>
|
||
</ul>
|
||
<p>Each of the typeclassed entities then extend this list with their own properties. Go to the
|
||
respective pages for <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>, <a class="reference internal" href="Accounts.html"><span class="doc std std-doc">Accounts</span></a> and
|
||
<a class="reference internal" href="Communications.html"><span class="doc std std-doc">Channels</span></a> for more info. It’s also recommended that you explore the available
|
||
entities using <a class="reference internal" href="Evennia-API.html"><span class="doc std std-doc">Evennia’s flat API</span></a> to explore which properties and methods they have
|
||
available.</p>
|
||
</section>
|
||
<section id="overloading-hooks">
|
||
<h3>Overloading hooks<a class="headerlink" href="#overloading-hooks" title="Permalink to this headline">¶</a></h3>
|
||
<p>The way to customize typeclasses is usually to overload <em>hook methods</em> on them. Hooks are methods
|
||
that Evennia call in various situations. An example is the <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> hook on <code class="docutils literal notranslate"><span class="pre">Objects</span></code>,
|
||
which is only called once, the very first time this object is saved to the database. Other examples
|
||
are the <code class="docutils literal notranslate"><span class="pre">at_login</span></code> hook of Accounts and the <code class="docutils literal notranslate"><span class="pre">at_repeat</span></code> hook of Scripts.</p>
|
||
</section>
|
||
<section id="querying-for-typeclasses">
|
||
<h3>Querying for typeclasses<a class="headerlink" href="#querying-for-typeclasses" title="Permalink to this headline">¶</a></h3>
|
||
<p>Most of the time you search for objects in the database by using convenience methods like the
|
||
<code class="docutils literal notranslate"><span class="pre">caller.search()</span></code> of <a class="reference internal" href="Commands.html"><span class="doc std std-doc">Commands</span></a> or the search functions like <code class="docutils literal notranslate"><span class="pre">evennia.search_objects</span></code>.</p>
|
||
<p>You can however also query for them directly using <a class="reference external" href="https://docs.djangoproject.com/en/1.7/topics/db/queries/">Django’s query
|
||
language</a>. This makes use of a <em>database
|
||
manager</em> that sits on all typeclasses, named <code class="docutils literal notranslate"><span class="pre">objects</span></code>. This manager holds methods that allow
|
||
database searches against that particular type of object (this is the way Django normally works
|
||
too). When using Django queries, you need to use the full field names (like <code class="docutils literal notranslate"><span class="pre">db_key</span></code>) to search:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">matches</span> <span class="o">=</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">db_key</span><span class="o">=</span><span class="s2">"Chair"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>It is important that this will <em>only</em> find objects inheriting directly from <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> in your
|
||
database. If there was a subclass of <code class="docutils literal notranslate"><span class="pre">Furniture</span></code> named <code class="docutils literal notranslate"><span class="pre">Sitables</span></code> you would not find any chairs
|
||
derived from <code class="docutils literal notranslate"><span class="pre">Sitables</span></code> with this query (this is not a Django feature but special to Evennia). To
|
||
find objects from subclasses Evennia instead makes the <code class="docutils literal notranslate"><span class="pre">get_family</span></code> and <code class="docutils literal notranslate"><span class="pre">filter_family</span></code> query
|
||
methods available:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># search for all furnitures and subclasses of furnitures</span>
|
||
<span class="c1"># whose names starts with "Chair"</span>
|
||
<span class="n">matches</span> <span class="o">=</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter_family</span><span class="p">(</span><span class="n">db_key__startswith</span><span class="o">=</span><span class="s2">"Chair"</span><span class="p">)</span>
|
||
|
||
</pre></div>
|
||
</div>
|
||
<p>To make sure to search, say, all <code class="docutils literal notranslate"><span class="pre">Scripts</span></code> <em>regardless</em> of typeclass, you need to query from the
|
||
database model itself. So for Objects, this would be <code class="docutils literal notranslate"><span class="pre">ObjectDB</span></code> in the diagram above. Here’s an
|
||
example for Scripts:</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">ScriptDB</span>
|
||
<span class="n">matches</span> <span class="o">=</span> <span class="n">ScriptDB</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">db_key__contains</span><span class="o">=</span><span class="s2">"Combat"</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>When querying from the database model parent you don’t need to use <code class="docutils literal notranslate"><span class="pre">filter_family</span></code> or <code class="docutils literal notranslate"><span class="pre">get_family</span></code> -
|
||
you will always query all children on the database model.</p>
|
||
</section>
|
||
</section>
|
||
<section id="updating-existing-typeclass-instances">
|
||
<h2>Updating existing typeclass instances<a class="headerlink" href="#updating-existing-typeclass-instances" title="Permalink to this headline">¶</a></h2>
|
||
<p>If you already have created instances of Typeclasses, you can modify the <em>Python code</em> at any time -
|
||
due to how Python inheritance works your changes will automatically be applied to all children once
|
||
you have reloaded the server.</p>
|
||
<p>However, database-saved data, like <code class="docutils literal notranslate"><span class="pre">db_*</span></code> fields, <a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a>, <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> etc, are
|
||
not themselves embedded into the class and will <em>not</em> be updated automatically. This you need to
|
||
manage yourself, by searching for all relevant objects and updating or adding the data:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># add a worth Attribute to all existing Furniture</span>
|
||
<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
|
||
<span class="c1"># this will loop over all Furniture instances</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">worth</span> <span class="o">=</span> <span class="mi">100</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>A common use case is putting all Attributes in the <code class="docutils literal notranslate"><span class="pre">at_*_creation</span></code> hook of the entity, such as
|
||
<code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> for <code class="docutils literal notranslate"><span class="pre">Objects</span></code>. This is called every time an object is created - and only then.
|
||
This is usually what you want but it does mean already existing objects won’t get updated if you
|
||
change the contents of <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> later. You can fix this in a similar way as above
|
||
(manually setting each Attribute) or with something like this:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="c1"># Re-run at_object_creation only on those objects not having the new Attribute</span>
|
||
<span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">():</span>
|
||
<span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">worth</span><span class="p">:</span>
|
||
<span class="n">obj</span><span class="o">.</span><span class="n">at_object_creation</span><span class="p">()</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The above examples can be run in the command prompt created by <code class="docutils literal notranslate"><span class="pre">evennia</span> <span class="pre">shell</span></code>. You could also run
|
||
it all in-game using <code class="docutils literal notranslate"><span class="pre">@py</span></code>. That however requires you to put the code (including imports) as one
|
||
single line using <code class="docutils literal notranslate"><span class="pre">;</span></code> and <a class="reference external" href="http://www.secnetix.de/olli/Python/list_comprehensions.hawk">list
|
||
comprehensions</a>, like this (ignore the
|
||
line break, that’s only for readability in the wiki):</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@py</span> <span class="kn">from</span> <span class="nn">typeclasses.furniture</span> <span class="kn">import</span> <span class="n">Furniture</span><span class="p">;</span>
|
||
<span class="p">[</span><span class="n">obj</span><span class="o">.</span><span class="n">at_object_creation</span><span class="p">()</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">Furniture</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span> <span class="k">if</span> <span class="ow">not</span> <span class="n">obj</span><span class="o">.</span><span class="n">db</span><span class="o">.</span><span class="n">worth</span><span class="p">]</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>It is recommended that you plan your game properly before starting to build, to avoid having to
|
||
retroactively update objects more than necessary.</p>
|
||
</section>
|
||
<section id="swap-typeclass">
|
||
<h2>Swap typeclass<a class="headerlink" href="#swap-typeclass" title="Permalink to this headline">¶</a></h2>
|
||
<p>If you want to swap an already existing typeclass, there are two ways to do so: From in-game and via
|
||
code. From inside the game you can use the default <code class="docutils literal notranslate"><span class="pre">@typeclass</span></code> command:</p>
|
||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="nd">@typeclass</span> <span class="n">objname</span> <span class="o">=</span> <span class="n">path</span><span class="o">.</span><span class="n">to</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">typeclass</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>There are two important switches to this command:</p>
|
||
<ul class="simple">
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">/reset</span></code> - This will purge all existing Attributes on the object and re-run the creation hook
|
||
(like <code class="docutils literal notranslate"><span class="pre">at_object_creation</span></code> for Objects). This assures you get an object which is purely of this new
|
||
class.</p></li>
|
||
<li><p><code class="docutils literal notranslate"><span class="pre">/force</span></code> - This is required if you are changing the class to be <em>the same</em> class the object
|
||
already has - it’s a safety check to avoid user errors. This is usually used together with <code class="docutils literal notranslate"><span class="pre">/reset</span></code>
|
||
to re-run the creation hook on an existing class.</p></li>
|
||
</ul>
|
||
<p>In code you instead use the <code class="docutils literal notranslate"><span class="pre">swap_typeclass</span></code> method which you can find on all typeclassed entities:</p>
|
||
<div class="highlight-python notranslate"><div class="highlight"><pre><span></span><span class="n">obj_to_change</span><span class="o">.</span><span class="n">swap_typeclass</span><span class="p">(</span><span class="n">new_typeclass_path</span><span class="p">,</span> <span class="n">clean_attributes</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
|
||
<span class="n">run_start_hooks</span><span class="o">=</span><span class="s2">"all"</span><span class="p">,</span> <span class="n">no_default</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">clean_cmdsets</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
|
||
</pre></div>
|
||
</div>
|
||
<p>The arguments to this method are described <a class="reference external" href="https://github.com/evennia/evennia/blob/master/evennia.typeclasses.models#typedobjectswap_typeclass">in the API docs
|
||
here</a>.</p>
|
||
</section>
|
||
<section id="how-typeclasses-actually-work">
|
||
<h2>How typeclasses actually work<a class="headerlink" href="#how-typeclasses-actually-work" title="Permalink to this headline">¶</a></h2>
|
||
<p><em>This is considered an advanced section.</em></p>
|
||
<p>Technically, typeclasses are <a class="reference external" href="https://docs.djangoproject.com/en/1.7/topics/db/models/#proxy-models">Django proxy
|
||
models</a>. The only database
|
||
models that are “real” in the typeclass system (that is, are represented by actual tables in the
|
||
database) are <code class="docutils literal notranslate"><span class="pre">AccountDB</span></code>, <code class="docutils literal notranslate"><span class="pre">ObjectDB</span></code>, <code class="docutils literal notranslate"><span class="pre">ScriptDB</span></code> and <code class="docutils literal notranslate"><span class="pre">ChannelDB</span></code> (there are also
|
||
<a class="reference internal" href="Attributes.html"><span class="doc std std-doc">Attributes</span></a> and <a class="reference internal" href="Tags.html"><span class="doc std std-doc">Tags</span></a> but they are not typeclasses themselves). All the
|
||
subclasses of them are “proxies”, extending them with Python code without actually modifying the
|
||
database layout.</p>
|
||
<p>Evennia modifies Django’s proxy model in various ways to allow them to work without any boiler plate
|
||
(for example you don’t need to set the Django “proxy” property in the model <code class="docutils literal notranslate"><span class="pre">Meta</span></code> subclass, Evennia
|
||
handles this for you using metaclasses). Evennia also makes sure you can query subclasses as well as
|
||
patches django to allow multiple inheritance from the same base class.</p>
|
||
<section id="caveats">
|
||
<h3>Caveats<a class="headerlink" href="#caveats" title="Permalink to this headline">¶</a></h3>
|
||
<p>Evennia uses the <em>idmapper</em> to cache its typeclasses (Django proxy models) in memory. The idmapper
|
||
allows things like on-object handlers and properties to be stored on typeclass instances and to not
|
||
get lost as long as the server is running (they will only be cleared on a Server reload). Django
|
||
does not work like this by default; by default every time you search for an object in the database
|
||
you’ll get a <em>different</em> instance of that object back and anything you stored on it that was not in
|
||
the database would be lost. The bottom line is that Evennia’s Typeclass instances subside in memory
|
||
a lot longer than vanilla Django model instance do.</p>
|
||
<p>There is one caveat to consider with this, and that relates to [making your own models](New-
|
||
Models): Foreign relationships to typeclasses are cached by Django and that means that if you were
|
||
to change an object in a foreign relationship via some other means than via that relationship, the
|
||
object seeing the relationship may not reliably update but will still see its old cached version.
|
||
Due to typeclasses staying so long in memory, stale caches of such relationships could be more
|
||
visible than common in Django. See the <a class="reference external" href="https://github.com/evennia/evennia/issues/1098">closed issue #1098 and its
|
||
comments</a> for examples and solutions.</p>
|
||
</section>
|
||
</section>
|
||
</section>
|
||
|
||
|
||
<div class="clearer"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<div class="sphinxsidebar" role="navigation" aria-label="main navigation">
|
||
<div class="sphinxsidebarwrapper">
|
||
<p class="logo"><a href="index.html">
|
||
<img class="logo" src="_static/evennia_logo.png" alt="Logo"/>
|
||
</a></p>
|
||
<div id="searchbox" style="display: none" role="search">
|
||
<h3 id="searchlabel">Quick search</h3>
|
||
<div class="searchformwrapper">
|
||
<form class="search" action="search.html" method="get">
|
||
<input type="text" name="q" aria-labelledby="searchlabel" />
|
||
<input type="submit" value="Go" />
|
||
</form>
|
||
</div>
|
||
</div>
|
||
<script>$('#searchbox').show(0);</script>
|
||
<p><h3><a href="index.html">Table of Contents</a></h3>
|
||
<ul>
|
||
<li><a class="reference internal" href="#">Typeclasses</a><ul>
|
||
<li><a class="reference internal" href="#difference-between-typeclasses-and-classes">Difference between typeclasses and classes</a></li>
|
||
<li><a class="reference internal" href="#creating-a-new-typeclass">Creating a new typeclass</a><ul>
|
||
<li><a class="reference internal" href="#about-typeclass-properties">About typeclass properties</a></li>
|
||
<li><a class="reference internal" href="#overloading-hooks">Overloading hooks</a></li>
|
||
<li><a class="reference internal" href="#querying-for-typeclasses">Querying for typeclasses</a></li>
|
||
</ul>
|
||
</li>
|
||
<li><a class="reference internal" href="#updating-existing-typeclass-instances">Updating existing typeclass instances</a></li>
|
||
<li><a class="reference internal" href="#swap-typeclass">Swap typeclass</a></li>
|
||
<li><a class="reference internal" href="#how-typeclasses-actually-work">How typeclasses actually work</a><ul>
|
||
<li><a class="reference internal" href="#caveats">Caveats</a></li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
</li>
|
||
</ul>
|
||
|
||
<div role="note" aria-label="source link">
|
||
<!--h3>This Page</h3-->
|
||
<ul class="this-page-menu">
|
||
<li><a href="_sources/Typeclasses.md.txt"
|
||
rel="nofollow">Show Page Source</a></li>
|
||
</ul>
|
||
</div><h3>Links</h3>
|
||
<ul>
|
||
<li><a href="https://www.evennia.com">Home page</a> </li>
|
||
<li><a href="https://github.com/evennia/evennia">Evennia Github</a> </li>
|
||
<li><a href="http://games.evennia.com">Game Index</a> </li>
|
||
<li><a href="http://webchat.freenode.net/?channels=evennia&uio=MT1mYWxzZSY5PXRydWUmMTE9MTk1JjEyPXRydWUbb">IRC</a> -
|
||
<a href="https://discord.gg/NecFePw">Discord</a> -
|
||
<a href="https://groups.google.com/forum/#%21forum/evennia">Forums</a>
|
||
</li>
|
||
<li><a href="http://evennia.blogspot.com/">Evennia Dev blog</a> </li>
|
||
</ul>
|
||
<h3>Versions</h3>
|
||
<ul>
|
||
<li><a href="../1.0-dev/index.html">1.0-dev (develop branch)</a></li>
|
||
<li><a href="Typeclasses.html">0.9.5 (v0.9.5 branch)</a></li>
|
||
</ul>
|
||
|
||
|
||
</div>
|
||
</div>
|
||
<div class="clearer"></div>
|
||
</div>
|
||
<div class="related" role="navigation" aria-label="related navigation">
|
||
<h3>Navigation</h3>
|
||
<ul>
|
||
<li class="right" style="margin-right: 10px">
|
||
<a href="genindex.html" title="General Index"
|
||
>index</a></li>
|
||
<li class="right" >
|
||
<a href="py-modindex.html" title="Python Module Index"
|
||
>modules</a> |</li>
|
||
<li class="nav-item nav-item-0"><a href="index.html">Evennia 0.9.5</a> »</li>
|
||
<li class="nav-item nav-item-this"><a href="">Typeclasses</a></li>
|
||
</ul>
|
||
</div>
|
||
<div class="footer" role="contentinfo">
|
||
© Copyright 2020, The Evennia developer community.
|
||
Created using <a href="https://www.sphinx-doc.org/">Sphinx</a> 3.2.1.
|
||
</div>
|
||
</body>
|
||
</html> |