How to make a proper inventory saving system

To whoever who wants to have a proper inventory saving system, here it is.

  • Saves the tool even if you are holding it while leaving the game

  • Can save multiple tools with the same name

  • IMPORTANT: Create a folder in ServerStorage called “Items”, put all the tools you want to be able to be saved in this folder.

Make a script in ServerScriptService, and paste this code inside of the script:

local dss = game:GetService("DataStoreService")
local toolsDS = dss:GetDataStore("ToolsData")

local toolsFolder = game.ServerStorage.Items

-- Store currently held tools in this table
local playerTools = {}

game.Players.PlayerAdded:Connect(function(plr)
	local toolsSaved = {}

	local success, err = pcall(function()
		toolsSaved = toolsDS:GetAsync(plr.UserId .. "-tools") or {}
	end)
	if not success then
		plr:Kick("There was an error while loading your inventory, please join the game again.")
		warn("Error loading tools for", plr.Name, ":", err)
		return
	end

	-- Prevents duplication
	plr.Backpack:ClearAllChildren()
	plr.StarterGear:ClearAllChildren()

	for toolName, toolCount in pairs(toolsSaved) do
		if toolsFolder:FindFirstChild(toolName) then
			for i = 1, toolCount do
				local clonedTool = toolsFolder[toolName]:Clone()
				clonedTool.Parent = plr.Backpack
				local starterTool = toolsFolder[toolName]:Clone()
				starterTool.Parent = plr.StarterGear
			end
		end
	end

	playerTools[plr.UserId] = {}

	plr.CharacterAdded:Connect(function(char)
		local function updateTools()
			local heldTools = {}
			for _, tool in pairs(char:GetChildren()) do
				if tool:IsA("Tool") then
					heldTools[tool.Name] = (heldTools[tool.Name] or 0) + 1
				end
			end
			playerTools[plr.UserId] = heldTools
		end

		-- track changes in the character
		char.ChildAdded:Connect(updateTools)
		char.ChildRemoved:Connect(updateTools)
		updateTools() -- run when the character spawns
	end)
end)

game.Players.PlayerRemoving:Connect(function(plr)
	local toolsOwned = {}

	for _, tool in pairs(plr.Backpack:GetChildren()) do
		toolsOwned[tool.Name] = (toolsOwned[tool.Name] or 0) + 1
	end

	if playerTools[plr.UserId] then
		for toolName, count in pairs(playerTools[plr.UserId]) do
			toolsOwned[toolName] = (toolsOwned[toolName] or 0) + count
		end
	end
	
	local success, err = pcall(function()
		toolsDS:SetAsync(plr.UserId .. "-tools", toolsOwned)
	end)
	if not success then
		warn("Error saving tools for", plr.Name, ":", err)
	end

	playerTools[plr.UserId] = nil
end)

4 Likes

Hey, i think it’s more of a #help-and-feedback:scripting-support topic than development discussion

3 Likes

Actually it would be #resources:community-resources I think you got confused by the title

3 Likes

Oh you’re right, i didn’t saw it’s tutorial, thx for correction :}

3 Likes

wait hold on do I need to delete this then

2 Likes

you can edit your post and change category

3 Likes

I’m new to the devforum so yeah

2 Likes

edit title of your post and then change category

2 Likes

Is this saving both the tools in the backpack, and the hotbar?

Do you have a .rbxl to check it out?

Will it work with custom hotbar systems, or just the roblox default?

Also is it modifiable to update the table every time a player picks up or drops a tool?

Can it also save what slot they are in ?

Thanks

2 Likes
  1. Do you mean hotbar like in the inventory? Or? If you mean the inventory, then yes.
  2. No, I thought y’all didn’t need it, because it’s so simple to setup.
  3. As you can see, the script saves the tools in the backpack and the character. So if the custom inventory system doesn’t store it in the backpack or character, you’ll need to modify it.
  4. Yes.
  5. Yeah, I haven’t implemented any logic for it, but it still does it based on my testing.
2 Likes

Hi,
How would item 4) Yes … be done ? “Also is it modifiable to update the table every time a player picks up or drops a tool?”

Thanks

2 Likes

If you want to listen for when the player picks up an item this is an example for it:

game.Players.PlayerAdded:Connect(function(player)
    player.Backpack.ChildAdded:Connect(function(child)
        if child:IsA("Tool") then
            print(player.Name .. " picked up: " .. child.Name)
        end
    end)
end)

And this is how to listen for when the player drops an item:

game.Players.PlayerAdded:Connect(function(player)
    player.Backpack.ChildRemoved:Connect(function(child)
        if child:IsA("Tool") then
            print(player.Name .. " dropped: " .. child.Name)
        end
    end)
end)
1 Like

Thanks!

Can you also tell what hotbar slot it went into , or if all the hotbar slots are full, if it went into the backpack over flow ?

Along with that , if it went into the backpack , can you force the tool to be dropped. So that nothing can go into the backpack (even if you have disabled opening the back pack, overflow will still go intio it )

2 Likes