Wednesday, January 15, 2014

Alter Aeon 19th anniversary - already?

This week is the 19th anniversary of Alter Aeon. Some time in the middle of January of 1995, I sat down and started writing the first code for what would become a major part of my life, a project that would land me jobs and teach me a lot about software engineering and project management. It actually seems like a long time ago now.

I've traditionally been the one to run the anniversary events, but I think next year I'm going to delegate it to other people. As much as players like events, they make me hate my life. Running an event is much harder work than people seem to realize; most event based things are one shot, so you don't really get to test them very well, and there's always something wrong. The content is one use, or limited use, so you know it probably won't be reused when it's done. I constantly feel like I'm just building things just to throw them away a week later, and that bothers me quite a bit.

All this said, it is almost always a good idea for me to personally run events, because it forces me to improve our codebase to support my ideas. Whenever I build an area, whenever I run an event, I invariably end up needing some trivial piece of code that really improves our ability to script things in the game. A number of really awesome dproc features have come about that way, and this year is no exception, with the addition of truly global data that allows dprocs to talk to each other from anywhere on the server.

Like anything in life, it's a tradeoff. As much as I don't want to run the event next year, I probably will, and the game will be better for it.

Sunday, December 1, 2013

Releasing a new class - Druid

It took a lot of effort, but we managed to release a new class, Druid, right on schedule. The actual core implementation of the mechanics and code only took about two full months; the hard part was the entropy, coming up with ideas. But ideas aren't really the hard part: if you ask your players for ideas, you'll get a steaming pile of hundreds of them. Ideas are easy. Good ideas that fit a model and work well together are not nearly so easy. I've been collecting good ideas that work together well for a few years now, and I needed pretty much all of them to make the class unique and not just a carbon copy of other classes.

Personally, I feel that just copying spells, skills, and classes is a bad idea, and while it might work in the short term to get content and features out the door quickly, I think it detracts from the long-term viability of a game. Part of what makes a long term game successful is how the pieces interact, the way you can get unexpected effects by strange configurations. Consider minecraft, a game with substantial complexity built on an extremely simple model and small set of ideas.

Unfortunately, holding new classes to such high standards means that I can't create many of them quickly. I would like to add a couple more classes if possible, but there might not actually be enough new and unique things left to do it. Over time, new mechanics will be added that might allow it, but it will probably be at least a couple of years before we have another class release.

I suppose my overall point is this: if you value the long term, don't cheese your game mechanics. Do it well, or not at all. Make something that surprises you from time to time, something that fits in with other stuff in the game, something which can't be done (or can't easily be done) in other ways. If you can't find a way to make races unique and interesting, don't add them. If you can't build a new class without photocopying existing effects from other classes, don't do it at all. Better to keep things sparse than pollute the game with uninteresting noise.

With this in mind, I'm proud to say that I'm happy with the new Druid class, as I was with the Necromancer class when it came out in 2010. They're both very well designed, and I'm certain the new Druid skills will make Alter Aeon and even better place to be. That's a pretty high bar.

Here's the official release announcement for the new class.

Druid Class Expansion on Alter Aeon

The long awaited sixth character class, Druid, has been released on Alter Aeon! Players can now add Druid powers to those of the other classes to create new skillset combinations and strengthen their characters.

This new character class adds a number of new abilities:

- control of the weather, to make storms and call lightning

- rune carving and runic enchantments

- magically controlling and growing plants

- animal lore and handling

- summon wind and dust storms to hinder your enemies

- use minions summoned from the earth to assist you in battle

- brew tinctures and salves for new special effects

- new item crafting skills using carving and runes

In addition to all this, it is now December, and the year-end Advent Calendar is now running! Log in for your daily advent calendar gifts, including practices, credits, storage locker time, unique items, and more.

Releases this big only happen every few years, so stop by and check it out!

Alter Aeon MUD

Thursday, May 23, 2013

Test cases are awesome

One of my major background projects for the past few months has been to extract common libraries from various codebases, and get everything into a global, unified tree. As an example of this, I have a set of string utility routines I've been using for many years, and my normal way of using them was to grab and copy the code into various projects as I needed it. For routines as well-defined as these, it wasn't really a problem, but for anything even remotely more complex, it becomes a huge maintenance nightmare.

As part of this consolidation, I now have around 20 standalone library parts I can pretty easily use. There's a unified notify/error reporting mechanism, but most importantly for the purposes of this post, there are test cases. Lots of test cases.

I have traditionally done very little in the way of formalized testing, but by the same token, I've only recently started switching to a true 'library' structure for my code. It turns out that test cases are way more powerful and useful than I ever gave credit to.

So how do these test cases work? First, the build system compiles all the libraries, then it automatically builds and runs all the test cases for them. Every time. Running all the test cases currently adds about four seconds to the build time, which I can live with. I also make sure to update the test cases as I find bugs in general usage - it's very hard to guess all the bugs that might happen in advance, so putting in new tests as bugs are discovered is pretty important.

Part of the reason this is so powerful is that it's changed my debugging method for most of the library code. I get a questionable result in the mainline, so instead of trying to debug the mainline, I go add a test case and fix the library before I even try the mainline code again. Usually after doing that, the mainline bug goes away.

Another reason the tests are so powerful is because you never have to worry about regressions, or if something you changed accidentally breaks something else. You've also got simple, clear, and obvious code that demonstrates how to use the module in question, including ways to abuse it which produce well understood errors.

The downside to doing this is time and effort. A lot of time and effort. If I had to hazard a guess, I'd say that building proper libraries and the associated test cases takes 3-4 times as much work as just hacking something together that functions. The key to making libraries pay off is to make up for the difference one of two areas: long term maintenance, and use in multiple projects.

If you expect to maintain a project for many years, you -might- make up the difference in maintenance costs.

If you expect to use the library in at least 3 projects, you will make up the difference in implementation time.

Another downside is that building libraries and test cases is decidedly unglamorous. There's nothing cool about it, nothing you can really show anybody, and if you do try to show someone, you'll get a response like "it took you 12 hours to code up a way to do dns lookup from inside the game server?" The thing that will be missing is that along the way, you added a platform independent threading and mutex model as well as an async DNS caching system. Users will see those words and think 'blah blah', and wonder why your time wasn't spent doing something productive.

Anyway, I'm sold. I'll be adding a lot more test cases in the future.

Thursday, February 14, 2013

Valentine's Day Server Updates

I had planned to open a bunch of things for Valentine's day, but I only managed to get about half of them done, largely due to laziness and akrasia. It's still a decent chunk of work though:

- There's a new slot machine based on a 'travelling merchant' theme. The first two slot machine wheels pick a random cargo and destination, the next few wheels pick your path through various terrain (or have you get robbed by thieves), and when you arrive at the destination you sell your cargo. If there's a local event and your cargo is badly needed, you make a premium on your cargo, for example if you're hauling food into a famine zone, or supplying weapons to a kingdom at war.

- There's a new level 14 area on the island of Kordan, the Haunted Hills. This is the first complete, full size area that I've personally built entirely myself in at least a decade, possibly more. I ended up making quite a few code changes for this - silly little things to make the area work the way I wanted it to, but important (at least to me.) This area taught me that I underestimate the creativity of my builders, and I overestimate the ability of the code. Several things that should have been easy to do and that I've seen other builders do were best handled as code updates; even though my awesome builders have managed to get similar effects, they had to use incredibly shitty workarounds to do it.

I'm now convinced that if I were to build full time, building areas would rapidly become easier and more powerful for all the builders. It may be worthwhile for me to simply build a zone every month or two to improve the building system. If only I had multiple copies of myself.

- There's also a new level 24 area on the island of Archais, the tinker gnome colony. This is a massive rebuild and rework of an ancient 15 room mini-area built by Aleph at the dawn of time; the rebuilt version is at least five times the size, and uses a lot of the snazzy new building features that weren't available in 1996.

- The planar research guild has opened their main offices in the city of Gad's Landing on the island of Archais. The guild gives out copies of a bunch of quests which were used in the 17th anniversary event of 2012. The players seemed to really like the anniversary quests, and with the opening of the planar knot observation platform, it makes sense that similar sorts of things would be available.

- I added a new level 31 mage spell, 'group teleport'. The whole point is so that people can teleport with their group, to die en-masse instead of solo. Now that we have obscure spells, I can safely add this and put it somewhere out of the way where new players won't kill themselves using it.

- As mentioned above, the 17th anniversary zone is now an official area. The observation platform is instanced and accessible to players of any level - the dangerous parts are cordoned off with a very powerful ward spell. My intent was that it would be a place to visit and/or sightsee, similar to the Lincoln monument. High level groups can break the wards and let loose the elementals in the rest of the area. It takes a group with a minimum of 5k mana and an obscure high level spell to do this, so I'm hoping that new players who wander into it will be safe.

- We also opened the 18th anniversary zone in the Ash Mountains. Ward breaking is needed to enter the main fortress, but honestly any group able to make it to the main fortress in one piece is probably capable of bringing down the wards. This and the 17th anniversary zones were primarily intended to be high level group experience.

There probably won't be any more area or event updates like this from me for a while. I'm pretty burned out now, having done christmas/new years, the anniversary, and now a gob of stuff for valentines day; I'm also really behind on work I had scheduled that is important, so I'll probably be spending some time on infrastructure for a while.

Friday, February 1, 2013

Alter Aeon Wiki

People have been harassing me for literally years to set up an AA wiki, but I always managed to avoid doing it for various reasons. I suspect the real reason I had been avoiding it was fear of the unknown, of not knowing if I could even figure it out (I have PTSD from the 1995 linux "recompile your compiler" era.) There's also the fear of it being a huge time sink, and many other such things.

To see the end result of a lot of hard work, the wiki URL is:

These fears were not unfounded, and had it not been for Uicli, I probably would never have done it. He set up an initial wiki on one of his servers, which would have made it the third or fourth player wiki over the years. All the other player-run wikis failed or vanished as the players moved on, so rather than have yet another player waste their time, I decided to set up an official AA wiki. Uicli guided me through most of the process, which was just the right amount of handholding.

Properly setting up a wiki is not simple:
  • Set up and install the web server and accounts
  • Grab the wiki package
  • Set up the database and PHP so they work properly with the web server
  • Initially configure and get the wiki itself working
  • Get database and server backups working
  • Set up game server SSH cron scripts to export valid account ids to wiki server
  • Use PHP to parse valid account info for registration
  • Get server email working and relayed through the external mail host
  • Use PHP to create a derived theme
  • Use CSS to make the theme not suck
Installing the basic web server and accounts took a while because I intend to use the wiki server as the insecure PHP/scripting server and keep it isolated from the actual important game server info. I wanted to make sure that the accounts were set up in a way that would be easily maintainable and expandable, which requires more thought than it would first appear.

Setting up the databases required me to read documentation again, and relearn things I had distantly touched on in the past. I only ever have to dig into them every year or two, so I'm never fresh on commands or how to do anything. Each time requires a little less startup time though.

Getting a custom theme in place was actually beyond my limited PHP abilities, but Uicli helpfully provided me a basic template to work with. Even he had to beat on it a handful of times to get it working properly.

The really surprising thing for me was how long it took to adjust the theme CSS. The initial/obvious stuff didn't take too long, and I've become fairly proficient in hunting down CSS entries using Firebug. Unfortunately, it's the little, unobvious things that really eat into your time budget: there's isolated, single use undocumented CSS entries all over the place, and I only figured out as many of them as I did by making all their colors bright green so they would stand out when they were finally displayed. There's still 20+ entries in the CSS I could not track down.

To top it all off, the wiki stores an additional CSS style sheet layer internally for use by templates, one which overrides ALL EXTERNAL CSS. Uicli and a couple other guys set this up, and I've been trying to slowly push the colors out to the external CSS while keeping the formatting and box styles in the internal CSS. Because the custom theme uses an inverted color scheme, it's a complete pain in the ass: if you do it wrong, either the default themes will be broken, or the custom theme, or both.

The email relaying I had done only a couple months ago when implementing the main game server email account verify code, so it didn't take too long. I have had very bad experiences with email in the distant past, and setting up mail servers still creeps me out.

Finally, I had to dig into the Wiki's PHP and add account restriction code to limit accounts based on game login id and email address. The game server exports a low-security file containing this information, and I've been using it on the AA forum to limit spam accounts. It's shockingly effective - simply limiting new accounts to being existing character names has dropped the number of spam accounts from 5 per day to less than 5 per year. I don't know how much more effective requiring the email address will be, but I'd be surprised to ever see a spam account on the wiki that doesn't come from an existing player (which I can siteban.)

That's a lot of different skillsets that have to come together in one place. While I could probably have muddled through it in the past, I'm glad I had at least introductions to all these things since then. If I had to set up another wiki, I could probably do it a lot more quickly now, and perhaps with this additional background, a few other modern web technologies will seem a bit less scary.

Don't expect me to jump on the Web 2.0 bandwagon just yet though.

Friday, October 26, 2012

2012 Halloween Havoc

[Repost from in-game]

Alter Aeon is pleased to announce our annual Halloween Havoc! The action starts on Monday, October 29, and continues until midnight on the 31st. Our preliminary schedule has several area openings, a number of voluntary pk events, pumpkin cannon contests, and other things.

Monday, Oct 29:

On monday, we will have the official release of Castle Kraftrager, on the island of Archais. Also known as the drake tower, this zone has a couple of interesting quests and lots of new beasties to fight.

Tuesday, Oct 30:

On tuesday, a new addition to the fire plane, the untamed wilds, will be released. This area is an extension to the tunnels and caverns below the fire giant keep, and is intended for very high level players.

Wednesday, Oct 31:

On wednesday, a handful of areas will be released on the western edge of Archais. The island archipelago has several new quests and deeds, including a cursed temple and hang gliding.

In addition, today, a new area was opened north of the Great Desert, near the Ash Mountains on the mainland. This area has many undead and elemental creatures, and should provide high level players with an interesting experience.

On all three days, we will be running arena and other events every few hours to give those in different time zones a chance to participate and say hello. We'll have novelty items and prizes for everyone.

We hope to see you there!

Wednesday, September 19, 2012

This code sucks?

A colleague recently asked me, ‘how can you tell code is crap?’ This is a very good question, one dear to my heart given a recent project I worked on.

The biggest indicators all seem in some way to link back to a high Kolmogorov complexity. The basic idea is that the code is more complicated than it needs to be to do a given task. Sometimes tasks require complicated code; sometimes, your given task is to optimize in a way that requires complicated constructs. But in general, one should not make code more complicated than it needs to be.

Some of the indicators I've been able to come up with off the top of my head:
  • 1) Lack of data hiding

    Any halfway complicated software module is going to have some internal state that it manages, and that nobody else has any business touching. Bad code often has cases where unrelated modules directly mess with data belonging to some other module.

    Data hiding takes many forms, and can be enforced by tools or simply willpower. Whether classes, undefined structure types, local variables, file scope data, or intentional exclusion of header files, there are many ways to hide and protect data. Bad code typically ignores those protections.

  • 2) Lack of chokepoint interfaces

    Chokepointing is a crucial part of managing complexity. It's very similar to an object-oriented interface, but I think that calling it a chokepoint better conveys what's happening: At the chokepoint, the complexity is the bare minimum of what is required for communication between the two sides.

    In short, by chokepointing complexity at well defined locations, you can more easily manage global complexity. Bad code typically doesn't have good chokepointing.

  • 3) Logic holes and unhandled cases

    Few things increase complexity faster than unhandled or fallthrough logic. Consider the case of a well chokepointed module, with a single commonly used interface that has a 'fall through' condition: every external module that uses that interface can potentially get a different output for exactly the same input.

    While this would seem an obvious bug to be fixed, keep in mind that computers are deterministic - all of the modules on the system may always get the same consistent result. And it may be that all of them get a usable result, except for an obscure usage in some minor library.

There's three more indicators that I don't think are directly attached to the complexity issue:

  • 4) Presence of any unexpected behaviour in the output

    If I've learned anything over the years, it's that any unexpected output needs to be examined and understood. Far more often than not, unexpected output is an indicator of #3, logic holes and unhandled cases.

  • 5) Bad customer interfaces

    If the publicly exported interface to a paying customer is crap, odds are good the code inside is crap. Customer interfaces should be simple, powerful, and obvious. They require attention to detail, and if that attention isn't present, it's probably not present in the code behind the interface either.

  • 6) Too little, or too much unfilterable debug logging

    The purpose of debug logging is to give visibility into the system to allow for debugging and analysis. If there is too little debug, odds are good failures are simply being ignored. If there is too much debug and no good way to filter it for important messages, odds are good the programmer missed something.

I can also think of one indicator of bad code that appears to violate the Kolmogorov complexity rule (IMHO, it doesn't actually violate the rule if you include the probability of programming bugs and programmer error into the definition of your given task.)

  • 7) Lack of sanity checks

    Sanity checks directly increase complexity, because they generally change the actual behaviour of the program when they trigger (unlike debug logging, which simply reports state without modification). However, they are cheap, fast, and very, very effective. While they do increase program complexity, they typically add a layer of reliability to the system.

This is definitely not a comprehensive list, but I've encountered each of these over the last month, on this one project alone. If any of you have other candidates, feel free to post them in the comments.