AshitaXI / Ashita

Issue tracker and wiki for the Ashita project.
https://ashitaxi.com/
7 stars 1 forks source link

[BUG] Error forwarding arguments to ashita.tasks.once #64

Closed FurryDT closed 2 weeks ago

FurryDT commented 1 month ago

Ashita Version (Type /ashita in-game to get this.) v4.2.0.3

FFXI Version (Type /version in-game to get this.) HorizonXI Game v1.2.7 (update 13)

Windows Version (ie. Start > About Your PC) Windows 11 Home

Describe The Bug When trying to use the argument forwarding for function sugar once, it gives error when calling underlying ashita.tasks.once here: https://github.com/AshitaXI/Ashita-v4beta/blob/612a57932acaa9862ab248de709a1df27700d89f/addons/libs/sugar/function.lua#L668

Steps To Reproduce Please give a clear, full list of steps to reproduce the bug, if applicable. Example addon code to reproduce:

addon.author   = 'FurryDT';
addon.name     = 'Test';
addon.desc     = 'Test Addon';
addon.version  = '0.0';

require ('common');

ashita.events.register('command', 'command_cb', function (e)
    -- Parse the command arguments..
    local args = e.command:args();
    if (#args == 0 or not args[1]:any('/test')) then
        return;
    end

    -- Block all related commands..
    e.blocked = true;

    local function foo(x)
        print(x);
    end
    -- working call
    print('Calling function with no delay:');
    foo('this is foo');
    -- broken delayed call
    print('Calling function with delay:');
    foo:once(2, 'this is delayed foo');

end);

Screenshots If applicable, add screenshots to help explain your problem. Error

Additional Information Please include any additional information you feel could help explain the bug/problem and get it resolved.

ConteAlmaviva commented 2 weeks ago

I think I am encountering the same problem, although it appears to happen when using ashita.tasks.once and not solely when using the sugar syntax. A function that doesn't take any arguments will work just fine, but if the function takes an argument, attempting to pass that argument in using ashita.tasks.once(delay,funcname,arg1) results in the error shown in OP. (I haven't yet tried with a function that takes two or more arguments.)

atom0s commented 2 weeks ago

Hello there, sorry for the delayed response. This is technically not a bug, and is rather an issue with some of our library code that was not updated after a bugfix that was done in the past. A few years ago, a critical bug was discovered in the binding library we use that prevents arguments from being passed (directly) to a coroutine when crossing the Lua/C++ bounds. This bug would cause said arguments to become corrupted. Due to this, we changed how the bindings are exposed for the task system, which mainly just removed the ability to directly pass arguments.

This means the following has changed:

-- Before (accepted arguments)..
ashita.tasks.once(func, ...);
ashita.tasks.once(delay, func, ...);
ashita.tasks.oncef(delay, func, ...);
ashita.tasks.repeating(delay, repeats, repeat_delay, func, ...);
ashita.tasks.repeatingf(delay, repeats, repeat_delay, func, ...);

-- After (no longer accepting arguments)..
ashita.tasks.once(func);
ashita.tasks.once(delay, func);
ashita.tasks.oncef(delay, func);
ashita.tasks.repeating(delay, repeats, repeat_delay, func);
ashita.tasks.repeatingf(delay, repeats, repeat_delay, func);

It appears I missed a few things in our libs (mainly sugar's function lib) that account for this change.

However, this does not mean you are not able to use arguments when calling functions passed to coroutines. Instead, you simply need to make use of 'bound functions' when passing a function to any of these calls now. The sugar library makes this easy by using the bind related helpers.

Here's an updated version of the example in the main post above that should work with these changes:

ashita.events.register('command', 'command_cb', function (e)
    local args = e.command:args();
    if (#args == 0 or not args[1]:any('/test')) then
        return;
    end

    e.blocked = true;

    local function foo1(str)
        print(str);
    end
    local function foo2(str1, str2);
        print(str1 .. ' ' .. str2);
    end

    -- No delay example..
    foo1('called foo1, no delay');

    -- Delay example..
    foo1:bind('called foo1, with delay'):once(2);

    -- Delay example, multiple arguments..
    foo2:bindn('called foo2, with delay', 'and multiple arguments'):once(2);
end);