I am trying to create a script that updates the GUI on a player accessory when the leaderstats value changes. I am currently updating the values locally and on a server script but the GUI isn’t updating on the server what would be the best approach to solve this issue?
Local Script:
while wait() do
local player = game.Players.LocalPlayer
game.ReplicatedStorage.Remotes.BackpackValue:FireServer()
script.Parent.Text = player:WaitForChild("leaderstats"):FindFirstChild("Oil").value.. "/20"
end
Server Script:
game.ReplicatedStorage.Remotes.BackpackValue.OnServerEvent:Connect(function()
game:GetService("Players").PlayerAdded:Connect(function(client)
client.CharacterAdded:Connect(function(character)
local player = game.Players.LocalPlayer
character.Backpack.Handle.GPart.SurfaceGui.TextLabel.Text = player:WaitForChild("leaderstats"):FindFirstChild("Oil").value.. "/20"
end)
end)
end)
The way you did it wont work since it’s going to make a PlayerAdded event every tick or so, which is not optimal
What I would is in the code you have to make the leaderstats values, use the Changed event on the Oil so when the Oil value changes, it’ll update the Text on the textlabel
The backpack is parented to the player not the character
LocalPlayer can only be called from the client
Why are you updating a gui thats inside of a tool?
Use Value.Changed, instead of an infinite loop, and don’t fire to the server that many times
Why do you change the gui value twice?
To fix this,
instead of character.Backpack, do player.Backpack
In the remote, add the player parameter (remote.OnServerEvent:Connect(function(player)
Parent that gui to the players PlayerGui (player.PlayerGui), and edit it there
Use .Changed
Change it once, on the client
Here are the edited scripts (may need to mess with them didnt test)
--LocalScript
local Oil = game.Players.LocalPlayer.leaderstats.Oil
Oil.Value.Changed:Connect(function()
game.ReplicatedStorage.Remotes.BackpackValue:FireServer()
script.Parent.Text = Oil.Value.. "/20"
end)
--ServerScript not needed
Edit: I didn’t see the attached pictures and I said to not change it on the server since I thought it was a gui. I’m assuming that this is parented to the workspace, so the LocalScript is not running, since it can not run in the workspace. You can easily do the same thing with a serverscript only
--Assuming this is parented to the players character
local player = game.Players:GetPlayerFromCharacter(script.Parent.Parent.Parent.Parent) --Assuming its Script > TextLabel > SurfaceGui > Backpack > Character
player.leaderstats.Oil.Changed:Connect(function()
script.Parent.Text = player.leaderstats.Oil.Value.. "/20
end)
What EmbatTheHybrid is true, and to add to that, you shouldn’t be using remote events, which burden the server in this case with rapid signals, and are not necessary, because you only need to do changes on the server. As you probably already know, such changes to GUIs on the client do not replicate. You can also narrow listening for value changes down to only values using :GetPropertyChangedSignal() method.
@Fl_ank
Something like this would be the final result:
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
Players.PlayerAdded:Connect(function(player)
-- After leaderboard is created and player has the copy.
local oil = player.leaderstats.Oil
local _connection
player.CharacterAdded:Connect(function(character)
local label = -- Proper TextLabel path here.
if (_connection) then _connection:Disconnect() end
_connection = oil.Changed:Connect(function(value)
label.Text = oil.Value .. "/20"
end)
end)
end)
What not to do
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
Players.PlayerAdded:Connect(function(player)
-- After leaderboard is created and player has the copy.
local oil = player.leaderstats.Oil
player.CharacterAdded:Connect(function(character)
local label = -- Proper TextLabel location here.
oil:GetPropertyChangedSignal("Value"):Connect(function()
label.Text = oil.Value .. "/20"
end)
end)
end)
EDIT MemezyDev I think Backpack is a folder or some instance that holds value in workspace, not player.Backpack. Everything else seems correct, except such changes done by client won’t replicate to anyone else’s machine.
That would be correct, but you don’t really need to narrow the listening via GetPropertyChangedSignal as the Changed event for BaseValues, such as int values, only listen for when the Value Property changes, the only difference being .Changed will return the new value for usage.
And something unrelated since I’m not too experienced on Events, but wouldn’t it make the event for checking the Oil’s Value again when the character respawns, wouldn’t that make more than one event for that or does it overwrite the event? I think it would also be good to disconnect the event on death to ensure only one event for checking the value is present at a time. Although I’m unsure about that
EDIT (Added a couple of words to correct some information in case anyone ever read this.)
.Changed events listens for any changes made to particular instance. IntValue has 6 active properties and some deprecated ones, which all fire when we make a change to one of them.
What I previously said is incorrect, because .Changed and :GetPropertyChangedSignal() have the same functionality here. Even though IntValue has a lot of properties and some hidden and deprecated ones, .Changed event fires each time value changes. :GetPropertyChangedSignal() is a good practice when it comes to more complex instances, like humanoid, seat, and so on.
“Connections disconnect eventually when player respawns.” – Only partially true.
That stands if the code is part of a local script.
Local script example:
Local script connections disconnect eventually when player respawns. Disconnecting earlier only frees up memory quicker, and requires connecting humanoid.Died event, which is another connection and makes manual disconnection relatively questionable.
Server script example:
Since server script doesn’t stop executing when character is removed from game, the old connection remains active and doesn’t collect. Thanks to @EmbatTheHybrid for pointing that out, I forgot we are talking about server script, so the previous information is not true when we are talking about the server side.
I’m appending later post here with most likely valid information, at least according to my previous experience and tests.
That is true, but that doesn’t apply to BaseValues, Changed only fires if their Value property has been changed, so if you changed their name, it wont detect that, but if you change their value, it will. To take fro mthe Article for Changed for IntValues for example,
Your method and Changed would be the same, but Changed would return the new value, but would only apply to BaseValues and nothing else, so using GetPropertyChangedSignal would be the more general approach to use, but personally I would use Changed since I would need to use the new value, but of course to each their own.
Wow you made that edit by the time I was writing this haha
So if I understand correctly, eventually the old event for the Oil would be disconnected by itself by the time you connect it? I never knew that before, I thought it just keep piling up connections, hence why I suggested manual disconnection to help free up some memory, even if it’s making another connection, which would be disconnected anyways when the Character respawns
I’m sorry for not clarifying the information correctly and stating some wrong information.
What I said stands, but only when the code is inside local script. Once new character is spawned, the old one stays present in memory for a relatively short time period and is collected by GC (garbage collector) soon unless it’s strongly referenced. Server script doesn’t stop working when player “dies” of course, so connection remains active.
Instead of connecting humanoid.Died, a better alternative would be storing current connection in a variable and disconnect it efficiently.
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
Players.PlayerAdded:Connect(function(player)
-- After leaderboard is created and player has the copy.
local oil = player.leaderstats.Oil
local _connection
player.CharacterAdded:Connect(function(character)
local label = -- Proper TextLabel path here.
if (_connection) then _connection:Disconnect() end
_connection = oil.Changed:Connect(function(value)
label.Text = oil.Value .. "/20"
end)
end)
end)
Connecting humanoid.Died would improve the situation, but add up some unnecessary code.
Thank you for bringing this up and please excuse me again for telling some partially false information today, I haven’t slept enough for a week now.
Okay I see now, thanks for clearing it up for me. Also I think my brain must’ve completely forgotten that @OP could just do that instead of putting it in a variable and disconnecting it when the player dies, that would be much more effective as an if statement is less demanding than an event. Thank you for clearing that up for me! and helping out my brain during a brain fart remember disconnection via if statement haha
This worked perfectly basically the main error was that I was using a local script inside of the workspace while it should’ve been a server script. Thank you all for your help and guidance!