Why is my remote function not working?

Hi! I am creating a team system called packs and I have made a remote function that will open another players team request gui so they can accept it or deny it, but none of the print functions print. Cna someone help me.

Script in ServerScriptService:

local replicatedStorage = game:GetService("ReplicatedStorage")

local RF = replicatedStorage:WaitForChild("OpenPackRequest")

local function openGui(localPlayer, player)
	print("ATTEMPTING TO OPEN GUI")
	local packRequestGui = player.PlayerGui.PacksGui.PackRequest
	packRequestGui.Visible = true
	
	print("GUI OPENED")

	packRequestGui.PackInfoText.Text = localPlayer.Name .." invited you to join the pack".. localPlayer.Team.Name ..". Do you accept?"
	packRequestGui.NoButton.MouseButton1Click:Connect(function()
		packRequestGui.Visible = false
		return "No"
	end)

	packRequestGui.YesButton.MouseButton1Click:Connect(function()
		packRequestGui.Visible = false
		return "Yes"
	end)

	wait(10)

	packRequestGui.Visible = false
	return "No"
end

RF.OnServerInvoke = openGui

LocalScript, a descendant of Player Gui:


PlayerFrameClone.AddToTeam.MouseButton1Click:Connect(function()
	if player.PlayerGui.PacksGui.PackRequest.Visible == true then return end
		if player.Team == nil then
			if plr.Team ~= nil then
				
				local result = RF:InvokeServer(player)
				if result == "Yes" then
                                --Add Player to team (NOTE: plr is the local player and player is the targeted player
                   end
              end
         end
     end
end)
1 Like

Instead of doing

RF.OnServerInvoke = openGui

Try

RF.OnServerInvoke:connect(openGui)
1 Like

I have done that before but it came with an error in the output

1 Like

I’m also assuming for the start of the local script that “PlayerFrameClone” and player AND plr is mentioned. But you also use “player” and then “plr.”

1 Like

Mind telling us what error? We can’t read your mind-

1 Like

When you are returning “No” or “Yes” from the mousebutton1click events, you are returning it to the connection, and not to the function. You can fix it by doing something like that

	packRequestGui.PackInfoText.Text = localPlayer.Name .." invited you to join the pack".. localPlayer.Team.Name ..". Do you accept?"
local returned
	packRequestGui.NoButton.MouseButton1Click:Connect(function()
		packRequestGui.Visible = false
		returned = "No"
	end)

	packRequestGui.YesButton.MouseButton1Click:Connect(function()
		packRequestGui.Visible = false
		returned = "Yes"
	end)

local t = 0
repeat 
t += 1
wait() until t >= 10 or returned

	packRequestGui.Visible = false
	return returned or "No"
end

It seems like a bad approach, but you can try improving it

1 Like

OnServerInvoke is a callback, not a a RBXScriptSignal. You can’t call :Connect() on a callback and there is nothing wrong with RF.OnServerInvoke = openGui.

2 Likes

Is there any better ways of doing what I am trying to achieve?

1 Like

Yeah, you should be using remote events, with :FireClient and :FireServer. It would always be better if the client manages its own player gui

1 Like

As @Jxl_s has said, you should be using :FireServer and :FireClient instead. The server is no longer able to edit the PlayerGuis of individual clients since filtering enabled was introduced. The server is able to edit PlayerGuis of individual clients, but that doesn’t mean you should do so. GUIs should be handled on the client, never on the server.

Your filtering enabled-compatible code should look something like this:

-- server script --

local replicatedStorage = game:GetService("ReplicatedStorage")
local packRequest = replicatedStorage:WaitForChild("OpenPackRequest")
local packAccept = replicatedStorage:WaitForChild("AcceptPackRequest")

packRequest.OnServerEvent:Connect(function(requestingPlayer, targetPlayer)
    -- fire a remote to the targetPlayer to setup their guis, with the requestingPlayer as an argument passed
    local response = packAccept:InvokeClient(targetPlayer, requestingPlayer)
    -- maybe someone more experienced with remotes can come up with a solution that doens't need InvokeClient, I can't think of any way to not use it in this case
    -- (roblox wiki says to avoid using InvokeClient as it can cause issues for the server)

    if response == true then
        -- change player's team
        targetPlayer.Team = requestingPlayer.Team
    end

    -- fire the remote to the requestingPlayer with a boolean that tells wether or not the pack request to targetPlayer was accepted
    packRequest:FireClient(requestingPlayer, targetPlayer, response)
end)

-- local script --

local replicatedStorage = game:GetService("ReplicatedStorage")
local packRequest = replicatedStorage:WaitForChild("OpenPackRequest")
local packAccept = replicatedStorage:WaitForChild("AcceptPackRequest")
local packRequestGui = game.Players.LocalPlayer.PlayerGui.PacksGui.PackRequest

packRequest.OnClientEvent:Connect(function(response, targetPlayer)
    if response == true then
        -- targetPlayer accepted your pack request!
    end
end)

packAccept.OnClientInvoke:Connect(function(requestingPlayer)
    print("ATTEMPTING TO OPEN GUI")

    packRequestGui.Visible = true

    print("GUI OPENED")

    -- using string.format is usually better for performance, and I personally think
    -- that it looks cleaner than lots .. of .. concatenate .. operators
    packRequestGui.PackInfoText.Text = string.format("%s invited you to join the pack %s. Do you accept?", requestingPlayer.Name, requestingPlayer.Team.Name)

    -- we have to use a bindable event here since we want to wait for a response
    -- if we put the return inside the MouseButton1Click function, it's only going to return the value to the
    -- MouseButton1Click function (as @Jxl_s also mentioned), instead of returning the value to the Invoke request
    local responseEvent = Instance.new("BindableEvent")

    -- you could also use the variable method they suggested, although I wouldn't reccomend using it
    -- not a fan of repeat wait() until ... loops (uses wait(), can cause unnesscary yielding)

    -- when connecting an event/RBXScriptSignal, it returns an RBXScriptConnection object which can be used to
    -- disconnect the function when it isn't needed anymore (very good for preventing memory leaks)
    local NoButton = packRequestGui.NoButton.MouseButton1Click:Connect(function()
        packRequestGui.Visible = false
        responseEvent:Fire(false) -- fire the BindableEvent with the parameter false (declining the pack request)
    end)

    local YesButton = packRequestGui.YesButton.MouseButton1Click:Connect(function()
        packRequestGui.Visible = false
        responseEvent:Fire(true) -- fire the BindableEvent with the parameter true (accepting the pack request)
    end)

    -- using a delay function here to avoid infinitely waiting for a response
    -- it essentially allows us to run several lines of code simultaneously,
    -- allowing us to create timeouts for yielding functions
    delay(10, function()
        if responseEvent then -- checks if the responseEvent variable still exists (isn't nil), if not then nothing happens
            responseEvent:Fire(false) -- fire the responeEvent with the parameter false, automatically declining the pack request
        end
    end)

    -- bindable events are just like real events, calling :Wait() will yield until the event
    -- is fired and returns the arguments passed to it
    local response = responseEvent.Event:Wait() -- wait for the event to be fired
    responseEvent:Destroy() -- here we call :Destroy() and set responseEvent to nil, after the event has been fired
    responseEvent = nil  -- in order to have the delay function not do anything to avoid an error, we set the responseEvent variable to nil

    -- disconnecting the NoButton and YesButton functions, this is so they don't again fire in the future
    -- and cause errors, and to prevent a memory leak from the two unused functions
    NoButton:Disconnect()
    YesButton:Disconnect()

    -- and finally we're done, put a print just for some debugging incase i got
    -- anything wrong, and then we return the response to the server (true for pack request accepted, false for declined)
    print("RESPONSE:", response)
    return response
end)

Further reading:

1 Like

Thank you for the detailed explanation and taking your time to write this. It was greatly appreciated!

1 Like

Actually, the server can still edit the playerguis of clients, but it cannot listen to some events.

1 Like

Did some testing and turns out you’re right, whoops. Edited the post to reflect that. But you should still be handling GUIs on the client instead of the server to reduce load on the server and improve responsiveness for the client.

2 Likes