GUI not updating

Made this script so that when a player joins their data is loaded and gui updates depending on the data. But only some of the gui updates, I have checked the data of a player and it is correct what is wrong?

script (local)

BTW this is only a part of the script. Also my variable are very much correct, so dont worry about those.

EquippedTP.Changed:Connect(function()
	if EquippedTP.Value == true then
		EquipButtonTP.Text = "Equipped"
	elseif EquippedTP.Value == false then
		EquipButtonTP.Text = "Equip"
    end
end)

EquippedGH.Changed:Connect(function()
	if EquippedGH.Value == true then
		EquipButtonGH.Text = "Equipped"
	elseif EquippedGH.Value == false then
		EquipButtonGH.Text = "Equip"
	end
end)

EquippedWH.Changed:Connect(function()
	if EquippedWH.Value == true then
		EquipButtonWH.Text = "Equipped"
	elseif EquippedWH.Value == false then
		EquipButtonWH.Text = "Equip"
	end
end)

EquippedIH.Changed:Connect(function()
	if EquippedIH.Value == true then
		EquipButtonIH.Text = "Equipped"
	elseif EquippedIH.Value == false then
		EquipButtonIH.Text = "Equip"
	end
end)
4 Likes

I’m assuming these are BoolValues inside of a folder of the player instance. How are these values being set on the server when the player first joins?

1 Like

They are BoolValues, and they are set based on the data the player has (I set up a data store), if they have no data everything will be false.

1 Like

My assumption is that some of the values are being set before the client loads and therefore the Changed event is not triggered for that particular BoolValue. Have you tried just updating the values outside of the Changed events as well? Like so:

EquippedTP.Changed:Connect(function()
	if EquippedTP.Value == true then
		EquipButtonTP.Text = "Equipped"
	elseif EquippedTP.Value == false then
		EquipButtonTP.Text = "Equip"
    end
end)

EquippedGH.Changed:Connect(function()
	if EquippedGH.Value == true then
		EquipButtonGH.Text = "Equipped"
	elseif EquippedGH.Value == false then
		EquipButtonGH.Text = "Equip"
	end
end)

EquippedWH.Changed:Connect(function()
	if EquippedWH.Value == true then
		EquipButtonWH.Text = "Equipped"
	elseif EquippedWH.Value == false then
		EquipButtonWH.Text = "Equip"
	end
end)

EquippedIH.Changed:Connect(function()
	if EquippedIH.Value == true then
		EquipButtonIH.Text = "Equipped"
	elseif EquippedIH.Value == false then
		EquipButtonIH.Text = "Equip"
	end
end)

EquipButtonTP.Text = EquippedTP.Value and "Equipped" or "Equip" -- This is equivalent to what you have inside of the Changed event
EquipButtonGH.Text = EquippedGH.Value and "Equipped" or "Equip"
EquipButtonWH.Text = EquippedWH.Value and "Equipped" or "Equip"
EquipButtonIH.Text = EquippedIH.Value and "Equipped" or "Equip"
1 Like

I thought so too, I just didnt really know how to fix it. I will try this out and see if it works.

Ok I tried it out and realized that only the first two work because they load in first, I can confirm this because I put a wait() before your addition and it worked, so I think I will do something like onCharacterLoaded or PlayerJoined and put your addition inside so if my part does not work, yours will act as a backup system. Did that make sense?

PlayerAdded and CharacterLoaded (I think thats what its called) didnt work, how do I delay it so it loads when the player successfully joins.

Can I see your server script? I want to know how you’re creating and setting the values.

Ok, hopefully this isnt to confusing.

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Event = ReplicatedStorage.Equipped
local Players = game:GetService("Players")




Event.OnServerEvent:Connect(function(Player, HookType)
	local GHOwned = Player:WaitForChild("GoldenHook"):WaitForChild("Owned")
	local TPOwned = Player:WaitForChild("TPose"):WaitForChild("Owned")
	local WHOwned = Player:WaitForChild("WoodenHook"):WaitForChild("Owned")
	local IHOwned = Player:WaitForChild("InvisibleHook"):WaitForChild("Owned")
	local TP = Player:WaitForChild("TPose"):WaitForChild("Equipped")
	local GH = Player:WaitForChild("GoldenHook"):WaitForChild("Equipped")
	local WH = Player:WaitForChild("WoodenHook"):WaitForChild("Equipped")
	local IH = Player:WaitForChild("InvisibleHook"):WaitForChild("Equipped")
	local Character = Player.Character
	
	if HookType == "TP" then
		if TPOwned.Value == true then
		TP.Value = not TP.Value
		end
	elseif HookType == "GH" then
		if GHOwned.Value == true then
		GH.Value = not GH.Value
		end
	elseif HookType == "WH" then
		if WHOwned.Value == true then
			WH.Value = not WH.Value
		end
	elseif HookType == "IH" then
		if IHOwned.Value == true then
			IH.Value = not IH.Value
		end
	end
end)

I meant the block of code that creates the BoolValues and sets them using the data from the DataStore.

This one is even more confusing:

--//Services
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")

--//Variables
local dataStore = DataStoreService:GetDataStore("MyDataStore")

--//Functions
local function saveData(player)
	local tableToSave = {
		
		Coins = player.leaderstats.Coins.Value,
		
		OwnedGH = player.GoldenHook.Owned.Value,
		EquippedGH = player.GoldenHook.Equipped.Value,

		OwnedTP = player.TPose.Owned.Value,
		EquippedTP = player.TPose.Equipped.Value,
		
		OwnedUS = player.UpsideDown.Owned.Value,
		EquippedUS = player.UpsideDown.Equipped.Value,
		
		OwnedWH = player.WoodenHook.Owned.Value,
		EquippedWH = player.WoodenHook.Equipped.Value,
		
		EquippedIH = player.InvisibleHook.Equipped.Value,
		OwnedIH = player.InvisibleHook.Owned.Value
		
	}

	local success, errorMessage = pcall(function()
		dataStore:SetAsync(player.UserId, tableToSave)
	end)

	if success then -- If the data has been saved
		print("Data has been saved!")
	else -- Else if the save failed
		print("Data hasn't been saved!")
		warn(errorMessage)
	end
end

Players.PlayerAdded:Connect(function(player)
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player

	--//Coins//--	
	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	
	--//InvisibleHook//--
	local InvisibleHook = Instance.new("Folder")
	InvisibleHook.Name = "InvisibleHook"
	InvisibleHook.Parent = player
	
	local OwnedIH = Instance.new("BoolValue")
	OwnedIH.Name = "Owned"
	OwnedIH.Parent = InvisibleHook
	
	local EquippedIH = Instance.new("BoolValue")
	EquippedIH.Name = "Equipped"
	EquippedIH.Parent = InvisibleHook
	--//WoodenHook//--
	local WoodenHook = Instance.new("Folder")
	WoodenHook.Name = "WoodenHook"
	WoodenHook.Parent = player
	
	local OwnedWH = Instance.new("BoolValue")
	OwnedWH.Name = "Owned"
	OwnedWH.Parent = WoodenHook
	
	local EquippedWH = Instance.new("BoolValue")
	EquippedWH.Name = "Equipped"
	EquippedWH.Parent = WoodenHook
	
	--//UpsideDown//--
	local UpsideDown = Instance.new("Folder")
	UpsideDown.Name = "UpsideDown"
	UpsideDown.Parent = player
	
	local OwnedUS = Instance.new("BoolValue")
	OwnedUS.Name = "Owned"
	OwnedUS.Parent = UpsideDown
	
	local EquippedUS = Instance.new("BoolValue")
	EquippedUS.Name = "Equipped"
	EquippedUS.Parent = UpsideDown
	
	--//Golden Hook//--
	local GoldenHook = Instance.new("Folder")
	GoldenHook.Name = "GoldenHook"
	GoldenHook.Parent = player

	local OwnedGH = Instance.new("BoolValue")
	OwnedGH.Name = "Owned"
	OwnedGH.Parent = GoldenHook
	
	local EquippedGH = Instance.new("BoolValue")
	EquippedGH.Name = "Equipped"
	EquippedGH.Parent = GoldenHook

	--//TPose//--
	local TPose = Instance.new("Folder")
	TPose.Name = "TPose"
	TPose.Parent = player

	local OwnedTP = Instance.new("BoolValue")
	OwnedTP.Name = "Owned"
	OwnedTP.Parent = TPose
	
	local EquippedTP = Instance.new("BoolValue")
	EquippedTP.Name = "Equipped"
	EquippedTP.Parent = TPose
	--//Other//--
	local Folder4 = Instance.new("Folder")
	Folder4.Name = "NumberOfHooks"
	Folder4.Parent = player

	local IntValue2 = Instance.new("IntValue")
	IntValue2.Name = "Amount"
	IntValue2.Parent = Folder4

	local data = nil

	local success, errorMessage = pcall(function()
		data = dataStore:GetAsync(player.UserId) 
	end)

	if success and data then 
		Coins.Value = data.Coins
		OwnedGH.Value = data.OwnedGH
		OwnedTP.Value = data.OwnedTP
		EquippedTP.Value = data.EquippedTP
		EquippedGH.Value = data.EquippedGH
		EquippedUS.Value = data.EquippedUS
		OwnedUS.Value = data.OwnedUS
		EquippedIH.Value = data.EquippedIH
		OwnedIH.Value = data.OwnedIH
		EquippedWH.Value = data.EquippedWH
		OwnedWH.Value = data.OwnedWH
	else 
		print("The player has no data!") -- The default will be set to 0
	end
end)

Players.PlayerRemoving:Connect(saveData)

game:BindToClose(function() -- When the server shuts down
	for _, player in Players:GetPlayers() do -- Loop through all the players
		saveData(player)
	end
end)

This is NOT the way you should manage data.

You should use a module that stores the player data.

About your issue, you could just launch a RemoteEvent after a value is changed, then do what ProgrammingRottie did:

RemoteFunction.OnClientEvent:Connect(function()
	EquipButtonTP.Text = EquippedTP.Value and "Equipped" or "Equip"
	EquipButtonGH.Text = EquippedGH.Value and "Equipped" or "Equip"
	EquipButtonWH.Text = EquippedWH.Value and "Equipped" or "Equip"
	EquipButtonIH.Text = EquippedIH.Value and "Equipped" or "Equip"
end)

You could also wrap these connections as the issue might be that these are not loading for the client, using coroutine.wrap() (so the connections wouldn’t need to wait for the previous connection to start), but this would take a lot of space on the script

coroutine.wrap(function()
	EquippedTP.Changed:Connect(function()
		if EquippedTP.Value == true then
			EquipButtonTP.Text = "Equipped"
		elseif EquippedTP.Value == false then
			EquipButtonTP.Text = "Equip"
		end
	end)
end)()

coroutine.wrap(function()
	EquippedGH.Changed:Connect(function()
		if EquippedGH.Value == true then
			EquipButtonGH.Text = "Equipped"
		elseif EquippedGH.Value == false then
			EquipButtonGH.Text = "Equip"
		end
	end)
end)()

coroutine.wrap(function()
	EquippedWH.Changed:Connect(function()
		if EquippedWH.Value == true then
			EquipButtonWH.Text = "Equipped"
		elseif EquippedWH.Value == false then
			EquipButtonWH.Text = "Equip"
		end
	end)
end)()

coroutine.wrap(function()
	EquippedIH.Changed:Connect(function()
		if EquippedIH.Value == true then
			EquipButtonIH.Text = "Equipped"
		elseif EquippedIH.Value == false then
			EquipButtonIH.Text = "Equip"
		end
	end)
end)()

My suggestion is using RemoteEvents and managing data inside a module instead.
Then you can send the data through the server and manage the data with ease

Don’t depend on instances and always manage data inside scripts and/or modules

What do I tie the remote event to? Also how would I use this module script, I dont want you to waste your time teaching a scripting newbie so if you could refer me to a page or smth that would be great.

You should tie the event to whenever updates the data inside a server-side script.

To use the module, it’s pretty easy. It’s like working with a table, but other scripts with the same level (in this case, all server scripts) would have access to it.

This would also work with client scripts, but the data is not replicated, so if you set something in the server-side, client won’t see it. This is good to avoid exploiters trying to modify the data.

Now, to retrieve a module, you need to include a variable with value require().
Inside the require(), you will have to put the instance. It’s the best option to put the module below the same main script, so you can only do local module = require(script.ModuleScript).

Inside the module script you will see this default code:

local module = {}

return module

So, you can set the module to make some data key for you, which would store player’s data.

local module = {}
module.PlayerData = {}

--[[ You can add the data and make the index the same as the PlayerId, so it would be like this:
module.PlayerData = {
      [12345678] = {} -- Data Table
}

12345678 would be the player's user id.
]]

return module
1 Like

I have the module script:

local module = {}

module.PlayerData = {

}

return module

But I dont know what to do with it.

Why don’t you just stall the datastore load so there is an actual change … or have a script to set up off the datastore separate from the changed script.

You can store data from the server script such as:

local UserId = Player.UserId

Module.PlayerData[UserId] = {
	Coins = 100,
	Hooks = {'Wood','Iron'},
}

Then you can retrieve it like this

if Module.PlayerData[UserId] then
	print('Player has '..Module.PlayerData[UserId].Coins..' coins!')
end

Useful to save inside DataStore tables, you just have to:

local DataStore = game:GetService('DataStoreService'):GetDataStore('A')

if Module.PlayerData[UserId] then
	local Saved, Nope = pcall(function()
		DataStore:SetAsync(UserId, Module.PlayerData[UserId])
	end)
	
	if Saved then
		print('Saved')
	else
		warn(Nope)
	end
end

So do I put my data Table inside the module script? If I do how do I get the player. I am so sorry that im so clueless.

You can get it from the UserId, you asign that index to the module, and the value will be the player’s table, which you can get when the player joins