[LUA] Sharing function between files when it returns a value

Perkus

Prince
Joined
Oct 16, 2010
Messages
316
Location
Ontario, Canada
The Modders' Guide p.13-14 shows how you can call the same function from different .lua script files by wrapping it with LuaEvents.FunctionName.Add(); I was able to successfully use this in an earlier mod where the function did not return any values.

I'm working on another mod where I need a shared function to return a value. I wrote it the same way, but it doesn't work right. The modder's guide doesn't address this situation. I'm guessing that going through this LuaEvents() hook prevents it from returning a value to the caller. Am I understanding this right? Is there something I can do to share a function that needs to return a value?

I guess I can duplicate the function in both files if I have to but it's very bad practice to have to maintain two identical versions...


Thanks in advance for any help you can provide.
 
If your files are within the same mod then it shouldn't matter if you are calling functions from different files or not. You should check thought that your function is initiated at the time when you call it. You will fail the function call if:
  • File A calls the function, but file B (where the function actual is) is not initiated yet. Make sure that you run these functions AFTER all your files are initiated.
  • File B (where the function actual is) is never read. Put a simple print("File X initiated") on top of every file to troubleshoot this.

That LuaEvents is normally supposed to be used if your wish to call a function from another mod. Here's an example how to pass values with it.

Code:
function HelloWorld(msg)
	print(msg)
end

--Adds HelloWorld-function to Hello-event
--Function name must be without parenthesis!
--Wrong: LuaEvents.Hello.Add(HelloWorld())
LuaEvents.Hello.Add(HelloWorld)

--Launch Hello-event
LuaEvents.Hello("Hello World")
 
Thanks! They are being shared within the same mod, but I never tried just calling it, I assumed I needed a LuaEvent. That's because the modder's guide just states "Lua scripts cannot directly call functions in other Lua scripts." It doesn't indicate that it matters if they're in one mod or not. I'll give that a try.

You example for passing values is showing how to pass arguments INTO an event function. I don't have a problem with that, what I was trying to do is get a value returned from the event function, and simply saying:
local result = LuaEvents.FunctionName(arguments);
which wasn't working.
 
I'm pretty sure each file runs in its own environment but has access to superglobals like GameInfo. So two separate files aren't going to naturally see each others functions or local globals. But an include("filename") statement in one file will include all the other file's contents, thus they will share the same environment and can both call each other's functions and overwrite each other's local globals. However, an include statement isn't always the answer. It's case specific. That's the reason for LuaEvents.

I am uncertain if LuaEvents become available across concurrent mods. That would be very interesting if they do.

The solution to your problem might be to store the intended return data either in the database or in an available superglobal to be retrieved by reference. You might be able to use GameInfo for that purpose, but I've never experimented with that. Tell us what you learn if you do.
 
I'm pretty sure each file runs in its own environment but has access to superglobals like GameInfo. So two separate files aren't going to naturally see each others functions or local globals. But an include("filename") statement in one file will include all the other file's contents, thus they will share the same environment and can both call each other's functions and overwrite each other's local globals. However, an include statement isn't always the answer. It's case specific. That's the reason for LuaEvents.
Hmm. There seem to be two ways of including files. Using that modinfo-files entrypoint-parameter (eg. InGameUIAddin) or using include statements in your main file (which you loaded with that entrypoint-parameter). Difference is that entrypoint-parameter creates a separate environment for every file, but include keeps them in the same environment. So I'm basically just repeating what you said. ;)

I always used that include method myself. Just include everything in the main file and then all your stuff is in the same environment.

You example for passing values is showing how to pass arguments INTO an event function. I don't have a problem with that, what I was trying to do is get a value returned from the event function, and simply saying:
local result = LuaEvents.FunctionName(arguments);
which wasn't working.

You can return a value from a LuaEvent using a "return-event". Like this:
Code:
function HelloWorld(msg)
	print(msg)
	LuaEvents.HelloReturn(msg.." again")
end

function HelloWorldReturn(msg)
	print(msg)
end

--Adds HelloWorld-function to Hello-event
--Function name must be without parenthesis!
--Wrong: LuaEvents.Hello.Add(HelloWorld())
LuaEvents.Hello.Add(HelloWorld)
LuaEvents.HelloReturn.Add(HelloWorldReturn)

--Launch Hello-event
LuaEvents.Hello("Hello World")

LuaEvents do come available across all mods and even core files. I just tested this with two different mods. I also confirmed that the calling environment has access to values from the source environment. I could even pass a function using this method. There is something tricky about this thought since I wasn't able to save this function to the target environment?
 
Thanks again guys, I'm still trying to digest all that. I think I understand it. For my simple purposes, the include method should be quite sufficient, I think. It did occur to me later than I could use a global to store the result, too. The return-event technique is pretty cool, but overkill for my needs, I believe.
 
I always used that include method myself. Just include everything in the main file and then all your stuff is in the same environment.

It's case specific tho. For example, I'm currently working on a NotificationPanel.lua replacement. The code has to go there for the superglobal ContextPtr to work properly with the rest of the UI. There are other UI files that work the same way. I'm not sure placing an include("main file") statement at the top of both files is going to give me good results. Thus I would have 3 files, my main file plus 2 separate UI files, none of which would include one another. So if I want to call functions of one from another, then I have to use LuaEvents.
 
To return a value from a LuaEvent, just pass an empty table (or something) that is passed by reference. The event function will modify it with a return value (or several), and once the event is resolved it will be changed when the calling code resumes.

Oh, and I believe that LuaEvents are supposed to be cross-mod, but it's not terribly clear.
 
Top Bottom