Jump to content

timer.scheduleFunction()


Yurgon

Recommended Posts

I recently spent several hours debugging a script that revolved around timer.scheduleFunction(). Since I didn't find any meaningful reference to it in the forum, maybe this will help someone avoid some headache in the future.

 

Note, I'm specifically talking about timer.scheduleFunction(), a function that comes with the DCS Simulator Scripting Engine (SSE). I'm not talking about mist.scheduleFunction() that comes with the 3rd party library "MIssion Scripting Tools", which may or may not behave alike.

 

Note 2, I mostly wrote the following code examples in the forum's message box, it's entirely possible that they will cause scripting errors if you copy & paste them. This post isn't meant as a working template, it's supposed to be an addendum to the documentation.

 

If by now you have absolutely no clue what I'm talking about, you're probably reading the wrong post. :smartass:

 

Okay, so what is it about? I wanted to play sound files in order (dynamic MGRS read-out; requires that the mission contains "A.ogg", "B.ogg", ..., "Z.ogg", "0.ogg", ..., "9.ogg").

 

Consider the following basic example:

 

 -- This example will play only the last sound file
 -- (At least that's what happens when I run it in a test mission)
 function MGRS2Speech (mgrs_string)
   local char
   for i = 1, string.len(mgrs_string), 1 do
     char = string.sub(mgrs_string, i, i)
     if char ~= " " then
       trigger.action.outSound(char .. ".ogg")
     end
   end
 end

 MGRS2Speech("GH 234987")

 

What happens is that "7.ogg" will be played once, nothing else. I assume that the Simulator Scripting Engine has some kind of sound buffer that doesn't automatically append sounds one after the other, instead (maybe someone can explain the reason) it just plays one sound.

 

So, the obvious answer is to delay the outSound() calls with timer.scheduleFunction().

 

Hoggit Wiki documentation:

 

-- Wiki documentation
functionId timer.scheduleFunction(function functionToCall, functionArgs anyFunctionArguement, time modelTime )

-- The following will run a function named "main" 120 seconds from one the code would run.
timer.scheduleFunction(main, {}, timer.getTime() + 120)

 

Now my problem was that I didn't want to write 36 different functions, I just wanted to pass a single parameter, and whenever I ran my mission the scheduled function failed and failed and failed to execute, and worse, there wasn't even any log entry in DCS.log. So here's what works for me. I'll highlight the way parameters are passed, because that's what I found particularly difficult to understand.

 

Isolated working code with timer.scheduleFunction():

 

 -- WORKING EXAMPLE

 -- This example should play the following sound files:
 -- "G.ogg" (1 second after function call)
 -- "H.ogg" (1.7 seconds after function call)
 -- "2.ogg" (2.4 seconds after function call)
 -- "3.ogg" (3.1 seconds after function call)
 -- "4.ogg" (3.8 seconds after function call)
 -- "9.ogg" (4.5 seconds after function call)
 -- "8.ogg" (5.2 seconds after function call)
 -- "7.ogg" (5.9 seconds after function call)

 function MGRS2Speech (mgrs_string)
   local char
   local delay = 1 -- Read out the next char after this time has passed
   for i = 1, string.len(mgrs_string), 1 do
     char = string.sub(mgrs_string, i, i)
     if char ~= " " then
       timer.scheduleFunction(MGRS2SpeechSound,[b] { ["sound_file"] = char .. ".ogg" }[/b], timer.getTime() + delay)
       delay = delay + 0.7 -- Wait this long in seconds until the next sound gets played
     end
   end
 end
 
 function MGRS2SpeechSound (params)
   if params == nil then
     params = {}
   end
   
   local sound_file = params["sound_file"] or ""
   
   if sound_file == "" or sound_file == " " then
     return ""
   end
   
   trigger.action.outSound(sound_file)
 end

 MGRS2Speech("GH 234987")

 

Now, one last thing. Let me focus on the parameter-passing to timer.scheduleFunction():

 

 -- This example will lead to the exact same parameter value being passed to
 -- each call of the scheduled function
 function MGRS2Speech (mgrs_string)
   local char
   local delay = 1 -- Read out the next char after this time has passed
   local param = {}
   for i = 1, string.len(mgrs_string), 1 do
     char = string.sub(mgrs_string, i, i)
     if char ~= " " then
       [b]param["sound_file"] = char .. ".ogg"[/b]
       timer.scheduleFunction(MGRS2SpeechSound, [b]param[/b], timer.getTime() + delay)
       delay = delay + 0.7 -- Wait this long in seconds until the next sound gets played
     end
   end
 end
 
 MGRS2Speech("GH 234987")

 

In my case and in the above example, the function MGRS2SpeechSound would be called 8 times, and each time the parameter would be ["sound_file"] = "7.ogg". It appears as if the SSE passes the parameter by reference, leading to the same parameter value each time the function is then actually called.

 

Therefore, in the above WORKING EXAMPLE, I chose to pass the parameter as an anonymous variable, leading to pass by value.

 

Okay, and finally an example to pass multiple parameters to a scheduled function:

 

params = {}

params["some_element"] = "Some element"
params["other_element"] = "Another element"
params[0] = "Yet another element"
params["some_number"] = 47

-- Call someFunc(params) in 10 seconds
timer.scheduleFunction(someFunc, params, timer.getTime() + 10)

function someFunc(args)
 env.info("someFunc() called at " .. timer.getTime() ..  " with these parameters: some_element: " .. args["some_element"] .. ", other_element: " .. args["other_element"] .. ", 0: " .. args[0] .. ", some_number: " .. args["some_number"])
end

Link to comment
Share on other sites

Good find! So that's what I call a brutal night shift.

And thanks for the "working example"... That is exactly what I am missing in almost every documentation. Simple working examples that actually use real parameters, not a syntax showcase that doesn't execute.

Really helpful.

Shagrat

 

- Flying Sims since 1984 -:pilotfly:

Win 10 | i5 10600K@4.1GHz | 64GB | GeForce RTX 3090 - Asus VG34VQL1B  | TrackIR5 | Simshaker & Jetseat | VPForce Rhino Base & VIRPIL T50 CM2 Stick on 200mm curved extension | VIRPIL T50 CM2 Throttle | VPC Rotor TCS Plus/Apache64 Grip | MFG Crosswind Rudder Pedals | WW Top Gun MIP | a hand made AHCP | 2x Elgato StreamDeck (Buttons galore)

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...