[MUD-Dev] Re: processors

Adam Wiggins adam at angel.com
Mon Feb 1 10:52:58 New Zealand Daylight Time 1999


On Sun, 31 Jan 1999, J C Lawrence wrote:
> diablo <diablo at best.com> wrote:
> > A 3 second task would take 20 seconds, but this only happened with a
> > heavy player load. Our tasks are held in a table indexed to some
> > number (some sort of ticker in linux? I don't know the proper names
> > for anything). That table is polled every time the game searches for
> > player input (it cycles through all our player lines constantly),
> > and if a task is found to be either overdue or ready to go off, it
> > goes off. 
> 
> Ouch.
> 
> Cheaper:
> 
>   1) Keep the table, but sort it by due time and pProcess the table
> only up to the first record that has a due date in the future.  You
> need to take care in your table and sort code to make it minimally
> expensive (choice of sorting algorithm), and in your storage format to
> ensure minimal traversal and ordering expense (no buffer copies, only
> pointer copies if possible).  

Standard event handlers.  I've written them at the start of so many projects
now I think I could do it blind, typing with my nose, and still finish
in less than 90 seconds.

In fact, here we go:

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;
};


This could, of course, easily be converted to C (I'd be happy to do so
if anyone desires, it'd take probably another 90 seconds).
Those into design patterns would probably also do the event manager as
a singleton (or perhaps have multiple event managers for different types
of events) rather than using all statics, but I wanted to keep the example
simple.


Adam W.






More information about the MUD-Dev mailing list