Hello. i have this simple shop system and it works, except when you leave the game and rejoin, only your currency saves. this means the button in the shop makes u buy it again, and the button in ur inventory is now gone. (bc it didnt save)
does anyone know how to make it save or how to fix this? I have a leaderboard / datastore script in server script service, but the buttons still will not save. if anyone could help me fix this that would be great.
here are some of the scripts -
the datastore / leaderstat
local datastore = game:GetService("DataStoreService")
local ds1 = datastore:GetDataStore("MoneySaveSystem")
local storage = game:GetService("ReplicatedStorage")
local players = game:GetService("Players")
local re = storage.RemoteEvent
re.OnServerEvent:Connect(function(player, value)
if player.leaderstats.FairyDust.Value >= value then
player.leaderstats.FairyDust.Value -= value
else
player:Kick("Do not exploit.")
end
end)
game.Players.PlayerAdded:connect(function(plr)
local folder = Instance.new("Folder", plr)
folder.Name = "leaderstats"
local FairyDust = Instance.new("IntValue", folder)
FairyDust.Name = "FairyDust"
FairyDust.Value = ds1:GetAsync(plr.UserId) or 0
ds1:SetAsync(plr.UserId, FairyDust.Value)
FairyDust.Changed:connect(function()
ds1:SetAsync(plr.UserId, FairyDust.Value)
end)
end)
game:BindToClose(function()
for _, plr in pairs(players:GetPlayers()) do
local money = plr.leaderstats.FairyDust
ds1:SetAsync(plr.UserId, money.Value)
end
end)
--Quest money -- ignore this
game.ReplicatedStorage.Quests.Hundred.OnServerEvent:Connect(function(plr)
plr.leaderstats.FairyDust.Value = plr.leaderstats.FairyDust.Value +100
end)```
---------------------------------------------------------------------------------------------------------------------------------
and this is the script in the buy button which is in the shop
local storage = game:GetService("ReplicatedStorage")
local re = storage.RemoteEvent
local players = game:GetService("Players")
local player = players.LocalPlayer or players.PlayerAdded:Wait()
local item = script.Parent
local shoes = script.Parent.Parent.Parent.Frame1.Shoes
local value = 40000
item.MouseButton1Click:Connect(function()
if player.leaderstats.FairyDust.Value >= value then
re:FireServer(value)
item.Text = "Purchased"
shoes.Visible = true
value = 0
else
item.Text = "Insuffiecetn Funds"
task.wait(2)
item.Text = "Purchase"
end
end)
i dont see anything other than saving the “FairyDust”.
anyway why dont you save the data using the PlayerRemoving event along with BindToClose? instead of spamming SetAsync everytime the FairyDust of a player changes its value.
local dss = game:GetService("DataStoreService")
local players = game:GetService("Players")
local shop = dss:GetDataStore("themonkeshop")
local item = workspace.flyingball -- (assume this is the item u want to give)
players.PlayerAdded:Connect(function(player)
-- in this case the game only has 1 item to purchase (if u have multiple just use for loops lol)
local key = "FlyingBallsOfFate_UID" .. player.UserId
if (shop:GetAsync(key)) then -- hooray, they have purchased it before.
-- give the item
item:Clone().Parent = player:WaitForChild("Backpack")
end
end)
-- assume `re` is the remote that's called when purchase
re.OnServerEvent:Connect(function(player, value) -- i think value is the price of the "item"?
if (player.leaderstats.FairyDust.Value < value) then return end; -- they dont have sufficient "FairyDust", nobody wants negative currency innit
local UserId = player.UserId
local key = "FlyingBallsOfFate_UID" .. UserId -- we make a key for an item. so if we assume the buyer's UserId is 123 the key becomes FlyingBallsOfFate_UID123
local status = shop:GetAsync(key)
if (status) then return end -- the person already has it so dont buy it again
player.leaderstats.FairyDust.Value -= value -- take away the "FairyDust" thingy
--- <do something>
-- give the item
item:Clone().Parent = player:WaitForChild("Backpack")
-- tell the datastore service that they already bought it.
shop:SetAsync(key, true)
end)
sorry if my comments aren’t understandable, i hope you can be a better scripter in the future
Hello and thanks for getting back to me. I dont know if this makes sense but there is no item. There is no backpack needed to be involved. Technically, the person is just clicking a button (the buy button) and that just makes another button in a different frame become visible, then when you click said button other stuff happens. I just need help making that button stay visible even when the person leaves the game.(and in the shop so u cannot buy it again bc u already bought it) Idk how you would do that though.
it’s very easy, just write to the datastore that the player already bought it and make the button not interactive once. then with that datastore data use it to know whenether the player already have bought something or haven’t, and the second the UI loads i suppose you can modify the player’s UI from a serverscript. also dont forget to modify it on the PlayerGui folder, not StarterGui. sorry for the late response.
is there anyway you could right out a little of it i literally like i understand that’s whant needs to be done i just literally do not understand anything about data saving and that stuff. if not that is totally ok.
Using .Changed can some times overflow the saving process you need to save on exit or use DataStore 2 thats just how roblox works thats Issue number 1 use PlayerRemoving to save Money instead of BindToClose and also save FairyDust on exit as well
Your problem here is that you save ONLY currency - that FairyDust, while you forgot about “Buttons” purchased. This results in resetting shop progress, while keeping currency one. To fix this, you need rewrite your system a bit:
local DataStore = game:GetService("DataStoreService")
local ProgressDataStore = datastore:GetDataStore("ProgressSaveSystem") <-- note that I changed name here to logically match a bit.
local RS = game:GetService("ReplicatedStorage")
local PLS = game:GetService("Players")
local Event = storage.RemoteEvent
local DefaultData = {
FairyDust = 0,
ShopItem1 = false,
ShopItem2 = false,
ShopItem3 = false,
-- and so on...
}
Event.OnServerEvent:Connect(function(player, value, ShopItem)
if player.Leaderstats.FairyDust.Value >= value then
player.Leaderstats.FairyDust.Value -= value
player.Leaderstats[ShopItem].Value = true
-- else do nothing not kick bc there's always possible for fair player to somehow glitch system
end
end)
PLS.PlayerAdded:connect(function(plr)
local Folder = Instance.new("Folder") -- never parent any object when it created, parent it only after all necessary properties and childrens are sat.
Folder.Name = "Leaderstats"
local Data = ProgressDataStore:GetAsync(plr.UserId) or default -- if there's no data, then use Default one
-- there you need way of setting up saving system for Shop. IDK how you structured it, so I'll do most basic way: with respective Values instances.
for PropName, PropValue in pairs(Data) do
local ValueType = typeof(PropValue)
ValueType = string.Upper(string.sub(ValueType, 1, 1)) .. string.sub(ValueType, 2 , -1)
local Value = Instance.new(PropValue .. "Value"])
Value.Value = PropValue
Value.Name = PropName
Value.Parent = Folder
end
Folder.Parent = plr
end)
game:BindToClose(function()
local Players = (PLS:GetPlayers()
for a = 1, #Players , 1 do
local Data = Default
local FolderData = Players[a].Leaderstats:GetChildren()
for i = 1, #FolderData, 1 do
Data[FolderData[i].Name] = FolderData[i].Value
end
ProgressDataStore:SetAsync(plr.UserId, Data)
end
end)
PLS.PlayerRemoving:Connect(function(plr)
local Data = Default
local FolderData = plr.Leaderstats:GetChildren()
for i = 1, #FolderData, 1 do
Data[FolderData[i].Name] = FolderData[i].Value
end
ProgressDataStore:SetAsync(plr.UserId, Data)
end)
game.ReplicatedStorage.Quests.Hundred.OnServerEvent:Connect(function(plr)
plr.leaderstats.FairyDust.Value = plr.leaderstats.FairyDust.Value +100
end)
--[==[
NOTE:
While this system saves what you buy, you need implement yourself
another system for your shop, which will check every item bought
and depending on that, it will turn button to already purchased
and that buttons, which not purchased yet.
! Also, this script may contain some small bugs and flaws !
--]==]
Also, you need remember that you should save data only when player leaves (or with 5 mins autosave to handle unexpected situations). Also, not use Instance.new(<Object>, Parent), and use Instance.new(<Object>), bc it’s slower than setting parent after everything other set.