This is the raw code of my event implementation as used on Abandoned
Reality (http://www.abandoned.org). You will not (and should not!) cut
and paste any of this code, but rather use this as inspiration for
creating your own event queue system. It is important that such a vital
system as events is code you fully understand.

In the rest of this file you will find some mails I have sent to
various mailing lists describing this event code.

There are a few things that are a bit clumsily implemented -
especially, the etemp_XXX, emisc_XXX defines/string tables should be
unified using macros.

Here is the copy of a post I sent to the MUD Design mailing list
(http://www.toof.net/~spectrum). I'm sure I have written more mail about
this, but I cant find it right now :)


  From: Erwin S. Andreasen <erwin@andreasen.org>
  To  : Hein Zelle <hein@bambix.icce.rug.nl>
  Date: Sat, 10 May 1997 23:27:55 +0200 (MET DST)

                                Re: event list
                                       
On Sat, 10 May 1997, Hein Zelle wrote:

> ok, giving it a shot: i'm building an event list to try out if i can get that
> working. if it all turns out to work i will try and add as many of the update
> things in there to get rid of the 'synchronised' updates of diku (envy in thi
s
> case). problem arises:

Some implementation details of an event queue for my Envy2 based MUD:

There are 64 event lists, hashed via the time they go off in. The time
unit is 1 pulse (here, 1/8 of a second), so events that happen on pulse 1,
65 and 641 go in the same bucket. The lists are kept sorted, threaded via
a "next_global" pointer. Currently, there are about 250 events waiting; if
the number increases, perhaps it will be necessary to adjust the number of
buckets.

Each pulse, event_update() runs, which keeps removing the first evnet from
the appropriate list and executing it, as long as the event is due to
happen now.

There are several major types of events, and some subtypes to each of
those types.

Also, all of the events have an actor (object, room, area or character),
and an actor type. The actors are in a union, for easy acesss without
casting:

    union
    {
        OBJ_DATA        *obj;
        CHAR_DATA       *ch;
        ROOM_INDEX_DATA *room;
        AREA_DATA       *area;
        void            *typeless;
    } actor;

    unsigned int actor_type : 4;

The actor_type is a 4 bit bitfield to save some space, I know it could be
3, but I have bitspace left because of padding :) Each actor that can have
an event list too; the list of events on an actor is threaded via another
next pointer, next_local. I don't use just "next" as I initially confused
them, setting next when I meant next_global, with lots of disasters to
follow <G>

I've chosen to split up events in major types, and then group them, to
make saving things easier. There is the mobprog event, which is an event
settable by mob/room/obj/area/whatever progs. There is the misc event,
which covers other things. Both of these save to pfiles. There is the
temporary event, which can have a callback function set. That one does not
save. And, there is the action event, which I am still working on, which
will events for prolonged actions (e.g. casting a spell or picking a
lock).

The event data is in another union. Misc events hold 4 numbers and a
string. Mobprog events hold a string, and a mobprog vnum (these could be
chnaged into a misc event subtype). Temporary events hold the callback
function, and a void *data pointer, which is used for various things.

Back to executing events: after the event has been removed from the global
list and the local list of the actor, something happens. Temporary events
have their function called. Misc events can also have a callback function
attached, it's looked up in a table (and so each subtype can only have one
callback function attached) but it can be useful to have an event that
does not do anything when it goes off, but just is. Mobprog events call a
mobprog.

Saving/Loading: when a player saves, his events save with him. The time
left is saved. Whenever a pfile is loaded, the events are loaded, but are
only kept in the local list of player/object, not added to the global
list. When the player actually enters the game, the events are injected
into the global lists. Those events are marked as loading.

The events are only used in a limited number of places. I have replaced
the violence_update with a violence event. Whenever someone starts
fighting, a 2 second event is scheduled in the room. This event takes care
of let all people in the room fight/assist as needed. It saves
significant CPU time; going down from about 4 to 3% now that the MUD does
not have to ask every of the 5000 mobs in the game each 2 seconds if it
wants to fight or something :)

Object timers have also been replaced by events. This is a misc event,
saving with the object. With the decay time being fuzzies, and not in
whole ticks, you will not see 5 corpses mysteriously decaying at exactly
the same time :)

Other things: area resetting. Stun/paralysis. Timed messages (these use a
send_string event, which str_dups the string, puts the result in the
temp.data field

I plan to move healing to an event based system: a heal event would
restore 1 hp or more (set so that one does not trigger too often, but say
4-5 seconds). There are many places that need changes however, for this to
work, as you need to start scheduling heal events whenever hits of a
character may change.

Another thing you could use events for would be aggression, as before
suggested by Oliver: whenever moving a player into a room, schedule an
agression event for the room, which when going off, checks the room for
agressive mobs.

There's also a number of other stuff in xxx_update() that could be moved;
some of it is tougher than the other (the violence_update change was
probably the one that helped reduced CPU usage the most, and was fairly
easy).

Oh yeah ,the event callback functions are just void functions that take an
event type as argument; the event structure contains all they need to know
:)



==============================================================================
Erwin Andreasen Grenaa, Denmark <erwin@andreasen.org>    UNIX System Programmer
<URL:http://pip.dknet.dk/~pip1773/>                     (not speaking for) DDE
==============================================================================



     _________________________________________________________________
   
   Index: [thread] [date] [subject] [author]

