Coroutine / Schedule Lua code without freezing Wesnoth

Discussion of Lua and LuaWML support, development, and ideas.

Moderators: Forum Moderators, Developers

Coroutine / Schedule Lua code without freezing Wesnoth

Postby Yutmeal2 » October 16th, 2017, 7:51 am

How to use coroutines included in multiplayer scenario?

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)

[/code]

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.
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutines

Postby Tad_Carlucci » October 16th, 2017, 1:51 pm

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.
I forked real life and now I'm getting merge conflicts.
Tad_Carlucci
Developer
 
Posts: 204
Joined: April 24th, 2016, 4:18 pm

Re: Coroutines

Postby Yutmeal2 » October 16th, 2017, 6:51 pm

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.
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutines

Postby Tad_Carlucci » October 17th, 2017, 12:38 am

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 forked real life and now I'm getting merge conflicts.
Tad_Carlucci
Developer
 
Posts: 204
Joined: April 24th, 2016, 4:18 pm

Re: Coroutines

Postby Yutmeal2 » October 17th, 2017, 1:08 am

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())
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutines

Postby shadowm » October 17th, 2017, 1:23 am

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.
I also made Wesnoth RCX, a team-color preview tool for artists and content creators.
Elsewhere: shadowmBlogFollow me on Twitter
User avatar
shadowm
Wesnoth.org Administrator
 
Posts: 6182
Joined: November 14th, 2006, 5:54 pm
Location: Chile

Re: Coroutines

Postby Yutmeal2 » October 17th, 2017, 4:51 am

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.

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}},
    })


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...
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutines

Postby Yutmeal2 » October 17th, 2017, 5:47 am

This works:

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


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.
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutine / Schedule Lua code without freezing Wesnoth

Postby Yutmeal2 » October 18th, 2017, 6:14 am

Timing by calculating approximate conversion between fake time and real time in every second.
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


New idea: The scheduler can use approximate time without increasingly lagging behind the actual time
if it knows how to play catch up.
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutine / Schedule Lua code without freezing Wesnoth

Postby Yutmeal2 » October 20th, 2017, 2:05 am

It would be nice if wesnoth's c++ can provide accurate time to lua.
Like wesnoth.realtime().
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutine / Schedule Lua code without freezing Wesnoth

Postby Sapient » October 20th, 2017, 6:17 am

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.
http://www.wesnoth.org/wiki/User:Sapient... "Looks like your skills saved us again. Uh, well at least, they saved Soarin's apple pie."
User avatar
Sapient
Developer
 
Posts: 4363
Joined: November 26th, 2005, 7:41 am

Re: Coroutine / Schedule Lua code without freezing Wesnoth

Postby gfgtdf » October 20th, 2017, 5:44 pm

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.
gfgtdf
Developer
 
Posts: 910
Joined: February 10th, 2013, 2:25 pm

Re: Coroutine / Schedule Lua code without freezing Wesnoth

Postby Yutmeal2 » October 21st, 2017, 2:14 am

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:

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


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
Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutine / Schedule Lua code without freezing Wesnoth

Postby Yutmeal2 » October 21st, 2017, 3:18 am

  • 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

Yutmeal2
 
Posts: 13
Joined: October 14th, 2017, 3:02 am

Re: Coroutine / Schedule Lua code without freezing Wesnoth

Postby Celtic_Minstrel » October 24th, 2017, 4:39 am

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.
Author of The Black Cross of Aleron campaign and Default++ era.
Maintainer of Steelhive.
User avatar
Celtic_Minstrel
Developer
 
Posts: 769
Joined: August 3rd, 2012, 11:26 pm


Return to Lua Labs

Who is online

Users browsing this forum: No registered users and 1 guest