Thread: how to write a timer?
-
Jul 15 2012 06:38 PM #1
how to write a timer?
Hey all, sorry if this is the wrong forum to post it in, seemed like the closest (or at least most active) part of the Lua scripting forums for my question.
I'm writing my first plugin, and I'm still quite a newbie when it comes to programming in general (no formal training) but I've been able to nearly finish my plugin until I ran into a problem trying to write a timer. Essentially I'm trying to write a simple timer that will call a function, wait 60 seconds, and then call another function. I've tried a few ways to get this to work using Turbine.Engine.GetGameTime(), something along the lines of:
that particular one got " \Main.lua:199: stack overflow" but it was a bit of a shot in the dark to begin withCode:function timer(duration,startTime) local completed = false local timestamp = Turbine.Engine.GetGameTime() if timestamp >= startTime + duration then completed = true return completed else timer(duration,startTime) end end curTime = Turbine.Engine.GetGameTime() if timer(60,curTime) == true then <do more stuff> end
I've also tried using while loops which crashed the client (such as: while timestamp <= duration do <stuff> timestamp = Turbine.Engine.GetGameTime() else <more stuff> )
anyway, I'm wondering if there is a way to accomplish this that I'm not seeing,or maybe if there's a way to fix my nubby little code there to make it work.
Thanks in advance
-IinfernoIinferno - r12 LM IVillKillU - r8 Reaver Dongramorthil - Warden Doalin - Hunter Defaelearin - RK Dongrailin - Captain (Officer of Preying Mantis)
Author of DebuffHelper
-
Jul 16 2012 12:04 AM #2
The simplest solution would be to use an Update event handler to compare the current game time to a desired game time. The reason you use the Update event is that it fires asynchronously, allowing you to check the time once every time a frame is rendered, preventing the endless loops you were encountering. A more robust solution is to use a Timer class which can be instantiated as many times as needed, will support the AddCallback/RemoveCallback mechanism and will thus allow triggering multiple events if needed:
Ideally you would also call RemoveCallback(timer1,"TimeRea ched",myEvent) when your plugin unloads or the timer is no longer needed.Code:function AddCallback(object, event, callback) if (object[event] == nil) then object[event] = callback; else if (type(object[event]) == "table") then table.insert(object[event], callback); else object[event] = {object[event], callback}; end end return callback; end function RemoveCallback(object, event, callback) if (object[event] == callback) then object[event] = nil; else if (type(object[event]) == "table") then local size = table.getn(object[event]); for i = 1, size do if (object[event][i] == callback) then table.remove(object[event], i); break; end end end end end Timer = class( Turbine.UI.Control ); function Timer:Constructor() Turbine.UI.Control.Constructor( self ); self.EndTime=Turbine.Engine.GetGameTime(); self.Repeat=false; self.SetTime=function(sender, numSeconds, setRepeat) numSeconds=tonumber(numSeconds); if numSeconds==nil or numSeconds<=0 then numSeconds=0; end self.EndTime=Turbine.Engine.GetGameTime()+numSeconds; self.Repeat=false; -- default self.NumSeconds=numSeconds; if setRepeat~=nil and setRepeat~=false then -- any non-false value will trigger a repeat self.Repeat=true; end self:SetWantsUpdates(true); end self.Update=function() if self.EndTime~=nil and Turbine.Engine.GetGameTime()>=self.EndTime then self:SetWantsUpdates(false); -- turn off timer to avoid firing again while we are processing (not likely but it's a good practice) -- fire whatever event you are trying to trigger if self.TimeReached~=nil then if type(self.TimeReached)=="function" then self.TimeReached(); elseif type(self.TimeReached)=="table" then for k,v in pairs(self.TimeReached) do if type(v)=="function" then v(); end end end end if self.Repeat then self.EndTime=Turbine.Engine.GetGameTime()+self.NumSeconds; self:SetWantsUpdates(true); end end end end -- somewhere else in code, you would instantiate an instance of the timer timer1=Timer(); -- then set the TimeReached event handler myEvent=function() Turbine.Shell.WriteLine("Timer Just Fired!"); end AddCallback(timer1,"TimeReached",myEvent) -- and finally, set the timer timer1:SetTime(60, true); -- cause the timer to fire every 60 seconds, auto repeating
EDIT: Fixed bug in Repeat codeLast edited by Garan; Jul 16 2012 at 05:23 PM. Reason: typo
Gnashtooth - Rank 10 Warg - My breath's worse than my bite - but what d'ya want? I eat Hobbitsess fer cryin' out loud
Garan - Captain of little note - got parked at a Fell Scrying Pool so long it dried up and blew away
and many, many others...
"No, no, the hamsters are for the forums. The servers run on chinchillas!"-Patience 7/20/2007
-
Jul 16 2012 02:24 PM #3
thanks alot
very helpful info. Game servers are still down so I can't try it quite yet but I'm pretty sure that's exactly what I needed.
Iinferno - r12 LM IVillKillU - r8 Reaver Dongramorthil - Warden Doalin - Hunter Defaelearin - RK Dongrailin - Captain (Officer of Preying Mantis)
Author of DebuffHelper
-
Jul 16 2012 05:27 PM #4
You're welcome. Note, there was a minor bug in the Repeat part of the code which I fixed after you posted so you probably should review the code you are using. The bug was that the line "if setRepeat~=nil and setRepeat~=false then" was incorrectly typed as "if setRepeat~=nil and self.Repeat~=false then" and the line "self.Repeat=setRepeat" should have been removed.
I will be adding this sample to the Writing LotRO Lua Plugins for Noobs thread as it seems to be a worthy addition.Last edited by Garan; Jul 16 2012 at 06:30 PM.
Gnashtooth - Rank 10 Warg - My breath's worse than my bite - but what d'ya want? I eat Hobbitsess fer cryin' out loud
Garan - Captain of little note - got parked at a Fell Scrying Pool so long it dried up and blew away
and many, many others...
"No, no, the hamsters are for the forums. The servers run on chinchillas!"-Patience 7/20/2007






Reply With Quote

