How to stop an HookTimer() ? :/
Displaying 1-16 of 16 total.
1
Please enter a numerical value for the importance of this sticky.
Enter 0 to unsticky.
ErayMan

Okay, this is very simple but confuses me.
Let's say I warp in a map and I want to set the volume gradually from 0 to 100 in 1 second.

I don't want to make a loop with showpage and render; I want to be able to do other things at the same time.
So I make a function:
void turnMusicOn()
{
   if (GetSongVolume() < 100)
   {
      SetSongVolume(GetSongVolume() + 1);
   }
}

Then:
HookTimer("turnMusicOn");


So far so good.
Now when the volume gets to 100, I want to stop hook timer, so:
void turnMusicOn()
{
   if (GetSongVolume() < 100)
   {
      SetSongVolume(GetSongVolume() + 1);
   }
   else
   {
      HookTimer("");
   }
}


But that crashes the game. I believe this is because you cannot delete the HookTimer from inside itself?

Then how do I know that it has finished outside of the function so that I can delete it from the maps .vc code?
Or do I use a HookRetrace? ;)

If I leave it there, each time I lower the volume manually it will get back up right away.

Thanks!
Eric

Posted on 2011-01-12 16:41:20

resident

Don't use a void? Make the function an int and return the current volume into a global variable. Then you can disable the timer safely from inside the main program based on the content of the global variable is zero?

This is probably inelegant though - I'm sure someone will be along with a much better suggestion shortly.

Posted on 2011-01-12 16:57:11 (last edited on 2011-01-12 16:59:16)

ErayMan

But that would force me to make a loop in the main program and wait until it finishes instead of letting it finish on its own :/

Posted on 2011-01-12 17:05:30

resident

Oh, fair point. I tended to just take over the entire render loop in Verge C, then I could just check stuff like this every time around in the loop, but you've expressed an interest in not doing that.

Posted on 2011-01-12 17:44:06

mcgrue

(Man, I really need to improve how code renders on this site...)

Posted on 2011-01-12 17:57:36

resident

I'm trying to remember what the hell it was I did in 100 zombies. sound and music fading wasn't a huge priority for me, but I'm pretty sure you could create a custom loop that you could use to control sound volume without needing to pause the engine.

IIRC, when you use Render, the entire engine state updates, so the game shouldn't pause at all, even if you have a loop, because every time the engine passes round the loop, the engine does all the stuff it was going to do anyway.

I'm not sure what "other" things you want to do that makes that impractical.

Posted on 2011-01-12 18:26:48 (last edited on 2011-01-12 18:37:21)

Overkill

If I can say something, it will be that you shouldn't use HookTimer.

Why? Basically, the engine runs in one thread, and HookTimer runs in another thread. The HookTimer thread calls a function in the interpreter, and meanwhile, the engine itself (and your regular VC/Lua code) can also be trying to use the interpreter. It's basically a giant race condition waiting to happen, and it's a miracle that it even works some of the time.

Don't think of this race condition as just being the code you see in your main system code and in your HookTimer as being run at the same time. Look at this as the C++ code implementing the global interpreter for VC or Lua is being run in two threads at once, and the execution is being interleaved unpredictably. And of course, there is still also a giant potential resource contention for VC variables themselves, and for any global built-ins inside the engine. There are a million ways this can blow up or give invalid results.

If you must have a time-sensitive event trigger, what you should do instead, is add a retrace layer, and use HookRetrace. Use the systemtime variable to check the timer yourself.

Eventually, I may end up fixing HookTimer to be like HookRetrace, in that it's run on render, but no requirement on there being a layer, and the hook will be called as many times as frames were missed. Effectively giving around 100 updates per second still, just now without the ability for things to crash.

But until then, use HookRetrace or your own game loop, and use the timer variables. HookTimer is baaaad.

Posted on 2011-01-12 22:05:56 (last edited on 2011-01-12 23:24:27)

resident

How's Hookbutton? safe?

Posted on 2011-01-13 06:10:21 (last edited on 2011-01-13 06:11:43)

Overkill

Yep, the rest of the hook functions are okay. HookTimer's the only one you have to really watch out for.

Posted on 2011-01-13 08:09:37

ErayMan

Thanks for your help! :)

One solution is to put everything in HookRetrace()... will I be able to stop it from inside itself calling HookRetrace(""); or will I have the same problem that I have with HookTimer? :)

In any case, my SetSongVolume example above was only a simplified way of telling what my problem is, not the actual situation.

I think I need to be more specific if I want to clear any doubts I have.
(Sorry if I seem to be repeating what was already said)

I'll tell the What I did and then Why, maybe you'll be able to help me in my ignorance :)

What:
I had my whole battle engine in one big loop, with a check that would only calculate and/or draw each 1/100 seconds.

I decided to split my calculations and other stuff that needs updating every 1/100 s. and the actual rendering based on thoses calculations.

So, smart me, I decided to put:
Everything that depends on timing in "HookTimer()"
Everything that needs to be drawn in "HookRetrace()"

And I do nothing else outside of these. I just wait for HookTimer to detect it has finished and then warp to another map.

It works great, the problem being that once inside HookTimer(), I realize that every monster is dead and want to quit, there's no way inside it to stop hookTimer, exept calling HookTimer(""); in HookRetrace. But then how will I stop HookRetrace? :P

Why I did that:
1. It seemed futile to do checks to ensure that it runs no more than 100 every second, if a function (hooktimer) was made specifically for it.
2. Splitting the rendering and the calculations is always a good idea
3. The most Important: I had terrible performance while having a giant loop. I thought that the fact that between every 1/100s it was constantly checking if 1/100s had passed was CPU intensive and was probably hitting performance, and that using HookTimer() would help ease the burden on the computer.

Sooo!
Your advices would be to make a giant loop in a function and place a check for every 1/100s, while still using HookRetrace() for rendering?
And if I have performance issues (on mid-end computers) it's probably due to other factors than the fact that it's a loop instead of HookTimer?


Eric

Posted on 2011-01-14 12:07:46

resident

Checking that 1/100s has passed isn't terribly intensive. it's a quick variable comparison. If it hasn't, you won't be doing anything else during that pass of the loop, so it'll go very quickly.

If it has passed, then your normal loop code will execute.

Posted on 2011-01-14 15:10:54

ErayMan

It's not the check itself that worries me, it's the fact that the computer can do hundreds or more checks before 1/100th of a second has passed.
The fastest the computer is, the more checks it'll do each time.

Juste being idle in my combat system my Dual Core 3800+ goes crazy with 100% CPU on both core.
It just seems... unnecessary :/

Eric

Posted on 2011-01-14 15:22:07

Kildorf

Whoa, both cores? Verge should only ever tie up one whole core (and it basically does all the time, since it runs as fast as it possibly can).

Really, V3 could probably benefit greatly from someone taking a look at this and figuring out how to make it play more nicely with multi-tasking. Anyone a bad enough dude to want to do this?

Posted on 2011-01-14 15:29:39

mcgrue

I think that's the wrong solution.

I think the right solution is to have everything be synchronous.

Posted on 2011-01-14 16:07:12

Overkill

I've already explained why HookTimer is a bad idea, and no other hooks have these problems. It is perfectly safe to unhook a retrace event from within the retrace event. And if you are mixing rendering and timing in a single retrace loop, you can do several things to toggle updates.

You could use a simple variable that toggles updates or you could use a string that points to the event to update, and call the event.

Verge shouldn't be using more than one core, and isn't on my Intel i5 750 quad core. If you're worried about CPU usage, basically check if any time has passed from the current frame. Otherwise sleep for a short interval using Sleep(), which will essentially yield the game's process to other processes running on your OS for at least the amount of time specified.

An example:
int lastFrame = 0;
int updateEnabled = 0;
void Retrace()
{
    int i, t;
    // ...
    // If we should update, then do some sort of processing.
    if(updateEnabled)
    {
        // Catch up on any time missed since the last updated frame.
        if(lastFrame < systemtime)
        {
            // Freeze a copy of the timer, so it doesn't change
            // any further while we're updating.
            t = systemtime;
            for(i = 0; i < t; i++)
            {
                UpdateGame();
            }
            lastFrame = t;
        }
        else
        {
            // Let the CPU rest a bit, no updates to catch up on yet.
            Sleep(10);
        }
    }
    // ...
}


This sort of logic works well, trust me. I have a few written games that actually have consistently timed loops. I usually take it one step further, make a frame throttler which has a max frame delta to prevent massive catch-up of lost frames in extreme cases. Instead it slows down slightly when behind, but this means smooth catchup rather than unpredictable skipping. This is generally good, and my low-end 1.6ghz netbook rarely falls that far behind.

It's more important to limit the CPUs that are running faster than the game was designed for (a strict fixed rate of 100 updates / second). Faster computers should likely use this time to sleep, so the end-user can multi-task better. It is important to let slower machines catch up, but it might be good to restrict how many frames can be caught up on, because over a certain amount, and you miss a noticeable amount of frames.

For networking, slowdown like that is unacceptable, and you'd want to sacrifice frames for consistent update timing. But on a regular offline kind of game, it's generally better to give the sense of smooth animation, and let the machine balance itself out. This is because usually time lag is a very temporary symptom I've found, and it resolves better if you don't sacrifice the visible frame rate excessively to accomplish catch-up.

A few frames, like maybe 3 or 4, but not much more. Anyways.

I probably shouldn't braindump like this at like 2 AM.

Hopefully this is of some use, and you can figure out something that works for you which is not HookTimer.

Posted on 2011-01-15 00:55:27 (last edited on 2011-01-15 00:57:31)

Overkill

Originally by Kildorf:

Really, V3 could probably benefit greatly from someone taking a look at this and figuring out how to make it play more nicely with multi-tasking. Anyone a bad enough dude to want to do this?


I'm with Grue in saying that this is probably not a good thing. On the one hand, it's nice to have programs that use all cores, but the Verge API as it stands currently was definitely written such that it was planned for single-core use. Besides, having multiple threads means more potential for deadlocks, race conditions, and could mean much slower performance if there is enough overhead to the barriers and locks needed.

And besides, I kind of like the ability to multitask while I'm running Verge. If Verge actually did use multiple cores, I would anticipate that I would be able to do less things at once. Not to mention that the kinds of games Verge was designed for -- we should expect they can mostly run on lower-spec machines, and also not pound on high-end machines. With asynchronous tasks, it could become a big hassle.

I'd rather just have one well-behaved single-threaded application that ran at decent frame-rate, and not multi-threaded one that will actually suffer because of time sharing when the user doesn't have the cores to actually run these tasks concurrently.

Anyways, I dunno.

Posted on 2011-01-15 01:12:05


Displaying 1-16 of 16 total.
1
 
Newest messages

Ben McGraw's lovingly crafted this website from scratch for years.
It's a lot prettier this go around because of Jon Wofford.
Verge-rpg.com is a member of the lunarnet irc network, and would like to take this opportunity to remind you that regardless how babies taste, it is wrong to eat them.