Author Topic: Lua Timers  (Read 7223 times)

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Lua Timers
« on: 26 August 2009, 11:58:18 »
This is something that many people have wanted so I'm posting my initial thoughts on code. Something, but not exactly, like this.

Code: [Select]
class ScriptTimer {
public:
ScriptTimer(int timeInMiliseconds, const string &name, bool repeat = false)
: name(name)
, _repeat(repeat)
, targetTime(0)
, duration(timeInMiliseconds) {
reset();
}

bool ready() {
if (getCurrentTime() >= targetTime) {
return true;
}
return false;
}

void reset() {
targetTime = getCurrentTime() + duration;
}

string getName() { return name; }
bool repeat() { return _repeat; }

private:
string name;
bool _repeat;
int targetTime, duration;
};

vector<ScriptTimer> timers;

void ScriptManager::setTimer(int timeInMiliseconds, const string &name) {
timers.push_back(ScriptTimer(timeInMiliseconds, name));
}

void ScriptManager::setInterval(int timeInMiliseconds, const string &name) {
timers.push_back(ScriptTimer(timeInMiliseconds, name, true));
}

void ScriptManager::stopTimer(const string &name) {
timers.remove(*name or something*);
}

void ScriptManager::onTimer() {
// when a timer is ready, call the corresponding xml block of lua code
// and remove the timer or reset to repeat.
for (*loop through timers*) {
timer = timers[i];
if ( timer.ready() ) {
luaScript.beginCall("timer_"+timer.getName());
luaScript.endCall();
if ( timer.repeat() ) {
timer.reset();
} else {
timers.remove( timer );
}
}
}
}

Will need to call onTimer() in World::update(). Also need to add a callback for each of the functions and register.

Maybe setTimer can have the repeat bool instead of having another lua function.

UPDATE: initialised "all" the data members and put in the order they're defined.
« Last Edit: 26 August 2009, 12:55:27 by hailstone »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Timers
« Reply #1 on: 26 August 2009, 12:26:06 »
Hella cool!

For the non C++ savy, what hailstone's snippet suggests is (roughly)
Code: [Select]
<starup>
  -- set a timer to go off in one second...
  setTimer ( 1000, "inOneSecond" )
  -- set a timer to go off 4 times a second
  setInterval ( 250, "periodicTimer", true )
</startup>

<timer name="inOneSecond">
  -- this code to be executed one second after game starts
</timer>

<timer name="periodicTimer">
  -- this code to be executed every 150 milliseconds
</timer>

But no need for millisecond accuracy... we can't give them that anyway, so why pretend we can.  At absolute best we can call the timer every world update, 40 per second.  So I think the 'time' should just be specified in world frames.  But a good plan! Got anything else tucked away up that sleeve ?? :)
Glest Advanced Engine - Code Monkey

Timeline | Downloads

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Lua Timers
« Reply #2 on: 29 August 2009, 05:32:04 »
I have timers working now, but if you stop a timer in a timer it makes the vector iterator invalid so I've made it break out of the loop. This means any timer that wasn't checked needs to wait for the next world update and might cause a significant delay for a timer firing. Perhaps someone else can figure out a better way.

This script will work:
Code: (basic_tutorial.xml) [Select]
       <startup>
            dofile(scenarioDir() .. '/startup.lua')
            count = 1
            setInterval(5, 'startup')
            setTimer(2, 'dummy')
</startup>
        <timer name="dummy">
            showMessage('dummy', 'GlestBasicTutorial')
        </timer>
        <timer name="startup">
            showMessage('Welcome', 'GlestBasicTutorial')
            if count==3 then
                stopTimer('startup')
                setTimer(5, 'dummy')
            else
                count = count + 1
            end
        </timer>

I have created a new branch called lua_ext which includes the timer code and the 3 new GameSettings functions.

EDIT: Thanks silnarm. I thought there must have been a better way. Calling from stopTimer() in a timer no longer causes any problems.

UPDATE:
I've made it so when a message is shown the game is paused. The problem is that the timers don't pause, so when you are finished reading the message many timers that are meant to fire sequentially are fired at the same time. I'm thinking there could be a tick method in ScriptTimer that would adjust the targetTime depending on the world updates which are paused. Or would people prefer it not to pause?

Also will people want asynchronous timers that aren't affected by a pause?
« Last Edit: 31 August 2009, 12:32:57 by hailstone »
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Timers
« Reply #3 on: 1 September 2009, 22:13:42 »
UPDATE:
I've made it so when a message is shown the game is paused. The problem is that the timers don't pause, so when you are finished reading the message many timers that are meant to fire sequentially are fired at the same time. I'm thinking there could be a tick method in ScriptTimer that would adjust the targetTime depending on the world updates which are paused. Or would people prefer it not to pause?

Also will people want asynchronous timers that aren't affected by a pause?

I think we have the the real time not game time problem... and basing it off world frames like I was suggesting will not solve the problem either, as there are 40 per second, regardless of game speed, the calculations are just scaled. I think they should definitely pause while the game is paused, and slow or speed up with the game speed.  Although I can see that someone may want a timer based on real time, I think the game time ones will be far more useful.  We might have to dig around a bit to figure this one out  :-\
Glest Advanced Engine - Code Monkey

Timeline | Downloads

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: Lua Timers
« Reply #4 on: 2 September 2009, 01:50:17 »
YE HAW! Fantastic. So it now works, despite speed problems. Personally, I don't think that's a big deal, since that could affect the difficulty levels. If someone keeps trying and dying, it's just no fun. Take it from someone who had to keep doing this stupid race thing once in a video game until I got a time of less than 0. Took some hundred tries, and a lot of frustration. If someone loses, they want an easier way of preventing that, so the ability to get more done before an event (ie: an attack) takes place.

Of course, maybe an option to choose the speed.
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert

PolitikerNEU

  • Guest
Re: Lua Timers
« Reply #5 on: 2 September 2009, 10:03:47 »
I do think that pausing should cause all timers to pause but I think that there should be two types of timers: Some are used for periodic checking of something - these timers should not be adjusted when increasing/decreasing game speed, others are used for e.g. abilities - there should be adjusted.

hailstone

  • Local Moderator
  • Battle Machine
  • ********
  • Posts: 1,568
    • View Profile
Re: Lua Timers
« Reply #6 on: 2 September 2009, 21:34:19 »
So you're saying that one time timers are dependent on game speed but interval timers aren't?

I don't think I tested setting two timers to the same event.
Glest Advanced Engine - Admin/Programmer
https://sourceforge.net/projects/glestae/

John.d.h

  • Moderator
  • Airship
  • ********
  • Posts: 3,757
  • I have to go now. My planet needs me.
    • View Profile
Re: Lua Timers
« Reply #7 on: 3 September 2009, 01:14:40 »
A timer based on IRL time could be useful for certain interface elements, like if you want to display a message for 10 seconds regardless of game speed.  I'm not sure if it would be worth the trouble, though.

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Timers
« Reply #8 on: 3 September 2009, 02:36:47 »
A timer based on IRL time could be useful for certain interface elements, like if you want to display a message for 10 seconds regardless of game speed.  I'm not sure if it would be worth the trouble, though.

No trouble, that's what we've got now :)

... and basing it off world frames like I was suggesting will not solve the problem either, as there are 40 per second, regardless of game speed,

How happy I am to be incorrect!
Our debug screen displays "Update FPS" which I took to be world updates, thus throwing me off the scent. This is not the case, adding code to count and display world updates we get at fastest and slowest speed settings...


So, we can have it all, and easily  ;D

Here's how I think it should work, a single Lua function,

setTimer ( string name, string type, number interval, boolean periodic )

"type" is the time type, "real" or "game", the interval is in seconds if type is real, or world updates if type is game, so it is then used thus:

Code: [Select]
setTimer ( "inTwoSeconds", "real", 2, false )
setTimer ( "everyFiveSeconds", "real", 5, true )
setTimer ( "gameTick", "game", 20, true )
setTimer ( "alertMsg", "game", 40*60*15, false )

This mean "inTwoSeconds" will go off once two seconds after the game starts, "everyFiveSeconds" will go off every five seconds, "gameTick" will go off every 20 world frames (every half a second at normal speed, once a second at slowest, every quarter of a second at fastest), and "alertMsg" will go off once after 40*60*15 world updates ( 15 minutes of 'play' time at normal speed).

I think that covers all bases :)
Glest Advanced Engine - Code Monkey

Timeline | Downloads

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: Lua Timers
« Reply #9 on: 3 September 2009, 05:25:20 »
Elementary, my dear Watson! ;)

That's exactly what I had in mind when I first thought of timers!

So... this'll be in 0.2.13?
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert

silnarm

  • Local Moderator
  • Behemoth
  • ********
  • Posts: 1,373
    • View Profile
Re: Lua Timers
« Reply #10 on: 3 September 2009, 05:45:04 »
Ok, done.

But we have another bad iterator problem, adding timers in response to timers.
Not going to be hard to fix, just need to queue new timers rather than adding them straight away, then add any queued at the end of ScriptManager::onTimer().

If it's good and stable this will probably be in 0.2.13, yes.

My test rig:
Code: [Select]
<?xml version="1.0" standalone="yes" ?>
<scenario>
 
<difficulty value="2"/>
<players>
<player control="human" faction="tech" team="1"/>
<player control="closed" />
<player control="closed" />
<player control="closed" />
</players>
<map value="conflict"/>
<tileset value="dark_forest"/>
<tech-tree value="magitech"/>
<default-resources value="false"/>
<default-units value="false"/>
<default-victory-conditions value="false"/>
<scripts>

<startup>
  setTimer ( 'stopSwords', 'real', 10, false )
  setTimer ( 'swordman', 'real', 2, true )
 
  setTimer ( 'machine', 'game', 40*5, true )
  setTimer ( 'stopMachines', 'game', 40*20, false )
</startup>
 
<timer name="swordman">
  createUnit ( "swordman", 0, startLocation(0) );
</timer>

<timer name="stopSwords">
  stopTimer ( 'swordman' );
</timer>
 
<timer name="machine">
 createUnit ( "battle_machine", 0, startLocation(0) );
</timer>

<timer name="stopMachines">
 stopTimer ( 'machine' );
</timer>
 
</scripts> 
</scenario>

If you move the calls to setTimer() for 'machine' and 'stopMahines' into the handler for 'stopSwords' you get the invalid iterator in ScriptManager::onTimer()
Glest Advanced Engine - Code Monkey

Timeline | Downloads

Omega

  • MegaGlest Team
  • Dragon
  • ********
  • Posts: 6,167
  • Professional bug writer
    • View Profile
    • Personal site
Re: Lua Timers
« Reply #11 on: 7 September 2009, 17:54:00 »
Fantastic! Military is probably going to be dependant on this. I realized there is no other way to check for an event unless something dies or is created.

OT: How IS 0.2.13 going? Military is waiting! ;)
Edit the MegaGlest wiki: http://docs.megaglest.org/

My personal projects: http://github.com/KatrinaHoffert