Issue with spectating

Hey! So, I was recently working on a spectate menu, and I got a small issue.

The spectating itself is broken, not sure what is causing this, and how is this even happening. More context is in the video attached bellow.

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 ButtonEvent = RS:WaitForChild("SpectateMenuEvents"):WaitForChild("ButtonClick")
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(targetPlayer)
	if targetPlayer.Team == Teams.Dead or targetPlayer.Team == Teams.Spectators then
		SpectateButton.Visible = true
	elseif targetPlayer.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()
		spectateButton(targetPlayer)
		SpectateEvent:FireServer(targetPlayer)
	end)
end

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

player.CharacterAdded:Connect(TeamChange)

ButtonEvent.OnClientEvent:Connect(function(targetPlayer)
	if DEBOUNCE == false then
		Spectating.Text = "SPECTATING: "..targetPlayer.Name
		Camera.CameraSubject = targetPlayer.Character:WaitForChild("Head")
		DEBOUNCE = true
	elseif DEBOUNCE == true then
		Spectating.Text = "SPECTATING: N/A"
		Camera.CameraSubject = player.Character:WaitForChild("Head")
		DEBOUNCE = false
	end
end)

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 ButtonEvent = RS:WaitForChild("SpectateMenuEvents"):WaitForChild("ButtonClick")
local DeadPlayerAssignedEvent = RS:WaitForChild("SpectateMenuEvents"):WaitForChild("DeadPlayerAssigned")
local Teams = game:GetService("Teams")
local Players = game:GetService("Players")
local Camera = workspace.CurrentCamera

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 template = Players[v.Name].PlayerGui.SpectateMenu.Holder.PlayerMenu.ScrollingFrame:FindFirstChild(targetPlayer.Name)
			if template then 
				print(template, v)
				continue 
			end
			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()
				ButtonEvent:FireClient(player, targetPlayer)
			end)
		end
	elseif targetPlayer.Team == Teams:FindFirstChild("Dead") or targetPlayer.Team == Teams:FindFirstChild("Spectators") then
		DeadPlayerAssignedEvent:FireAllClients(targetPlayer)
	end
end)

You are using a for loop through tablePlayers but you I think you want to only select the player triggering the event? The continue keyword is interrupting the for loop if any player has a valid template; I see that as an issue. It would help if you gave more context to what each script is supposed to do.

Instead of this for loop

SpectateEvent.OnServerEvent:Connect(function(player, targetPlayer)
	if targetPlayer.Team == Teams:FindFirstChild("Alive") then
		local tablePlayers = Players:GetPlayers()
		for i,v in pairs(tablePlayers) do
			-- ^^ starting here ^^

Try using player in place of v, for example the next three lines would look like this

SpectateEvent.OnServerEvent:Connect(function(player, targetPlayer)
	if targetPlayer.Team == Teams:FindFirstChild("Alive") then
		local tablePlayers = Players:GetPlayers()
		-- was for-loop, now 'player'
		local targetThumbnail = Players:GetUserThumbnailAsync(targetPlayer.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size352x352)
		local playerGui = player.PlayerGui:WaitForChild("SpectateMenu")
		local template = player.PlayerGui.SpectateMenu.Holder.PlayerMenu.ScrollingFrame:FindFirstChild(targetPlayer.Name)

It’s not meant to be player (the LocalPlayer variable) there. What that loop does is that it clones the certain GUI to all players. Also the continue keyword should be there, because players that don’t have the template property shouldn’t be able to get assigned of the rest of the lines, that are below that. I mean I could possibly put all of it directly in the if template check, but I don’t think that would help with anything.

Btw, I’m firing two player values (both of them are “local” basically) to a ServerScript, through only one LocalScript. One of the values, player is for the Players.LocalPlayer variable itself. targetPlayer is for the player, whose Team got changed (on who the :GetPropertyChangedSignal() function got fired). That’s why there are two player values.

Okay that is a helpful overview of your code! I wouldn’t refer to any player as a LocalPlayer in a server script as you know the first argument is the player firing the remove event. You have three player values to use, v iterates over every player, player is whom changed teams, targetPlayer is supplied by the former.

Try changing this line from player to v, that way the button event will fire to individual players, rather than the first one to create templates.

CloneTemplate.PlayerName.MouseButton1Click:Connect(function()
	-- was
	-- ButtonEvent:FireClient(player, targetPlayer)

	-- now
	ButtonEvent:FireClient(v, targetPlayer)
end)
1 Like

Oh my god, thank you so much!

I have been trying to fix this for so long. It now seems that the spectate menu should be fully working. Thank you!!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.