[MUD-Dev] Generic event handling

Adam Wiggins adam at angel.com
Fri Mar 5 11:55:56 New Zealand Daylight Time 1999


A little while back I posted some generic event-handling code in C++.
I got a request for a C version, so here it is.
All of this is completely untested, I just typed it in off the top of
my head, so there may be typos or other compile errors.

Here's the C++ code, as a reminder:

------------------------

typedef float Tick;

class Event
{
	friend class EventManager;

public:
	Event(Tick time)
	{
		RipenTime = EventManager::GetCurrentTime() + time;
		EventManager::AddEvent(this);
	}

	virtual void Ripen() = 0;

	bool RipensBefore(Event *e)	{ return (RipenTime < e->RipenTime); }
	bool RipensBy(Tick time)	{ return (RipenTime <= time); }
	
private:
	Tick RipenTime;			// time at which event ripens
	bool HasRipened;		// flag for deletion
	Event *Next;
};

class EventManager
{
public:	
	EventManager() { Events = NULL; GameTick = 0; }
	static void Update()
	{
		bool update = false;

		// Execute each event that is due to ripen
		Event *e;
		for (e = Events; e; e = e->Next)
		{
			if (e->RipensBy(GameTick))
			{
				e->Ripen();
				e->HasRipened = true;
				update = true;
			}
		}

		// Second pass, delete all ripened events
		if (update)
		{
			Event *next, *prev = NULL;
			for (e = Events; e; e = Next)
			{
				next = e->Next;

				if (!e->HasRipened)
					prev = e;
				else
				{
					if (prev)
						prev->Next = e->Next;
					else
						events = e->Next;

					delete e;
				}
			}
		}

		// Increment the game timer
		GameTick += TimeManager::GetTicksEllapsedLastUpdate();
	}

	static void AddEvent(Event *newEvent);
	{
		// Descend the list until a later event is found
		Event *e, *prev = NULL;
		for (e = events; e && e->RipensBefore(newEvent); e = e->Next)
			prev = e;

		// Insert the new event before that event
		newEvent->HasRipened = false;
		newEvent->Next = e;
		if (prev)
			prev->Next = newEvent;
		else
			Events = newEvent;
	}
	static Tick GetCurrentTime()		{ return GameTick; }

protected:
	static Event *Events;
	static Tick GameTick;
};

-----------------------------

Here's the C version:

------------------------

/* If you don't have bool in your C compiler use this */
typedef char bool;
#define true 1
#define false 0
/* end bool section */

typedef float Tick;

#define EVENT_ALPHA		0
#define EVENT_BETA		1
#define EVENT_GAMMA		2

#define NUM_EVENTS		(EVENT_GAMMA + 1)

type struct SEvent
{
	int Type;				/* EVENT_x */
	Tick RipenTime;			/* time at which event ripens */
	void *Data;				/* any extra data */
	bool HasRipened;		/* flag for deletion */
	struct SEvent *Next;
} Event;

typedef void (*EventCallback)(void *);

EventCallback EventAlpha;
EventCallback EventBeta;
EventCallback EventGamma;

EventCallback EventCallBacks[NUM_EVENTS] =
{ EventAlpha, EventBeta, EventGamma };

Event *EventList = NULL;
Tick GameTick = 0;

void AddEvent(int type, Tick time, void *data)
{
	/* Create the event */
	Event *newEvent = (struct Event *)malloc(sizeof(struct Event));
	newEvent->Type = type;
	newEvent->RipenTime = GameTick + time;
	newEvent->Data = data;

	/* Descend the list until a later event is found */
	Event *e, *prev = NULL;
	for (e = events; e && e->RipenTime < newEvent->RipenTime; e = e->Next)
		prev = e;

	// Insert the new event before that event
	newEvent->HasRipened = false;
	newEvent->Next = e;
	if (prev)
		prev->Next = newEvent;
	else
		Events = newEvent;
}

/* Call the function below during your update loop */
/* The parameter is how many game ticks have passed since the last update */
void EventUpdate(Tick ticks)
{
	GameTick += ticks;

	bool update = false;

	/* Execute each event that is due to ripen */
	Event *e;
	for (e = Events; e; e = e->Next)
	{
		if (e->RipenTime <= GameTick)
		{
			(*EventCallbacks[e->Type])(e->Data);
			e->HasRipened = true;
			update = true;
		}
	}

	/* Second pass, delete all ripened events */
	if (update)
	{
		Event *next, *prev = NULL;
		for (e = Events; e; e = Next)
		{
			next = e->Next;

			if (!e->HasRipened)
				prev = e;
			else
			{
				if (prev)
					prev->Next = e->Next;
				else
					events = e->Next;

				delete e;
			}
		}
	}
}

-----------------------------

One thing is that this uses event "types", which are probably going to be
handy on a MUD where you're calling the same sort of event all the time.
You could easily get rid of all the type stuff and just pass the callback
function directly if you wanted to make it even more generic.
You could even mix the two (that is, store the callback pointer on the
event structure, but have a special add function that takes a type and
just looks up the callback right then and there and stores it on the event).

Adam W.




_______________________________________________
MUD-Dev maillist  -  MUD-Dev at kanga.nu
http://www.kanga.nu/lists/listinfo/mud-dev




More information about the MUD-Dev mailing list