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:
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