Thursday, April 14, 2005

Triggers and events

While thinking about the scripting language to use (a topic for another day), the idea of event-handling and triggers came to mind. Whatever language I choose to use or write should be able to support them, because I feel that events are a big part of a virtual world.

The best example is speech. A character walks up to the banker and says, "I'd like to access my bank box please." Or he walks onto a magic circle and says a certain word, finding himself teleported to another part of the world. Both of these examples are from Ultima Online, but I'm sure every virtual world has some case of this. Maybe not speech, exactly, but some way for an NPC or object to react to something a character does.

The issue is how to implement it. There are two ways that I can see: each object (which includes PCs and NPCs) has a youJustHeard() function, which is passed a reference to the speaker, and the text spoken; or each speaker has a youJustSaid() function, which takes the text spoken.

In the first case, every object in the world has a listener function. There are really two ways to deal with this: each object, upon creation, must register itself as a listener, to let the world know that it might be interested in things that are said in the world; or whenever something is spoken, the world looks around the speaker to get a list of all the objects within range, and "tells" each of them what was said.

If the world has to check for nearby listeners every time anything is spoken, it should be obvious that there is going to be a lot of this searching. When characters start gabbing in-game, every table, door, dog and character within a given distance is going to be told, whether or not they want to know. In this case, we better hope that we have one hell of an optimized way to get a list of objects within a certain area.

With the registration method, the world would be able to reduce the number of objects that it has to look through, because only objects that can listen are registered. Again, we would still want this to be very optimized, since every character will be in this list, as will many NPCs and probably some inanimate objects.

Both of these methods of listening seem to have a lot of overhead for every word said.

Taking the other approach, it's the responsibility of the speaker to let everyone know what was said. Instead of relying on the server to do all the figuring for finding listeners, the logic for that could be part of the speaker's youJustSaid() script, which would ask the system for a list of things within range (something that seems to be inescapable), and then the speaker's script would call each of the listener's youJustHeard() functions.

At first glance, this seems to be less effective than letting the server do it directly, because the same work is being done (finding a list of listeners, calling each of their functions), but now it's (most likely) being done in an interpreter, which isn't as optimal as a compiled server core. And while that's probably true, having the logic take place in a dynamic spot -- that is, something that the game designer can change -- allows for more flexibility whenever something is spoken.

For instance, perhaps our world allows spells, and instead of clicking an icon or scroll to cast, you simply say the words out loud. As well as having every listener's youJustHeard() being called, we would also want the character to start waving his or her hands, and spell effects to happen, and an apple to appear. Or a certain class of character might be able to open doors with but a word; the doors by themselves have no logic to listen for such things (though it could of course be added), but the speaker's script could not only inform all listeners of the words, but also call the door's use() function. Having the speech handler "local" to the speaker also allows them to control who hears them - they might have a slider that defines how loud they speak (whisper, murmur, talk, yell), or they might be able to speak to one person specifically (telepathy).

All of these things can, of course, be done at the listener's side instead of the speaker's side, and is just as accessible to the world designer, for he or she controls the scripts for everything in the world. And there's no reason that you can't mix the two; the generic "character speaker" script may know how to open doors or cast spells when the character speaks, but there's no need to put the logic for word-activated teleporters in every character when the teleporter itself can have that functionality coded into its listener script. But with this approach, we're saying that it's still the speaker's responsibility to let the teleporter know that something is said -- and what it does with that is up to it.

A third possibility, which I'm not going to entertain, is a "speech parser", which looks at everything everyone says and decides how to handle it. If a sentence contains the word "bank", then search for any bankers nearby and tell them. If one of the four magic words in the game are spoken, check the character is in one of the few places that it matters.

This is very limiting. It basically hard-codes these trigger words, requiring a list of words and their effectual area or audience. The parser might also be responsible for making the effect happen, instead of calling a function on some other object -- again, very awkward.

So, speaker or listener. A decision needs to be made... but not so fast. Triggering and events based on speech is only one possibility. What about the shopkeeper that sees you steal something? What about the citizen that sees you attack another? What about the guard that sees you discard items on the ground - littering!

Speech is only one of the generic actions that we might want world objects to react to. NPCs and monsters should likely defend themselves when you attack them; guards might arrest you if you move somewhere you shouldn't; and the shopkeeper certainly shouldn't sit idly while you get his inventory without paying.

But again, who should handle this? If my character attacks a monster, then it's pretty easy to let that monster (and its beingAttackedBy() function) know this. But what about onlookers? Maybe another monster will step in if you attack its buddy, or a nearby NPC will come to aid you.

If I drop an item on the ground, do I tell every object about this put action I just did, or do I broadcast a "I just put X at Y" message and let the "listeners" do what they will with that knowledge (fined for littering, beggars run over to pick it up). Note that depending on the game interface, this might also "push" a look action to some clients so they now know the item's there, or the world has a constant look going. But it's different to see an object suddenly appear on the ground, and to know that character X put it there. Or at least it should be.

I don't think I've convinced myself either way on who should take care of these messages about the events in the world. I'm hoping as I continue to mull over it that I can find an example that definitively says that one method is better than the other (and I equally hope I don't find two examples that contradict).

Friday, April 08, 2005

Never trust the client

A few days ago, in the #ddo IRC channel on SorceryNet, the topic of packet sniffers came up, with respect to the upcoming Dungeons & Dragons Online game.

The issue goes back to the more general rule, "never trust the client", or "The client is in the hands of the enemy". The fact is that no matter how much you try to hide or obfuscate the operation of your client, there are people out there that will figure it out, and they will write a cheat program for your users to use.

The solution, then, is "never trust the client" - that is, anything your client says to do, you verify as "correct" or possible. Instead of taking orders from the client, you take suggestions. And client trust doesn't even have to be in communication, where you are listening to what the client is saying. You can't even trust the client to perform in a commanded way, such as display something it should or hide something it shouldn't. The earliest case I had first heard of (as a player in the community) was in Ultima Online, where the game servers would tell the clients to darken the screen, because it was nighttime or because the player was in a dark dungeon. It was meant to provide atmosphere, but also, I presume, to add more challenge to adventuring in the darkness. I don't know how long it took, but individuals had figured out the packets being passed back and forth between the server and client, had isolated the one that said "make the screen dark", and stripped it out (or modified it to say "make the screen bright").

In the case of the conversation in #ddo, there were the issues of being able to see traps that you hadn't detected yet, or knowing of the presence of monsters that were hiding in the shadows. I, of course, stated flat out that this kind of information shouldn't be in the hands of the client until the player is supposed to know about these. This started a flurry of responses, from "yeah, but every other MMO has had the problem" to "it would be too laggy if you didn't send this stuff beforehand".

Now, I'm one of the first to grit my teeth when I'm reading gaming forums and see people say "they should add feature X. It's really easy, they just need to ..." Invariably, these people are not programmers, and if they are, they're not good ones, and if they are good, then they still don't have the knowledge to say how easy it is to add a feature to someone else's codebase. Almost as bad are people who seem to know what *can't* be done. This is, however, what the discussion became, me included.

One party insisted that game developers are going to keep doing it, even though (I assured them that) experienced developers know about these previous mistakes in this industry, and would know better. Another party insisted that they couldn't get away from sending early information to the client because of lag problems (which is a little better argument than "they'll do it because all games have it").

I disagree with them both. One, at least, is a programmer. And while I find many of the vocal "easy" people on forums try claiming programming skill as well, I usually call bollocks on their abilities, and chalk them up as know-it-alls that know nothing. This chatroom member, though, I'm willing to give credit as a capable programmer, and thus I just disagree with him.

First of all, the "there's always something that a packet sniffer can find" argument is just crap. Yes, it might be that every game so far has had some client vulnerability, but to argue that every game in the future must therefore have the same is ludicrous. The client is just an interface to the information send by and to the server. It should never have extra information that isn't displayed. Enough of that argument.

But the point about lag is valid. The example went something like "if a dozen goblins were sneaking up on you, and suddenly stepped out of the shadows, the sudden surge of data from the server to the client would cause the client to lag and the player to die (or be at a disadvantage)". Fair enough, that might happen. But, this brings up a few points:

  • Is the protocol so "bulky" that the information about these dozen goblins (or whatever information suddenly because available) will cause such a discernable lag? If so, can the protocol be optimized? There's a reason why MMOs aren't "twitch" games -- because of the latency of the Internet (discussed previously) and disparate speeds of players' computers - is the game too twitchy if this sudden information is a problem?
  • Does all the information have to be sent immediately? Can the server not say "draw some shadowy figures - I'll let you know what they are in a sec"? Are full texture descriptions being sent up, as one of my debaters suggested, instead of them being pre-existing on the client, or send a little later?
  • Can the game be designed so that any information sent early (and thus hacked) is of insignificant value? In the case of the darkness if UO, I think it might have been changed so "dark" wasn't really so bad, and it was moved from a game-affecting feature (and thus an advantage to the cheaters) to solely a mood-lighting, visual effect.
The point of the original speaker was valid, in that a game can be ruined if certain kinds of information are available to some players and not others. And that's my point as well I suppose: to release a game that has any of this information available is foolish. Any developer who does this should look at this information and say, "since some people will have it, everyone should to make it fair." And that line of logic, in the case of the sneaking goblins, would mean that they're sneaking no longer. Is that a problem? Perhaps, if your game really depended on the idea of monsters sneaking up on players. But I insist it would be a bigger problem if there were players upon whom the monsters could not sneak, because that will affect the community instead of the gameplay, and that's a much bigger problem. Myself, I'm giving the Turbine developers the benefit of the doubt. They made Asheron's Call and Asheron's Call 2 (at least, I'm assuming some of the DDO developers were also developers on those projects), and thus have made some of the mistakes that the pioneers did. If not, then I will also assume that they've read the same materials I have, which expound on the problem of trusting the client at all, and thus I hope and believe that the DDO developers will not make this mistake.

Please, prove that one chatroomer wrong.