1.1 Name: Events Explained
1.2 Author: Brian Jones brianj@otterspace.com
1.3 Purpose: describe the concept of events in detail.
1.4 Creation: April 22, 2004
1.5 CVS $Id: events_explained.html,v 1.1 2004/06/24 21:22:47 brianj Exp $
1.6 Change history
1.1 series of email messages between Brian Jones and D.Midgley on April 22, 2004
1.2 See the Core Concepts document for definition of terms used.
1.3 Logs from discussion with Jon Smith on Nameless MUCK on April 22, 2004
This document describes the mechanism for events in the NMC2 system.
Specifically, this describes how events are created, delivered, dispatched, and listened for and responded to in the context of what the Core does and how a user can extend these abilities within a running game.
This example is from D. Midgley's email, with no modifications other than wrapping in conversion to HTML..
But...let's create an example of this. To see how far we can take it. I have just come up with a sample 'event' I wish to be able to add to my NMC2 server - neat, huh? I will be called the 'storming' event. I have decided that there will be a special sort of "room" object on my game. It will be a copy of the typical NMC1 object - but with a few mods. It will be called "Gateway". For one, it will have the normal _arrive events etc., but it will also have a "storm" event. We can call it "_storm" if it makes you happier :) It certainly looks better.
Typically in my game as it stands now, to achieve this I would write MUF within the code that handles 'exits' in the MUD - either that, or I would create a global _arrive that launches code which will continue to run only if the situation is suitable. The latter is wasteful, and the former is a little inelegant.
Now, the _storm event is an event that alerts (sends a message to) a character or program if other characters or MOBs are deemed to be 'storming' a high-security area. So, there will be the "Gateway" room, with a "_storm" event on it. The "_storm" event runs whenever three or more characters enter a "Gateway"-type room within the space of 2.5 seconds. It is a security measure designed to alert forces that someone may be attacking a high-value building. The _storm event will only run if the characters are entering through an exit that is not deemed 'risk-free' according to - well, according to what, I don't know. "Props" on the Gateway room? Or on the exits? Or on the event? And if the exits are "re-linked", you know, the props relating to that particular _storm event shouldn't affect them any more, and perhaps should even be removed. Also, if the builder chooses to send a program a message, obviously the program should be able to interpret any templated event variables (a 'names' array of storming characters/MOBs, the gateway room, etc) and then run user-built code. If the event is set to notify a character or characters, it should be able to handle another names array - of characters to notify. It should _also_ be able to call other code to get their names if that's required.
This is a nice, complicated, real-game example of a use for events and room-types and exit-types, as well as program interaction. Not to mention timing! (did you spot how I slid that one in there? ;) I would like to know what the current thinking is on how the server would provide for a game owner who wanted to implement that. Obviously, it could currently be done in NMC1 with a bunch of hacks, but we are talking super-smooth, in-server, fast prepared code for as much as possible here, after all.
The example challenge is an excellent one. It is realistic, would have nice effects, is easily tested, and crosses a variety of issues.
My response in the email isn't going to be quoted, but rather is the basis for the expanded text that follows.
First. the context of the problem.
A room exists that acts as a guard-room or containment area for outsiders to enter a protected location. This room thus has many doors. Some lead to the inner areas, and anyone who exits from those doors is harmless, because they're "insiders." When people come from outside who aren't people we know to be safe, a few at a time, it's harmless. but if a LOT of people come in a very short time period, it could easily be an attempt to storm the castle. What's desired then is a way for the people in the castle to be notified when a possible storming situation is at hand.
To recognize this situation, we want to do as little work as possible.
An easy approach to recognizing when people arrive is to monitor the arrival events. But not all arrival events; just those arrival events that come from doors leading outside. Thus, we task an object with listening to arrival events and filtering out all arrivals from the internal secure area. Note that we chose to remove the safe entries both people we know and people from the inside rooms, not look only for the dangerous ones. If somehow the bad-guys learn to teleport, they would appear in the room, triggering an arrive, but they wouldn't have used the outside door. We still want to notice them!
So, our listening object (let's call him a guardian) is receiving the arrival messages for that important room. Each arrival event that isn't from the inside is added to a list. Since the event includes a timestamp of when the event happened, this list can be read in order of times. If the configuration says "three or more in a 2.5 second period" then the third entry (third most recent) is grabbed. If it's timestamp is within 2.5 seconds of the top-most entry, then we have recognized the "storming" situation. As a side-note, any event in the list over 2.5 seconds from the top can be discarded.
When the guardian realizes that the castle might be being stormed, he creates an object and sets the properties that make it a valid event object (whatever those might be). He adds the properties that indicate what room he's in and that its storming as well. He invents properties and adds them to the object. Notice he doesn't have to make a new "class" or anything, just add more data to make the event hold the additional detail that storming requires. There's no reasonable limit to the amount of details that can be added to an object.
Now, the guardian hands this object to the Core's event handling machinery (how this happens is magic at this point). The event system will deliver this event object to every object that has requested notification. Just as the guardian requested notifications of arrivals, other objects would have to have requested notification of storming events. Perhaps an object called the "Alarm Bell" is setup as a listener for storming events. When this event is received by the core, it sends it off to the Alarm Bell. The alarm bell's event handler then causes the Bell to start generating "ringing sound" events.
Notice that no changes to the core were needed. There needs to be some language to write the steps described, but that code could be any language supported, including MPI internal scripting. This does not need to be done by "skilled developers" in Java.
Furthermore, if events are always described in an object delivered to the event system then any events with no listeners would die in the core without any further processing.
We have the ability to filter on events, also. Perhaps the Alarm Bell responds to any event generated by a guardian. So any guardian, not just the one in the entry hall, who generates an event causes the bell to ring.
There was no knowledge by the event generator of who would respond to the event. This is a very important fact! It means that there is a separation between the generator of an event and the recipient. The only thing they have in common is that an object created by one is delivered to the other. There is absolutely no reason nor benefit in the sender knowing the receiver.
The object that is delivered is a normal object. It can be stored, such as the list used by the guardian. It can be passed into the event system again (propagation), it could simply be ignored.
The event system passes a copy of the object to each event listener, so the object can even be modified after received. It could be modified and re-dispatched propagating a modified object.
The proposed solution seems to meet the goals with a minimum amount of work on the part of the person seeking to create a brand new event and use it.
Almost everything that happens in VR causes or is caused by events. When a player uses a command to control a character, the result normally causes one or more events.
For instance, the basic "say Hello" command causes the creation of an object which is setup to be a VR Message. This object is delivered to the event-handling machinery in the core. The core then notifies all the listeners (which would likely be the place in which the character speaks, and possibly the parents of that place to give a message the range). This ends up being delivered to the characters in the room that would hear it.
It could also be delivered to a radio channel if the room is broadcasting. It could be delivered to a web-logging facility that is tracking RP. It could be sent to the owner of the room if they like to spy.
The beauty of the massively event-driven nature of the core is that it doesn't matter to the sender who or what processes the events, if anything. Once the event is delivered to the core, the work for the sender is complete. Many commands in NMC1 do nothing more than generate events, including:
Many other commands cause events as a side-effect. When a character moves from one place to another, the movement causes departure events in the old place, and arrival events in the new. When a character picks something up ("get sword" in NMC1 terms) there is a depart message to the old place, and an arrive message to the new place.
The messages that are typically described in NMC1 (such as "@succ" and "@osucc") are also messages generated as a side-effect of change of location.
To change the event-model of the system then involves updating the code in the commands that do nothing more than generate events. It may also involve updating the events the VR persistence model manages, such as change of location. These need to be rules in the system instead of coded in Java. And it may also involve the creation of new events or even the deletion of events.
None of these changes should need any Java code to be changed in the core whatsoever.
The event model is thus extensible and dynamic.