2015 is here and t
here is a lot of activity going on in Evennia's repository, mailing list and IRC channel right now, with plenty of people asking questions and starting to use the system to build online games.
We get newcomers of all kinds, from experienced coders wanting to migrate from other code bases to newbies who are well versed in mudding but who aim to use Evennia for learning Python. At the moment the types of games planned or under development seems rather evenly distributed between RPI-style MUDs and MUSH games (maybe with a little dominance of MUSH) but there are also a couple of hack-and-slash concepts thrown into the mix. We also get some really wild concepts pitched to us now and then. What final games actually comes of it, who can tell, but people are certainly getting their MU*-creative urges scratched in greater numbers, which is a good sign.
Since Christmas our "devel"
branch is visible online and is teeming with activity. So I thought I'd post an summary about it in this blog. The more detailed technical details for active developers can be found on Evennia's mailing list here
(note that full docs are not yet written for devel-branch). Django proxies for Typeclasses
I have written about Evennia's Typeclass system before on this blog. It is basically a way to "decorate" Django database models with a second set of classes to allow Evennia developers to create any type of game entity without having to modify the database schema. It does so by connecting one django model instance to one typeclass instance and overloading __setattr__
to transparently communicate between the two.
For the devel branch I have refactored our typeclass system to make use of Django's proxy models
instead. Proxy models have existed for quite a while in Django, but they simply slipped under my radar until a user pointed them out to me late last year. A proxy model is basically a way to "replace the Python representation of a database table with a proxy class". Sounds like a Typeclass, doesn't it?
Now, proxy models doesn't work quite
like typeclasses out of the box - for one thing if you query for them in the database you will get back the original model and not the proxy one. They also do not allow multiple inheritance. Finally I don't want Evennia users to have to set up django Meta
info every time they use a proxy. So most work went into overloading the proxy multiclass inheritance check (there is a django issue about how to fix this). Along the way I also redefined the default managers and __init__
methods to always load the proxy actually searched for and not the model. I finally created metaclasses to handle all the boilerplate. We choose to keep the name Typeclass
also for this extended proxy. This is partly for legacy reasons, but typeclasses do have their own identity: they are not vanilla Django-proxies nor completely normal Python classes (although they are very close to the latter from the perspective of the end user).
Since typeclasses now are directly inheriting from the base class (due to meta-classing this looks like normal Python inheritance), it makes things a lot easier to visualize, explain and use. Performance-wise this system is en par with the old, or maybe a little faster, but it will also be a lot more straight forward to cache than the old. I have done preliminary testing with threading and it looks promising (but more on that in a future post). Evennia as a Python library package
Evennia has until now been solely distributed as a version controlled source tree (first under SVN, then Mercurial and now via GIT and Github). In its current inception you clone the tree and find inside it a game/
directory where you create your game. A problem we have when helping newbies is that we can't easily put pre-filled templates in there - if people used them there might be merge conflicts when we update the templates upstream. So the way people configure Evennia is to make copies of template modules and then change the settings to point to that copy rather than the default module. This works well but it means a higher threshold of setup for new users and a lot of describing text. Also, while learning GIT is a useful skill, it's another hurdle to get past for those who just want to change something minor to see if Evennia is for them.
In the devel branch, Evennia is now a library. The game/
folder is no longer distributed as part of the repository but is created dynamically by using the new binary evennia
launcher program, which is also responsible for creating (or migrating) the database as well as operating the server:
evennia --init mygame
Since this new folder is not
under our source tree, we can set up and copy pre-made template modules to it that people can just immediately start filling in without worrying about merge conflicts. We can also dynamically create a setting file that fits the environment as well as set up a correct tree for overloading web functionality and so on. It also makes it a lot easier for people wanting to create multiple games and to put their work under separate version control.
Rather than traversing the repository structure as before you henceforth will just do import evennia
in your code to have access to the entirety of the API. And finally this means it will (eventually) be possible to install Evennia from pypi
with something like pip install evennia
. This will greatly ease the first steps for those not keen on learning GIT. For existing users
Both the typeclasses-as-proxies and the evennia library changes are now live in the devel branch. Some brave users have already started taking it through its paces (and is helping to flesh it out) but it will take some time before it merges into master.
The interesting thing is that despite all this sounding like a huge change to Evennia, the coding API doesn't change very much, the database schema almost not at all. With the exception of some properties specific to the old connection between the typeclass and model, code translate over pretty much without change from the developer's standpoint.
The main translation work for existing developers lies in copying over their code from the old game/
directory to the new dynamically created game folder. They need to do a search-and-replace so that they import from evennia
rather than from src
There may possibly be some other minor things. But so far testers have not found it too cumbersome or time consuming to do. And all agree that the new structure is worth it.
So, onward into 2015!Image: "Bibliothek St. Florian" by Original uploader was Stephan Brunker at de.wikipedia Later versions were uploaded by Luestling at de.wikipedia. - Originally from de.wikipedia; description page is/was here.. Licensed under CC BY-SA 3.0 via Wikimedia Commons - http://commons.wikimedia.org/wiki/File:Bibliothek_St._Florian.jpg#mediaviewer/File:Bibliothek_St._Florian.jpg
After getting questions about it I recently added the Slow Exit contribution
to the main repository as an example.
Delayed movement is something often seen in various text games, it simply means that the time to move from room to room is artificially extended.
Evennia's default model uses traditional MU* rooms. These are simple nodes with exits linking them together. Such Rooms have no internal size and no inherent spatial relationship to each other. Moving from any Room to any other is happening as fast as the system can process the movement.
Introducing a delay on exit traversal can have a surprisingly big effect on a game:
- It dramatically changes the "feel" of the game. It often makes the game feel less "twitch" and slows things down in a very real way. It lets Players consider movement as a "cost".
- It simulates movement speed. A "quick" (or maybe well-rested) character might perceive an actual difference in traversal. The traversal speed can vary depending on if the Character is "running" or "walking".
- It can emulate travel distance. An Exit leading to "the top of the mountain" may take longer to traverse than going "inside the tent".
- It makes movement a "cost" to take into consideration in the game. Moving back and forth over and over across a distance of multiple rooms becomes a much more daunting prospect with a time delay than if you could just zip along as quickly as you could press the button. This also has effects on map and quest design.
Introducing delayed movement in Evennia is simple. But to explain the idea, let's first briefly explain how Evennia implements Exits.
A brief sideline: About Exits
in Evennia is a persistent Object
sitting in a room. The Exit
class is just like any Object
except for two things - it stores a "destination
" property and it houses a CommandSet
on itself. This particular CommandSet
holds a single command with the same name as the Exit
are things I've covered in earlier blog posts
. Suffice to say is that any number of command sets can be merged together dynamically to at any moment represent the commands available to the Character at any given time or situation.
What happens when an Exit
bject is in the same room as a Character is that the Exit
's command set is dynamically merged with that of the Character. This means a new command - which always has the same name as the Exit
- becomes available. The result is that if the Exit
object is called "south", the Character can use the command "south". By default all the command does is to call a hook method on the Exit
object. This hook hooks simply moves the calling Character to the "destination
" stored by the Exit
The nice thing with this is that the whole system is implemented without any special cases or custom hard-wired code. It also means that the entire Exit system can be changed and modified without ever touching Evennia's core.
To delay the traversal, the principle is simple - after the Exit command has triggered, wait for a little while before continuing.
Technically we define a new class of Exit
, let's call it SlowExit
, inheriting from the default Exit
. We locate the spot where the Exit
normally sends traversing objects on their way (this is a method called move_to()
Since Evennia is based on Twisted, we use Twisted's intrinsic CallLater()
function to delay the move for as many seconds we desire (in the contrib I use a thin wrapper around CallLater
). The result is that the command is called, you get a little text saying that you have started moving ... and a few seconds later you actually move.
Once one understands how Exits work it's really quite straight forward - see the code on github
for more details (it's got plenty of comments).
In the contrib are also some example utility commands for setting one's movement speed and to abort movement if you change your mind before the timeout has passed.
This simple start can easily be expanded as befits each individual game. One can imagine introducing anything from stamina costs to make travel time be dynamically calculated based on terrain or other factors.
In many traditional multiplayer text engines for MUD/MUSH/MU*, the player connects to the game with an account name that also becomes their character's in-game name. When they log into the game they immediately "become" that character. If they want to play with another character, they need to create a new account.
A single-login system is easy to implement but many code bases try to expand with some sort of "account system" where a single login "account" will allow you to manage one or more game characters. Matthew “Chaos” Sheahan beautifully argues for the benefits of an account system in the April issue of Imaginary Realities
; you can read his article here
Evennia and account systems
First a brief show of how Evennia handles this. We use the following separation:
Session(s) <-> Player <-> Objects/Characters(s)
object represents individual client connections to Evennia. The Player
is our "account" object. It holds the password hash and your login name but has no in-game existence. Finally we have Objects
, the most common being a subclass of Object we call Character.
Objects exist in the game. They are "puppeted" by Sessions via the Player account.
From this separation an account system follows naturally. Evennia also offers fully flexible puppeting out of the box: Changing characters (or for staff to puppet an NPC) is simply a matter of "disconnecting" from one Character and connecting to another (presuming you have permission to do so).
The Multisession modes of Evennia
This is the main gist of this entry since we just added another of these (mode 3). Evennia now offers four different multisession modes
for the game designer to choose between. They affect how you gamers may control their characters and can be changed with just a server reload.
This is emulates the "traditional" mud codebase style. In mode 0 a Session controls one Character and one character only. Only one Session per account is allowed - that is, if a user try to connect to their Player account with a different client the old connection will be disconnected. In the default command set a new Character is created with the same name as the Player account and the two are automatically connected whenever they log in. To the user this makes Player and Character seem to be virtually the same thing.
In this mode, multiple Sessions are allowed per Player account. You still only have one Character per account but you can control that Character from any number of simultaneously connected clients. This is a requirement from MUSHes and some slower-moving games where there are communities of gamers who want to conveniently track the progress of the game continuously on multiple clients and computers.
In multisession mode 2, multiple Characters are allowed per Player account. No Characters are created by default in this mode, rather the default command set will drop you to a simplified OOC management screen where you can create new characters, list the ones you already have and puppet them. This mode offers true multiplaying, where you can connect via several clients simultaneously, each Session controlling a different Character.
This mode allows gamers not only to play multiple Characters on the same Player account (as in mode 2) but to also connect multiple Sessions to each Character.
This is a multi-character version of Mode 1, where players can control the same Character via Player logins from several different clients on different machines in any combination.
It's interesting that some of these modes may seem silly or superfluous to people used to a certain type of MU* yet are killer features for other communities. It goes to show how different the needs are for users of different game styles.