hossimo / GMA3Plugins

Plugins and unofficial lua docs for the grandMA3 Lighting Console.
MIT License
78 stars 5 forks source link

Timer() #36

Closed GralfR closed 1 year ago

GralfR commented 1 year ago

Some more info on the Timer() Function:

If the parameter maxCount is zero, then the timer runs forever. If the parameter is not zero, then the timer runs the given number of loops. Compared to Timer inside LUA on MA2.

The parameter "cleanup" is the name of a function, that is called, when the timer is stopped. You can use this to run a certain task once the plugin is stopped. I use this to restart the plugin when it should run forever (maxCount=0) and was stopped by user. See issue #35 for an example.

hossimo commented 1 year ago

Hey there thanks for the note, I'll add this later.

Just a guess here but I believe there is another parameter that you can pass to Timer(), it seems to give it some context when stopping. I'm not 100% sure since the internal documentation is not clear and I can't find a proper example except one that uses signals that I can't dig into right now.

The function signature seems to be the following:

Timer(
        function : name,
        number : delaytime,
        number : max_count,
        [function : cleanup],
        [light_userdata : context]
) -> nothing

If I pass anything to the context parameter it just does not call the cleanup function. so my guess is this stop call happens outside of the context of the user's runtime so it does not have access to the CurrnetUser() for like you did in #35 thus it gets a nil value causing the error.

I tried passing the handle:

local handle = select(4,...);
Timer(running, 1, 0, stop, handle)

as well as the display_handle:

local function start(display_handle)
    Timer(running, 1, 0, stop, display_handle)
end

I even tried passing self:

    Timer(running, 1, 0, stop, self)

but each just causes the cleanup function not to run, I wonder what this value should be?

anyway, testing for nil is a workaround for the moment.

local function stop()
    Echo("Stopping")
    if CurrentUser() == nil then
        Echo("Timer Stopped")
    else
        Printf("timer stopped by "..CurrentUser().Name)
    end
end
GralfR commented 1 year ago

Thanks for testing and the effort with examples. Testing the CurrentUser() for nil is just a workaround to not let the plugin crash on cleanup, but it's not an option for my initial goal: testing, if the user has the right to stop the plugin and the timer. This was easy in MA2, but a big problem on MA3, since a guest-user with playback-rights may stop a plugin but is not allowed to start it (bug already reported to MA). My goal was to check not only the user-name but the user-rights the current user has, when the plugin was stopped and then for example try to restart the plugin or do other things. This was no problem on MA2.

Concerning the last argument I have no clue at all. I did not understand the whole object-structur on MA3 LUA yet. The last argument did not exist in MA2 LUA. So I can't explain, what it might be for. Maybe it's not yet implemented because it's optional. Or the hint "context" might give a clue: maybe it's the environment, the timer should run, or it's the context in which the timer was stopped. Maybe it's not an argument passed to the timer but a placeholder for a feedback/return-value of the timer? I just started the transition from MA2 LUA to MA3 and it's very hard to learn new stuff, that is not well documented. What is the object-structure of MA3? What's about the "signals" or "hooks"? Are these trigger/interrupts? I never got deep into LUA. Just the few things is needed for MA2. Tried to dig a bit deeper into LUA but was stuck soon because MA2 did not have certain libraries included. Maybe this is better on MA3, but nobody knows because of the lack of good introduction, what MA3 means for LUA. I can get LUA tutorials everywhere, but they don't know about MA3-objects/functions. So it stays a nightmare to reverse-engineer and spend a lot of time for trial and error. Thanks for Your effort in this! Hope You'll find enough time to keep this up and maybe write a MA3-LUA-Beginners-Tutorial for anybody that knows LUA, but needs a MA3 LUA jumpstart.

hossimo commented 1 year ago

back early in v1.1 or maybe 1.2, I made a few test plugins using coroutines.

Before markers were a thing I made this to see how well I could do moving trusses. It worked well but I didn't spend much time ironing out the bugs so I never released the code. But looking at the video and the code again I see that the Plugin was not running and if I recall the coroutine ran in the background without keeping the plugin or the UI busy.

It's been a few years since I looked at this code but this was the main pump of the plugin.

Basically, it would loop until run was false and wait for the rate (1/30 for example)

local function Main(display_handle, argument)
    local arguments = Drt.split(argument, ",")
-- ...
        -- For the moment just set the arguments to the result of r
        arguments = {}
        arguments[1] = r.run
        arguments[2] = r.fid
        arguments[3] = r.posz
        arguments[4] = r.posx
        arguments[5] = r.posy
        arguments[6] = r.rotz
        arguments[7] = r.rotx
        arguments[8] = r.roty
        arguments[9] = r.scalez
        arguments[10] = r.scalex
        arguments[11] = r.scaley
    end

    if tostring(arguments[1]) == "0" then
        E("Stopping Kinetic")
        run = false
    end
    if tostring(arguments[1]) == "1" then
        run = false
        coroutine.yield(rate * 2)
        E("Starting Kinetic")
        run = true
    end
-- ...
while run do
        if speedPos.z > 0.0 then translate("posz") end
        if speedPos.x > 0.0 then translate("posx") end
        if speedPos.y > 0.0 then translate("posy") end

        if speedRot.z > 0.0 then translate("rotz") end
        if speedRot.x > 0.0 then translate("rotx") end
        if speedRot.y > 0.0 then translate("roty") end

        coroutine.yield(rate)
end

USBStomper or maybe even FadeMaster are other examples of coroutines. that I have messed with.

About that last argument, it would be really helpful to know what it wants, but you could be right and it might not be implemented yet. the only example I found was commented out in system_test_dev.lua

signalTable.OnLoaded = function(caller,status,creator)
    local testSelector = caller.Content.TestList;
    testSelector:AddListStringItem("WorkInProgress","");
    testSelector:AddListStringItem("Test","");
    testSelector:SelectListItemByIndex(1);

    -- HookObjectChange(signalTable.PluginsChanged,  -- 1. function to call
    -- DataPool().Plugins,                 -- 2. object to hook
    -- my_handle:Parent(),                 -- 3. plugin object ( internally needed )
    -- caller)                             -- 4. user callback parameter

    -- Timer(delayedInit,1,0,nil,caller)

    LoadSystemTest()
    UpdateStatusButton(overlay.Content.Status)
end

For sure LUA needs a ton more documentation, I know they have been adding to the Manual over time but I'm sure it will take a while. I kind of fell off on updating the wiki, one because I've been busy and 2 because they started documenting LUA. I was hoping they would be further along by now but I still get a fair amount of traffic onto the wiki last I checked.

I'll try and keep it up to date when things slow down a little.

hossimo commented 1 year ago

I finally got around to updating this:

https://github.com/hossimo/GMA3Plugins/wiki/Timer