Datastore script not working

hey so i have this script with datastore and for some reason the second item doesnt save after i leave but the first itemn does save heres the server scirpt and the local scirpt

local DataStoreService = game:GetService("DataStoreService")
local purchaseDataStore = DataStoreService:GetDataStore("PurchaseStore")
local remoteEvent = game.ReplicatedStorage:WaitForChild("PurchaseEvent")

-- List of items to manage
local items = {"Item1", "Item2"}

-- Load player's purchase state when they join
game.Players.PlayerAdded:Connect(function(player)
	for _, itemName in pairs(items) do
		local hasPurchased = Instance.new("BoolValue")
		hasPurchased.Name = itemName .. "Purchased"
		hasPurchased.Parent = player

		-- Retrieve purchase state
		local success, data = pcall(function()
			return purchaseDataStore:GetAsync(player.UserId .. "_" .. itemName)
		end)

		if success then
			hasPurchased.Value = data or false -- Defaults to false if no data found
			print(player.Name .. " has purchased " .. itemName .. ": " .. tostring(hasPurchased.Value))
		else
			warn("Error loading purchase state for " .. itemName .. ": " .. tostring(data))
		end
	end
end)

-- Save purchase states when player leaves
game.Players.PlayerRemoving:Connect(function(player)
	for _, itemName in pairs(items) do
		local hasPurchased = player:FindFirstChild(itemName .. "Purchased")
		if hasPurchased then
			local success, errorMessage = pcall(function()
				-- Ensure saving the current state before removing the player
				purchaseDataStore:SetAsync(player.UserId .. "_" .. itemName, hasPurchased.Value)
			end)

			if success then
				print("Saved purchase state for " .. itemName .. ": " .. tostring(hasPurchased.Value))
			else
				warn("Error saving purchase state for " .. itemName .. ": " .. tostring(errorMessage))
			end
		else
			warn(itemName .. " BoolValue not found for " .. player.Name)
		end
	end
end)

-- Handle button clicks for purchases
remoteEvent.OnServerEvent:Connect(function(player, itemName, price)
	local leaderstats = player:FindFirstChild("leaderstats")
	local hasPurchased = player:FindFirstChild(itemName .. "Purchased")

	if leaderstats and hasPurchased then
		local sparks = leaderstats:FindFirstChild("Sparks")
		if sparks and sparks.Value >= price then
			sparks.Value = sparks.Value - price
			hasPurchased.Value = true

			-- Notify the client of successful purchase
			remoteEvent:FireClient(player, itemName)

			-- Save the purchase state
			local success, errorMessage = pcall(function()
				purchaseDataStore:SetAsync(player.UserId .. "_" .. itemName, true)
			end)

			if success then
				print("Successfully purchased " .. itemName .. " for " .. player.Name)
			else
				warn("Error saving purchase state for " .. itemName .. ": " .. tostring(errorMessage))
			end
		else
			warn(player.Name .. " does not have enough Sparks for " .. itemName)
		end
	else
		warn("Leaderstats or hasPurchased not found for " .. player.Name)
	end
end)

local player = game.Players.LocalPlayer
local itemName = "Item2" -- Change for each button (Item1, Item2, etc.)
local price = 100 -- Set price for each button
local button = script.Parent
local remoteEvent = game.ReplicatedStorage:WaitForChild("PurchaseEvent")

local function checkPurchase()
	local hasPurchased = player:FindFirstChild(itemName .. "Purchased")

	if hasPurchased then
		if hasPurchased.Value then
			button.Visible = false
		else
			button.Visible = true
		end
	end
end

checkPurchase() -- Check purchase status on load

button.MouseButton1Click:Connect(function()
	remoteEvent:FireServer(itemName, price)
end)

remoteEvent.OnClientEvent:Connect(function(purchasedItem)
	if purchasedItem == itemName then
		button.Visible = false
	end
end)

Is there any errors in the output?

2 Likes

nope there isnt any i checked many times

warn("Error saving purchase state for " .. itemName .. ": " .. tostring(errorMessage))

Does this line print for the second item?

2 Likes

Yes, that line will print for the second item if there is an error when saving the purchase state for that item. The output will include the specific item name and the associated error message.

What is the errorMessage you are receiving?

i dont get any error messages its only saying super_marvel1232 has purchased Item1: true and super_marvel1232 has purchased Item2 true but when i tested the second time it doesnt save both items anymroe

1 Like

Maybe instead of saving it directly when purchased, Check if the Value changed then save:

game.Players.PlayerAdded:Connect(function(player)
	for _, itemName in pairs(items) do
		local hasPurchased = Instance.new("BoolValue")
		hasPurchased.Name = itemName .. "Purchased"
		hasPurchased.Parent = player

		-- Retrieve purchase state
		local success, data = pcall(function()
			return purchaseDataStore:GetAsync(player.UserId .. "_" .. itemName)
		end)

		if success then
			hasPurchased.Value = data or false -- Defaults to false if no data found
			print(player.Name .. " has purchased " .. itemName .. ": " .. tostring(hasPurchased.Value))
		else
			warn("Error loading purchase state for " .. itemName .. ": " .. tostring(data))
		end

        hasPurchased:GetPropertyChangedSignal("Value"):Connect(function()
            local success, err = pcall(function()
			    purchaseDataStore:GetAsync(player.UserId .. "_" .. itemName)
		    end)

		    if success then
		          print(player.Name .. " saved " .. itemName .. ": " .. tostring(hasPurchased.Value))
		     else
		          warn(err)
		    end

        end)
	end
end)

and remove the saving part from the remote event part:

remoteEvent.OnServerEvent:Connect(function(player, itemName, price)
	local leaderstats = player:FindFirstChild("leaderstats")
	local hasPurchased = player:FindFirstChild(itemName .. "Purchased")

	if leaderstats and hasPurchased then
		local sparks = leaderstats:FindFirstChild("Sparks")
		if sparks and sparks.Value >= price then
			sparks.Value = sparks.Value - price
			hasPurchased.Value = true

			-- Notify the client of successful purchase
			remoteEvent:FireClient(player, itemName)

		else
			warn(player.Name .. " does not have enough Sparks for " .. itemName)
		end
	else
		warn("Leaderstats or hasPurchased not found for " .. player.Name)
	end
end)
1 Like

now it saves only the first item again

Try this:

game.Players.PlayerAdded:Connect(function(player)
	for _, itemName in pairs(items) do
 coroutine.wrap(function()
		local hasPurchased = Instance.new("BoolValue")
		hasPurchased.Name = itemName .. "Purchased"
		hasPurchased.Parent = player

		-- Retrieve purchase state
		local success, data = pcall(function()
			return purchaseDataStore:GetAsync(player.UserId .. "_" .. itemName)
		end)

		if success then
			hasPurchased.Value = data or false -- Defaults to false if no data found
			print(player.Name .. " has purchased " .. itemName .. ": " .. tostring(hasPurchased.Value))
		else
			warn("Error loading purchase state for " .. itemName .. ": " .. tostring(data))
		end

        hasPurchased:GetPropertyChangedSignal("Value"):Connect(function()
            local success, err = pcall(function()
			    purchaseDataStore:GetAsync(player.UserId .. "_" .. itemName)
		    end)

		    if success then
		          print(player.Name .. " saved " .. itemName .. ": " .. tostring(hasPurchased.Value))
		     else
		          warn(err)
		    end

        end)
end)()
	end
end)
1 Like

It is generally bad practice to save data the way you do. You should only call :SetAsync() once. How do you do that? Simply put all your purchased items in a table and then save that table. My wild guess is that the server sometimes already shut down before the second :SetAsync() was able to be called.

wow thank you so much it actually worked ive been trying to fix this script for days thank you so much!!!

1 Like