View Full Version : [SOLVED] Timer is currently broken when it comes to Load and Undo

01-23-2017, 08:22 PM
If a timer is running while you load or undo (or apply a new script), then it will continue to run despite that instance coming to an end. There is also no way to destroy it completely (onObjectDestroyed and onDestroy do not trigger on load/undo, I checked).

So, here is an example object script to highlight the problem. Here we are using a timer to reference back to itself. This can also be illustrated with a repetitions=0, but I'm using this method because I think it better highlights the issue. Example code:

function onload()
timerName = "a_special_snowflake_of_a_name"
--This does nothing to kill the timer from previous loops


function startTimerLoop()
--Without this, an error is thrown due to repeated names
--Considering the previous timer would have had to end before it can be
--created again, I do not see how this is possible.

identifier = timerName, function_name="loopingUpdate",
function_owner=self, delay=1


function loopingUpdate()
--Stuff happens here

With the timer.create commented out, this timer will not start. It prints Test once and ends. Now remove the commenting around Timer and save/apply the script. It will now print Test once per second. Now, comment out the timer.Create again and save/apply code. Notice that despite there not being a timer.create in the script, it is still printing Test over and over again. It will continue to do so. I believe disabling the function as a whole will cause the timer to throw an error.

If I was using repetition=0 on my timer instead of calling the starting function over and over, that error spam would continue over and over forever with no way to stop it.

If possible, please just kill all co-routines and timers whenever any load/undo action is taken. If this is not possible, could we have an API trigger that goes off whenever a load/undo is activated. Something we could put a Timer.destroy inside of to end the timer before the next instance is laid on top of it?

Thank you

01-23-2017, 11:31 PM
Here is the mod I made to demonstrate a lot of the problems with Load and Undo:


And I'll take the opportunity to plug my suggestion to give scripts control over autosaved undo states, since it's quite relevant:


04-17-2017, 02:54 PM
I'm having trouble with this. Is there a way around it?

04-23-2017, 11:30 AM
Huffel mentioned this in the old thread I made about this problem:

Timer.destroy() in the onDestroy() event should take care of that I think.

I don't know if I ever tried it.

04-23-2017, 01:41 PM
I put the Timer in a cube and made it remove the timer onDestroy(). It still produces loads of errors until the amount of repetitions runs out when I reload the mod. So that doesn't fix it. :*(

04-23-2017, 03:36 PM
I tested it just now, for me it still works to delete the timer in the onDestroy() event. It is important to consider that the onDestroy events are only called for objects, not global:

Did you implement it in Global perhaps? It seems to work only for objects (which is strange for onObjectDestroyed). Alternatively you could implement it in the onLoad event as well to make sure there is no active Timer when the object is spawned.

My test code (code implemented in an object):

function onLoad(save_state)
local button_parameters = {}
button_parameters.click_function = 'startTimer'
button_parameters.function_owner = self
button_parameters.label = 'Start'
button_parameters.position = {0.0, 1.0, 0.0}
button_parameters.width = 2000
button_parameters.height = 1000
button_parameters.font_size = 100

function startTimer()
Timer.create({identifier = 'testTimer', function_name = 'printsth', function_owner = self, delay = 3.0, repetitions = 12})
function printsth()

function onDestroy()

04-23-2017, 04:55 PM
I must have messed something up then. I'll try again and see if I can get it to work. Thanks Huffel.



scale = 2
myText = nil
timerID = "gameTimer"
playerTimers = {}
coloursPlaying = {}

function onLoad()
myText = getObjectFromGUID("8955f6")
if myText ~= nil then

local myPos = self:getPosition()
myText:setPosition({myPos.x, myPos.y+0.1, myPos.z+2})

local myRot = self:getRotation()
myText:setRotation({myRot.x + 90, myRot.y - 90, myRot.z})
playerTimers = Global:getTable("playerTimers")

function onDestroy()
print("onDestroy() has been triggered.")

function startTimer(info)
local seconds, function_name, useCountdown, needToBeDone = info[1], info[2], info[3], info[4]
if seconds == nil then print("ERROR: startTimer not set to an amount of seconds.") return end


local timerP = {}
timerP.identifier = timerID
timerP.function_owner = Global
if useCountdown == true then
self:setScale({x=8, y=0.2, z=8})

coloursPlaying = Global:getTable("coloursPlaying")
for col, _ in pairs(coloursPlaying) do

timerP.function_name = "timerInterval"
timerP.delay = 1
timerP.repetitions = seconds
timerP.parameters = info
elseif type(function_name) == "table" then
timerP.function_name = "goToTable"
timerP.delay = seconds
timerP.function_name = function_name
timerP.delay = seconds


Here's my code. When I manually delete it, it triggers the onDestroy() function but the timer doesn't stop. When I reload the mod, the onDestroy() function never triggers to remove the timer (there could just be a problem with print). I keep getting error messages after relogging with the timer still active.

I'm not sure what I'm doing wrong as the timer works as intended otherwise.

04-23-2017, 08:01 PM
I had the same issue trying to use onDestroy remove the timer when the map is reloaded or changed entirely.

04-24-2017, 11:53 AM
This is really strange. I played around with my example some more but I cannot get it to break.
I tested:

Putting the timer ID in a variable
Make the timer function throw an error instead of just a message
creating the timer from a coroutine

Everything works perfectly. The only thing I noticed: If I put a print in the onDestroy event there is no message when rewinding or reloading the save.

Have you tried to copy my example into an object and see if it will work for you?

04-24-2017, 01:48 PM
Your example works fine, I'm just trying to figure out what part of my code is different to cause it to behave this way.
I'm using Hotseat, but I also tried yours in Hotseat and there wasn't a problem.

I will update this post if I figure it out.

04-28-2017, 11:43 AM
I purposefully stop all events that trigger for a frame when resetting the Table to avoid people being able to spawn objects after the table has been cleared (and have a unkillable zombie scripting object).

05-03-2017, 06:18 PM
Hey Knil, thanks for the info. Here's the things you could 'fix' to solve this problem:

Timers should stop themselves automatically on a new load and shouldn't be allowed to continue.
If Timer.destroy() is called in the onLoad() function with the Timer's ID, the old Timer should actually get destroyed regardless of whether it was made in this instance.

05-25-2017, 02:51 PM
Thank you for fixing this in 9.2! :)