Jump to content

How to pass functions across server and client


vicisdev

Recommended Posts

Posted (edited)

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
Posted
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
Posted
Just now, majqq said:

You can pass tables in triggerClientEvent/triggerServerEvent as argument.

6UFzADa.png

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

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

  • Moderators
Posted (edited)

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
Posted
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 ,_, )

  • Moderators
Posted
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
Posted
1 minute ago, stPatrick said:

But why you want to share functions?

I'm making a key binding api for my server, but I'll need to change the approach I guess

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

  • Moderators
Posted
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
Posted
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!

  • Moderators
Posted
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
Posted
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
  • Moderators
Posted
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
]]

 

Posted
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?

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