Currency doesn't save after purchase

Hello there,

I have my own currency in my game which allows you to rent items such as a tool, hat, or horse. When people purchase an item, it removes the amount you spent, for example if the horse cost 250 gold, it will remove 250 gold once the horse is bought, however when you the currency adds a bit after every minute or so it goes back to the exact amount you had before you bought the item. Which means people can get items in my game for free. Does anyone know how to fix this? Any help is greatly appreciated.

Shop Script
local receiveTool = game.ReplicatedStorage:WaitForChild("ReceiveTool")
local Player = game.Players.LocalPlayer.Backpack
repeat wait() until game.Players.LocalPlayer
game.Players.LocalPlayer:WaitForChild("Silver")

function onClicked() 
if game.Players.LocalPlayer.Silver.Value >= 250 then
game.Players.LocalPlayer.Silver.Value = game.Players.LocalPlayer.Silver.Value-250
receiveTool:InvokeServer("Horses", "BrownHorse")
end 
end
script.Parent.MouseButton1Down:connect(onClicked)
game.Players.LocalPlayer.Silver.Changed:connect(function()
	script.Parent.Text=(game.Players.LocalPlayer.Silver.Value)
end)
Server Script
local DataStore = game:GetService("DataStoreService"):GetGlobalDataStore("SILVER")
game.Players.PlayerAdded:connect(function(player)
	
	local silver = "Silver"..player.UserId 
	local Silver = Instance.new("IntValue", player) 
	Silver.Name = "Silver" 
	Silver.Value = DataStore:GetAsync(silver)
	Silver.Changed:connect(function(Val) 
		DataStore:SetAsync(silver, Val) 
	end)
end)
game.Players.PlayerRemoving:connect(function(player)
	local silver = "Silver"..player.UserId
	DataStore:SetAsync(silver, (player.Currency.Silver.Value)) 
end)
2 Likes

Your problem here is that you’re trying to change server data from the client. You’ll need to edit the server side of the ReceiveTool remote to perform the following:

  • Confirm that the user can afford the item
  • Subtract the appropriate cost

This will fix your problem and increase security (an exploiter could easily call the ReceiveTool remote and get items for free).

The server code will look something like this:

local receiveToolRemote=game.ReplicatedStorage.ReceiveTool --remote function
function invoked(player,category,name) --function to be invoked
	if player.Silver.Value>=250 then --check for adequate money
		player.Silver.Value=player.Silver.Value-250 --subtract the money
		--TODO: give horse or thing or whatever
	end
end
receiveToolRemote.OnServerInvoke=invoked --connect the function to the remote

And the client code will look something like this:

function onClicked() --function to be called on click
	if game.Players.LocalPlayer.Silver.Value>=250 then --it doesn't hurt to check on the client anyway
		receiveTool:InvokeServer("Horses","BrownHorse") --invoke the server to do all of the work
	end
end
3 Likes

Would I need to put every shop item inside the server script?

Yes, unfortunately.

1 Like

I added in what you told me and it’s not letting me purchase anything anymore. Did I do something wrong?

Fill out the code with print() statements and figure out where the code stops. How far does it get?

1 Like

Ok,

1st why are you using a RF if you aren’t returning something? Just use a RE

2nd That’s terrible coding practice don’t Save every time the Money changes, you’ll run out of Budget and then your code falls apart.

Only save when

1.A player presses Save (Also add a Cooldown)
2.Auto Save
3.When the player leaves + Game Close (Bind To Close)

1 Like

Don’t update the player’s data everytime the value changes (they purchase something), this can throttle the request and return an error. There’s a 60-second cooldown for using SetAsync, so use it wisely. I’d rather add a loop that automatically saves the player’s data every 60 seconds or more to not throttle the request.

1 Like

It’s reccomended to save when a change is made to a player’s stats that’s noticeable enough to save, I. E. Buying an item, buying currency, earning a lot of currency at once, etc.

1 Like

Who recommended this?


Saving when

Isn’t need if the Data is Saved at these 3 Times

I understand that you want to make sure that the Player’s Data is Saved when they spend Robux or Earn something but

Isn’t really worth considering it all the Players won’t be able to save because someone spammed SetAsync.

2 Likes

Ah, I remembered it wrong.

I remembered the stats changing from this, but forgot about the context.

There was also this too.

1 Like

That’s not what I meant. I meant to have a while loop running on the server saving the player’s data every 60 seconds. If you saved the data below the required time, it will just return an error and won’t save at all.

1 Like

I thought you meant that it will stop working for 1 Minute if you spam it enough, which isn’t worth saving every time a Stat changes.

But if you are saying that saving every 1 Minute is good practice then yes I agree.

1 Like

What would throttle the request and make it not save, and throw an error instead, is having the data getting saved every time the values changes, which someone could abuse by purchasing a lot of items within a minute.

1 Like