<h1><spanclass="section-number">1. </span>Code Structure and Utilities<aclass="headerlink"href="#code-structure-and-utilities"title="Permalink to this headline">¶</a></h1>
<p>In this lesson, we will set up the file structure for <em>EvAdventure</em>. We will make some
<p>We make the <codeclass="docutils literal notranslate"><spanclass="pre">evadventure</span></code> folder stand-alone for the sake of the tutorial only. Leaving the code isolated in this way makes it clear what we have changed — and for you to grab what you want later. It also makes it easier to refer to the matching code in <codeclass="docutils literal notranslate"><spanclass="pre">evennia/contrib/tutorials/evadventure</span></code>.</p>
<p>For your own game, you are instead encouraged to modify your game dir in-place (i.e, directly add to <codeclass="docutils literal notranslate"><spanclass="pre">commands/commands.py</span></code> and modify the <codeclass="docutils literal notranslate"><spanclass="pre">typeclasses/</span></code> modules directly). Except for the <codeclass="docutils literal notranslate"><spanclass="pre">server/</span></code> folder, you are, in fact, free to structure your game dir code pretty much as you like.</p>
<p>Create a new folder named <codeclass="docutils literal notranslate"><spanclass="pre">evadventure</span></code> under your <codeclass="docutils literal notranslate"><spanclass="pre">mygame</span></code> folder. Inside it the new folder, create another folder named <codeclass="docutils literal notranslate"><spanclass="pre">tests/</span></code>. Make sure to put empty <codeclass="docutils literal notranslate"><spanclass="pre">__init__.py</span></code> files in both new folders. Doing so turns both new folders into packages from which Python understands to import automatically.</p>
<p>Importing anything from inside this folder from anywhere else under <codeclass="docutils literal notranslate"><spanclass="pre">mygame</span></code> will be done by</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># from anywhere in mygame/</span>
<p>This is the ‘absolute path` type of import.</p>
<p>Between two modules both in <codeclass="docutils literal notranslate"><spanclass="pre">evadventure/</span></code>, you can use a ‘relative’ import with <codeclass="docutils literal notranslate"><spanclass="pre">.</span></code>:</p>
<divclass="highlight-python notranslate"><divclass="highlight"><pre><span></span><spanclass="c1"># from a module inside mygame/evadventure</span>
<p>From e.g. inside <codeclass="docutils literal notranslate"><spanclass="pre">mygame/evadventure/tests/</span></code> you can import from one level above using <codeclass="docutils literal notranslate"><spanclass="pre">..</span></code>:</p>
<p>An <aclass="reference external"href="https://docs.python.org/3/library/enum.html">enum</a> (enumeration) is a way to establish constants in Python. For example:</p>
<spanclass="n">Ability</span><spanclass="o">.</span><spanclass="n">STR</span><spanclass="o">.</span><spanclass="n">value</span><spanclass="c1"># this is the string "strength"</span>
<p>Using enums is a recommended practice. With enums set up, we can make sure to refer to the same constant or variable every time. Keeping all enums in one place also means we have a good overview of the constants with which we are dealing.</p>
<p>The alternative to enums would be, for example, to pass around a string named <codeclass="docutils literal notranslate"><spanclass="pre">"constitution"</span></code>. If you mis-spelled this as, say, <codeclass="docutils literal notranslate"><spanclass="pre">"consitution"</span></code>, you would not necessarily know it right away because the error would happen later when the string is not recognized. By using the enum practice,should you make a typo getting <codeclass="docutils literal notranslate"><spanclass="pre">Ability.COM</span></code> instead of <codeclass="docutils literal notranslate"><spanclass="pre">Ability.CON</span></code>, Python will immediately raise an error becase this enum with the typo will not be recognized.</p>
<p>With enums, you can also do nice direct comparisons like <codeclass="docutils literal notranslate"><spanclass="pre">if</span><spanclass="pre">ability</span><spanclass="pre">is</span><spanclass="pre">Ability.WIS:</span><spanclass="pre"><do</span><spanclass="pre">stuff></span></code>.</p>
<p>Note that the <codeclass="docutils literal notranslate"><spanclass="pre">Ability.STR</span></code> enum does not have the actual <em>value</em> of, for instance, your Strength. <codeclass="docutils literal notranslate"><spanclass="pre">Ability.STR</span></code> is just a fixed label for the Strength ability.</p>
<p>Below is the <codeclass="docutils literal notranslate"><spanclass="pre">enum.py</span></code> module needed for <em>Knave</em>. It covers the basic aspects of the rule system we need to track. (Check out the <em>Knave</em> rules.) Should you later use another rule system, you’ll likely expand on your enums gradually as you figure out what you’ll need.</p>
<p>Above, the <codeclass="docutils literal notranslate"><spanclass="pre">Ability</span></code> class holds some basic properties of a character sheet.</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">ABILITY_REVERSE_MAP</span></code> is a convenient map to go the other way — if in some command we were to enter the string ‘cha’, we could use this mapping to directly convert your input to the correct <codeclass="docutils literal notranslate"><spanclass="pre">Ability</span></code>. For example:</p>
<p>The utility module is used to contain general functions we may need to call repeatedly from various other modules. In this tutorial example, we only crate one utility: a function that produces a pretty display of any object we pass to it.</p>
<p>Below is an example of the string we want to see:</p>
<spanclass="s2">Slots: |w</span><spanclass="si">{size}</span><spanclass="s2">|n, Used from: |w</span><spanclass="si">{use_slot_name}</span><spanclass="s2">|n</span>
<spanclass="s2">Attacks using |w</span><spanclass="si">{attack_type_name}</span><spanclass="s2">|n against |w</span><spanclass="si">{defense_type_name}</span><spanclass="s2">|n</span>
<p>In our new <codeclass="docutils literal notranslate"><spanclass="pre">get_obj_stats</span></code> function above, we set up a string template with place holders for where every element of stats information should go. Study this string so that you understand what it does. The <codeclass="docutils literal notranslate"><spanclass="pre">|c</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">|y</span></code>, <codeclass="docutils literal notranslate"><spanclass="pre">|w</span></code> and <codeclass="docutils literal notranslate"><spanclass="pre">|n</span></code> markers are <aclass="reference internal"href="../../../Concepts/Colors.html"><spanclass="doc std std-doc">Evennia color markup</span></a> for making the text cyan, yellow, white and neutral-color, respectively.</p>
<p>Some stats elements are easy to identify in the above code. For instance, <codeclass="docutils literal notranslate"><spanclass="pre">obj.key</span></code> is the name of an object and <codeclass="docutils literal notranslate"><spanclass="pre">obj.db.desc</span></code> will hold an object’s description — this is also how default Evennia works.</p>
<p>So far, here in our tutorial, we have not yet established how to get any of the other properties like <codeclass="docutils literal notranslate"><spanclass="pre">size</span></code> or <codeclass="docutils literal notranslate"><spanclass="pre">attack_type</span></code>. For our current purposes, we will just set them to dummy values and we’ll need to revisit them later when we have more code in place!</p>
<p>Evennia comes with extensive functionality to help you test your code. A <em>unit test</em> allows you to set up automated testing of code. Once you’ve written your test, you can then run it over and over again to ensure later changes to your code didn’t break things by introducing errors.</p>
<p>How would you know if you made a typo in the code above? You can <em>manually</em> test it by reloading your Evennia server and issuing the following in-game python command:</p>
<p>Doing so should spit back a nice bit of string ouput about yourself! If that works, great! But, you’ll need to remember re-running that test manually when you later change the code.</p>
is an example of the testing module. To dive deeper into unit testing in Evennia, see the <aclass="reference internal"href="../../../Coding/Unit-Testing.html"><spanclass="doc std std-doc">Unit testing</span></a> documentation.</p>
<p>In our particular case of this tutorial, we should <em>expect</em> to need to later update the test when the <codeclass="docutils literal notranslate"><spanclass="pre">get_obj_stats</span></code> code becomes more complete and returns more pertinent data.</p>
<p>Here’s a module for testing <codeclass="docutils literal notranslate"><spanclass="pre">get_obj_stats</span></code>.</p>
<spanclass="n">attributes</span><spanclass="o">=</span><spanclass="p">((</span><spanclass="s2">"desc"</span><spanclass="p">,</span><spanclass="s2">"A test object"</span><spanclass="p">),)</span>
<p>What happens in the above code is that we create a new test-class named <codeclass="docutils literal notranslate"><spanclass="pre">TestUtils</span></code> that inherits from <codeclass="docutils literal notranslate"><spanclass="pre">EvenniaTest</span></code>. It is this inheritance that makes this a testing class.</p>
<p>It’s useful for any game dev to know how to test their code effectively. So, we’ll try to include a <em>Testing</em> section at the end of each implementation lesson that follows in this tutorial.</p>
<p>Writing tests for your code is optional, but highly recommended. Initially, unit testing may feel a little cumbersome or time-consuming… but you’ll thank yourself later.</p>
<p>We can have any number of methods called on this class. To have Evennia automatically recognize a method as one containing code to test, its name <em>must</em> start with the <codeclass="docutils literal notranslate"><spanclass="pre">test_</span></code> prefix. We have one here as <codeclass="docutils literal notranslate"><spanclass="pre">test_get_obj_stats</span></code>.</p>
<p>In our <codeclass="docutils literal notranslate"><spanclass="pre">test_get_obj_stats</span></code> method, we create a dummy <codeclass="docutils literal notranslate"><spanclass="pre">obj</span></code> and assign it a <codeclass="docutils literal notranslate"><spanclass="pre">key</span></code> “testobj”. Note that we add the<codeclass="docutils literal notranslate"><spanclass="pre">desc</span></code><aclass="reference internal"href="../../../Components/Attributes.html"><spanclass="doc std std-doc">Attribute</span></a> directly in the <codeclass="docutils literal notranslate"><spanclass="pre">create_object</span></code> call by specifying the attribute as a tuple <codeclass="docutils literal notranslate"><spanclass="pre">(name,</span><spanclass="pre">value)</span></code>!</p>
<p>Then, we can get the result of passing this dummy-object through the <codeclass="docutils literal notranslate"><spanclass="pre">get_obj_stats</span></code> function that we imported earlier.</p>
<p>The <codeclass="docutils literal notranslate"><spanclass="pre">assertEqual</span></code> method is available on all testing classes and checks that the <codeclass="docutils literal notranslate"><spanclass="pre">result</span></code> is equal to the string we specify. If they are the same, the test <em>passes</em>. Otherwise, it <em>fails</em> and we need to investigate what went wrong.</p>
<h3><spanclass="section-number">1.4.1. </span>Running your Test<aclass="headerlink"href="#running-your-test"title="Permalink to this headline">¶</a></h3>
<p>To run our utility module test, we need to issue the following command directly from the <codeclass="docutils literal notranslate"><spanclass="pre">mygame</span></code> folder:</p>
<p>The above command will run all <codeclass="docutils literal notranslate"><spanclass="pre">evadventure</span></code> tests found in the <codeclass="docutils literal notranslate"><spanclass="pre">mygame/evadventure/tests</span></code> folder. To run only our utility tests we might instead specify the test individually:</p>
<p>If all goes well, the above utility test should produce output ending with <codeclass="docutils literal notranslate"><spanclass="pre">OK</span></code> to indicate our code has passed the test.</p>
<p>However, if our return string doesn’t quite match what we expected, the test will fail. We will then need to begin examining and troubleshooting our failing code.</p>
<div><p>Hint: The above example unit test code contains a deliberate error in capitalization. See if you can examine the output to interpret the deliberate error, and then fix it!</p>
<p>It’s very important to understand how you import code among modules in Python. If importing from Python modules is still confusing to you, it’s worth it to read more on the topic.</p>
<p>That said, many newcomers are confused with how to tackle these concepts. In this lesson, by creating the folder structure, two small modules and even making our first unit test, you are off to a great start!</p>