[SOLVED] Execute local function by name from table

Discussion in 'Programming' started by Agent_Y, Mar 15, 2022.

  1. Agent_Y

    Agent_Y
    Expand Collapse
    Jbeam/QA support
    BeamNG Team

    Joined:
    Jul 10, 2020
    Messages:
    10,061
    So I have a table with function names and I need to select a random one from them and execute it. This works:
    Code:
    local randomFunction = toggleDamages[math.random(#toggleDamages)] --select random function from table
    load(randomFunction.."()")() --execute it
    
    But only on global functions. Alternatively:
    Code:
    local randomFunction = toggleDamages[math.random(#toggleDamages)] --select random function from table
    _G[randomFunction]() --execute it
    
    Also works only on global ones.
    Is a similar thing possible with local functions? Or do I have to keep my ones global? I know about loadString but it doesn't work in the game as it uses LUA 5.1 and that was added in 5.4, and not sure if it would have worked anyway.
     
  2. vulcan-dev

    vulcan-dev
    Expand Collapse

    Joined:
    Jan 28, 2017
    Messages:
    245
    Here, this works. Maybe there's a better way, not sure but I'll look into it.
    Code:
    -- [[ Utility Function ]] --
    local function TableLength(T)
      local count = 0
      for _ in pairs(T) do count = count + 1 end
      return count
    end
    
    -- [[ Function Table ]] --
    local Functions = {
        F1 = function() print('F1') end,
        F2 = function() print('F2') end,
        F3 = function() print('F3') end,
        F4 = function() print('F4') end,
        F5 = function() print('F5') end,
        F6 = function() print('F6') end,
    }
    
    local function Main()
        -- Generate random number from 1 to the length of the table
        math.randomseed(os.time())
        local rand = math.random(1, TableLength(Functions))
    
        local i = 1 -- Iterations
        for k in pairs(Functions) do
            if i == rand then -- If the iteration is the random number then call the function
                Functions[k]()
                break
            end
    
            i = i + 1 -- Increase iterations
        end
    end
    
    Main()
     
  3. Agent_Y

    Agent_Y
    Expand Collapse
    Jbeam/QA support
    BeamNG Team

    Joined:
    Jul 10, 2020
    Messages:
    10,061
    The table I am using is variable, can have or not have certain functions in it, can even be empty, so they need to be called by name specifically instead of a number like this. Also can't put the whole function code in a table as they are hundreds of lines long, I would need 1 line dummy functions that call those functions and do nothing else.
     
  4. vulcan-dev

    vulcan-dev
    Expand Collapse

    Joined:
    Jan 28, 2017
    Messages:
    245
    Alright, if that's the case then just check if it's nil.
    Code:
    if Functions[funcName] ~= nil then ... end
     
  5. Agent_Y

    Agent_Y
    Expand Collapse
    Jbeam/QA support
    BeamNG Team

    Joined:
    Jul 10, 2020
    Messages:
    10,061
    I didn't think of it, this could work, thanks!
     
  6. vulcan-dev

    vulcan-dev
    Expand Collapse

    Joined:
    Jan 28, 2017
    Messages:
    245
    Alright, no problem :)
     
  7. Agent_Y

    Agent_Y
    Expand Collapse
    Jbeam/QA support
    BeamNG Team

    Joined:
    Jul 10, 2020
    Messages:
    10,061
    That still only works if the declared functions are global... It just changes the functions that I need to make global, previously the main ones, now the ones in the table
     
    #7 Agent_Y, Mar 18, 2022
    Last edited: Mar 18, 2022
  8. _N_S_

    _N_S_
    Expand Collapse

    Joined:
    Oct 28, 2017
    Messages:
    66
    Same, but in 2 lines:)

    Code:
    local Functions = {
        F1 = function() print('F1') end,
        F2 = function() print('F2') end,
        F3 = function() print('F3') end,
        F4 = function() print('F4') end,
        F5 = function() print('F5') end,
        F6 = function() print('F6') end
    }
    
    local function Main()
        if tableSize(Functions) == 0 then return end
        Functions[tableKeys(Functions)[math.random(tableSize(Functions))]]()
    end
    
     
  9. angelo234

    angelo234
    Expand Collapse
    Programmer
    BeamNG Team

    Joined:
    Aug 11, 2017
    Messages:
    540
    The reason why it might not be working is that the Functions table needs to appear after the declared functions and not before. So it should look something like this and you only need to add the functions to the table like this:
    Code:
    local M = {}
    
    local function F1()
        print('F1')
    end
    
    local function F2()
        print('F2')
    end
    
    local Functions = {
        F1,
      F2
    }
    
    local function onExtensionLoaded()
        if tableSize(Functions) == 0 then return end
        Functions[math.random(tableSize(Functions))]()
    end
    
    M.onExtensionLoaded = onExtensionLoaded
    
    return M
     
  10. Agent_Y

    Agent_Y
    Expand Collapse
    Jbeam/QA support
    BeamNG Team

    Joined:
    Jul 10, 2020
    Messages:
    10,061
    The problem in my case is that the table with functions needs to be editable from the js side, I need to dynamically insert and remove functions from it... How do I know if they are declared at the moment of executing the function from js that adds or removes them?
     
  11. angelo234

    angelo234
    Expand Collapse
    Programmer
    BeamNG Team

    Joined:
    Aug 11, 2017
    Messages:
    540
    This should do the trick. So to add a function, call addFunction("function name"). Remove a function using removeFunction("function name"). Get all functions with getFunctions(). And call a function with callFunction("function name") and callRandomFunction() for random function. You want to add all the possible functions that can be used in the fullFunctionsLists table.

    Code:
    local M = {}
    
    local function F1()
        print('F1')
    end
    
    local function F2()
        print('F2')
    end
    
    local function F3()
        print('F3')
    end
    
    local fullFunctionsLists = {
        ['F1'] = F1,
        ['F2'] = F2,
        ['F3'] = F3
    }
    
    local functions = {}
    
    local function addFunction(func)
        if fullFunctionsLists[func] then
            functions[func] = fullFunctionsLists[func]
        end
    end
    
    local function removeFunction(func)
        functions[func] = nil
    end
    
    local function getFunctions()
        return functions
    end
    
    local function callFunction(func)
        if functions[func] then
            functions[func]()
        end
    end
    
    local function callRandomFunction()
        functions[tableKeys(functions)[math.random(tableSize(functions))]]()
    end
    
    local function onExtensionLoaded()
        --if tableSize(functions) == 0 then return end
        --functions[math.random(tableSize(functions))]()
    end
    
    M.addFunction = addFunction
    M.removeFunction = removeFunction
    M.getFunctions = getFunctions
    M.callFunction = callFunction
    M.callRandomFunction = callRandomFunction
    M.onExtensionLoaded = onExtensionLoaded
    
    return M

    And here's some JS side code for using this for example (assumming calling GE Lua functions):
    Code:
    bngApi.engineLua('scripts_test_extension.addFunction("F1")');   
    bngApi.engineLua('scripts_test_extension.addFunction("F2")'); 
    bngApi.engineLua('scripts_test_extension.addFunction("F3")'); 
    bngApi.engineLua('scripts_test_extension.callRandomFunction()');    
     
    • Like Like x 1
  12. Agent_Y

    Agent_Y
    Expand Collapse
    Jbeam/QA support
    BeamNG Team

    Joined:
    Jul 10, 2020
    Messages:
    10,061
    This will do, thanks!
    EDIT: It works!!! I will credit you in the mod, if I forget then remind me!
     
    #12 Agent_Y, Mar 19, 2022
    Last edited: Mar 22, 2022
    • Like Like x 1
  13. angelo234

    angelo234
    Expand Collapse
    Programmer
    BeamNG Team

    Joined:
    Aug 11, 2017
    Messages:
    540
    Good to know it actually works :)
     
  1. This site uses cookies to help personalise content, tailor your experience and to keep you logged in if you register.
    By continuing to use this site, you are consenting to our use of cookies.
    Dismiss Notice