Jump to content

[REL] bakaGaijin - No more exports/elements. Save metatables


Recommended Posts

Hello community. This is my first decent post on the forums, so bear with me.

Currently, if you want two resources to share some data, or call some functions from each other, there are two methods:

-You could use exports to call functions in another resource. Such a function needs to be global, defined statically in meta.xml, and called using exports.

In such a function call, only certain datatypes are transferred. Functions, etc are lost. Any tables transferred are passed by value not reference (You get a copy, so any changes you make do not change the actual table) and any information about metatables is lost.

-You could use elements. Information can be shared and set using setElementData, and functions can be called by making the functions event handlers, and using triggerEvent instead of function calls.

Again, function objects cannot be passed, tables are passed by value, and metatables are not applied.

The syntax for these is also terrible and inconvenient.

I bring to you, bakaGaijin.

The one stop solution for all your inter resource communications.

-Now, letting another resource use your function is as easy as:

  
--This is the first resource, called "Resource1" 
bakaGaijin.SomeFunction = function() 
outputChatBox("Hello world") 
end 
  
 
  
--This is the second resource, called "Resource2" 
bakaGaijin("Resource1").SomeFunction() 
--Resource1 will output "Hello World" 
  
 

No need to edit the meta.xml file for every time you wish to export some thing.

The sharing is done at runtime!

The syntax to "export" something is:

bakaGaijin.EXPORTED_NAME = SOME_VALUE

SOME_VALUE can be anything, not just a function.

So you can even expose your tables to other resources.

Or constant literals, anything you want.

  
--This is the first resource, called "Resource1" 
bakaGaijin.SomeTable = {1, 2, 3} 
  
 
  
--This is the second resource, called "Resource2" 
local table = bakaGaijin("Resource1").SomeTable 
for i, v in ipairs( table ) do 
outputChatBox(v) 
table[i] = 0 
end 
  
 

Tables are passed BY REFERENCE. So any changes you make to the table are actually reflected on the one in the other resource.

This means that after Resource2 has run, the table that was in Resource1 will have 0 for all it's values.

(This assumes Resource2 was started after Resource1, for the table to exist first)

Functions are not lost, and are transferred safely. So they can be used as parameters for other functions, can be returned by a function, stored in a table etc.

Tables do not lose any values. Tables with functions in them (key or value) transfer while preserving the functions.

Metatables are also not lost. Any __newindex or __index metamethods you set on a table will be active even when it is passed to another resource.

(Caveat: Only the host resource that originally created the table can set it's metatable properly. I'll fix this in later versions of the resource)

On top of that, it's fast. I've optimized it so that you will never even feel that you're working with different virtual machines at the same time.

To use bakaGaijin, all you need to do is:

1) Export a function called "bakaGaijin_export" in your meta.xml file for the resource that wants to use bakaGaijin.

2) Make sure you download and start bakaGaijin before the resources that will use it.

You can download bakaGaijin from https://github.com/Luca-spopo/bakaGaijin

(If you're a developer, then folk the repo to show your appreciation! Contributions are welcome, just send me a pull request)

3) Append this line to your program:

loadstring(exports["bakaGaijin"]:use())() 
 

OR

add bakaGaijin.lua (provided in the folder bakaGaijin) to your meta.xml file as a script. (Before all other scripts)

This:

  
element = createElement() 
setElementData(element, "x", 200.001) --Used to give floating point errors at some point 
setElementData(element, "y", 100) --Also, the field names must be strings AFAIK 
exports["SomeResource"]:sendElementToMe(element) --The colon notation changes the signature of the function 
  
 

turns into this:

  
local table = {x=200.001, y=100, 1, 2, 3, 4,  = table} --Indices dont have to be strings, and recursion is allowed 
bakaGaijin("SomeResource").sendElementToMe(table) 
  
 

This also means that you can make and use Lua classes across resources. No need to include files made by other people into each one of your resource.

So something like 50p's GUI classes https://forum.multitheftauto.com/viewtopic.php?f=108&t=24122&hilit=class can become an actual part of DxLib.

(In fact, my current project is to use bakaGaijin to make my own dxGUI library)

You can do some really cool shiz with bakaGaijin. Remember, the objects that you are exposing using bakaGaijin.blabla are only the "named" objects. Any objects belonging to the closure or a table in blabla are also accessible.

Moreover, bakaGaijin.blabla itself is an object, and can be used as such. You can use it as a parameter if you want.

Something like this is totally valid:

  
--Resource1 
loadstring(exports["bakaGaijin"]:use())() 
  
bakaGaijin.fun1 = function(a, b, c) 
     bakaGaijin("Resource2").checkA(a) 
     b.i = true 
     bakaGaijin("Resouce2").checkB() 
     assert(c==bakaGaijin.fun1) 
end 
  
 
  
--Resource2 
loadstring(exports["bakaGaijin"]:use())() 
  
local a = function() end 
local b = {i = false} 
local c = bakaGaijin("Resource1").fun1 --Assuming Resource1 started first. 
bakaGaijin.checkA = function(par) 
     local keyTest = {} 
     keyTest[a] = false 
     keyTest[par] = true 
     assert(keyTest[a]) --True 
end 
function bakaGaijin.checkB(par) --This syntax also works, and is super cute. 
    assert(b.i) --Resource1 set it to true, so it's true 
end 
c(a, b, c) --Calls the function in Resource1 
  
 

Note that the length operator (#) does not work on exported tables, and I cannot make it work unless MTA upgrades to Lua 5.2

bakaGaijin provides a global function called len that should be used instead.

len(table) will give the length of a table properly, even if it is an "exported" table.

A word of caution: bakaGaijin has it's own garbage collector on top of Lua's garbage collector. Any object that goes from one resource to another is monitored for usage, and deleted when unused. So try to not load the garbage collector too much and dont use gaijin objects for things that will happen very often.

In case you are wondering about the name, bakaGaijin means "Stupid Foreigner". The objects that are being sent to other resources are foreigners. Yes I know it's lame.

I have included two resources called bakaGaijinTest1 and bakaGaijinTest2 on the github repo, run these alongside bakaGaijin and then type "/bakaTest" to see that everything works.

You can open driver.lua and driver2.lua in these resources to see examples of how to do stuff, and to go through it's features.

Have fun!

Leave a reply if you like it.

Or help me build the documentation or wiki or whatever.

Link to source code: https://github.com/Luca-spopo/bakaGaijin

  • Like 2
Link to comment

Where is the link to your resource? Great job btw.

It will be better if you put the github link at bottom or top of your post. :D

Looks good!

It should be very useful too!

I added you on skype, please explain me how you did this!

Meta-tables? I really don't understand them!

Before you dive deep into the concepts of meta tables, le t me tell you that this is the most challenging part in lua you'll ever face. Go to lua.org for better explanations. You can also search for examples on forum to understand how they work. Also you can check out setfenv, setmetatable and lua environments. It took me like a month to understand them. Keep practising and you'll eventually learn.

Edited by Guest
Link to comment

wow, what a great work =D> =D>

very useful and easy for sharing data between resources but i have a littel question :3

if i maked a table here, i can change the values of it from another resource ? like this

-- resource1 
bakaGaijin.mytable = { [1] = "aa", [2] = "bb" } 

-- resource2 
mytable = bakaGaijin("resource1").mytable 
mytable[3] = "cc" 

Link to comment
wow, what a great work =D> =D>

very useful and easy for sharing data between resources but i have a littel question :3

if i maked a table here, i can change the values of it from another resource ? like this

-- resource1 
bakaGaijin.mytable = { [1] = "aa", [2] = "bb" } 

-- resource2 
mytable = bakaGaijin("resource1").mytable 
mytable[3] = "cc" 

Yes!

I plan to add "read only mode" later if you don't want that behavior, but the right now it lets you.

Where is the link to your resource? Great job btw.

Thanks!

The GitHub link is in there, I'll put it at the bottom where it's more visible.

Link to comment
  • 4 months later...

Hello @specahawk,

we've been trying to use this to handle all of our gui on our server, with some success however, I have some issues with it. When I use baka to create new gui elements in another resource there's no way for it to know when the other resource has stopped. Of course I could just pass the resource name as an argument and use onClientResourceStop, but it would be nice if it was passed as a hidden argument or something or maybe there's already something there that would help deal with this issue? The comments in your code on GitHub didn't make a lot of sense to me.

Also, something else I've noticed, not sure if it's a bug or a missing feature but it seems that you can't pass tables like below. You'll get a tail call warning/error.
 

local dx = bakaGaijin("dxx").dx
local win = dx.window("my window", 0, 0, 600, 225)
win.setStyle({
	color = tocolor(255, 0, 0, 255),
	bgColor = tocolor(0, 0, 0, 175)
})

I had to add an alternative syntax, 

win.setStyle("bgColor", tocolor(0, 0, 0, 175))

which of course works fine.

 

Thanks for writing this wonderful thing :) I'll still be using it but it would be nice to see these issues resolved.

  • Like 1
Link to comment
  • 2 weeks later...
On 11/1/2017 at 15:35, Tails said:

Hello @specahawk,

we've been trying to use this to handle all of our gui on our server, with some success however, I have some issues with it. When I use baka to create new gui elements in another resource there's no way for it to know when the other resource has stopped. Of course I could just pass the resource name as an argument and use onClientResourceStop, but it would be nice if it was passed as a hidden argument or something or maybe there's already something there that would help deal with this issue? The comments in your code on GitHub didn't make a lot of sense to me.

Also, something else I've noticed, not sure if it's a bug or a missing feature but it seems that you can't pass tables like below. You'll get a tail call warning/error.
 


local dx = bakaGaijin("dxx").dx
local win = dx.window("my window", 0, 0, 600, 225)
win.setStyle({
	color = tocolor(255, 0, 0, 255),
	bgColor = tocolor(0, 0, 0, 175)
})

I had to add an alternative syntax, 


win.setStyle("bgColor", tocolor(0, 0, 0, 175))

which of course works fine.

 

Thanks for writing this wonderful thing :) I'll still be using it but it would be nice to see these issues resolved.

Hey @Tails, thanks for using bakaGaijin!

I'm glad you're using it. It gives me a very nice feeling knowing that someone is using something I made.

As for the first feature request, I'll make it so you can add destroy callbacks for when the host resource of an element stops. Expect it soon.

As for the bug report, I'll have to run it myself to check what's wrong exactly.

If you have a github account, please consider opening both of these are issues there, as I am not very active on these forums.

https://github.com/luca-spopo/bakagaijin/issues

It would also be great if you can send the example scripts where the bug occurs (remove the parts that are not relevant to the bug) in case I am not able to reproduce it.

Edited by specahawk
  • Like 2
Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...