How can I fix this?

I am a rookie scripter (I use tutorials + devforum stuff to script) and I want to save loadouts using a inventory saving system, and, it primarily works, however, when I rejoin to edit my saved loadout… THIS happens:

image

Here’s my loadout saving script:

local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")
local InventoryStore = DataStoreService:GetDataStore("PlayerInventory")

local playerData = {}

-- Remove any duplicate tools from player's inventory incase there's a duping bug
local function removeDuplicateTools(player)
	local toolNames = {}
	for _, tool in pairs(player.Backpack:GetChildren()) do
		if tool:IsA("Tool") then
			if toolNames[tool.Name] then
				tool:Destroy()
			else
				toolNames[tool.Name] = true
			end
		end
	end

	for _, tool in pairs(player.Character:GetChildren()) do
		if tool:IsA("Tool") then
			if toolNames[tool.Name] then
				tool:Destroy()
			else
				toolNames[tool.Name] = true
			end
		end
	end
end

-- Function to save player's inventory
local function saveInventory(player)
	local userId = player.UserId
	local playerInventory = {}

	for _, tool in pairs(player.Backpack:GetChildren()) do
		if tool:IsA("Tool") then
			table.insert(playerInventory, tool.Name)
		end
	end

	-- Save inventory to DataStore
	local success, errorMessage = pcall(function()
		InventoryStore:SetAsync(userId, playerInventory)
	end)

	if success then
		print("Inventory saved for player: " .. player.Name)
	else
		warn("Failed to save inventory for player: " .. player.Name .. ". Error: " .. tostring(errorMessage))
	end
end

-- Function to load player's inventory
local function loadInventory(player)
	local userId = player.UserId

	-- Load inventory from DataStore
	local success, playerInventory = pcall(function()
		return InventoryStore:GetAsync(userId)
	end)

	if success then
		if playerInventory then
			-- Remove any existing tools from the backpack and character
			for _, tool in pairs(player.Backpack:GetChildren()) do
				if tool:IsA("Tool") then
					tool:Destroy()
				end
			end

			for _, tool in pairs(player.Character:GetChildren()) do
				if tool:IsA("Tool") then
					tool:Destroy()
				end
			end

			-- Add tools back, ensuring no duplicates
			local addedTools = {}
			for _, toolName in pairs(playerInventory) do
				if not addedTools[toolName] then
					local tool = game.ReplicatedStorage.Tools:FindFirstChild(toolName) or
						game.ReplicatedStorage.Coins:FindFirstChild(toolName) or
						game.ReplicatedStorage.Gamepass:FindFirstChild(toolName)
					if tool then
						local clonedTool = tool:Clone()
						clonedTool.Parent = player.Backpack
						addedTools[toolName] = true
					else
						warn("Tool not found in ReplicatedStorage: " .. toolName)
					end
				end
			end
			print("Inventory loaded for player: " .. player.Name)
			playerData[player] = {loaded = true}
		else
			print("No inventory found for player: " .. player.Name)
		end
	else
		warn("Failed to load inventory for player: " .. player.Name .. ". Error: " .. tostring(playerInventory))
	end
end

-- Event handlers for player joining and leaving
Players.PlayerAdded:Connect(function(player)
	-- Load inventory when player joins
	player.CharacterAdded:Connect(function()
		if not playerData[player] or not playerData[player].loaded then
			loadInventory(player)
		end

		-- Remove duplicate tools on character added
		removeDuplicateTools(player)
	end)

	-- Monitor backpack changes to save automatically
	player.Backpack.ChildAdded:Connect(function(child)
		if child:IsA("Tool") then
			saveInventory(player)
		end
	end)

	player.Backpack.ChildRemoved:Connect(function(child)
		if child:IsA("Tool") then
			saveInventory(player)
		end
	end)
end)

Players.PlayerRemoving:Connect(function(player)
	-- Save inventory when player leaves
	saveInventory(player)
	playerData[player] = nil
end)

Here’s my Loadout System (pls ignore the folder names, they’re named like that bc I used a tutorial to have multiple categories for the shop, and the 3rd folder is for gadgets/perks, which I did not equip one when posting the screenshot, sorry, also, tools folder is for secondaries, coins is for primaries, and gamepass is for gadgets/perks):

local tools = game.ReplicatedStorage:WaitForChild("Tools")
local coins = game.ReplicatedStorage:WaitForChild("Coins")
local gamepass = game.ReplicatedStorage:WaitForChild("Gamepass")
local conf = game.ReplicatedStorage:WaitForChild("Configuration")
local currencyName = conf:WaitForChild("CurrencyName")
local canBuyMultipleTimes = conf:WaitForChild("CanBuyItemMultipleTimes")

local rsModules = game.ReplicatedStorage:WaitForChild("ModuleScripts")
local GetTools = require(rsModules:WaitForChild("GetTools"))

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

local SelectToolFunctions = require(script.Parent:WaitForChild("SelectTool"))
local SelectTool = SelectToolFunctions.SelectTool
local GetSelectedTool = SelectToolFunctions.GetSelectedTool

-- Keep track of purchased tools separately for each folder
local purchasedTools = {
	Tools = {},
	Coins = {},
	Gamepass = {},
}

function UnequipToolFromFolder(plr, folderName)
	for _, child in pairs(plr.Backpack:GetChildren()) do
		if child:IsA("Tool") and child:IsDescendantOf(tools:FindFirstChild(folderName)) and purchasedTools[folderName][child.Name] then
			child:Destroy()
		end
	end
	for _, child in pairs(plr.Character:GetChildren()) do
		if child:IsA("Tool") and child:IsDescendantOf(tools:FindFirstChild(folderName)) and purchasedTools[folderName][child.Name] then
			child:Destroy()
		end
	end
end

function BuySelectedTool()
	local currentlySelectedTool = GetSelectedTool()

	local toolName = currentlySelectedTool.Name
	local toolPrice = currentlySelectedTool.Configuration.Price.Value

	local plrTools = GetTools(game.Players.LocalPlayer)

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

	if toolIndex then
		-- If the player owns the tool, unequip it if it was purchased
		local toolInstance = game.Players.LocalPlayer.Backpack:FindFirstChild(toolName) or game.Players.LocalPlayer.Character:FindFirstChild(toolName)
		local toolFolderName = currentlySelectedTool.Parent.Name
		if toolInstance and purchasedTools[toolFolderName][toolName] then
			toolInstance:Destroy()
			purchasedTools[toolFolderName][toolName] = nil
		end

		-- Remove the tool from the player's inventory
		table.remove(plrTools, toolIndex)

		-- Refund the player for the unequipped tool
		game.Players.LocalPlayer.leaderstats[currencyName.Value].Value += toolPrice
	else
		-- Unequip any previously equipped tool from the same folder
		local toolFolderName = currentlySelectedTool.Parent.Name
		UnequipToolFromFolder(game.Players.LocalPlayer, toolFolderName)

		-- Proceed with the regular purchase flow
		if game.Players.LocalPlayer.leaderstats[currencyName.Value].Value >= toolPrice then
			-- Mark the tool as purchased for the respective folder
			purchasedTools[toolFolderName][toolName] = true
			buyToolRE:FireServer(toolName)
		else
			-- Not enough currency to purchase the tool
			return
		end
	end
end

return BuySelectedTool
2 Likes

Hi,

I’m not quite sure what should happen if it had worked. The inventory went: Primary, Primary, Secondary. How should it actually go?

1 Like

It should have went: Primary, and then Secondary, Instead of 2 primaries (1 is saved, 1 is the primary I wanted to replace the saved primary with) and then 1 secondary (it would also happen with any other weapon type, just used primary as an example)

1 Like

Is there a way to fix it? orr?..

Sorry, took a break from this, yes there’s a definitely a way to fix it, just have to find it…

Hello. Is the issue just your primary weapon duplicating?

No, not duplicating, the issue is that the loadout system ignores the saved primary and doesn’t replace it with the new one, so I end up with 2 seperate primaries instead, 1 being the one I wanted to replace the saved one with, and the other being well, the saved one

I see. So you want it so that when you spawn in with a previously saved loadout, then a primary/secondary shouldn’t appear alongside the previously saved loadout.

Here’s what I propose we do. First off, let’s troubleshoot the issue by using print statements. If possible, I would like you to print out the saved loadout. It should be in the “loadInventory” function.

1 Like

I think I misunderstood your message, but this is what I want to happen basically after rejoining and wanting to edit my loadout:

image

Primary (new) replaces primary (saved) basically, anyway, okay :+1: I’mma go do that rq

Do the tools share the same name?

No, all tools have a different name, the icons when I took the picture did not load, so I added in text to signify which tool is a primary and which is a secondary.

One more question, do each tool have an attribute to classify themselves as either a primary or secondary?

1 Like

No, the script identifies them based on which folder they are in

(Also I made the print statements for when the player’s inventory loads)

Does it print out the list of weapons?

1 Like

Yes :+1: It does print out the list of weapons that is in the player’s inventory

Hello? What do I have to do next?