Sign in to follow this  

Event Handlers!? ARGLEARGLEARGLE

This topic is 4395 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm coding a MUD In PHP And I've built enough helper functions to truly give me the flexible design tools I need to accomplish the task, from referenced cell search returns to a dynamic object container that saves its own data to a file automatically... everything is going smooth! The entire package so far is 90k in solid, well-documented, modular code. But data flow is killing me... - A SOCKET is socket/server data about the actual connection. A connection holds the sock_id, the IP, the input buffer, a temporary cache, and the account id it is logged in on. - A PLAYER is human data about the CONNECTION as well as a list of characters the CONNECTION has at his disposal. - A CHARACTER is server data about the virtual character within the game.
Game Loop Core
{
	Update gametime
	(CHECK) Socket Activity
	{
		(CHECK) Activity on listening port
		{
			Create a new connection and set’s state to new_user
			Show menu;
		}
		Else activity is from an established socket
		{
			(CHECK) To see if not link dead
			{
				(CHECK) Activity for return carriage:
					Parse input;
					Appent input to the Event List;
			}
			Else player is link dead
			{
				Remove connection;
			}
		}
	}
	(CHECK) AI Activity
	{
		Add weather, map, monster, and other automated activity to 
		the Event List.
	}
	Run Event Handler;
}
The EVENT LIST contains a massive array of all changes that have taken place since the last game loop. The EVENT HANDLER navigates the event list and determines how and what events are executed. All events are timestamped in gametime for when they are to be processed. Player inputs are timestamped at 0 for immediate execution.
Event Handler
{
	(CHECK) Events that have already expired
	{
		(CHECK) Player Event
		{
			Based on connection status, send the player to the appropriate area.
			If the player is currently playing: Execute Event; 
		}
		Else it is a different kind of event (combat, item, spell, etc.)
		{
			And do it!;
		}
	}
}

A problem I just realized is that since my event handler is using timestamps... I've hit what appears to be equivilent to red/blueshifting. When the game loop runs, it checks to see what tick the game is at. (I've set it to 1 tick being equal to three seconds, but this can be changed.) The game loops once and it updates the time at 1 tick... it runs though 1000 playerss input and 10000000 AI event appending and then proceeds to check to see what events are executed based on the clock. Now given that when the timer was updated way before the original loops, the real-time has progressed significantly at this point. When I run the game loop again, I appear to hit a situation where upon calculation, it is possible for the tick sequence to skip numbers. One solution is to not base it off the timer, but the actual loop itself. I disagree with this because the faster yoru CPU is, the faster the game loop will go, and thus, the entire game will move at a ridiculous pace. MY question is: is the tick skipping detrimental to an event handler that triggers based on tick-count? Events only are executed when its timestamp is less then the current tick. This would mean I need some sort of compensator to determine event priority then, correct?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
What is the problem? What is a tick? What is the problem with skipping ticks?

Why not make the event list a priority queue so that you can easily look at earlier events before later events?

Share this post


Link to post
Share on other sites
If your "current time" tick count > any event timestamp, run the event. However, run the events with lowest timestamp first, and run events with the same timestamp in order of insertion into your event list. So it's just like the AP said - you need a priority queue instead of a simple list.

Share this post


Link to post
Share on other sites
That is basically what this is. A priority queue.

However, there are events that occur that are outside of the instant realm. Say, doing a skill, casting a spell, etc. I need these events to go off at specific times, not as soon as all the other events above them have gone off.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
It is entirely unclear that a problem even exists. If all the events have a timestamp for when they are supposed to occur, they are placed in a priority queue, and events are dequeued and executed up until an event is found that is not supposed to occur yet, then where is the problem?

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
It is entirely unclear that a problem even exists. If all the events have a timestamp for when they are supposed to occur, they are placed in a priority queue, and events are dequeued and executed up until an event is found that is not supposed to occur yet, then where is the problem?


That's what I wanna know. :O

3000 Events goes of at tick 8
120 Events goes of at tick 9
1000 Events goes of at tick 10

It is now tick 8 and the tick is still at 8. When the events have been done, the tick is now at 10. So in theory, events at tick 9 would go first, then events at tick 10. Doesn't this keep my tick timer significantly trailing behind the real-time?

Share this post


Link to post
Share on other sites
Why are you defining events in real-time? Because you can't guarantee it, as you've discovered.

So would there be a problem if you only constrained a minimum time for the loop to run? ie. a tick would happen after each game loop, and if the loop takes under 2 seconds, then you pad it out to 2 seconds. EDIT: And if it takes more than 2 seconds, then the tick just turns over when the loop ends.

There should be no time-critical events in your game engine, especially in a MUD. If my computer isn't fast enough to run an RTS game, the game just slows down - its internal state doesn't go barmy. It should not be any different for your game.

Share this post


Link to post
Share on other sites
Quote:
Original post by Argus2
Why are you defining events in real-time? Because you can't guarantee it, as you've discovered.

So would there be a problem if you only constrained a minimum time for the loop to run? ie. a tick would happen after each game loop, and if the loop takes under 2 seconds, then you pad it out to 2 seconds. EDIT: And if it takes more than 2 seconds, then the tick just turns over when the loop ends.

There should be no time-critical events in your game engine, especially in a MUD. If my computer isn't fast enough to run an RTS game, the game just slows down - its internal state doesn't go barmy. It should not be any different for your game.


hmmmmm lets see if i got this correct

- game loop goes and is 1.5 seconds long
- at end of loop, tick doesn't go, needs an extra .5 seconds? or just round up to let the tick happen?
- game loop goes and is 3 seconds long
- at end of loop, only one tick goes?

I dont uderstand what you mean by 'pad it out' or 'turns over'

Share this post


Link to post
Share on other sites
I mean that it shouldn't really matter how long the tick takes. Why synchronise ticks with real time?

So you could just tick over only after a game loop, no matter how long it takes. But you might not want it ticking over too fast, so you might have a minimum time for a tick, and if the loop finishes in less than that, then you 'sleep' the thread until the minimum time is up.

Share this post


Link to post
Share on other sites
Quote:
Original post by Argus2
I mean that it shouldn't really matter how long the tick takes. Why synchronise ticks with real time?

So you could just tick over only after a game loop, no matter how long it takes. But you might not want it ticking over too fast, so you might have a minimum time for a tick, and if the loop finishes in less than that, then you 'sleep' the thread until the minimum time is up.


Running tick based on the game loop causes a problem when running this application of different boxes because on a very decked out box... the game will run FASTER. And be faster I don't mean better, I mean literally sped-up.

Sleep adds an unnessecary delay in which other computations could have taken place.

Share this post


Link to post
Share on other sites
Quote:
Sleep adds an unnessecary delay in which other computations could have taken place.

1. The delay is necessary, because by your own admission, you don't want the game to run too fast.
2. Sleep simply means that the current thread becomes unrunnable for a certain period of time - you are welcome to have computations running in other threads in the interim.

If you're determined not to believe in a solution, then don't ask for help.

Share this post


Link to post
Share on other sites
Quote:
Original post by Argus2
Quote:
Sleep adds an unnessecary delay in which other computations could have taken place.

1. The delay is necessary, because by your own admission, you don't want the game to run too fast.
2. Sleep simply means that the current thread becomes unrunnable for a certain period of time - you are welcome to have computations running in other threads in the interim.

If you're determined not to believe in a solution, then don't ask for help.


I'm sorry... threads? My understanding of programming is that there is no such thing as paralell processing.

The delay may or may not be nessecary.. and sometimes the opposite will be needed... due to limitations of... say.. quantum mechanics, there is no such thing as a SpeedUp() function. The solution needs to be dynamic and adaptable to the situation.

Share this post


Link to post
Share on other sites
Quote:
Original post by ghetalion
I'm sorry... threads? My understanding of programming is that there is no such thing as paralell processing.

The delay may or may not be nessecary.. and sometimes the opposite will be needed... due to limitations of... say.. quantum mechanics, there is no such thing as a SpeedUp() function. The solution needs to be dynamic and adaptable to the situation.


Well, your understanding of programming is flawed by not having an idea of threading, but I won't go there since PHP doesn't really have a facility for threading... yet.

Meanwhile, the sleep is nessicary if you want to sync the Event Hander's loop to realtime. You don't have anything more to process, so let the loop idle for however much time adds up to the three seconds that the Event Handler's supposed to activate on anyways.

Your "Blueshifting/Redshifting" problem is caused by the event loop's intervals terminating too early or too late; if you want it to happen every 3 seconds, you must have a way of telling the computer to stop after 3 seconds, and you must have a way of telling the computer how to cope with extra time. This is where sleep and a good timing function come in. Sleep() when you have extra time, peek on the timer before doing anything you know takes a bit of time, if there's even a question that the event will put you over-time on your processing budget, simply delay processing the event until the next clock interval and sleep away the rest of the time. (keep in mind that peeking on the timer will also cost you time, so you shouldn't simply do it before every single function call, just the ones you know are slow such as a database query or an image blitting function).

--- top of event handler's inner loop ---
if (($preEventTime + 3) > getTime()) {
//go ahead and keep the loop running, we still have time.

if ((getTime() + .5) >= $preEventTime)
{
//skip processing this event, it's simply going to take too long
// EDIT: If you're using a priority queue, instead of continuing the loop,
// break here instead, and Sleep() the rest of the time until the 3 seconds
// are up. How do you know if this is ineffecient? Well, if you're spending
// more than half of your time asleep, you know something's wrong.
// Perhaps your event simply can't be processed in a timely manner (3 secs)?
continue; //move on to the next event in the loop
} else {
doSlowQuery();
}

} else {
//log the fact that you've spent too much time
$log .= "too little time\n";
//break out of the inner loop
break (2);
}
--- bottom of event handler's inner loop ---
Believe it or not, even big fancy games coded by game studios will use this to get around timing issues. If you want something to work in real time, you have to cope with the computer's abilities. Someone with a really fast computer's going to be able to process events much, much quicker than my 486 in the closet. Sleep() may be "wasting", but it allows for events to occur at the same time on both the ultra new machine, and the 486.

So really, just add the sleep and peek on the timer when you need to. It's the fix to the problem you're having, even if you don't understand why its neccesary now. Continuing to argue that you don't want to do it is only going to drive people on this site crazy (like the guy who couldn't figure out asin() is always going to be faster and more bugfree than his own implementation). Believe it or not, Sleep() is effecient programming if you want to do something in a timely manner, and its the reason modern processors have the nop ability. Think about it; if everything could run sychronous to realtime and not use sleep, who would? Why would the facility be left in the language?

[Edited by - ciroknight on January 2, 2006 6:34:20 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by ciroknight
Quote:
Original post by ghetalion
I'm sorry... threads? My understanding of programming is that there is no such thing as paralell processing.

The delay may or may not be nessecary.. and sometimes the opposite will be needed... due to limitations of... say.. quantum mechanics, there is no such thing as a SpeedUp() function. The solution needs to be dynamic and adaptable to the situation.


Well, your understanding of programming is flawed by not having an idea of threading, but I won't go there since PHP doesn't really have a facility for threading... yet.

Meanwhile, the sleep is nessicary if you want to sync the Event Hander's loop to realtime. You don't have anything more to process, so let the loop idle for however much time adds up to the three seconds that the Event Handler's supposed to activate on anyways.

Your "Blueshifting/Redshifting" problem is caused by the event loop's intervals terminating too early or too late; if you want it to happen every 3 seconds, you must have a way of telling the computer to stop after 3 seconds, and you must have a way of telling the computer how to cope with extra time. This is where sleep and a good timing function come in. Sleep() when you have extra time, peek on the timer before doing anything you know takes a bit of time, if there's even a question that the event will put you over-time on your processing budget, simply delay processing the event until the next clock interval and sleep away the rest of the time. (keep in mind that peeking on the timer will also cost you time, so you shouldn't simply do it before every single function call, just the ones you know are slow such as a database query or an image blitting function).

--- top of event handler's inner loop ---
if (($preEventTime + 3) > getTime()) {
//go ahead and keep the loop running, we still have time.

if ((getTime() + .5) >= $preEventTime)
{
//skip processing this event, it's simply going to take too long
// EDIT: If you're using a priority queue, instead of continuing the loop,
// break here instead, and Sleep() the rest of the time until the 3 seconds
// are up. How do you know if this is ineffecient? Well, if you're spending
// more than half of your time asleep, you know something's wrong.
// Perhaps your event simply can't be processed in a timely manner (3 secs)?
continue; //move on to the next event in the loop
} else {
doSlowQuery();
}

} else {
//log the fact that you've spent too much time
$log .= "too little time\n";
//break out of the inner loop
break (2);
}
--- bottom of event handler's inner loop ---
Believe it or not, even big fancy games coded by game studios will use this to get around timing issues. If you want something to work in real time, you have to cope with the computer's abilities. Someone with a really fast computer's going to be able to process events much, much quicker than my 486 in the closet. Sleep() may be "wasting", but it allows for events to occur at the same time on both the ultra new machine, and the 486.

So really, just add the sleep and peek on the timer when you need to. It's the fix to the problem you're having, even if you don't understand why its neccesary now. Continuing to argue that you don't want to do it is only going to drive people on this site crazy (like the guy who couldn't figure out asin() is always going to be faster and more bugfree than his own implementation). Believe it or not, Sleep() is effecient programming if you want to do something in a timely manner, and its the reason modern processors have the nop ability. Think about it; if everything could run sychronous to realtime and not use sleep, who would? Why would the facility be left in the language?


I understand your analysis. I'm not saying it doesn't make sense.

I'm just kinda weirded out by the entire concept of forcefully cutting into cycles to regulate timing.

But by dividing the sleep into fractions and checking them... this is a good idea.

Thanks for the detailed insight. :D

Share this post


Link to post
Share on other sites

This topic is 4395 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this