Complex event system for DungeonKeeper like game

Started by
3 comments, last by paul424 11 years, 10 months ago
I am working on opensource GPL3 game. http://opendungeons.sourceforge.net/ , new coders would be welcome. Now there's design question regarding Event System:
We want to improve the game logic, that is program a new event system. I will just repost what's settled up already on http://forum.freegam...php?f=45&t=3033. From the discussion came the idea of the Publisher / Subscriber pattern + "domains":
My current idea is to use the subscirbers / publishers model.
Its similar to Observable pattern, but instead one subscribes to Events types, not Object's Events.
For each Event would like to have both static and dynamic type. Static that is its's type would be resolved by belonging to the proper inherited class from Event. That is from Event we would have EventTile, EventCreature, EvenMapLoader, EventGameMap etc.
From that there are of course subtypes like EventCreature would be EventKobold, EventKnight, EventTentacle etc.
The listeners would collect the event from publishers, and send them subcribers , each of them would be a global singleton. The Listeners type hierachy would exactly mirror the type hierarchy of Events. In each constructor of Event type, the created instance would notify the proper listeners. That is when calling EventKnight the proper ctor would notify the Listeners : EventListener, CreatureLisener and KnightListener.
The default action for an listner would be to notify all subscribers, but there would be some exceptions , like EventAttack would notify AttackListener which would dispatch event by the dynamic part ( that is the Creature pointer or hash). Any comments ?


[source lang="cpp"] #include <vector>
class Subscriber;
class SubscriberAttack;

class Event{
private:
int foo;
int bar;


protected:
// static std::vector<Publisher*> publishersList;
static std::vector<Subscriber*> subscribersList;
static std::vector<Event*> eventQueue;
public:
Event(){
eventQueue.push_back(this);


}
static int subscribe(Subscriber* ss);
static int unsubscribe(Subscriber* ss);
//static int reg_publisher(Publisher* pp);
//static int unreg_publisher(Publisher* pp);



};

// class Publisher{
// };

class Subscriber{
public:
int (*newEvent) (Event* ee);
Subscriber( ){
Event::subscribe(this);

}
Subscriber( int (*fp) (Event* ee) ):newEvent(fp){
Subscriber();
}
~Subscriber(){
Event::unsubscribe(this);

}

};

class EventAttack: Event{
private:
int foo;
int bar;


protected:
// static std::vector<Publisher*> publishersList;
static std::vector<SubscriberAttack*> subscribersList;
static std::vector<EventAttack*> eventQueue;
public:
EventAttack(){
eventQueue.push_back(this);


}
static int subscribe(SubscriberAttack* ss);
static int unsubscribe(SubscriberAttack* ss);
//static int reg_publisher(Publisher* pp);
//static int unreg_publisher(Publisher* pp);



};

class AttackSubscriber :Subscriber{
public:
int (*newEvent) (EventAttack* ee);

AttackSubscriber( ){
EventAttack::subscribe(this);

}
AttackSubscriber( int (*fp) (EventAttack* ee) ):newEventAttack(fp){
AttackSubscriber();
}

~AttackSubscriber(){
EventAttack::unsubscribe(this);

}

};
[/source]
From that point, others wanted the Subject-Observer pattern, that is one would subscribe to all event types produced by particular object. That way it came out to add the domain system :




[indent=1]
Huh, to meet the ability to listen to particular game's object events, I though of introducing entity domains .



>>>>
Domains are trees, which nodes are labeled by unique names for each level. ( like the www addresses ). Each Entity wanting to participate in our event system ( that is be able to publish / produce events ) should at least now its domain name. That would end up in Player1/Room/Treasury/#24 or Player1/Creature/Kobold/#3 producing events.
The subscriber picks some part of a tree. For example by specifiing subtree with the root in one of the nodes like Player1/Room/* ,would subscribe us to all Players1's room's event, and Player1/Creature/Kobold/#3 would subscribe to Players' third kobold's event.
Does such event system make sense to you ? I have many implementation details to ask as well, but first let's start some general discussion.
<<<<

Note1: Notice that in the case of a fight between two creatues fight , the creature being attacked would have to throw an event, becuase it is HE/SHE/IT who have its domain address. So that would be BeingAttackedEvent() etc. I will edit that post if some other reflections on this would come out.
Note2: the existing class hierarchy might be used to get the domains addresses being build in constructor . In a ctor you would just add + ."className" to domain address. If you are in a class'es hierarchy leaf constructor one might use nextID , hash or any other charactteristic, just to make the addresses distinguishable .
Note3:subscribing to all entity's Events would require knowledge of all possible events produced by this entity . This could be done in one function call, but information on E produced would have to be handled for every Entity.
SmartNote4 : Finding proper subscribers in a tree would be easy. One would start in particular Leaf for example Player1/Creature/Kobold/#3 and go up one parent a time , notifiying each Subscriber in a Node ie. : Player1/Creature/Kobold/* , Player1/Creature/* , Player1/* etc, , up to a root that is /* .
Note5: The Event system was needed to have some way of incorporating Angelscript code into application. So the Event dispatcher was to be a gate to A-script functions. But it came out to this one.
Advertisement
0 views , 0 replies ? what's wrong with my post >_>
I'd argue that rather than considering any Singleton like approach, consider your Event objects as dynamic, which are allocated and deallocated depending upon game play needs. For example, the Event Subsystem itself is merely a mediator which acts as a conduit to transfer heterogenious data between stuff in your application. These events you allocate shouldn't be considered singletons as their lifetime doesn't conicide with the lifetime of the game itself. And just because you only want 1 of a particular object doesn't necessitate the need for singleton patterns either.

As for "Domains", I truly don't see the need for them as I feel it just over complicates what should be an efficient and easy "dispatcher" paradigm. if I want to subscribe to messages in player 1's room, its most likely because I joined his or her room to begin with. So why not have whatever mechanism creates Player 1's room to start simply allocate a Player1Room event handle. Every other subsequent join to the room would be given the same handle, allowing everyone to send/receive events without the need for some hierarchical approach.
Domains where to allow on listening for intresting events caused by particular entities' group of interest. A noble example : after a creature falls dead we might want our minions to take it to mortuary . That is I would like to listen to all DeathEvent in Player1/Creatures/Mortal/*. Opposite of this would be subscribing each new minion to all exisiting creature DeathEvent, and subscribe whenever there is a new "mortal" creature as well.
Domains are maybe not as nessecery for their own being, but better would be system of quantifiers of events , as much possible orthogonal , like "Creature" , "Attack" , "Death", "Dissappear " etc.

This topic is closed to new replies.

Advertisement