Saving BoolValue Help

Hey all

I have a game where players can buy buttons from a shop, or ‘hatch’ special ones from a pet hatch system sort of thing. How this works is the buttons are in the shop gui, just not showing. When a player ‘hatches’ a button, a boolvalue inside of the button model (called ‘Shown’) becomes true, and shows in the shop. I have figured out how to save this fine, but with this comes another problem.

Now I have it set up where the Shown boolvalue is updated on the client, but this data needs to be sent to the server to store in the datastore. because of this, if a player hatches a button that nobody else in the server has, everybody in the server would get that button, when it should only be the player who hatched it. When I fix this glitch, the buttons don’t save properly. It’s basically just a neverending loop of error.

hopefully that made sense. If you don’t understand, I can simplify it for you.

Here are the scripts that handle this stuff:

ClientScript:

-- Client Script
local RS = game:GetService("ReplicatedStorage")
local updateShownValueRemote = RS:WaitForChild("UpdateShownValue")

-- Function to notify the server of a Shown value change
local function notifyServerOfChange(buttonName, newValue)
	updateShownValueRemote:FireServer(buttonName, newValue)
end

-- Set up listeners for Shown value changes
local function setupShownValueListener()
	for _, button in pairs(RS.Buttons:GetChildren()) do
		local shownValue = button:FindFirstChild("Shown")
		if shownValue and shownValue:IsA("BoolValue") then
			-- Use a local copy of the value to prevent broadcasting to all clients
			local localShownValue = Instance.new("BoolValue")
			localShownValue.Name = shownValue.Name
			localShownValue.Value = shownValue.Value
			shownValue:GetPropertyChangedSignal("Value"):Connect(function()
				localShownValue.Value = shownValue.Value
				notifyServerOfChange(button.Name, localShownValue.Value)
			end)
		end
	end
end

setupShownValueListener()

ServerScript:

-- Server Script
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")

local shownValuesDataStore = DataStoreService:GetDataStore("adsadasdew3qdasdqw")

-- RemoteEvent for handling Shown value updates
local updateShownValueRemote = Instance.new("RemoteEvent")
updateShownValueRemote.Name = "UpdateShownValue"
updateShownValueRemote.Parent = RS

-- Function to save a single Shown value
local function saveShownValue(player, buttonName, value)
	local success, errorMessage = pcall(function()
		local data = shownValuesDataStore:GetAsync(player.UserId) or {}
		data[buttonName] = value
		shownValuesDataStore:SetAsync(player.UserId, data)
	end)

	if success then
		print("Successfully saved Shown value for button " .. buttonName .. " for player " .. player.Name)
	else
		warn("Failed to save Shown value for button " .. buttonName .. " for player " .. player.Name .. ": " .. errorMessage)
	end
end

-- Handle the event when the client notifies of a Shown value change
updateShownValueRemote.OnServerEvent:Connect(function(player, buttonName, newValue)
	local button = RS.Buttons:FindFirstChild(buttonName)
	if button then
		local shownValue = button:FindFirstChild("Shown")
		if shownValue and shownValue:IsA("BoolValue") then
			-- Only update the value on the server
			shownValue.Value = newValue
			saveShownValue(player, buttonName, newValue)
		else
			warn("Shown BoolValue not found for button: " .. buttonName)
		end
	else
		warn("Button not found in ReplicatedStorage: " .. buttonName)
	end
end)

-- Load the player's Shown values when they join
Players.PlayerAdded:Connect(function(player)
	local success, data = pcall(function()
		return shownValuesDataStore:GetAsync(player.UserId)
	end)

	if success and data then
		for buttonName, value in pairs(data) do
			local button = RS.Buttons:FindFirstChild(buttonName)
			if button then
				local shownValue = button:FindFirstChild("Shown")
				if shownValue and shownValue:IsA("BoolValue") then
					-- Set the value for the specific player
					shownValue.Value = value
				else
					warn("Shown BoolValue not found for button: " .. buttonName)
				end
			else
				warn("Button not found in ReplicatedStorage: " .. buttonName)
			end
		end
		print("Successfully loaded data for " .. player.Name)
	else
		if not success then
			warn("Failed to load data for " .. player.Name .. ": " .. tostring(data))
		else
			print("No data found for " .. player.Name)
		end
	end
end)

sorry if this code is a mess.

thanks for any help.

1 Like

Might I suggest that you abandon parts of your current system and instead use a simpler one that achieves the exact same thing? You should store what buttons each player has via leaderstats on the server (each player should get their own leaderstat, if you don’t know how those work, hopefully this video will help) You should then instead check the leaderstats and use those to show/hide buttons on the client (they are replicated). Then, simply save the leaderstats into a DataStore.

Basically:
Leaderstats on the server which stores all button data (use bool values ig?)
When you hatch, you send remoteEvent which changes leaderstat one server
When you look at menu, show/hide UI using the leaderstats info (they replicate to client)
Save entire leaderstats folder when saving

1 Like

Honestly, why do you need that Shown value? Once the player clicks the button you can play the hatching animation for them right there, then you can fire a remote function to the server with relevant information for saving. When they join back, you can fire a remote event to make visual changes on the client

ocal JBE = game.ReplicatedStorage.JoinBackEvent
local DHE = game.ReplicatedStorage.DoneHatchingEvent
local button = script.Parent.HatchDog
button.Activated:Connect(function()
  — Play hatching animation and other stuff
  local s = DHE:InvokeServer(button.Name)
  If s then button.Visible = false end
end)

Then on the server…

localJBE = game.ReplicatedStorage.JoinBackEvent
local DHE = game.ReplicatedStorage.DoneHatchingEvent
local SaveTable = {}
DHE.OnServerInvoke = function(plr,name)
   table.insert(SaveTable[plr.Name],name)
   return true
end

And when they’re joining back…

localJBE = game.ReplicatedStorage.JoinBackEvent
local DHE = game.ReplicatedStorage.DoneHatchingEvent
local SaveTable = {}
game.Players.PlayerAdded:Connect(function(plr)
   local data
   — Do your saving stuff here
   for i,v in ipairs(data) do
      table.insert(SaveTable[plr.Name],v)
   end
   JBE:FireClient(plr,data)
end)
local hatchbuttons = script.Parent.HatchButtons
JBE.OnClientEvent:Connect(function(data)
   for i,v in ipairs(data) do
      hatchbuttons[v].Visible = false
   end
end)
1 Like