22 Jan, 2009, Grimble wrote in the 1st comment:
Votes: 0
Am looking for a little feedback on a piece of functionality…

I have filters that are attached to objects. The idea is that when something happens, it is passed through a stack of these filters for processing. It's similar to the Chain of Responsibility behavioral pattern, if you're familiar with that. Some use case examples follow…

1. A player picks up a treasure item. A (behavior) filter attached to a guard post-processes the action and sets the guard to attack.
2. A player takes damage in combat. A (protection) filter pre-processes the damage and halves it before it is applied to the health attribute.
3. A player attempts to exit north. A (confusion) filter pre-processes the command and replaces north with another random exit.

In terms of general requirements, the following appear to fall out of the use cases…

1. a trigger is a command action or an attribute update
2. a filter can pre or post process a trigger
3. a filter can pass (to the next filter), cancel, or modify a trigger

It's the first of these that I'm mainly looking for some feedback on. Specifically, what other potential types of triggers could be filtered?

-Grimble
22 Jan, 2009, quixadhal wrote in the 2nd comment:
Votes: 0
Depending on how general a system you're trying to make, I could see lots of events acting as triggers.

Recurring spell actions (DOT or HOT, most commonly) could be triggers for further processing – both in terms of filters (such as auras or spells to amplify or reduce damage, and in terms of procs to spawn additional effects or induce reactions in the environment.

For example. Let's say you are infected with a disease. The disease could be implemented as a DOT spell where you take damage and/or attribute reductions every tick. At the same time, each tick could also give a chance for contagion. If you were to implement it fully, you might have obvious symptoms be displayed as each tick happens (from sneezing, to doubling over in pain, to clouds of green fumes erupting from sores)… that means it could act as a behavioural trigger to NPC's around the infected victim. They might run in fear, guards might attempt to subdue or kill the plauge bringer, clerics might offer their services… you get the idea.

Likewise, a mob walking into the room could be a trigger. You might have a set of armor that increases in strength as the number of foes around you goes up.
22 Jan, 2009, Grimble wrote in the 3rd comment:
Votes: 0
quixadhal said:
Depending on how general a system you're trying to make, I could see lots of events acting as triggers.

Recurring spell actions (DOT or HOT, most commonly) could be triggers for further processing – both in terms of filters (such as auras or spells to amplify or reduce damage, and in terms of procs to spawn additional effects or induce reactions in the environment.

For example. Let's say you are infected with a disease. The disease could be implemented as a DOT spell where you take damage and/or attribute reductions every tick. At the same time, each tick could also give a chance for contagion. If you were to implement it fully, you might have obvious symptoms be displayed as each tick happens (from sneezing, to doubling over in pain, to clouds of green fumes erupting from sores)… that means it could act as a behavioural trigger to NPC's around the infected victim. They might run in fear, guards might attempt to subdue or kill the plauge bringer, clerics might offer their services… you get the idea.

Likewise, a mob walking into the room could be a trigger. You might have a set of armor that increases in strength as the number of foes around you goes up.


Yes, it's a generalized system.

Any healing/damage is a +/- modification to the health attribute. Similarly, strength/weakness spells are +/- modifications to the strength attribute, and restore/drain spells are +/- modifications to the mana attribute. So in this case, I had envisioned the attribute update trigger mentioned earlier (with attribute type and modifier properties, and the cause/source) that a filter can pass, cancel, or modify. Same goes for command actions. A mob walking into the room is the completion of a movement command, covered by a command action trigger (with command info properties) that is looking for exit commands. Each filter decides if it will process the trigger, and how.

One potential event not covered by either the attribute update or command action triggers is the death of a mob/player. It could possibly be covered by an attribute update trigger in that the filter could test to see if the modifier will take the health attribute to 0, but I'll need to think it through a bit more. Any other triggers come to mind?

The reaction to progressive disease is interesting. I'm not sure I'd want to attach a filter to every mob, looking for damage to another mob/player caused by disease. I have a mechanism for handling stateful effects (of which a filter can be derived from), and would probably have it force reactions by other mobs (under the right conditions).
22 Jan, 2009, quixadhal wrote in the 4th comment:
Votes: 0
I assume, then, that you treat state changes to attributes like health as messages? In order to distinguish the source of the change, and react with the appropriate set of filters? IE: ordinary healing from time passing might trigger hunger, but healing from a clerical spell might not.

The way you had phrased it, a "command action" sounds like a player command, and as a mud/D&D player I tend to automatically relate the term "attribute" with physical attributes such as strength, dexterity, etc. It sounds like you're referring to any function call that causes an in-game action, and any character property.

You could probably implement cursed items, aligned items, etc. via triggers on changes to the player inventory.
22 Jan, 2009, Scandum wrote in the 5th comment:
Votes: 0
Grimble said:
The reaction to progressive disease is interesting. I'm not sure I'd want to attach a filter to every mob, looking for damage to another mob/player caused by disease. I have a mechanism for handling stateful effects (of which a filter can be derived from), and would probably have it force reactions by other mobs (under the right conditions).

You could contain the program within the spell affect, though it'd make more sense to have the virus carried by a program on an ethereal object.

What I'm missing so far is a reference to variables. You'd want an elegant mechanism to store an interaction state on objects, mobs, players, and areas.
22 Jan, 2009, David Haley wrote in the 6th comment:
Votes: 0
I'm not sure what exactly the question is, since it looks like you could be talking about an extremely general action/effect/trigger type of system, or a rather limited set of reactions to very specific actions. It seems like you've covered everything, in some sense: you have triggers on actions, and on state changes. That is everything pretty much by definition. The question is whether or not you truly need that level of granularity, I suppose. Err, I guess what I'm trying to ask is: what exactly are you looking for feedback on? This whole issue is a pretty complex one…
22 Jan, 2009, Grimble wrote in the 7th comment:
Votes: 0
If you've played Guild Wars, the way the set of conditions on your character affect the final damage applied is a good example of what I'm after.

I'm taking a more generalized approach, where attribute updates (e.g., health, mana, strength, etc) is one class of triggers, and command actions (e.g., take, say, jump, etc) is another class of triggers. The filters that process these triggers are attached to objects as a result of a spell/skill, or inherent special behavior.

Likely, the attribute trigger will have something like { source, target, attribute, modifier } properties, and the command trigger will have something like { source, target, command } properties. A filter could change these properties as the trigger passes through.

In the use case examples I gave originally, the guard reacting to a taken treasure would be handled by a command action filter attached to the guard that looks for the "take" command executed against the "treasure" target, and sets the guard to attack the "source". Likewise, the damage getting halved by a protection spell would be handled by an attribute update filter attached to the player that looks for a "negative" modifier to the "health" attribute, and halves it.

I'm trying to determine if there are other classes of triggers beyond the two already mentioned.
22 Jan, 2009, David Haley wrote in the 8th comment:
Votes: 0
Ah, I think I see what you mean now (although I'm not familiar with Guild Wars). I think that there are several other things that could happen that are neither commands (strictly speaking) nor attribute modification. For instance, you might want to react to the time of day, or you could have repeated actions that aren't entered as commands, but perhaps you could model these as commands of some kind. Perhaps you plan on handling these in some other system.

I think you don't need to make the distinction you did between attributes and commands. Really, what you have is a set of events, and reactions to those events. When an event is raised, various people might react to it. For example, taking the treasure is an event, and guards look for events with category "object picked up" and the right target.

Once you model things as general events, you don't care at all about "classes of triggers" because you have a generic system for raising, modifying, processing and responding to events.

The problem gets pretty tricky pretty quickly, though… Let's go back to the guard example. Are you pre- or post-processing the action? I.e., is the guard preventing you from taking the treasure, or is the guard attacking you after you took it?

In the most general form, I think you have three kinds of events to raise for any action: the about-to-happen, the happening, and the after-it-happened. You could introduce "filters" (I'm not sure that's quite the right word but it'll do for now) at any of these points. For example, you could imagine trying to take something, and a filter would modify your action to cause you to instead take something else.

Anyhow, the event system is kind of nice IMO because it lets you treat everything the same way. In fact, if done carefully, absolutely everything could be an event, so you could react to an event by generating a new event that when processed causes something to happen. You could have the event of trying to move north, processed such that the character instead slips and a new event is generated to move the character west. Or, the event could go through normally, generating the event to move the character north. I.e., you have events that are triggers, causing other events that actually effect change and otherwise affect the world.

Sorry if the discourse is a little choppy, I'm just putting down thoughts as they come to me. The issue is a very complex one to me, and I might be generalizing further than you intended.
22 Jan, 2009, quixadhal wrote in the 9th comment:
Votes: 0
Grimble said:
In the use case examples I gave originally, the guard reacting to a taken treasure would be handled by a command action filter attached to the guard that looks for the "take" command executed against the "treasure" target, and sets the guard to attack the "source".


One issue that might come up here, is the fact that the complexity of the environment will have a huge impact on how much processing you're going to have to do for this.

In your guard example, if the trigger is not on the user's "take" command, but rather on the things which might respond to "take", it means every command will have to broadcast a message to every listening object that might be able to respond to that action. If you have 4 guards in the room, all 4 of them might be able to see the theft, and one would presume any of them would respond. At the same time, you might have other mobs on the street who could notice it and have different reactions – perhaps a member of the thieve's guild reports you for stealing off the clock, perhaps a citizen reports you to one of the guards, maybe a kid is impressed and starts following you.

Objects too. If the event were a magic missile, there could be a shield around the victim that would intercept it. There could also be anti-magic devices in the room which suppress it.

As David said, each event also has pre and post conditions to consider. If the anti-magic field in the room works, it would be a pre-filter to prevent you from casting the spell entirely. However, if you managed to cast despite it (saving throw, more powerful than the artifact, whatever), you could still have a post-filter for the target's shield spell.

I'm all for event-based systems, and message passing is a good solution for systems like this. I just forsee the complexity ramping up much faster than you probably expect it to.

If you're not planning on multi-threading, I would suggest a system we developed a few years back for a database driven web system, which used an event queue. In that case, events were placed on the queue and anything else could pull events from the queue if they deemed them interesting, process them, and (possibly) place them back on the queue for further processing.

It worked pretty well, but didn't scale easily because the queue proved to be a chokepoint with multiple processes, as they had to spend time waiting for locks to free up to access the job queue. In our case, we had a limited set of agent types, so we could have them grab chunks of jobs to lower that wait potential, but it still was an issue. If you're not multi-threading though, the issue won't show up since only one thing can interact with the queue at a time.
22 Jan, 2009, David Haley wrote in the 10th comment:
Votes: 0
It's possible to alleviate the broadcast problem to some extent by using a subscription based model. You know that you're only interested in such-and-such kind of event, so you subscribe to only that. Then, when an event is broadcast, you simply iterate over the list of interested people as opposed to the full list. Otherwise you get all kinds of very complicated scoping issues: do you stop at the room, the surrounding rooms, the whole area, etc.

As Quix said, this kind of system can have complexity ramp up extremely quickly.

Many years ago I started writing some of this up for the BabbleMUD project. The relevant section is "The Game Logic", specifically, "Message-driven Game". Please note that: (1) this was written about 5 years ago and I haven't updated it since, and so not only have my thoughts changed/developed since, but also I've learned much and might think some of it is wrong now; (2) although I have toy implementations of some of it, the ideas were never truly "field tested" on large universes with lots of things happening all over the world.
22 Jan, 2009, Grimble wrote in the 11th comment:
Votes: 0
There is a trigger/event/whatever base class, with the attribute/command/other variations inheriting from it since they have unique properties. With respect to filtering/processing these, I agree that it should be supported pro-actively (before) and re-actively (after). Not so sure about simultaneously as I haven't had a use case for that come up (yet).

I opted for a variation on the Chain of Responsibility approach over Publisher/Subscriber because I didn't want to deal with subscribing/unsubscribing based on objects entering/exiting the scope of the filter. Using the guard as the example again, the "take" trigger/event is generated by the player and it would be a pain to have the filter on the guard subscribe/unsubscribe for that on a player/mob each time one entered/exited the room.

I don't think the "broadcast" issue is a big deal in a typical MUD environment in that the number of filters within range of a given trigger/event is typically none to few. That is, a room with dozens of players, mobs, items, etc, each with numerous filters attached, is highly unlikely. And even if this did happen, I suspect it's still not going to be enough to load down a contemporary CPU.
22 Jan, 2009, David Haley wrote in the 12th comment:
Votes: 0
If you don't have any subscribing, then you have to broadcast everything to everybody who might possibly be interested. If an object can respond to things being picked up, then picking something up will mean sending the message to every single object in the room, etc. That will get very expensive very quickly.

Chain of responsibility is most appropriate when there actually is a chain to follow. What you're doing is a broadcast to all interested parties. If you don't have a list of interested parties, you need to broadcast to all potentially interested parties. The point isn't so much how many triggers are actually present, the point is how many entities there are that might have triggers to be examined.

Note that you can handle subscription intelligently and efficiently. You don't have to do anything to the guards when people enter or leave the room. Just have the guard subscribe to events of type X scoped in location Y. So, when the guard moves, you need to edit the subscriptions, but you don't need to react to every person entering and leaving.
22 Jan, 2009, Grimble wrote in the 13th comment:
Votes: 0
DavidHaley said:
Chain of responsibility is most appropriate when there actually is a chain to follow.

There is a chain. More accurately, there may be multiple chains. An object can have a chain of multiple filters, and each filter has the opportunity to pass the event/trigger to the next filter (modified or unmodified) or cancel/consume it. The broadcast comes into it because more than one object may have a filter that does something with the given event/trigger (e.g., several guards react to the same "take" command).

This (somewhat brute force) approach is simpler than managing subscriptions in a dynamic environment. Although there may be many objects in a room, few will have filters, and the expense should be on par with iterating over objects in a number of other situations (e.g., the "look" command).
22 Jan, 2009, Grimble wrote in the 14th comment:
Votes: 0
[edit] *sigh* hit back on the browser and then the wrong button - ignore this particular post please.

Grimble said:
DavidHaley said:
Chain of responsibility is most appropriate when there actually is a chain to follow.

There is a chain. More accurately, there may be multiple chains. An object can have a chain of multiple filters, and each filter has the opportunity to pass the event/trigger to the next filter (modified or unmodified) or cancel/consume it. The broadcast comes into it because more than one object may have a filter that does something with the given event/trigger (e.g., several guards react to the same "take" command).

This (somewhat brute force) approach is simpler than managing subscriptions in a dynamic environment. Although there may be many objects in a room, few will have filters, and the expense should be on par with iterating over objects in a number of other situations (e.g., the "look" command).
22 Jan, 2009, David Haley wrote in the 15th comment:
Votes: 0
Could you trace for me the exact process that occurs when the player picks up the treasure? Exactly how does the message get sent to the guard? I strongly suspect that unless you have some kind of registration, you have to visit every single object in the room that might be interested. You don't necessarily have to subscribe to a given event type – you could just register yourself as being interested in events in the first place, which would mean that you only have to iterate over those things with programs in the first place.

Yes, the expense is on par with any kind of iteration. But the problem is that if you have an event model that's firing off events left and right, it starts being very expensive, very quickly, to have to do the iteration over and over again. Note also that you have to iterate over potentially all characters in the room, each object in their inventory, and so forth. If you have effects that can be felt inter-room, you have to start iterating over all things in other rooms, too, which will be very expensive, very quickly.

Frankly, the subscription system I mentioned in the previous post is not that hard to manage. Define scopes for events, and then you register to a scope. Thus one entity subscribes to one or more scopes, instead of having to subscribe to individual objects.
22 Jan, 2009, David Haley wrote in the 16th comment:
Votes: 0
To expand upon what I said slightly, a simple full-broadcast model might work for small sets of events and potential interested parties, but the system will experience serious growing pains as you try to do more stuff. You have already stated, for example, that every attribute change (e.g. damage) will be an event that goes through this system. In combat, therefore, you'll be shooting off huge numbers of events just for the very basic logic of people whacking each other. It is likely that at some point you will want events to have effects on the surrounding rooms or even the area; suddenly you have to iterate over a great deal more things.

IMHO it might really be safer to go for a model that will reduce the number of events flying around, even if it takes a little bit longer to get started. (And really, the simple model I proposed is not that hard at all, and already slices the number of iterations you need to do very dramatically.) As you expand, you will almost certainly find that you need to do this eventually anyhow.
22 Jan, 2009, Grimble wrote in the 17th comment:
Votes: 0
DavidHaley said:
Could you trace for me the exact process that occurs when the player picks up the treasure? Exactly how does the message get sent to the guard? I strongly suspect that unless you have some kind of registration, you have to visit every single object in the room that might be interested. You don't necessarily have to subscribe to a given event type – you could just register yourself as being interested in events in the first place, which would mean that you only have to iterate over those things with programs in the first place.

Yes, the expense is on par with any kind of iteration. But the problem is that if you have an event model that's firing off events left and right, it starts being very expensive, very quickly, to have to do the iteration over and over again. Note also that you have to iterate over potentially all characters in the room, each object in their inventory, and so forth. If you have effects that can be felt inter-room, you have to start iterating over all things in other rooms, too, which will be very expensive, very quickly.

Frankly, the subscription system I mentioned in the previous post is not that hard to manage. Define scopes for events, and then you register to a scope. Thus one entity subscribes to one or more scopes, instead of having to subscribe to individual objects.

I'm not sure it should be the event that defines the scope, but rather the filter. I can envision filters attached to zone objects that process events occurring within (e.g., every 10th mob that's killed triggers a reward of some kind).

That's not to say some form of scoped subscription isn't still applicable, but it's not clear to me where the scoped subscriptions would be stored in order to realize an efficiency gain. If the scope of a given filter is the room, do the filters of objects (and potentially their child/inventory objects) in the room register against an event with the room object? If the scope is multi-room, do the subscriptions register against all those rooms? If the scope is the zone or world? Managing those subscriptions as objects with filters are created/deleted/moved doesn't seem very simple/efficient now, and when an event occurs there remains the work of checking for interested filters at each scope.
22 Jan, 2009, David Haley wrote in the 18th comment:
Votes: 0
Well, the point is that if you do things as you have proposed, you have to iterate over all possibly interested people. Since you have filters on zone objects, they need to be notified of everything that happens in the zone. The vast majority of those notifications will go ignored, but you still need to process them. Basically this is really not going to be workable if you have a non-trivial set of possible events and listeners.

As for scopes… Just create a scope object, and have events be sent to that scope. Entities register for events on a given scope. Events can be passed up the scope. Associate scope objects logically, for example have a room scope, contained by an area scope, contained by the world scope. (You could imagine having a scope for each entity inside the room, as well.) When an event hits a scope, iterate over all people registered for that scope.

Now your cost is proportional to the number of people actually listening, as opposed to the number of people potentially listening (which can be a very large number).

A guard character that cares about things being picked up in a given room would always register to the current room's event scope. When that guard changes rooms, the scope subscription has to be updated to point to the new room.

If you're not interested in any events, you simply don't register, and therefore you add no extra cost to the process.

You could further optimize by associating event types with a registration, and then index subscribers based on event type, so that a damage event won't iterate over people interested in objects being picked up. This is probably wasteful on local scopes, but could be very important on world-level scope depending on how many things are listening to how many event types.

Really, though, in the end of the day the point isn't so much if this is simple or not – the point is that the full broadcast solution will simply not be workable, and you'll need some kind of alternative. This scoping business is just an idea for an alternative that I haven't put much thought into, but it's already far more efficient in terms of necessary iterations than the full broadcast solution.
22 Jan, 2009, elanthis wrote in the 19th comment:
Votes: 0
I think you guys are WAY over-reacting to the burden that events and signals are going to incur here. Sure, there will be a lot of them. No, it isn't going to even noticeably lag down the server.

The only "optimization" I'd even begin to consider necessary here might be batching of property-change events, but only if multiple properties are changing simultaneously. If your combat system has only a single player health score then combat wouldn't benefit from this; if your combat system involves multiple hit-location damage tracking, armor damage tracking, magic shield levels, elemental resistance reduction, and so on (to the point where a single attack might cause half a dozen or more property modifications) then batching would be an improvement.

Efficiency also depends on how finely grained your events are going to be, and what kinds of events you're going to send out. A new player walks into a room: do you send just one EnterRoom event, or do you send a WalkEvent, an EnterRoom event, a BecameVisible event, and then multiple SawEntity events for each receiving mob? You can usually compose events together into larger events that convey a lot of information. For example, an EnterRoom event can include data on who entered, where he entered from, how he entered, and any visibility flags (did he sneak into the room, etc.), so that your receivers can much more efficiently filter out uninteresting events without having to repeatedly query the event subject.

I can't imagine a subscription model in a conventional MUD to be even remotely worth the implementation cost. Either an event dispatcher has to iterate over every entity in the room (and adjacent rooms at most) or it has to iterate over subscription filters (possibly stored in a hash/tree by event id) where the number of subscription filters active will often greatly outweigh the number of event receivers on account of most interesting receivers being interested in multiple event types.

My biggest suggeestion to you is to make a comprehensive event debugging facility. A builder should be able to see a log of every single event sent and received, including event properties and receiver actions. Without such a log or other way of seeing events it will be very difficult to debug the behavior of most interesting actors in the game world.
22 Jan, 2009, David Haley wrote in the 20th comment:
Votes: 0
Well, Grimble has already said that all attribute changes will be events. He's also said that it's possible for things to care about events in the whole zone, so no, it doesn't suffice to iterate over adjacent rooms at most. So, if you just do a full broadcast model, you will have to broadcast all attribute changes to all objects in the same zone. Even if you were a little clever and maintained a separate list of things that reacted to anything at all (and so didn't iterate over objects that will never react to an event) you have a large universe of potentially interested parties for a very large universe of events that will be fired very frequently.

You can compose events, but if you have pre-/post-processing, you can't compose those separate phases.

EDIT: I shudder to think what would happen if you cared about events in the whole world, not just the same zone…
Here's yet another problem: it was discussed that a spell that protected you could be implemented as an event filter that halved damage of the attribute change. Now, this spell has to receive every single health change event to determine if it should be modified unless you have some notion of event scope.
0.0/29