Hi,
So Im currently working on a DominationPointSystem.
Im managing all my UIs with FireAllClients Events. I have 2 Counter which are counting up. Now I noticed that when a new player joins, the counter is starting from 0, because of course I manage the UI on the Client and I want to keep it that way. Now I tried to get the new infos from older people in the game and give them to the new one that joins on the Server but I cant access the PlayerGui, which the Error, that my Frame “Points” is not existing.
Here’s the code:
OnPlr = {}
game.Players.PlayerAdded:Connect(function(plr)
if #OnPlr ~= 0 then
plr.PlayerGui:FindFirstChild("CaptureGUI").Points.T1.Text = OnPlr[1].PlayerGui:FindFirstChild("CaptureGUI").Points.T1.Text
plr.PlayerGui:FindFirstChild("CaptureGUI").Points.T2.Text = OnPlr[1].PlayerGui:FindFirstChild("CaptureGUI").Points.T2.Text
end
table.insert(OnPlr, plr)
print(OnPlr)
end)
game.Players.PlayerRemoving:Connect(function(plr)
table.remove(OnPlr, table.find(OnPlr, plr))
print(OnPlr)
end)

First things first:
This should also be a sort of server script so technically the thing you are trying to make will not work at all. Its not possible for it to work at all as well. Its best to see the second thing I mentioned.
local Players = game.Players
game.Players.PlayerAdded:Connect(function(plr)
if #Players:GetPlayers() > 0 then
plr.PlayerGui:FindFirstChild("CaptureGUI").Points.T1.Text = Players:GetPlayers()[1].PlayerGui:FindFirstChild("CaptureGUI").Points.T1.Text
plr.PlayerGui:FindFirstChild("CaptureGUI").Points.T2.Text = Players:GetPlayers()[1].PlayerGui:FindFirstChild("CaptureGUI").Points.T2.Text
end
end)
And second:
Its not a good practice to use a counter on the client. Instead add a numbervalue in say ReplicateStorage named counter and update it using a server script and then just display the value of the counter on every individual client.
Also, I wonder when using :GetPlayers(), the new Player will be added to that so in your method the info of the newPlayer is given to the newPlayer… When Im right
Disregarding the rather unusual approach you’ve taken to achieve what I’m not fully understanding yet, if you’re certain CaptureGUI will exist on all clients, simply yield your code until it does with a timeout.
Initially your use of FindFirstChild() here is completely redundant. FindFirstChild returns the queried Instance if it exists or returns nil. By doing this: plr.PlayerGui:FindFirstChild("CaptureGUI").Points.T1.Text, you’re invalidating and disregarding what the function might return, hence it will return no different result than directly referencing the raw path without using the function. If your FindFirstChild call returns nil, it’ll attempt to index nil with Points, and hence the error.
Additionally, you’re adding the plr Instance to the OnPlr array without checking if it already exists. Always helps to verify if what you’re attempting to add to the array already exists to minimize redundancy and unnecessary stacking of elements.
Similarly with your table.find() call, while understandable, the instance is bound to exist due to it’s guaranteed addition on PlayerAdded, for whatever reason if your table.find() call returned nil, your PlayerRemoving function would throw out for an error which could’ve been handled appropriately.
Without having you change too much of your code regardless of there being possibly better ways of handling this, below should be your tentative fix (keeping the above points in mind):
-- ServerScript
local Players = game:GetService("Players")
local OnPlr = {}
Players.PlayerAdded:Connect(function(plr)
local CaptureGUI = plr:WaitForChild("PlayerGui"):WaitForChild("CaptureGUI", 3)
if #OnPlr ~= 0 then
local targetGUI = OnPlr[1]:WaitForChild("PlayerGui"):WaitForChild("CaptureGUI", 3)
if CaptureGUI and targetGUI then
CaptureGUI.Points.T1.Text = targetGUI.Points.T1.Text
CaptureGUI.Points.T2.Text = targetGUI.Points.T2.Text
end
end
if not table.find(OnPlr, plr) then
table.insert(OnPlr, plr)
end
print(OnPlr)
end)
Players.PlayerRemoving:Connect(function(plr)
local found = table.find(OnPlr, plr)
if found then
table.remove(OnPlr, found)
end
print(OnPlr)
end)
So this is not printing an error, but testing it ingame with a friend, the text is not getting updated and is 0 and not a higher count which it was at my screen
The problem I see is how are you communicating two ways? A lot of people who code GUI’s and start out don’t understand how two way communication works with the server. Believe it or not, just like updating stats from a local script on a player, it will NEVER be saved to the server. You are only updating the server, you need to use a local script and a remote event fire when you would like to update the condition invokeserver to return the two way communication and then update the GUI on BOTH the SERVER and the CLIENT. I hope that helps you should look up some guides.
I see. In such situations, Tracing areas of your code through print-debugging can be helpful to check what bounds of your code are actually read when it’s ran.
From the sounds of it, it seems that either of CaptureGUI or targetGUI are returning nil, hence resulting in the condition not being true. Have you attempted to check if plr’s CaptureGUI and OnPlr[1]'s CaptureGUI both exist (on the server, in player’s PlayerGui) when the function is executed? Also, keeping in mind that when you first join, #OnPlr will be 0 until the array is further populated.
Where exactly is CaptureGUI located and how are you parenting it to PlayerGui?
Once again, I’m not quite understanding what exactly are you trying to achieve here, and the reason behind why you’ve picked this approach. But if you’d still like to stick with it, proceed with some baseline debugging to see what goes wrong and where.
So I have a script to detect when the counter should rise and which then fires all clients to rise the counter +1. To that, it works completely fine but a problem occurs when a new player joins because the counter for the new player will start at 0 and I want now to get the current counter from an older player and transmit it to the new player so he starts at the right count
The lines where the Text should be transmitted is running, since a print command is executed succesfull. The 2 OnPlr Prints are also working and printing the both player`s names
Why don’t you use one centralized variable or instance on the server that handles and stores the time and then dispatch that data to all clients as they join instead of treating clients like a server? This will help eliminate most of the discrepancy you have among times across clients and will maintain consistency and control over all client timers.
Well I know now that what I did was dumb as hell to do it like that but it would be hours of work again to change it so I tried looking for an alternative like I tried here
First of all, don’t worry, there’s nothing “dumb” about this. You’re still actively and logically trying to head towards a solution, just in a different, unnecessarily complex way.
May I ask why exactly would it take hours to change this approach? Can you show how are you counting the timers up in your LocalScript (assuming that’s where the counting is happening)? To me, this seems like a straightforward change which will help optimize your timers much more and eliminate lot of the unneeded complications you are/will run into.
Well so here is the part of the LOCAL SCRIPT in StarterGui (which you can see in my pic before) which rises the counter.
local Frame = script.Parent.Objects
local Points = script.Parent.Points
local Win = script.Parent.WinFrame
newC = coroutine.create(function() --Start of the coroutine
while wait(1) do --While loop to stay the counter alive
-- Checks if the Counter reached its limit
if tonumber(Points.T2.Text) >= 5000 then
Win.T1.BackgroundColor = BrickColor.Red()
GameOver("Red") --Function for the Win Event
elseif tonumber(Points.T1.Text) >= 5000 then
Win.T1.BackgroundColor = BrickColor.Blue()
GameOver("Blue") --Function for the Win Event
end
-- Checks which of the 2 Counters should rise, depending on the BrickColors of the 4 domination Zones (The color is changed in the same script here, but not included in this extract)
if Frame.C1.BackgroundColor == BrickColor.Red() then
Points.T2.Text += 1
elseif Frame.C1.BackgroundColor == BrickColor.Blue() then
Points.T1.Text += 1
end
if Frame.C2.BackgroundColor == BrickColor.Red() then
Points.T2.Text += 1
elseif Frame.C2.BackgroundColor == BrickColor.Blue() then
Points.T1.Text += 1
end
if Frame.C3.BackgroundColor == BrickColor.Red() then
Points.T2.Text += 1
elseif Frame.C3.BackgroundColor == BrickColor.Blue() then
Points.T1.Text += 1
end
if Frame.C4.BackgroundColor == BrickColor.Red() then
Points.T2.Text += 1
elseif Frame.C4.BackgroundColor == BrickColor.Blue() then
Points.T1.Text += 1
end
end
end)
coroutine.resume(newC) --Firing Coroutine
Ah that makes so much more sense, of course your not replicating the data on the server to the client GUI. You need to make a variable (not a counter) that holds the counter amount on the server. Then when you fire that to all the clients you need to update the gui accordingly. If I were to write something like this it would go as follows:
--SERVER SCRIPT--
local players = game:GetService("Players")
local repStorage = game:GetService("ReplicatedStorage")
local timerRemote = repStorage:WaitForChild("TimerRemote")
local timer = 20 --change to number of seconds
function startTimer()
for i = timer, 0, -1 do
local playerList = players:GetPlayers()
for _, player in pairs(playerList) do
timerRemote:FireClient(player, i)
end
task.wait(1)
end
end
task.wait(5)
startTimer()
--LOCAL SCRIPT--
local players = game:GetService("Players")
local player = players.LocalPlayer or players.PlayerAdded:Wait()
local repStorage = game:GetService("ReplicatedStorage")
local timerRemote = repStorage:WaitForChild("TimerRemote")
timerRemote.OnClientEvent:Connect(function(i)
local playerGui = player:WaitForChild("PlayerGui")
local screenGui = playerGui:WaitForChild("ScreenGui")
local frame = screenGui:WaitForChild("Frame")
local textLabel = frame:WaitForChild("TextLabel")
textLabel.Text = i.." seconds remaining!"
end)
original post of someone trying to update the timer to all players who join:
No problem! Just took some guiding to get you to the solution, everything takes time and effort. But I had the same exact problem and found a solution when people were saying the server GUI was updating and the player GUI wasn’t.