Building an online MMO Part 3: Teleportation and Refactoring
This is the 3rd part in my series on building an MMO, and it is no longer just an architecture. Basic game functionality has now been implemented: incredibly boring combat, the ability to walk between locations, and the ability to have persistent maps. Progress has slowed down, and these posts will consequently begin growing shorter and more broad.
The major project that reached completion is teleportation. I am not talking about a game mechanic but a core part of the architecture. Here's the question: What is the difference between a teleport spell and moving from one room/location to another? here's the answer: the latter has a different sound or graphic (not that this will have graphics, at least not in the immediate future).
This necessitated only one small change to the game protocol: the realization that new_object messages are not actually new_object messages.
The intent of a new_object message was to create an object. In practice, it was more of a logical assertion. They were being used to assert that
the destinations of the message (they can have 2 or more: all clients in a place, plus the actual target) have an updated copy of the object. I consequently renamed them to state_update
.
Objects themselves are incredibly simple, and do not contain direct references to other objects, so doing this is safe and does not result in huge quantities of unnecessary data.
I will take this opportunity to reiterate that any sort of automatic serialization is a bad idea for this kind of project. Really.
The game needed a larger change, though only one very small addition was made to the protocol to support it.
The object tree is an externally stored hierarchy of object ids. An object id may have a parent and any number of children.
This is clearly the ability to put things in containers, but also the ability to record things as being inside of a particular location.
Objects have a reference to the game's object tree. Looking up parents and children is simply Python properties: obj.parent
and obj.children
. In future, I suspect that keeping this hierarchy separate
will allow multiple processes to all keep a copy; at the moment, it removes some complicated algorithmic code from the middle of complicated gameplay code.
The specific addition to the protocol to support hierarchies was recording parents in state_update
messages, though one other internal change was needed.
Objects now serialize themselves first, followed by messages for their entire inventory in a breadth-first manner. get_state_message
was pluralized to get_state_messages
and returns a list.
Teleportation is itself easy, given the above: acquire the state of some object and all of its inventory, send delete_object
messages to the object's current location, and then send state_update
messages to the object's new location. I am glossing over some trivial internal details for brevity.
The teleportation code is some of the longest code in the project, but also some of the most self-contained and simplest to look at. This project has made the idea of the false correlation between code amount and code meaning practical, not intellectual: the online_game folder contains about a third of the code in Camlorn_audio, but each line has on average at least 3 times the meaning.
But technically, Camlorn_audio and Game_engine both count as part of this project, given that I wrote them. Taken together, it's something like 5000 lines.
As for the refactoring aspect, I hereby coin the term Refactor-driven Development. More than half of what I did was gained from refactoring, and the immediate project is yet more refactoring. Refactor-driven development works as follows: realize that the code can be refactored, refactor, add a new feature in 20 or 30 lines, repeat.
Finally, this project has revealed shortcomings in Camlorn_audio as well as one crippling bug. I plan to release a bugfix release in the near future, but don't expect one for a while after that. Streaming must be rewritten from the ground up, and a new system must be added. In short, to support all the capabilities that Camlorn_audio needs to have, I am going to have to do what amounts to streaming from ram. Simple Sound3D and Music classes wil remain, as streaming from ram requires a great deal of additional resources. The additional capabilities that using those resources give in exchange are astronomical.