Coroutine / Schedule Lua code without freezing Wesnoth
Moderator: Forum Moderators
Coroutine / Schedule Lua code without freezing Wesnoth
How to use coroutines included in multiplayer scenario?
I tried:
[/code]
I get lua error:
attempt to index global 'coroutine' (a nil value)
Mostly I want to run lua function without freezing wesnoth.
I tried:
Code: Select all
local helper = wesnoth.require("lua/helper.lua")
function cotest()
while 1 do
os.execute("sleep " .. tonumber(0.2))
end
coroutine.yield()
end
co = coroutine.create(cotest)
I get lua error:
attempt to index global 'coroutine' (a nil value)
Mostly I want to run lua function without freezing wesnoth.
Last edited by Yutmeal2 on October 18th, 2017, 4:29 am, edited 2 times in total.
-
- Inactive Developer
- Posts: 503
- Joined: April 24th, 2016, 4:18 pm
Re: Coroutines
You can't use os.execute().
If you could, you'd never hit the yield because its outside the infinite loop.
Co-routines are NOT multi-tasking. Even if you did a co-routine to split up the workload, you'd still have the engine waiting until your entire process finished.
If you could, you'd never hit the yield because its outside the infinite loop.
Co-routines are NOT multi-tasking. Even if you did a co-routine to split up the workload, you'd still have the engine waiting until your entire process finished.
I forked real life and now I'm getting merge conflicts.
Re: Coroutines
The thing is, it can't recognize "coroutine". Not "coroutine.yield()", not "coroutine.create(...)". The lua script can't even execute in wesnoth.
Is it possible to ask lua do something (like wait x seconds before changing a label) while wesnoth can still listen to user input?
Ideally, lua should pass control back for wesnoth in those x seconds and notify wesnoth that lua wants control at a specific time... if true multi-tasking is not possible.
I haven't tried using a wesnoth [while] loop to poll result from a lua script. May be I should.
Or a wesnoth while loop with a bunch of lua tags. Each checks if x seconds have passed. If yes, do action. If no, quickly exits. That would work if the player can still move units when wesnoth runs the while loop in background, or if wesnoth has an onrealtime event.
Is it possible to ask lua do something (like wait x seconds before changing a label) while wesnoth can still listen to user input?
Ideally, lua should pass control back for wesnoth in those x seconds and notify wesnoth that lua wants control at a specific time... if true multi-tasking is not possible.
I haven't tried using a wesnoth [while] loop to poll result from a lua script. May be I should.
Or a wesnoth while loop with a bunch of lua tags. Each checks if x seconds have passed. If yes, do action. If no, quickly exits. That would work if the player can still move units when wesnoth runs the while loop in background, or if wesnoth has an onrealtime event.
-
- Inactive Developer
- Posts: 503
- Joined: April 24th, 2016, 4:18 pm
Re: Coroutines
A number of Lua library functions are disabled. Mainly because they're not portable (for instance os.* functions).
I don't recall seeing a 'sleep' function. You could probably write one in C++ but it may be hard to get it accepted because anything which halts the WML/Lua thread is going to be a problem.
I would suggest that you look for an alternate solution. Stopping the game for N seconds while you await a timeout is not going to play well.
I don't recall seeing a 'sleep' function. You could probably write one in C++ but it may be hard to get it accepted because anything which halts the WML/Lua thread is going to be a problem.
I would suggest that you look for an alternate solution. Stopping the game for N seconds while you await a timeout is not going to play well.
I forked real life and now I'm getting merge conflicts.
Re: Coroutines
I tried os.time() in lua on linux, and it works for 1.12. I don't know if that works on windows.
Code: Select all
wesnoth.message(os.time())
Re: Coroutines
debug.traceback
, os.clock
, os.date
, os.time
, os.difftime
are the only functions allowed from debug
and os
. From the Lua standard library only core, table
, string
, and math
functions are allowed otherwise, and dofile
and loadfile
are disabled.Author of the unofficial UtBS sequels Invasion from the Unknown and After the Storm.
Re: Coroutines
The wesnoth while loop idea doesn't work. The game freezes for a while and then gives up on running the while loop.
I guess this means wesnoth doesn't listen to user input when it runs the while loop.
I was reading the Tetris source code, which creates four special units.
Whenever the player's cursor hovers the unit, wesnoth displays the unit, and runs the lua code.
The lua code moves and draw the tetromino.
New idea: Put Lua code into an element of wesnoth's user interface that is redrawn regularly.
Wesnoth might run the lua script regularly while still listens to user input.
Probably the clock for turn limit can work half of the time...
I guess this means wesnoth doesn't listen to user input when it runs the while loop.
I was reading the Tetris source code, which creates four special units.
Whenever the player's cursor hovers the unit, wesnoth displays the unit, and runs the lua code.
The lua code moves and draw the tetromino.
Code: Select all
wesnoth.fire("unit", {
x=x, y=y,
side = not_me_side,
type = "Fog Clearer",
{"abilities",{{"dummy",{{"filter",{lua_function="tetris_notice"}},}},}},
{"status",{petrified=true}},
})
Wesnoth might run the lua script regularly while still listens to user input.
Probably the clock for turn limit can work half of the time...
Re: Coroutines
This works:
What if one of the players pause the game in a multiplayer game? Is the timing still accurate for local time?
I wonder if I can insert lua functions into animation frames. hmm..
~~~~~~~~~~
I tried this code in 1.13.8. This still works, but the timing is not correct.
After the code prints "286.48", I would have to wait 30 seconds instead of 1 second before the code prints "287.48".
Maybe it is because wesnoth 1.13.8 switch to Lua5.2?
The user interface of 1.12 constantly call "report_countdown()", but I guess 1.13.8 doesn't do that.
When I change 1.0 to 0.01, Wesnoth prints the messages much more frequently. So, the user interface still call "report_countdown()" frequently.
Timing by os.clock() is incorrect.
~~~~~~~~~~
If I use os.time() instead of os.clock(), the timing is correct. But I only get 1 second resolution for timing instead of millisecond resolution.
New Idea: Make the code adaptively calculate how many fake miliseconds from os.clock() is equivalent to 1 real second from os.time().
That way, I get an approximate timer with milisecond resolution.
Code: Select all
local old_report_countdown = wesnoth.theme_items.report_countdown
old_time = os.clock()
function wesnoth.theme_items.report_countdown()
new_time = os.clock()
if new_time - old_time > 1.0 then
old_time = new_time
wesnoth.message(new_time)
end
return old_report_countdown()
end
I wonder if I can insert lua functions into animation frames. hmm..
~~~~~~~~~~
I tried this code in 1.13.8. This still works, but the timing is not correct.
After the code prints "286.48", I would have to wait 30 seconds instead of 1 second before the code prints "287.48".
Maybe it is because wesnoth 1.13.8 switch to Lua5.2?
The user interface of 1.12 constantly call "report_countdown()", but I guess 1.13.8 doesn't do that.
When I change 1.0 to 0.01, Wesnoth prints the messages much more frequently. So, the user interface still call "report_countdown()" frequently.
Timing by os.clock() is incorrect.
~~~~~~~~~~
If I use os.time() instead of os.clock(), the timing is correct. But I only get 1 second resolution for timing instead of millisecond resolution.
New Idea: Make the code adaptively calculate how many fake miliseconds from os.clock() is equivalent to 1 real second from os.time().
That way, I get an approximate timer with milisecond resolution.
Re: Coroutine / Schedule Lua code without freezing Wesnoth
Timing by calculating approximate conversion between fake time and real time in every second.
It seems not accurate for counting 0.1 seconds.
New idea: The scheduler can use approximate time without increasingly lagging behind the actual time
if it knows how to play catch up.
It seems not accurate for counting 0.1 seconds.
Code: Select all
old_report_countdown = wesnoth.theme_items.report_countdown
old_clock = os.clock()
old_time = os.time()
old_clock2 = os.clock()
real_dt = 1.0
fake_dt = real_dt
dif = 1.0
function wesnoth.theme_items.report_countdown()
new_clock = os.clock()
new_time = os.time()
if new_time > old_time then
old_time = new_time
dif = (new_clock - old_clock + dif) / 2
old_clock = new_clock
wesnoth.message("real sec per fake sec: " .. dif)
fake_dt = real_dt * dif
end
if new_clock - old_clock2 > fake_dt then
old_clock2 = new_clock
wesnoth.message("time: "..os.time() .. ", clock: " .. os.clock())
end
return old_report_countdown()
end
if it knows how to play catch up.
Re: Coroutine / Schedule Lua code without freezing Wesnoth
It would be nice if wesnoth's c++ can provide accurate time to lua.
Like wesnoth.realtime().
Like wesnoth.realtime().
Re: Coroutine / Schedule Lua code without freezing Wesnoth
well, of course you are going to lose accuracy if you keep resetting old_time.
FYI, there is also [set_variable] time=stamp, but I don't think you need that.
FYI, there is also [set_variable] time=stamp, but I don't think you need that.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
Re: Coroutine / Schedule Lua code without freezing Wesnoth
To stop wesntoh from freezeing (to 'pull' user input) wesnoth.delay(0) is usually used.
Scenario with Robots SP scenario (1.11/1.12), allows you to build your units with components, PYR No preperation turn 1.12 mp-mod that allows you to select your units immideately after the game begins.
Re: Coroutine / Schedule Lua code without freezing Wesnoth
Sapient,
Hi. I don't quite get the part about resetting.
I would think the lua virtual machine is fast enough and resetting old_time would only lose accuracy below milliseconds.
The problem is that this old code gives perfectly accurate time in wesnoth 1.12:
It is supposed to print a message every 1 seconds.
But in wesnoth 1.13, I have to wait like about 30 seconds to get one message from the program.
If I move the cursor more often, I have to wait about 45 seconds.
Having the Lua VM to slow down 30x in 1.13 is a bit crazy.
I don't know why because I haven't dived into the c++ part of Wesnoth.
If anyone knows the reason, I am all ears.
I wish wesnoth can provide a function that give accurate system time with milliseconds resolution.
This is because os.clock() in Lua is somehow too unreliable...
When will particle effect be implemented? If it is not in the near future, I might try to make a Lua hack.
Mostly I just want to make an elf clock for fun.
Hmm. I didn't know about "time=stamp"! I might give it a try and see how accurate it is.
@gfgtdf thanks for the tip. If all else fail, I might consider taking control of every thing from Lua side and just occasionally takes in user input.
Upate:
Found "wesnoth.get_time_stamp()" at viewtopic.php?f=10&t=46370&start=0
Hi. I don't quite get the part about resetting.
I would think the lua virtual machine is fast enough and resetting old_time would only lose accuracy below milliseconds.
The problem is that this old code gives perfectly accurate time in wesnoth 1.12:
Code: Select all
local old_report_countdown = wesnoth.theme_items.report_countdown
old_time = os.clock()
function wesnoth.theme_items.report_countdown()
new_time = os.clock()
if new_time - old_time > 1.0 then
old_time = new_time
wesnoth.message(new_time)
end
return old_report_countdown()
end
But in wesnoth 1.13, I have to wait like about 30 seconds to get one message from the program.
If I move the cursor more often, I have to wait about 45 seconds.
Having the Lua VM to slow down 30x in 1.13 is a bit crazy.
I don't know why because I haven't dived into the c++ part of Wesnoth.
If anyone knows the reason, I am all ears.
I wish wesnoth can provide a function that give accurate system time with milliseconds resolution.
This is because os.clock() in Lua is somehow too unreliable...
When will particle effect be implemented? If it is not in the near future, I might try to make a Lua hack.
Mostly I just want to make an elf clock for fun.
Hmm. I didn't know about "time=stamp"! I might give it a try and see how accurate it is.
@gfgtdf thanks for the tip. If all else fail, I might consider taking control of every thing from Lua side and just occasionally takes in user input.
Upate:
Found "wesnoth.get_time_stamp()" at viewtopic.php?f=10&t=46370&start=0
Re: Coroutine / Schedule Lua code without freezing Wesnoth
- Timer that catches up with target.
- At most 1 millisecond unrecoverable lag/gain per firing.
- Works in 1.13
- 3% cpu load ...
Code: Select all
local old_time = wesnoth.get_time_stamp()
local old_report_countdown = wesnoth.theme_items.report_countdown
local target = 1000
local dif, new_time
local target2 = target
function wesnoth.theme_items.report_countdown()
new_time = wesnoth.get_time_stamp()
dif = new_time - old_time - target2
if dif >= 0 then
old_time = new_time
target2 = target - dif
wesnoth.message(old_time)
end
return old_report_countdown()
end
- Timer that catches up with target.
- No unrecoverable lag/gain
- Works in 1.13
- 11% cpu load ...
Code: Select all
local old_report_countdown = wesnoth.theme_items.report_countdown
local target = 1000
local new_time
local target_time = wesnoth.get_time_stamp() + target
function wesnoth.theme_items.report_countdown()
new_time = wesnoth.get_time_stamp()
if new_time >= target_time then
target_time = target_time + target
wesnoth.message(new_time)
end
return old_report_countdown()
end
- Timer that catches up with target.
- No unrecoverable lag/gain
- Works in 1.13
- 3% cpu load ...
Code: Select all
local old_report_countdown = wesnoth.theme_items.report_countdown
local target = 1000
local dif
local target_time = wesnoth.get_time_stamp() + target
function wesnoth.theme_items.report_countdown()
dif = wesnoth.get_time_stamp() - target_time
if dif > 0 then
wesnoth.message(target_time)
target_time = target_time + target
end
return old_report_countdown()
end
- 2.5% cpu load
Code: Select all
local old_report_countdown = wesnoth.theme_items.report_countdown
local target = 1000
local target_time = wesnoth.get_time_stamp() + target
function wesnoth.theme_items.report_countdown()
if wesnoth.get_time_stamp() - target_time > 0 then
wesnoth.message(target_time)
target_time = target_time + target
end
return old_report_countdown()
end
- Celtic_Minstrel
- Developer
- Posts: 2216
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Coroutine / Schedule Lua code without freezing Wesnoth
For the record, coroutines in Lua are supported only starting in 1.13, so since you're using 1.12, they won't be available.