UtterChaos Mud Engine
Contents
Utter Chaos Mud Engine
(aka eMud)
I have never been happy with the way most MUD servers work, especially those of the LPC variety. I want the server's programming language to be flexible, safe, and simple. Meaning that I would like the language to be much more Java like. I would also like to have the system running in a virtual machine that supports runtime object manipulation.
I decided that it would actually be easiest and most productive for me to implement eMud in Java, but there is an even more interesting idea behind my decision.
I can have eMud dynamically load Java Objects that have been compiled while the program is running. This means that I can have wizards write code in Java, compile it with javac, and then dynamically load that code into the Java environment. That eliminates the need to write a VM and a compiler. All my effort can instead be placed on the API which is the important and distinguishing characteristic anyway.
Design Concepts
In a system like a MUD engine, the design is very important to ensuring the usability of the system. The following concepts are things that I felt was important to cover before making final design decisions.
Security Policy
While most wizards on MUDs are capable and benign, there are always the few who either accidentally cause problems or feel like being maleficent. Due to this, there is a need for some form of security policy in eMud. This policy should prevent access to the underlying system components such as filesystems and network sockets, and should prevent objects from modifying other objects without going through the required channels.
This security policy will be based on two design ideas.
Mud Object Sandbox
The use of the standard Java SecurityManager allows the creation of a sandbox which will prevent code being executed within its confines from having access to protected system resources. The policy file used for the MUD will allow access to the protected resources only through classes in the core MUD Libraries.
Mud Object Access Restrictions
Another problem which occurs in MUDs is that wizards inevitably become lazy and will build objects that interact with other objects in direct abstact-violating ways. By requiring all object interactions to pass through a set of standard channels, this type of bad coding practice can be avoided. This will also prevent the accidental additions of objects which do not conform to standards of interaction. If a new form of interaction is needed, it should be added to the standards, so that other objects will be able to us it as well.
This form of Access Restriction can be implemented as an extension to the Java SecurityManager. An additional Permission can be added to the policy files which will allow only the core MUD API classes to use the mutable methods of the MUD objects.
As an example, take the case that a teleporter wants to transport a player into a different room. The teleporter should not be allowed to just directly modify the player's environment. Instead the teleporter should invoke the methods in the API that request that the player be moved into the target room. This means that the API will be able to run all its standard checks before moving the player such as if the player is allowed to be in that room first. Then the API will move the player as it deems appropriate.
Dynamic Class Loading
The driving force on a MUD for a wizard is the ability to change the environment at runtime. It is one thing to be able to change a database of descriptions, but it another thing to be able to change the implementations of various class while the system is currently running.
In order to support the dynamic reloading of classes that have been modified in Java, a new ClassLoader must be used for each reload. This prevents having two objects instantiated with different versions of the class file from being identified as the same class. While this can cause some difficulties, they can mostly be avoided by holding onto objects references as interfaces instead of as classes. Since interfaces are unlikely to change even when classes undergo major revisions, this will reduce the difficulties involved in interacting with both old and new versions of objects.
The other requirement is the ability to support updating an object to a new class implementation without destroying any runtime data on the object. In order to do this the MUD objects need to support serialization and de-serialization methods. Using these methods, the objects can be serialized, destroyed, reloaded, and de-serialized so that there is a new object with the same runtime data as the original object.
Code Revisioning
When working with a MUD there are some important considerations to make when coding. There are many people working on the same code and sometimes changes to the code can cause unexpected and negative effects, so the logical solution is to use a versioning system such as CVS.
Each wizard will have a checked out copy of the MUD code, so that they can make and test their own changes before committing them for the rest of the wizards to critique and use. This approach can be further aided by allowing multiple MUDs to run. The testing MUD can be used to handle the testing and debugging of code without affecting the real MUD
The actual MUD that the players are logged into should undergo fewer changes than the testing MUD. This would effectively work as two branches of the MUD code: a stable version and a testing version. When the testing version is in a working and state and ready for packaging, it can be committed as the stable version. Then players will be able to play the new areas, and use the new changes.