Jump to content

How to pass functions across server and client


vicisdev

Recommended Posts

I have a shared script that stores a parameter provided function into a table:

-- shared_script.Lua

local my_table = {}

function addFunctionality(key, handler)
  my_table[key] = handler
end

The point is that it's stored two different tables - client and server side. When addFunctionality is called from a client script the handler is stored only inside the respective side table.

What I need is a way to communicate between both client and server to store the handler in both tables independently of who is calling addFunctionality. The tables need to be synced and have the same data.

I know there are functions server/client only, but forget that for now. For the purpose of this help bear in mind I'm trying to store this function:

function() return true end

But from the point of view of addFunctionality you never know how handler's implementation looks like.

I've already tried to:

- Use events, but they do not accept functions as arguments

- Store the table in the root element, but it's not possible at all

- Use loadstring, but 1) I don't know how handler's implementation looks like and 2) it doesn't return values

Thanks xD

Edited by vicisdev
Link to comment
  • Scripting Moderators
11 minutes ago, vicisdev said:

I have a shared script that stores a parameter provided function into a table:


-- shared_script.Lua

local my_table = {}

function addFunctionality(key, handler)
  my_table[key] = handler
end

The point is that it's stored two different tables - client and server side. When addFunctionality is called from a client script the handler is stored only inside the respective side table.

What I need is a way to communicate between both client and server to store the handler in both tables independently of who is calling addFunctionality. The tables need to be synced and have the same data.

I know there are functions server/client only, but forget that for now. For the purpose of this help bear in mind I'm trying to store this function:


function() return true end

But from the point of view of addFunctionality you never know how handler's implementation looks like.

I've already tried to:

- Use events, but they do not accept functions as arguments

- Store the table in the root element, but it's not possible at all

- Use loadstring, but 1) I don't know how handler's implementation looks like and 2) it doesn't return values

Thanks xD

You can pass tables in triggerClientEvent/triggerServerEvent as argument.

6UFzADa.png

  • Thanks 1
Link to comment
  • Scripting Moderators
1 minute ago, vicisdev said:

I'll try it. But I have almost sure the entries are going to be nil ... let me see and I'll give feedback

Why? I'm using tables n triggers since past year, and everything works well :)

  • Thanks 1
Link to comment
Just now, majqq said:

Why? I'm using tables n triggers since past year, and everything works well :)

Idk really ... I've tried to store the table full of functions in the root element with setElementData and all entries gone nil, so maybe functions are not synceable ... idk :p

Link to comment
  • Moderators

Try to sync table, something like this:

 

-- SHARED

local thisIsClientSide = isElement(localPlayer) -- it returns true if script running on client side and localPlayer defined
local t = {}

function f(i, v)
	print((thisIsClientSide and "Client:" or "Server:").." f => i:"..i..", v:"..v) -- debug
	t[i] = v
	
	-- send sync to different side
	if not source then -- if source is exists, don't need to send back to different side, because we got it from there (otherwise we would make a loop)
		if thisIsClientSide then
			triggerServerEvent("f:sync", resourceRoot, i, v)
		else
			triggerClientEvent("f:sync", resourceRoot, i, v)
		end
	end
end
addEvent("f:sync", true)
addEventHandler("f:sync", root, f)

 

Edited by stPatrick
  • Like 1
Link to comment
43 minutes ago, stPatrick said:

Try to sync table, something like this:

 

56 minutes ago, majqq said:

Why? I'm using tables n triggers since past year, and everything works well :)

Yeah guys ... it sadly doesn't work

-- shared_script.Lua

addEventHandler("onPlayerJoin", root, function()
    local server_table = {
        function() return true end,
        function() outputChatBox("ANOTHER FUNCTION") return false end,
        "sadsad"
    }

    for k, v in pairs(server_table) do
        triggerClientEvent("r", source, k, v)
    end
end)

addEvent("r", true)
addEventHandler("r", root, function(i, v)
    outputChatBox("RECEIVED > " .. inspect(i) .. " > " .. inspect(v))
end)

https://i.imgur.com/E5TV6dS.png (i cant insert images ,_, )

Link to comment
  • Moderators
3 minutes ago, vicisdev said:

 

Yeah guys ... it sadly doesn't work


-- shared_script.Lua

addEventHandler("onPlayerJoin", root, function()
    local server_table = {
        function() return true end,
        function() outputChatBox("ANOTHER FUNCTION") return false end,
        "sadsad"
    }

    for k, v in pairs(server_table) do
        triggerClientEvent("r", source, k, v)
    end
end)

addEvent("r", true)
addEventHandler("r", root, function(i, v)
    outputChatBox("RECEIVED > " .. inspect(i) .. " > " .. inspect(v))
end)

https://i.imgur.com/E5TV6dS.png (i cant insert images ,_, )

But why you want to share functions?

  • Thanks 1
Link to comment
  • Moderators
addEventHandler("onPlayerJoin", root, function()
    local server_table = {
        'function() return true end',
        'function() outputChatBox("ANOTHER FUNCTION") return false end',
    }

    for k, v in pairs(server_table) do
        triggerClientEvent("r", source, k, v)
    end
end)

addEvent("r", true)
addEventHandler("r", root, function(i, v)
    outputChatBox("RECEIVED > " .. i .. " > " .. v)
	
	-- load
	local func, err = loadstring("return "..v)
	local results = {pcall(func)}
	
	-- call
	local func_results = {results[2]()}
	outputChatBox(inspect(func_results))
end)

 

  • Thanks 1
Link to comment
23 minutes ago, stPatrick said:

addEventHandler("onPlayerJoin", root, function()
    local server_table = {
        'function() return true end',
        'function() outputChatBox("ANOTHER FUNCTION") return false end',
    }

    for k, v in pairs(server_table) do
        triggerClientEvent("r", source, k, v)
    end
end)

addEvent("r", true)
addEventHandler("r", root, function(i, v)
    outputChatBox("RECEIVED > " .. i .. " > " .. v)
	
	-- load
	local func, err = loadstring("return "..v)
	local results = {pcall(func)}
	
	-- call
	local func_results = {results[2]()}
	outputChatBox(inspect(func_results))
end)

 

Ooh, great solution, actually. I've read loadstring doesn't return values, I was wrong. I'll need to change some implementations, but this is fine, thank you!

Link to comment
  • Moderators
2 hours ago, vicisdev said:

I would really like to know what @IIYAMA has to say about this

It seems everything is fine.

 

You can't send loaded functions to the other side, because they are bound they their environment. The file and every variable around the function is part of the environment. If you actually could transfer functions, then Lua would also copy all other variables to the other side, in fact the entire Lua file. That would be catastrophic.

local test1, test2

function test1 ()
	local testValue = "test"
  
	function test2 ()
		print(testValue)
	end
end

test1()

 

I would recommend to use 3 files instead.

 

1 shared with all the functions inside of a table

allStuff = {
	doThis = function () end,
  	doThat = function () end,
	dontDoThat = function () end
}

 

1 clientside

function handlerFunction (key, ...)
	allStuff[key](...)
  	-- client stuff
end

 

1 serverside

function handlerFunction (key, ...)
	allStuff[key](...)
  	-- server stuff
end

 

etc.

  • Like 1
Link to comment
16 hours ago, IIYAMA said:

I would recommend to use 3 files instead.

Yeah, but the main thing is adding new entries programatically which leads to server/client only insertions. It would be magic if I could force a shared environment when calling a function so the api knows "ok this has to be added here and there" just like what happens when you manually, directly, make calls or insert data on a shared file.

There is a way to extract a loaded function's implementation so you get its string? If so ... maaan, revolutionary!

  • Like 1
Link to comment
  • Moderators
30 minutes ago, vicisdev said:

There is a way to extract a loaded function's implementation so you get its string? If so ... maaan, revolutionary!

Not that I know of, but you can change the order. So instead of starting with a function, you could start with a multiline string.

thisString = [[
function getName ()

end
]]

 

Link to comment
1 hour ago, IIYAMA said:

Not that I know of, but you can change the order. So instead of starting with a function, you could start with a multiline string.


thisString = [[
function getName ()

end
]]

 

Yeah, this is the approach I'm following now. Where can I share it when it's finished, like a showcase and stuff?

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...