One of the key features that I enjoy about developing an LPC mud is the ease with which one may modify code on the fly at runtime. The vast majority of the game’s functionality can be developed and tested very rapidly without any interruption in the game environment or rebooting the mud. This rapid development is compounded by the ability to grant code access to any user, which has the potential to result in a very chaotic environment of concurrent development.
In order to help ensure code quality and manage the development of the mud in such rapid-pace environment, I’ve employed the use of subversion, an open-source revision control system. I’ve had a few issues pop up while getting subversion and Dead Souls to play nicely, but most of them have been smoothed out by now.
The problems I’ve encountered, and my solutions to them:
1) Subversion ignores files with an .o extension by default.
Subversion has a default list of filename patterns that it ignores. One of the patterns is “*.o”, which happens to match most LPC drivers’ save-file formats. What this means in practice is that these savefiles will not be recognized when you import Dead Souls into your subversion repository, or during any other subversion operation. One solution that I’ve used is checking the directory tree for all .o files and importing them manually, and then committing new savefiles as they are created. This worked for a while, but got very tedious and there was always the possibility of missing a crucial savefile at the wrong time.
The second solution I tried was disabling subversion’s default ignore list entirely. This proved to be far more user-friendly and effective in helping me keep track of all the various savefiles used by the mud. To disable the default ignore list, I added “global-ignores = ” to subversion’s config file in my mud’s shell user home directory (located at ~/.subversion/config).
2) LPC mappings are unordered, even in savefiles.
The mapping datatype in LPC is unordered in many drivers, including Dead Souls’s preferred driver MudOS. What this means is that savefiles which contain mappings might change on disk after being loaded and resaved by the mud, even if the actual data in the file is unchanged. A mapping like ([ “one”:10, “two”:20, ]) might change to ([ “two”:20, “one”:10, ]). Subversion will see the change as exactly that, a change, and now you have to decide how to handle it. My solution is based on the tenet that revision control is not a backup. What I keep in version control is what is effectively the ’stock’ distribution of code, documentation, and auxiliary files. I do not keep intermediary changes to files (such as the frequent savefile changes due to mappings), player savefiles, logs, and other ‘live’ data in version control. The subversion repository contains what is necessary to run a stock copy of the mud and that is all.
To facilitate this, I’ve commited many files to the repository by copying the original stock copy of the savefile with a different extension, and then track that static copy rather than the ‘live’ ever-changing savefile. For example, I copied “lib/save/races.o” to “lib/save/races.o.dist” and commited races.o.dist to the repository. Whenever the races are modified, I copy the current races.o over the races.o.dist file and commit the changes. When users checkout a copy of the mud from the repository for the first time, they must copy these *.dist files back to their original names and then the mud is ready to run. I will likely be creating a helper script to help with this and other initial tasks that are necessary in order to properly prepare the lib for booting.
Despite not tracking ‘live’ data in subversion, meticulous backups are kept of the subversion repository and the mud itself so that quick recovery is possible in case anything goes wrong. This is in accordance with my tenet that source control is not a backup — not everything should be tracked and not every change should be commited to the repository, but backups should -always- be made. I highly suggest automated backups (at least daily) that are transferred to multiple safe locations.
3) Dead Souls and Subversion both rely on the filesystem directory structure.
Dead Souls manages code access primarily by allowing or denying access to the various directories and files in the mudlib. Subversion operates by creating a .svn subdirectory for metadata and other operating data within every directory in a checked out working copy. It can be very dangerous to run the mud from a subversion working copy that you’ve checked out. If a creator is given access to domains/town/ in order to develop that domain, then they also have access to domains/town/.svn and can modify the files within from inside the mud and corrupt the subversion working copy. To combat this, I modified the valid_read and valid_write driver applies in the master object (lib/secure/daemon/master.c). The new checks make sure that no object or user in the mud, even the master, can access a .svn directory. You may view my changes to the master object here.
Other than the minor issues outline above, I’ve had great success managing mud development with subversion. I hope these solutions will be useful to you if you find yourself in a similar situation.