Weird Datastore Money Saving Glitch

Hey!

I have a datastore for a project I am working on, and it works great. It saves money how it’s supposed to, and is all around working amazingly.

In the same game there is a shop where you can purchase gears using the money. This is where the problem starts.

When buying an item, it charges the player the cost of the gear and the player receives the gear. All normal. In the game is a script that gives the player one dollar every minute. When the player obtains cash in any other way after the purchase, their money value returns to what it was before the purchase.

For example; Let’s say a player has 100 dollars, and buys a sword for 50. The player now has 50 dollars after the purchase. Then they get their one dollar a minute, and now they have 101 dollars.

I have been trying to figure this out for weeks and have hit a dead end.

any help would be greatly appreciated!

The Leaderstats script:


local coinsStatName = "Doubloons"


local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("PlayerCoins")


local function savePlayerCoins(player)
	
	local userId = tostring(player.UserId)

	
	local success, error = pcall(function()
		dataStore:SetAsync(userId, player.leaderstats[coinsStatName].Value)
	end)

	if not success then
		warn("Failed to save player coins:", error)
	end
end


local function loadPlayerCoins(player)
	
	local userId = tostring(player.UserId)

	
	local success, coins = pcall(function()
		return dataStore:GetAsync(userId)
	end)

	if success and coins then
		
		local leaderstats = player:FindFirstChild("leaderstats")
		if not leaderstats then
			leaderstats = Instance.new("Folder")
			leaderstats.Name = "leaderstats"
			leaderstats.Parent = player
		end

		
		local coinsStat = leaderstats:FindFirstChild(coinsStatName)
		if not coinsStat then
			coinsStat = Instance.new("IntValue")
			coinsStat.Name = coinsStatName
			coinsStat.Value = coins
			coinsStat.Parent = leaderstats
		else
			coinsStat.Value = coins
		end
	end
end


game.Players.PlayerRemoving:Connect(function(player)
	
	savePlayerCoins(player)
end)


game.Players.PlayerAdded:Connect(function(player)
	
	loadPlayerCoins(player)
end)

The Sword Purchase Script:

local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local ShopGui = Players.LocalPlayer.PlayerGui.Shop
local ShopFrame = ShopGui.Frame
local SwordButton = ShopFrame.ScrollingFrame.Sword

SwordButton.MouseButton1Click:Connect(function()
	local player = Players.LocalPlayer
	local cash = player.leaderstats.Doubloons

	if cash.Value >= 10 then
		if player.Backpack:FindFirstChild("Sword") == nil and player.Character:FindFirstChild("Sword") == nil then
			cash.Value = cash.Value - 10
			local sword = ReplicatedStorage.Sword:Clone()
			sword.Parent = player.Backpack
		else
			print("You already have the Sword!")
		end
	else
		print("Not enough cash to purchase Sword!")
	end
end)

The issue is you’re removing the cash on the client. Never trust the client. Make a RemoteEvent and fire that when a purchase has to be made. Like this:

--> LocalScript
local RemoteEvent = ReplicatedStorage.RemoteEvent --> Location of RemoteEvent

SwordButton.MouseButton1Click:Connect(function()
   local player = Players.LocalPlayer
   local cash = player.leaderstats.Doubloons
   
   if cash.Value >= 10 then
     RemoteEvent:FireServer()
   end
end)
--> Server Script

local RemoteEvent = ReplicatedStorage.RemoteEvent --> Location of RemoteEvent

RemoteEvent.OnServerEvent:Connect(function(player,)
   local cash = player.leaderstats.Doubloons
   if cash.Value >= 10 then
      cash.Value -= 10
      --> Give Sword
   end
end

This is the basic system. Of course, you could make it better by having one remote handle all purchases and have a table with the items’ stats like price so you can check on the server. Like this:

{
   ["Sword"] = {
      Cost = 50
   },

   ["Another Sword"] = {
      Cost = 50000
   }
}
2 Likes

Thanks alot! I was suffering from this problem too!