Organizing your Evennia Game #3666
Replies: 1 comment
-
Thanks for this writeup, @InspectorCaracal! 👍 One thing worth adding is the placement of unit test files. Generally, if I write tests for a single module, put those in a
But the moment you start making tests for multiple modules, make a
For the general structure, I tend to mostly make isolated systems like contribs when I do larger things, and for that I just make a new folder and put everything as separate top-level files in there (see the EvAdventure game contrib as an example of this). As long as the number of files is not crazy, this gives a good overview IMO. I wouldn't do that for an actual full game though - in that case the entire game dir is the container, and I'd probably make use of the default structure. :) |
Beta Was this translation helpful? Give feedback.
-
"How should I organize my Evennia game dir?"
This question comes up quite often and came up again today on Discord, so I figured I would start a thread for it where we can all collect our own thoughts and experiences for posterity. And I'll start it off with An Entire Essay, as is my wont. 😆
The Quick Answer
In my experience, the two absolute most important things to keep in mind - in order! - are these:
The first point can vary from person to person, and as such from project to project, but an initial Evennia gamedir is always organized the same way. Follow that default organization, UNLESS it makes it harder for you to find your own code.
Default Evennia organization
These are the folders you will be using the most:
commands
is where all of your modules containing command classes and command sets go.typeclasses
is where all of your modules containing typeclasses and their subclasses should go. Anything descending from Objects, Scripts, Accounts, etc. goes here.world
is where all other mechanics go. Prototype definitions, utility functions, systems based on Python classes that aren't typeclasses, global constant definitions, etc. This is the general catch-all location.These are the folders you will mostly only be using to modify Evennia's code rather than create your own:
server/conf
is where you will modify the game's settings, and contains the default modules for adding your own lockfuncs, inputfuncs, server start/stop hooks, and other modifications that hook more deeply into Evennia's infrastructure than the other categories.web
is where you go to modify the website portion of the game's presence. This folder is 100% pure Django and is completely distinct from your game's mechanics, although the website framework here can import and access all the rest of your game code and data if necessary.The long answer
If you're a reasonably experienced Python developer (or other-language developer), you likely already have a sense of how to meet Rule no. 1 up above. In which case, you can just skip this part, because this is where I'm going to explain some basic rules of thumb that can help a fresh game developer avoid realizing that they can't find anything any more and needing to reorganize.
So, how do you best organize things in your game dir so you can find them again?
1. Group by related function
It is a pretty universal human assumption that if two things are similar, you expect them to be together. This applies to code organization, as well! If you have classes or functions or global definitions that do similar things, or are part of the same basic system, put them in the same module.
If you're expecting that category to have a lot of code - or you weren't expecting it, but it turns out that way - split them into related sub-groups into new modules. (I like to put those related-but-separate modules into a new subfolder, but ymmv.)
Some examples:
typeclasses/gear.py
- now, when you look at that file, you immediately know that it contains typeclasses for gear-type Objects.Shopkeeper
orGuard
, and a lot of enemy mob typeclasses likeWanderingMonster
andUndead
. Put the first group intotypeclasses/npcs.py
and the second group intotypeclasses/mobs.py
- it's still clear which ones are where, but it's split to be much more manageable.world/utils.py
file and now it's unimaginably enormous. Split those up into new modules within it - put, say, dice-rolling or other random-selection functions intoworld/rolls.py
, functions for helping format particular kinds of output intoworld/formatting.py
, functions for doing mathematical calculations inworld/math.py
, etc.Being able to look at your game directory and identify which folder or file is most likely going to have what you're looking for just from the name of it the single most helpful thing to do.
2. Document Everything
Don't be intimidated! I'm not talking about professional-level documentation for this - just a simple docstring or comment saying "this is the function that does the thing".
But why, you might be asking. The reason is simple: using search tools.
Let's use one of my function definitions as an example:
I've already put that in a pretty easy to find place,
world/events.py
, but let's say I forget holiday events is what the events module is for and I don't think to look in there, but I need to find this function for whatever reason. Since the name of the function is itself descriptive (this is called "self-documenting") and I also have that very simple docstring, I can now just do a normal IDE or file search for a relevant term like "ghost", "transform", or "trick or treat", and it'll find exactly what I'm looking for.In contrast, you might think to write that function definition like this, without a docstring at all:
Your search tools aren't going to help you there if you're looking for "the function that transforms a ghost into a candy or something", because you didn't give yourself anything to find it from. Write stuff down! You don't have a word-count budget!
3. Keep things grouped within modules
Grouping related functionality into different modules is the first line of attack, but it's also very helpful to keep things grouped by related functionality within your modules, as well.
Going back to one of my earlier examples, let's say you have a
typeclasses/gear.py
module. Inside of that, you have three general categories of wearable objects: weapons, armor, and bags. You can keep your weapons all together at the top, your armor all together in the middle, and your bags all together at the bottom.This has two effects:
typeclasses/gear.py
and moving it into a newtypeclasses/armor.py
file becomes trivial.4. Don't get hung up on The Right Way ™️
The only "right" way to organize your code is to follow the first two rules I laid out at the very beginning. Everything else is just "wisdom of experience" advice that hopefully helps you avoid stumbling your way through mistakes other people already made for you.
If you find yourself fretting over whether your code is organized "correctly" or not, or asking yourself should I be doing this in a better way - ask yourself this, instead:
Am I or my team having trouble finding things?
If the answer is "no", then you're already doing great. Don't waste the time and energy moving things around.
Beta Was this translation helpful? Give feedback.
All reactions