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)
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.
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
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)
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)
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.