Wednesday, July 05, 2006
Garage Weekend Update
The four day Fourth of July weekend was a pretty productive one for me. At least, it was if you consider working on the Garage of DOOM "productive." But I'll put that question aside for now and get on with the update.
Much of my time was spent trying to separate multipurpose scripts into multiple single-function scripts. This is a process somewhat on par with trying to untangle a bowl of wet spaghetti using a single chopstick. But the task proved to be necessary in order to more efficiently clear backlogs of chat traffic from one script to another. I found that, when things are moving fast and a number of things are happening at once, some of my combined scripts would tend to bog down as they tried to deal with the constant stream of incoming data. It irks me that a script can choke on a mere five or six incoming chat commands per second (Oh Mono, where art thou?), put there's no help for it.
I'll give you an example. The central server (conveniently located inside a manhole cover in the center of the garage) serves several functions. It listens for monster calls from player HUDs, and selects monsters and power-ups to send to the remote monster dispensers for rezzing. It tracks and counts players by sending out a signal for a roll call, listening for a "here" response from all currently active players, compiling a list of active player keys, and sending this list to the monsters. It performs a similar roll call function with the monsters, and limits the maximum monster count to a predetermined number. And there are a number of one-shot and ancillary functions that must be taken care of during the game, as well. Initially, I naively put all these functions in one large script. But, when there were two or three players and a dozen monsters all talking back and forth with the server every second or two, it tended to lag a bit behind.
So, each of the functions was split into small parts, some of them only 20 lines long. Similar things were done with the player HUD, to deal with power-ups, health tracking, time tracking, collision tracking, and so on. (Fortunately, I had the good sense to use modular parts for the nine-and-counting monsters from the beginning.) And then came the test, check, and debug process required to pass the required information back and forth between them all. Long and tedious. But everything seems to work considerably faster and more reliably now.
I'm a little concerned about script count, though. I've been doing everything I can to filter out extraneous chats (such as limiting listens to specific keywords, as opposed to using if-thens to check for them later, and using the various link-here, link-there, link-everywhere-but-here link messaging directions to avoid processing extraneous internal communications) and make each individual script more efficient and less laggy. But I fear the net result is still more overall sim load. I'm going to be watching that very carefully during my load tests. I'd hate to throw away all this work, but I don't own the sim, and I don't have the right to consume significantly more than my share of the resources. Fortunately, the garage is not a constant load. It deletes itself after 10 minutes of inactivity, and is only under load for a few minutes at a time (the length of a typical game- which I'm trying my darnedest to make shorter, for a variety of reasons). I hope that's enough. In the meantime, it's streamline, conserve, and reduce at every turn. It officially works, now it just has to work smarter.
Once I completed the modularization of the various parts, I had the brilliant idea of making them all interconnected again. Well, that wasn't my original intent, but it sure seemed to work out that way. See, I decided to add a new type of power-up: the Freeze Pack. When activated, the Freezer stops all currently active monsters in their tracks, and stops new monsters from appearing, for a 30 second period. Simple, right?
Yeah, I thought so, too. Those of you who managed to stay awake through previous posts may remember a passing reference to an aborted invisibility power-up. Basically, this is effectively the same thing, on a mass scale. At its heart, the Freeze effect directs the monster server to feed empty player lists to the monsters. After that, the monsters can't find any valid targets, and they just coast to a halt until they hear otherwise. Then, after the Freeze period has elapsed, a populated player list is sent, and they leap into action again.
At least, that's how I hoped it would work. But there were a massive number of little hidden consequences to flipping the player list on and off. First, the monsters are more-or-less autonomous. They do their own thing, under the direction of the player list and their own programming. So, if the bogus list isn't heard (due to lag effects, or rezzing at exactly the wrong time), they'll keep pounding on the hapless player. And even the monsters that did hear the command took a few seconds to react. And, during this time, they'd keep following and pounding on the player. Not terribly satisfactory.
Before it was complete, the Freeze power-up had some variable or toggle in just about every major component of the game. And it required flipping the monsters back and forth between physical and non-physical, in order to get them to stop in their tracks (as opposed to sort of meandering to a stop a few meters later). This is another perfect example of a small change with huge unanticipated consequences.
In any case, after half a day's work, I now have one more power-up. It's a spinning ice cube, and it makes a wave of blue-white particles and the sound of a burst of arctic wind when it's activated. Umm, yeah. I don't think I'll be making any more power-ups for a while.
Beyond that, most of the weekend was spent with minor tinkering and enhancement on the monsters. Most of this was with an eye for making them tougher, faster, and smarter. They're getting there. The walking undead still tend to follow the players in a straight line, and are a bit too easy to coax into an ineffectual clump. But they're getting better.
In the middle of all that, I came up with a rather nifty (if I do say so myself) avoidance algorithm to prevent the creatures from clumping together quite so badly. On collision, they calculate the direction vector away from the obstruction, and move back a step in the proper direction. In a group, this means that the monsters tend to briefly bumble about, then spread themselves out nicely. It's a small thing, but it's made a huge difference.
And it's opened the way for one of the most often requested features for the garage: cars! Now that the monsters know how to sidestep, as opposed to either repeatedly slamming into or attempting to climb over obstructions, I can afford to carefully add a car or two for cover. I'll have to see what kind of impact this has on the game. For theme purposes, it would add quite a bit to the game to have a couple of old junkers in the garage. But I don't know if the obstruction will cause too many problems, or make it too easy to run and hide.
And I seem to have run out of time for this update. More to come.