Phantasmal MUD Lib for DGD

Phantasmal Site > Development > Old document

Sourceforge Development (legacy)

I consider everything here to be generally good etiquette for doing work based on Phantasmal. These are only mandatory when you're working with me specifically. But you may find that they're good for your own work, too.

When you add a significant new feature, be sure to update the documentation. At a minimum try to update the Changelog and add any new appropriate online help. Other stuff to consider: new tutorials, post what you did on the forums, update bug/feature reports in the SourceForge tracker. Also consider adding it to more than one Phantasmal game if it applies -- we've got both testgame and the mudlib.

Where it's reasonable to do, try to make stuff update itself when recompiled with the upgraded() function. This turns out to be highly useful for things that read data files, such as the HELPD, the various binders, phrase repositories and so on. Basically, make a given entity reread its data files when you recompile it. That keeps you from needing a command-line "@update_help", "@update_phrases", "@update_mob_binder", etc command for everything with its own data files. Instead, type "%full_rebuild" and you're there. No muss, no fuss.

CVS Checkins

(to be updated, we use Subversion now)

  • Make sure to do a "cvs update -Pd" before you check in new files. Immediately before. This means you won't randomly blow away other people's changes unless you actually mean to, and that you can do a resolve easily on your own machine.
  • Check in only files where you've made meaningful changes. The roomfile and mobfile, for instance, don't need to be checked in unless you've actually built something significant. The bug-report and idea-report files normally shouldn't be checked in at all. Don't include your character's body and mobile in the roomfiles or the mobfile, either.
  • If you add debugging print statements, log statements, driver messages or whatnot, make sure you do it in keeping with the way Phantasmal works now. Notice the current lack of any DRIVER->message() calls after bootup, and how almost every LOGD->write_syslog() call specifies a log level so you can turn it off easily. Keep up that tradition.
  • When you do your update, you'll notice which files in your repository have been modified -- "cvs update" will show you this stuff. Check it over again to make sure you checked in everything you meant to.
  • Never check in code that doesn't compile. For preference, never check in code that breaks other people's stuff. It really sucks to do an update and get code that won't let you start up or won't let you run. And if you do that to other people, you're stopping the whole project from getting any work done. That's not friendly.
  • Make your checkin comments meaningful and relevant. People who read your comments and then look through the diffs on the mailing list (I make sure to, and I'm probably not the only one) should simply nod and say, "yep, that's the way to do what he mentioned". If instead they find themselves saying "huh? That's not what the checkin comment said," then you did it wrong.
  • Check in your code a couple of files at a time, where possible. Rather than checking in a huge swath of files at once and giving a comment like "redesigned frobnication in c minor", for a given couple of files, say something like "added new fields to the DTD for mobiles. Added new parsing and UNQ code to make them useful." The exception to this is if you've written and checked in a design document detailing your changes in minute detail, and that design document is expected to be available for a long time. So you could check in a bunch of stuff and say "see doc/design/frobnication_spec" and that'd be okay as long as frobnication_spec spells out everything -- down to what files changed in what ways.
  • If you can't recall what you changed in a given file, "cvs diff -c" is your friend. This prevents checkin comments like "changed some stuff".

Bugtracking, Features, Tasks, etc

  • SourceForge provides this stuff for a reason. You can work on a bug/feature/etc without it having a formal tracker report, but if you're going to be doing very much work you should enter a tracker item if one doesn't already exist.
  • SourceForge bug numbers aren't very recognizable. Still, if you can you should mention the tracker number on any relevant checkin. For instance, "Finished task #74094, object weight and volume" would be a good sentence to see in a checkin comment. It lets people find the tracker object unambiguously and get any extra commentary you've been doing on the bug.
  • Use the tracker. If you're working on a bug/task/feature, assign it to yourself. If you change approach or fix it differently than you expected, mention that in a comment in the tracker.
  • When you fix the bug, if you're feeling like a go-getter, mention what files you changed, and possibly what the new revisions of the given files are. CVS doesn't provide us checkin numbers, alas -- they're a much better way to do this.
  • If you finish a roadmap task, mention it to a project admin. We keep a separate roadmap document updated and a number of the tasks are mentioned there. We should remove them when those tasks are completed -- they're done, so they don't belong on the roadmap.

Inter-Object Security

  • Upgraded() functions should be guarded by "if(SYSTEM())" constructs, plus perhaps a guard for being called by the object itself or its child objects. Create() functions should be static. Destructed() functions should also be callable only by System callers. In a library, the upgraded() and destructed() functions, if present, should be static.
  • Use the SYSTEM(), COMMON() and GAME() checks liberally. Decide who should call a particular function and guard it appropriately. The best, of course, is to specifically check previous_program() so that only the expected caller can call the function. Functions that only the current object calls should be marked private.
  • Every Phantasmal function should be one of: static, private, checks previous_program(), or documented to say exactly why not. The only functions that don't need to be access-protected are utility functions like the ones in STRINGD that have no access to any Phantasmal data. They can exist, but you should document why anybody is allowed to call them.
  • Never call anything in a publicly writable directory. Never call a method of any object in a writable directory if you don't trust all possible writers. Remember who has access to what. Remember that if a directory is writable by a given object, that object could have overwritten the file and recompiled the object while you weren't looking. Don't trust it.
  • Never pass your internal data structures to the outside world without copying. The caller may not realize that the data structure is sensitive to you. Always copy it first so that you don't have to trust the caller not to modify it.
  • Never gratuitously add callers without reason. Sure, you may trust "common", but why give it specific access to something it doesn't need? You should know who calls a function. Give them, and only them, access.

Adding Commands

  • Add an entry to the online help for that command
  • Add the command to "/data/phrase/user_cmds.unq", "/usr/System/obj/wiztool.c" or the equivalent.
  • Add the command's associated function to the user object or userlib, or one of the wiztool libraries in "/usr/System/lib/".
  • Make sure the command checks usage. See one of the existing commands for how to do this. If it's used improperly, it should print a message saying so.
  • Make sure the command gives status messages to the user object that called it. Then if there's an error midway through, the user will know if it succeeded properly. That way you don't have to be subscribed to the error channel to know that an error occurred.
  • Players and administrators need to have a good example of how to use the command. A Tutorial is an appropriate way to handle this for administrators.
  • Mention in the Changelog that you added the command.

Adding New Types of Objects

  • If a user or admin can see them or manipulate them in any way, physically or with any command, add them to the online help.
  • Make sure that their code can be upgraded when the file is recompiled, to the extent that you can.
  • Objects should save and load with %datadump and %shutdown and stuff. If they don't, they should either be entirely made of code (no data, no data structures) or have some other serviceable way to save and load. Requiring %reboot is not an acceptable way to save and load, it must be possible for objects to survive a %shutdown.
  • Objects should survive a %shutdown and reload as near to unaltered as possible. They should behave the same way before as after. Seriously.
  • If these new objects can be created or manipulated by users or administrators, we'll need web documentation. Submitting a Tutorial would be a great way to handle this for admin commands. You could also submit API docs.
  • Mention in the Changelog that you added the objects and any commands that deal with them.

Adding Fields to an Object Type

  • Add commands to manipulate the field -- see "Adding Commands" for further details. There should always be admin commands in the wiztool for the fields, and there may be user commands as well.
  • Add get and set functions for the new field to the object it's a member of. If there's a document for that object in "/doc/api", add documentation for those functions.
  • Add the field to the object's UNQ DTD. Add it to the object's UNQ read and write functions. This only applies to fields that need to be loadable and saveable.
  • If the field may need to be set for common objects, add it to the MAKE_ROOM user state. Make sure the field is prompted for only when appropriate, and that it behaves reasonably for portables, rooms and details.
  • If appropriate, submit a Tutorial that covers the new field and how to use it.
  • Mention in the Changelog that you added the field.