Failing to buy items

I changed my saving system, and I am trying to make my shop (which beforehand used a different saving system) be compatible with the new one, and I am failing to make things be buy-able.

There are no errors present in the output however, so I don’t know what causes those issues… I don’t know which script is messed up to cause this.

Help would be really appreciated : )

SavingData:

local DataStoreService = game:GetService("DataStoreService")
local conf = game.ReplicatedStorage:WaitForChild("Configuration")
local currencyName = conf:WaitForChild("CurrencyName")
local startingCurrency = conf:WaitForChild("StartingCurrency")
local dsKey = conf:WaitForChild("DatastoreKey")

local datastore = DataStoreService:GetDataStore(dsKey.Value)

-- Function to save player data
local function SaveData(player)
	if not player then
		return
	end

	local plrKey = player.UserId

	local plrCash = player:WaitForChild("leaderstats"):WaitForChild(currencyName.Value).Value

	-- Collect player's tools data
	local tools = {}
	for _, tool in ipairs(player.Backpack:GetChildren()) do
		table.insert(tools, tool.Name)
	end

	local plrData = { Cash = plrCash, Tools = tools }

	local success, err = pcall(function()
		datastore:SetAsync(plrKey, plrData)
	end)

	if not success then
		warn("Error saving " .. player.Name .. "'s (" .. plrKey .. ") data:\n" .. err)
	else
		print("Data saved successfully for player:", player.Name)
	end
end

-- Connect function to player leaving event
game.Players.PlayerRemoving:Connect(function(player)
	SaveData(player)
end)

game:BindToClose(function()
	for _, player in ipairs(game.Players:GetPlayers()) do
		SaveData(player)
	end
end)

-- Function to load player data
local function LoadData(player)
	if not player then
		return
	end

	local plrKey = player.UserId

	local dataFailedWarning = Instance.new("BoolValue")
	dataFailedWarning.Name = "DataLoadFailed"
	dataFailedWarning.Value = true
	dataFailedWarning.Parent = player

	local success, plrData = pcall(function()
		return datastore:GetAsync(plrKey)
	end)

	if success and plrData then
		-- Create leaderstats if not already present
		local leaderstats = player:FindFirstChild("leaderstats")
		if not leaderstats then
			leaderstats = Instance.new("Folder")
			leaderstats.Name = "leaderstats"
			leaderstats.Parent = player
		end

		local currency = leaderstats:FindFirstChild(currencyName.Value)
		if not currency then
			currency = Instance.new("IntValue")
			currency.Name = currencyName.Value
			currency.Parent = leaderstats
		end
		currency.Value = plrData.Cash or startingCurrency.Value

		-- Give the player their saved tools
		local backpack = player:WaitForChild("Backpack")
		for _, toolName in ipairs(plrData.Tools or {}) do
			local tool = game.ServerStorage:FindFirstChild(toolName)
			if tool then
				tool:Clone().Parent = backpack
			end
		end

		dataFailedWarning.Value = false
	else
		warn("Error loading " .. player.Name .. "'s (" .. plrKey .. ") data.")
	end

	dataFailedWarning:Destroy()
end

-- Connect function to player joining event
game.Players.PlayerAdded:Connect(function(player)
	player.CharacterAdded:Connect(function()
		LoadData(player)
	end)
end)

ShopServer:

local conf = game.ReplicatedStorage:WaitForChild("Configuration")
local currencyName = conf:WaitForChild("CurrencyName")
local startingCurrency = conf:WaitForChild("StartingCurrency")
local canBuyMultipleTimes = conf:WaitForChild("CanBuyItemMultipleTimes")

local SavingData = game.ServerScriptService:WaitForChild("SavingData")
local CreateLeaderstats = require(SavingData:WaitForChild("CreateLeaderstats"))
local CreateTools = require(SavingData:WaitForChild("CreateTools"))
local BuyTool = require(SavingData:WaitForChild("BuyTool"))

local remotes = game.ReplicatedStorage:WaitForChild("RemoteEvents")
local buyToolRE = remotes:WaitForChild("BuyTool")

local equippedTools = {}

game.Players.PlayerAdded:Connect(function(plr)
    plr.CharacterAdded:Connect(function(char)
        char.ChildAdded:Connect(function(child)
            local equippedTool = char:FindFirstChildOfClass("Tool")
            equippedTools[plr] = equippedTool and equippedTool.Name
        end)
    end)

    local plrData = SavingData:LoadData(plr)
    local plrCash = plrData and plrData.Cash or startingCurrency.Value
    local plrTools = plrData and plrData.Tools or {}

    CreateLeaderstats(plr, plrCash)
    CreateTools(plr, plrTools)
end)

game.Players.PlayerRemoving:Connect(function(plr)
    SavingData:SaveData(plr, equippedTools[plr])
end)

game:BindToClose(function()
    for _, plr in pairs(game.Players:GetPlayers()) do
        SavingData:SaveData(plr, equippedTools[plr])
    end
end)

buyToolRE.OnServerEvent:Connect(function(plr, toolName)
    BuyTool(plr, toolName)
end)

BuyTool:

local conf = game.ReplicatedStorage:WaitForChild("Configuration")
local currencyName = conf:WaitForChild("CurrencyName")
local canBuyMultipleTimes = conf:WaitForChild("CanBuyItemMultipleTimes")
local keepItemsOnDeath = conf:WaitForChild("KeepItemsOnDeath")

local tools = game.ReplicatedStorage:WaitForChild("Tools")
local coins = game.ReplicatedStorage:WaitForChild("Coins")
local gamepass = game.ReplicatedStorage:WaitForChild("Gamepass")

local remotes = game.ReplicatedStorage:WaitForChild("RemoteEvents")
local buyToolRE = remotes:WaitForChild("BuyTool")

function BuyTool(plr, toolName)
	local toolToBuy = nil

	-- Check if the tool is in the Tools category
	toolToBuy = tools:FindFirstChild(toolName)

	-- If not, check if it's in the Coins category
	if not toolToBuy then
		toolToBuy = coins:FindFirstChild(toolName)
	end

	-- If still not found, check if it's in the Gamepass category
	if not toolToBuy then
		toolToBuy = gamepass:FindFirstChild(toolName)
	end

	-- If the tool wasn't found in any category, return
	if not toolToBuy then
		warn("Tool '" .. toolName .. "' doesn't exist!")
		return
	end

	local toolConfig = toolToBuy:FindFirstChild("Configuration")
	if not toolConfig then
		warn("Tool '" .. toolName .. "' doesn't have a Configuration folder!")
		return
	end

	local toolPriceValue = toolConfig:FindFirstChild("Price")
	if not toolPriceValue then
		warn("Tool '" .. toolName .. "' doesn't have a Price value!")
		return
	end

	local plrCash = plr.leaderstats[currencyName.Value]
	local toolPrice = toolPriceValue.Value

	if plrCash.Value < toolPrice then
		warn("Player " .. plr.Name .. " (" .. plr.UserId .. ") doesn't have enough cash to buy '" .. toolName .. "'!")
		return
	end

	local plrTools = require(game.ReplicatedStorage.ModuleScripts.GetTools)(plr)

	-- Check if the player already owns the tool
	local alreadyOwnsTool = table.find(plrTools, toolName)

	if alreadyOwnsTool then
		-- Player already owns the tool, replace it
		local existingTool = plr.Backpack:FindFirstChild(toolName)
		if existingTool then
			existingTool:Destroy()
		end
	end

	-- Deduct the price from the player's cash balance
	plrCash.Value -= toolPrice

	-- Give the player the new tool
	local newTool = toolToBuy:Clone()
	newTool.Parent = plr.Backpack

	-- If configured to keep items on death, add the new tool to the starter gear
	if keepItemsOnDeath.Value then
		local starterGear = plr:FindFirstChild("StarterGear")
		if starterGear then
			newTool:Clone().Parent = starterGear
		end
	end

	-- Notify the client about the purchase
	buyToolRE:FireClient(plr, toolToBuy)
end

return BuyTool
2 Likes

The tool data shouldn’t just go over their backpack but try and find tools inside of their character too… I think that might do something but I gtg (didn;t read all of it my bad).

1 Like

Could you elaborate on what you mean?

When a plr equips a tool it goes into their character and is removed from their backpack. I didn’t read all of it yet so I’m not sure if you do check inside he character…

(Mb I misread it it was a module script)

Idk… maybe elaborate more on the issue. What goes wrong? Also… maybe provide the local scripts too?

Apologies for the late response, but the issue is that after I changed the way data is saved, I am struggling to fix the bug where the player cannot buy items, like, I press the buy button and nothing happens when I do

I think this warning in output has to do with the issue:

16:43:25.876 Infinite yield possible on ‘ServerScriptService.SavingData:WaitForChild(“CreateLeaderstats”)’ - Studio

That stuff is for the loadout system that is combined with the shop

Maybe try checking the name of CreateLeaderstats and make sure it matches the module… also maybe try not using WaitForChild() and see if that works. I’m pretty sure inside serverscriptservice you don’t need to do WaitForChild… If I remember correctly when you wait for something that doesn’t exist it’ll just wait forever… so I’d assume it’s just the name being different?

1 Like

I think I did find the issue, the SavingData script tried creating leaderstats, whilst Createleaderstats also did it’s purpose (create leaderstats), so I think that caused the issue? I am not sure

update: no, not it