RemoteEvent player values

Hey! I have been wondering, how could I enter two player values into a RemoteEvent fire, if both of them are “local”? Let me give you more context, so that I explain what I mean.

I have a variable for the LocalPlayer:

local Players = game:GetService("Players")
local player = Players.LocalPlayer

If the player’s property Team gets changed, a function will get fired:

player:GetPropertyChangedSignal("Team"):Connect(function()
end)

Now in the function, there is a RemoteEvent, which gets fired alongside a local function (the local function is pointless to know for now, as it’s just for making a GUI visible/invisible, and it works)

player:GetPropertyChangedSignal("Team"):Connect(function()
	spectateButton()
	SpectateEvent:FireServer()
end)

In the ServerScript, which handles the SpectateEvent RemoteEvent, it looks like this:

SpectateEvent.OnServerEvent:Connect(function(targetPlayer)
end)

targetPlayer returns the player, whose Team property got changed. However, I also want to add a value for the LOCAL player, meaning every player in the server, on their own each client-side.
Problem is, that if I make (player, targetPlayer), it’s not gonna help and basically be just two same values. What causes this is that the GetPropertyChangedSignal function is checked on the LocalPlayer (in the LocalScript), meaning that it’s basically two same values.
I don’t know how to fix this issue.

TL;DR: I need to fire two “local” values. One for the LocalPlayer itself, and another one for a player whose Team property gets changed (both in the same LocalScript). I’m not sure if this can be fixed by some loop instead of the GetPropertyChangedSignal function, or something like that. That’s why I’d like to get help.

2 Likes

I don’t really get what you mean. From what I understand, you wanna check every player on the server and see if the team got changed. Correct me if I’m wrong, but couldn’t you just do something like this?

while wait() do
	for _, desc in pairs(game.Players:GetPlayers()) do
		if desc:IsA("Player") then
			desc:GetPropertyChangedSignal("Team"):Connect(function()
				print("Team of player "..desc.Name.." changed")
			end)
		end
	end
end

Again, I don’t know what you mean exactly, and I also haven’t tested that script yet. If you could explain what you wanted to do a bit more, I’d be happy to help you further :slight_smile:

1 Like

Hi! Well, what I want to do is fire two player values in one RemoteEvent (from a LocalScript to a ServerScript).

One value represents the LocalPlayer variable itself, another one (targetPlayer) represents the player, whose Team property got changed.

2 Likes

So you need to get the player whose team was changed from a localscript, and that player could be any player on the server?

If that’s the case, you would need to make the serverscript I sent, make it fire a remoteevent to the player with the “targetplayer” variable, and then send the “targetplayer” back to the server, along with the “localplayer” and I think that should work. It’s a little inefficient though.

Also, why would need to send these two specific variables? What is your script trying to do?

1 Like

This is for a spectate menu. The reason, why I need two player values is simple. The targetPlayer value is used for numerous things, such as changing a new, cloned Frame to their name, changing an Image’s ID to their Roblox thumbnail etcetera. And for the player value (LocalPlayer variable), it’s used to change the LocalPlayer’s camera back to their own character, when they stop spectating a certain player, or when the player, which they are currently spectating leaves the game.

I can send you the full script if you want, so that you see how it works and what exactly I am intending to do.

Just a heads up, I wouldn’t put an event listener inside of a while loop. This will be a huge memory leak. Instead you want to for loop through all the existing players and attach the team event listener once and then using PlayerAdded to attach the team event listener to all the new players.

1 Like

I know this might be kind of a dumb question, but I genuinely forgot how it works a little bit.
So if I just did something like this:

for i,v in pairs(Players:GetPlayers() do
end

Would it work even after a new player joins? (aka loop through all players constantly, not just once)

It would loop through all existing players + any new players that joined before that loop is executed, so running it in a while loop would mean connecting the OnTeamChange event listener multiple times on existing players.

1 Like

So what do you suggest to do, so that the for loop would constantly loop through all players, seeking for anybody, whose Team property got changed? As I indeed realize that putting it in a while loop is not really a good idea. (I need to constantly loop through all players, not just once)

You could supposedly do something like this:

local function BindTeamOnChange with player:
    Connect team event listener

for loop AllPlayers with player:
    BindTeamOnChange(player)


PlayerAdded:Connect(BindTeamOnChange)
1 Like

So, would it work like this?

local function TeamChange(targetPlayer)
	targetPlayer:GetPropertyChangedSignal("Team"):Connect(function()
		SpectateEvent:FireServer(targetPlayer)
	end)
end

for i,targetPlayer in pairs(Players:GetPlayers()) do
	TeamChange(targetPlayer)
end

Players.PlayerAdded:Connect(TeamChange)

It kinda works now, seen that some previous issues got fixed, though, there is still a small problem. Now the spectating itself doesn’t work. In other words, player’s CameraSubject doesn’t get changed to the targetPlayer’s Head. The print doesn’t get printed as well.
Do you know what could be causing this, and how could I fix it? Because I didn’t manage to fix it by myself, yet.
LocalScript:

local Players = game:GetService("Players")
local player = Players.LocalPlayer
local RS = game:GetService("ReplicatedStorage")
local Teams = game:GetService("Teams")
local SpectateEvent = RS:WaitForChild("SpectateMenuEvents"):WaitForChild("SpectateMenu")
local DeadPlayerAssignedEvent = RS:WaitForChild("SpectateMenuEvents"):WaitForChild("DeadPlayerAssigned")
local Gui = player:WaitForChild("PlayerGui"):WaitForChild("SpectateMenu")
local HolderFrame = Gui:WaitForChild("Holder")
local SpectateButton = HolderFrame:WaitForChild("SpectateButton")
local PlayerMenu = HolderFrame:WaitForChild("PlayerMenu")
local ScrollingFrame = PlayerMenu:WaitForChild("ScrollingFrame")
local Title = HolderFrame:WaitForChild("Title")
local Spectating = HolderFrame:WaitForChild("Spectating")
local Camera = workspace.CurrentCamera

local DEBOUNCE = false
local SPECTATE_DEBOUNCE = false

local function spectateButton()
	if player.Team == Teams.Dead or player.Team == Teams.Spectators then
		SpectateButton.Visible = true
	elseif player.Team == Teams.Alive then
		SpectateButton.Visible = false
	end
end

SpectateButton.MouseButton1Click:Connect(function()
	if SPECTATE_DEBOUNCE == false then
		PlayerMenu.Visible = true
		Title.Visible = true
		HolderFrame.Spectating.Visible = true
		SPECTATE_DEBOUNCE = true
	elseif SPECTATE_DEBOUNCE == true then
		Title.Visible = false
		HolderFrame.Spectating.Visible = false
		PlayerMenu.Visible = false
		SPECTATE_DEBOUNCE = false
	end
end) 

local function TeamChange(targetPlayer)
	targetPlayer:GetPropertyChangedSignal("Team"):Connect(function()
		SpectateEvent:FireServer(targetPlayer)
	end)
end

for i,targetPlayer in pairs(Players:GetPlayers()) do
	TeamChange(targetPlayer)
end

Players.PlayerAdded:Connect(TeamChange)

DeadPlayerAssignedEvent.OnClientEvent:Connect(function(targetPlayer)
	local tableTemplates = ScrollingFrame:GetChildren()
	for i,v in pairs(tableTemplates) do
		if v.ClassName == "Frame" then
			if v.Name == targetPlayer.Name then
				v:Destroy()
				Spectating.Text = "SPECTATING: N/A"
				Camera.CameraSubject = player.Character:WaitForChild("Head")
			else
				v:Destroy()
			end
		end
	end
end)

ServerScript:

local RS = game:GetService("ReplicatedStorage")
local SS = game:GetService("ServerStorage")
local PlayerTemplate = SS:WaitForChild("PlayerTemplate")
local SpectateEvent = RS:WaitForChild("SpectateMenuEvents"):WaitForChild("SpectateMenu")
local DeadPlayerAssignedEvent = RS:WaitForChild("SpectateMenuEvents"):WaitForChild("DeadPlayerAssigned")
local Teams = game:GetService("Teams")
local Players = game:GetService("Players")
local Camera = workspace.CurrentCamera

local DEBOUNCE = false

SpectateEvent.OnServerEvent:Connect(function(player, targetPlayer)
	if targetPlayer.Team == Teams:FindFirstChild("Alive") then
		local tablePlayers = Players:GetPlayers()
		for i,v in pairs(tablePlayers) do
			local targetThumbnail = Players:GetUserThumbnailAsync(targetPlayer.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size352x352)
			local playerGui = v.PlayerGui:WaitForChild("SpectateMenu")
			local CloneTemplateParent = playerGui:WaitForChild("Holder"):WaitForChild("PlayerMenu"):WaitForChild("ScrollingFrame")
			local CloneTemplate = PlayerTemplate:clone()
			CloneTemplate.Parent = CloneTemplateParent
			CloneTemplate.Name = targetPlayer.Name
			CloneTemplate.PlayerName.Text = targetPlayer.Name
			CloneTemplate.PlayerThumbnail.Image = targetThumbnail
			CloneTemplate.PlayerName.MouseButton1Click:Connect(function()
				local Spectating = CloneTemplateParent.Parent.Parent.Spectating
				local targetPlayer = Players:FindFirstChild(targetPlayer.Name)
				if DEBOUNCE == false then
					DEBOUNCE = true
					Spectating.Text = "SPECTATING: "..targetPlayer.Name
					Camera.CameraSubject = targetPlayer.Character:WaitForChild("Head")
					print("after targetPlayer CameraSubject")
				elseif DEBOUNCE == true then
					Spectating.Text = "SPECTATING: N/A"
					Camera.CameraSubject = player.Character:WaitForChild("Head")
					print("after LocalPlayer CameraSubject")
					DEBOUNCE = false
				end
			end)
		end
	elseif targetPlayer.Team == Teams:FindFirstChild("Dead") or targetPlayer.Team == Teams:FindFirstChild("Spectators") then
		DeadPlayerAssignedEvent:FireAllClients(targetPlayer)
	end
end)

Correct me if I’m wrong but shouldn’t “player” in this line Camera.CameraSubject = player.Character:WaitForChild("Head") be “targetPlayer” instead? Right now I think you’re just setting the CameraSubject to your own player over and over again.

If you mean after the if check “DEBOUNCE == true then”, then no, it’s meant to be like that. It means that the LocalPlayer clicked on the same targetPlayer button again, meaning they stopped spectating them, and got their CameraSubject resetted (set back to their own character).

I also realized another problem. The Frame now gets cloned twice for some reason.

Yup didn’t realize that. Issue on my part, I apologize.
For the cloning issue, maybe use :Clone() instead of :clone(), maybe that fixes it

although i don’t think it will

1 Like

Hmm, it seems that it works when I test by just the “Play” feature in Studio. Though, when I test with 2 players, it gets cloned twice. I think it may be cloning by how many players are in game? (aka if there were 3 players, it would clone 3 times).

Not sure why would it do that, but I think it does.

I had the exact same issue a few days ago and I also haven’t found a fix for it yet…
Maybe try asking the Roblox AI or something?

1 Like

Yeah, I guess I’ll look for that issue and the CameraSubject issue by myself, or on another post. Though, I’m pretty sure the fix itself by @XxprofessgamerxX works! :smiley:

SpectateEvent.OnServerEvent:Connect(function(player, targetPlayer)
    if targetPlayer.Team == Teams:FindFirstChild("Alive") then
        local tablePlayers = Players:GetPlayers()
        local playerGui = player.PlayerGui:WaitForChild("SpectateMenu")
        local CloneTemplateParent = playerGui:WaitForChild("Holder"):WaitForChild("PlayerMenu"):WaitForChild("ScrollingFrame")
        local CloneTemplate = PlayerTemplate:clone()
        
        for i,v in pairs(tablePlayers) do
            local targetThumbnail = Players:GetUserThumbnailAsync(targetPlayer.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size352x352)
            
            CloneTemplate.Parent = CloneTemplateParent
            CloneTemplate.Name = targetPlayer.Name
            CloneTemplate.PlayerName.Text = targetPlayer.Name
            CloneTemplate.PlayerThumbnail.Image = targetThumbnail
            
            CloneTemplate.PlayerName.MouseButton1Click:Connect(function()
                local Spectating = CloneTemplateParent.Parent.Parent.Spectating
                local targetPlayer = Players:FindFirstChild(targetPlayer.Name)
                
                if DEBOUNCE == false then
                    DEBOUNCE = true
                    Spectating.Text = "SPECTATING: "..targetPlayer.Name
                    Camera.CameraSubject = targetPlayer.Character:WaitForChild("Head")
                    print("after targetPlayer CameraSubject")
                elseif DEBOUNCE == true then
                    Spectating.Text = "SPECTATING: N/A"
                    Camera.CameraSubject = player.Character:WaitForChild("Head")
                    print("after LocalPlayer CameraSubject")
                    DEBOUNCE = false
                end
            end)
        end
    elseif targetPlayer.Team == Teams:FindFirstChild("Dead") or targetPlayer.Team == Teams:FindFirstChild("Spectators") then
        DeadPlayerAssignedEvent:FireAllClients(targetPlayer)
    end
end)

Last post here, this is what the AI came up with, incase that fixes it. Idk if it is correct though.

1 Like