Why I'm doing this:
Hidden/Spoiler:
For this test, I wanted to see if lua coroutines work at all, so I ran this code inside of the ScriptPostLoad function:
Code: Select all
local testco = coroutine.create(
function()
print("ABC: Coroutines work as expected (1).")
end
)
coroutine.resume(testco)
-- First, see if creating a timer impacts coroutines
local test_timer = "breaktimer"
CreateTimer(test_timer)
local testco2 = coroutine.create(
function()
print("ABC: Coroutines work as expected (2).")
end
)
coroutine.resume(testco2)
-- Test nested coroutines
local testco3 = coroutine.create(
function()
print("ABC: Coroutines work as expected (3).")
local testco4 = coroutine.create(
function()
print("ABC: Coroutines work as expected (4).")
end
)
coroutine.resume(testco4)
end
)
coroutine.resume(testco3)
-- In it's simplest form (I've had this glitch before), show that you can't create timers inside coroutines
local testco5 = coroutine.create(
function()
local co_timer = "cotimer"
CreateTimer(co_timer)
print("ABC: Coroutines work as expected (5).")
end
)
coroutine.resume(testco5)
This is the relevant section of the resulting debug log:
Code: Select all
ABC: Coroutines work as expected (1).
ABC: Coroutines work as expected (2).
ABC: Coroutines work as expected (3).
ABC: Coroutines work as expected (4).
Message Severity: 3
C:\Battlefront2\main\Battlefront2\Source\LuaHelper.cpp(312)
CallProc failed: bad argument #1 to `resume' (string expected, got thread)
stack traceback:
[C]: in function `resume'
(none): in function `ScriptPostLoad'
For this test, I've created a timer outside of a coroutine, but I attempted to set and read the timer values from inside the coroutine. This is the test code from the ScriptPostLoad function:
Code: Select all
local control = "controltimer"
CreateTimer(control)
SetTimerValue(control, 4)
print("ABC: Control Timer Value: "..GetTimerValue(control))
local t1 = "testtimer"
CreateTimer(t1)
local co = coroutine.create(
function()
print("ABC: Coroutine was resumed successfully.")
SetTimerValue(t1, 4)
print("ABC: Timer Value reading from inside the coroutine: "..GetTimerValue(t1))
end
)
coroutine.resume(co)
print("ABC: Timer Value reading from outside the coroutine (after resume): "..GetTimerValue(t1))
And this is the test result from the debug log:
Code: Select all
ABC: Control Timer Value: 4
ABC: Coroutine was resumed successfully.
ABC: Timer Value reading from inside the coroutine: testtimer
ABC: Timer Value reading from outside the coroutine (after resume): 0
Another straightforward test. I created a 1 second timer, tried to start it from inside a coroutine and made it print to debug if it ever elapsed. I made a separate timer to print when 5 seconds had passed. This is the test code from the ScriptPostLoad function:
Code: Select all
-- setup
local test_timer = "testtimer"
CreateTimer(test_timer)
OnTimerElapse(
function(timer)
print("ABC: The timer elapsed successfully.")
end,
test_timer
)
-- test
SetTimerValue(test_timer, 1)
local co = coroutine.create(
function()
print("ABC: The coroutine was resumed successfully.")
StartTimer(test_timer)
end
)
coroutine.resume(co)
-- timeout
local t2 = "timeout"
CreateTimer(t2)
SetTimerValue(t2, 5)
OnTimerElapse(
function(timer)
print("ABC: 5 seconds have now passed so the test timer should have elapsed by now.")
end,
t2
)
StartTimer(t2)
And this is the result:
Code: Select all
ABC: The coroutine was resumed successfully.
ifs_sideselect_fnEnter(): Map does not support custom era teams
ifs_sideselect_fnEnter(): The award settings file does not exist
ABC: 5 seconds have now passed so the test timer should have elapsed by now.
Since coroutines shouldn't contain/interact with ingame timers, the next question is what about the reverse? I ran this test to see if coroutines can be created and run from an OnTimerElapse event. This is the test code from the ScriptPostLoad function:
Code: Select all
local t1 = "t1"
CreateTimer(t1)
SetTimerValue(t1, 3)
OnTimerElapse(
function(timer)
print("ABC: Timer elapsed.")
local testco = coroutine.create(
function()
print("ABC: Coroutine running.")
end
)
print("ABC: Starting coroutine.")
coroutine.resume(testco)
print("ABC: Coroutine finished.")
end,
t1
)
StartTimer(t1)
And this is the result:
Code: Select all
ABC: Timer elapsed.
ABC: Starting coroutine.
ABC: Coroutine running.
ABC: Coroutine finished.
This might look like an oddly specific test but it doubles as a proof of concept for something I'm trying to achieve. Notice a few things.
- I haven't created the coroutine inside the OnTimerElapse event, so yielding a coroutine that was created inside OnTimerElapse is still untested for the time being.
- This is a looping timer I created just for testing purposes. The way I've programmed this is bad practice because this test timer will never be destroyed at the end of the match. I've known there to be a problem with timers crashing instant action playlists either when they're not destroyed or never stopped (one of those things, but I don't know which).
- The coroutine in this test is a stand in for an actually useful timer elapse function, where meaningful code can be placed in the same spots as the print functions. The OnTimerElapse event is just behaving like a coroutine handler.
Code: Select all
-- setup
local t1 = "t1"
CreateTimer(t1)
SetTimerValue(t1, 3)
-- the code to be run inside OnTimerElapse
local co = coroutine.create(
function()
print("ABC: First section of the desired OnTimerElapse code.")
coroutine.yield()
print("ABC: Second section of the desired OnTimerElapse code.")
coroutine.yield()
print("ABC: Third section of the desired OnTimerElapse code.")
end
)
OnTimerElapse(
function(timer)
print("ABC: Timer elapsed.")
if coroutine.status(co) == "dead" then
print("ABC: Coroutine has already finished")
return
end
print("ABC: Resuming the coroutine.")
coroutine.resume(co)
print("ABC: Restarting the timer.")
SetTimerValue(timer, 3)
StartTimer(timer)
end,
t1
)
-- test begins
print("ABC: Starting the timer for the first time.")
StartTimer(t1)
And this is the result:
Code: Select all
ABC: Starting the timer for the first time.
ifs_sideselect_fnEnter(): Map does not support custom era teams
ifs_sideselect_fnEnter(): The award settings file does not exist
ABC: Timer elapsed.
ABC: Resuming the coroutine.
ABC: First section of the desired OnTimerElapse code.
ABC: Restarting the timer.
ABC: Timer elapsed.
ABC: Resuming the coroutine.
ABC: Second section of the desired OnTimerElapse code.
ABC: Restarting the timer.
ABC: Timer elapsed.
ABC: Resuming the coroutine.
ABC: Third section of the desired OnTimerElapse code.
ABC: Restarting the timer.
ABC: Timer elapsed.
ABC: Coroutine has already finished
PS You may be asking why I don't just make multiple timers with different OnTimerElapse events and jump from one to the other. It's because I'm doing OOP, and want to be able to pass the object a custom timer elapse function. I can hide the coroutine's yield calls inside the object's member functions. This method is just better for what I'm doing.