2
\$\begingroup\$

I've been working with Lua for sometime and there is a problem that I could never solve it. First, I'm using a single lua state to have a connection between my scripts so they could transfer data via global table _G.

My scripts have a template like this:

-- Vars
local somevar = 0

-- Update
function Update()
  -- stuff
end

I call Update() function from my application every game step, but since there are other scripts loaded in current lua state with the same template only the Update() function from the last chunk in lua is getting called and there is no way I can call all of Update() functions in my scripts.

If I load my scripts every time I want to call the functions, It'll work the way I want, but this way my local variables and every change that I have made to the scripts would get dumped because the chunk is replaced with a new one.

I've seen a message on Lua's site itself which talks about setting an environment for each chunk that is going to get loaded, but that's not what I want because it forces each script to reside in a unique table and there is no way to communicate with global table since we're going to override the global table for our unique tables.

I'd really appreciate if someone give me some advice because there isn't really much on the internet about these kinds of stuff.

UPDATE

I know the answer to first part of my question. Right now I'm using a table for each of my scripts, something like this:

code1.lua

code1 = {}

function code1.Update()
  -- Update
end

This makes every script accessible via the global table with their table name. The problem is if I load this script for another object in my game, then it'll conflict with the previously loaded script because they're both using the same source and therefore the same names and I can only access the last loaded. As you can see, I've stated this about environments in first part of my question.

\$\endgroup\$
1
\$\begingroup\$

I had same problem and I solved it with event system

local __events = {}
function addEventListener(event, callback)
    local listeners = __events[event]
    if listeners ~= nil then
        listeners[#listeners + 1] = callback
    else
        __events[event] = {callback}
    end
end

function trigger(event, ...)
    local listeners = __events[event]
    if listeners ~= nil then
        for i = 1, #listeners do
            listeners[i](...)
        end
    end
end

Add event listener function saves callback function into table with array of functions for each event. Trigger function find array of functions for event and call all of them. For each event C code will call I create one function which just call trigger("EventName")

function event_update(elapsed)
    trigger("update", elapsed)
end

And all other scripts use

addEventListener("update", function(elapsed)

end)
\$\endgroup\$
  • 1
    \$\begingroup\$ I guess a downside of this method is that you can't easily trigger a single update. \$\endgroup\$ – Sergio Jul 31 '14 at 16:46
1
\$\begingroup\$

You can use environments and communicate using the global table using metatables, which will allow the local environment to inherit the global one. With Lua 5.2:

function loadEnv(file)
    local newenv = {}
    setmetatable(newenv, { __index=_G })
    loadfile(file, "bt", newenv)()
    return newenv
end
globalVar = "Global"
newenv1 = loadEnv("update1.lua")
newenv2 = loadEnv("update2.lua")

newenv1.Update()
newenv2.Update()

With the scripts:

-- update1.lua
local somevar = 0
print(_ENV)
function Update()
    print("update1")
    print(somevar)
    print(globalVar)
    _G.globalVar = "global2" -- use this to create/modify a global variable
end

And

-- update2.lua
local somevar = 1
print(_ENV)
function Update()
    print("update2")
    print(somevar)
    print(globalVar)
end

You'll get:

table: 0044ED78
table: 009C9AC0
update1
0
Global
update2
1
global2
\$\endgroup\$
  • \$\begingroup\$ Well I intended to do that, but I did it another way. I'm using a unique table for each script which is pretty similar to this method, but the problem with this is whenever I create two objects which have two scripts with the same source, there would be this whole thing again because I can't choose a unique name for every runtime created object. \$\endgroup\$ – MahanGM Jul 31 '14 at 11:33
  • \$\begingroup\$ You can run the scripts as many times as you want, and they will remain independent as they will have their own private environment. This is because the environment is set externally, and not in the script itself. The table returned by loadEnv represents the object. \$\endgroup\$ – Sergio Jul 31 '14 at 16:41
  • \$\begingroup\$ I think I'm not clear enough. For example, newenv1 and newenv2 are written by us which means we've written them with further information about the code. What I say is, I create real game objects in C++ which they have a script list to run. When I create instances from these objects at runtime I can't choose a unique environment name for each of the newly created scripts, therefore I don't have any access to them after that. Thanks for your answer anyway. \$\endgroup\$ – MahanGM Jul 31 '14 at 19:29
  • \$\begingroup\$ You might want to edit the question then, to add clarity, and describe the solution you went with. \$\endgroup\$ – Sergio Jul 31 '14 at 20:17
  • \$\begingroup\$ I'm afraid that makes it two questions in a row. That's why I tended to ask one. I'll add extra information. \$\endgroup\$ – MahanGM Aug 1 '14 at 13:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.