[Open Source] DataStore Inventory + Unique Item ID Generator (Script, no Gui)

INTRO
It’s been three days since I started trying to make an inventory system for an Mmo-Rpg game I’m developing. After surfing the developer hub for hours on end looking for something to help create the system I’m going for, I finally picked up bits and pieces of information that finally formed into the system I have created.

How It Works
1. Items within the inventory are stored as Instance Values. The inventory folder is parented to the player. The item then has more instance values stored within it. These values are properties that can be used for sorting. Properties can be changed or added very easily.
image

2. When Saving the items I use UpdateAsync() instead of SetAsync(). Each item saved is a dictionary containing the name of the item and its properties. A problem I was facing was that PlayerRemoving wasn’t working but thanks to @rogeriodec_games 's solution I was able to fix it using the script he posted. https://devforum.roblox.com/t/studio-wont-correctly-complete-bindtoclose-and-playerremoving/1776593/14?u=trinitydevelepment

local CanCloseServer = false

game.Players.PlayerRemoving:Connect(function(Player)
	
	local NewInventoryData = {}
	local InventoryFolder = Player:FindFirstChild("Inventory")
	
	for Inventory, Child in pairs(InventoryFolder:GetChildren()) do
		
		local Item = {}
		
		Item["ItemName"] = Child.Name
		
		for ItemName, ItemProperty in pairs(Child:GetChildren()) do
			
			Item[ItemProperty.Name] = ItemProperty.Value
			
			
		end
		
		table.insert(NewInventoryData, Item)
		
	end
	
	print(NewInventoryData)
	
	Data:UpdateAsync(Player.UserId.."-Inventory", function(CurrentInventoryData)
		
		if NewInventoryData == CurrentInventoryData then
			return CurrentInventoryData
		else
			return NewInventoryData
		end
		
	end)
	
	CanCloseServer = true
	
	
end)

game:BindToClose(function()
	while RunService:IsRunning() and not CanCloseServer do
		task.wait()
	end
	
	
	
end)

3. When Loading I create the inventory folder and parent it to the player. I then load items into the folder using string values as the name holder using Instance.name instead of instance.value. then i load the properties and parent it to the name holder.

local DataStore = game:GetService("DataStoreService")
local Data = DataStore:GetDataStore("InventoryDataStore")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

game.Players.PlayerAdded:Connect(function(Player)
	
	local InventoryFolder = Instance.new("Folder")
	InventoryFolder.Parent = Player
	InventoryFolder.Name = "Inventory"
	
	local LoadInventory = Data:GetAsync(Player.UserId.."-Inventory")
	
	if type(LoadInventory) == "table" then
		
		for Inv, Item in pairs(LoadInventory) do
			
			
			if Item["ItemName"] then
				
				local NewStringVal = Instance.new("StringValue")
				NewStringVal.Parent = InventoryFolder
				NewStringVal.Name = Item["ItemName"]

				
			end
			
			if Item["ItemID"] then 
				
				local NewStringVal = Instance.new("StringValue")
				NewStringVal.Parent  = InventoryFolder:FindFirstChild(Item["ItemName"])
				NewStringVal.Name = "ItemID"
				NewStringVal.Value = Item["ItemID"]
				
			end
			
			if Item["ItemType"] then
				
				local NewStringVal = Instance.new("StringValue")
				NewStringVal.Parent  = InventoryFolder:FindFirstChild(Item["ItemName"])
				NewStringVal.Name = "ItemType"
				NewStringVal.Value = Item["ItemType"]
				
			end
			
			
			if Item["ItemType"] then

				local NewIntVal = Instance.new("IntValue")
				NewIntVal.Parent  = InventoryFolder:FindFirstChild(Item["ItemName"])
				NewIntVal.Name = "ItemAmount"
				NewIntVal.Value = Item["ItemAmount"]

			end
			
		end
		
	end
	
	
end)

ENTIRE DATASTORE SCRIPT

local DataStore = game:GetService("DataStoreService")
local Data = DataStore:GetDataStore("InventoryDataStore")
local Players = game:GetService("Players")
local RunService = game:GetService("RunService")

game.Players.PlayerAdded:Connect(function(Player)
	
	local InventoryFolder = Instance.new("Folder")
	InventoryFolder.Parent = Player
	InventoryFolder.Name = "Inventory"
	
	local LoadInventory = Data:GetAsync(Player.UserId.."-Inventory")
	
	if type(LoadInventory) == "table" then
		
		for Inv, Item in pairs(LoadInventory) do
			
			
			if Item["ItemName"] then
				
				local NewStringVal = Instance.new("StringValue")
				NewStringVal.Parent = InventoryFolder
				NewStringVal.Name = Item["ItemName"]

				
			end
			
			if Item["ItemID"] then 
				
				local NewStringVal = Instance.new("StringValue")
				NewStringVal.Parent  = InventoryFolder:FindFirstChild(Item["ItemName"])
				NewStringVal.Name = "ItemID"
				NewStringVal.Value = Item["ItemID"]
				
			end
			
			if Item["ItemType"] then
				
				local NewStringVal = Instance.new("StringValue")
				NewStringVal.Parent  = InventoryFolder:FindFirstChild(Item["ItemName"])
				NewStringVal.Name = "ItemType"
				NewStringVal.Value = Item["ItemType"]
				
			end
			
			
			if Item["ItemType"] then

				local NewIntVal = Instance.new("IntValue")
				NewIntVal.Parent  = InventoryFolder:FindFirstChild(Item["ItemName"])
				NewIntVal.Name = "ItemAmount"
				NewIntVal.Value = Item["ItemAmount"]

			end
			
		end
		
	end
	
	
	
end)

local CanCloseServer = false

game.Players.PlayerRemoving:Connect(function(Player)
	
	local NewInventoryData = {}
	local InventoryFolder = Player:FindFirstChild("Inventory")
	
	for Inventory, Child in pairs(InventoryFolder:GetChildren()) do
		
		local Item = {}
		
		Item["ItemName"] = Child.Name
		
		for ItemName, ItemProperty in pairs(Child:GetChildren()) do
			
			Item[ItemProperty.Name] = ItemProperty.Value
			
			
		end
		
		table.insert(NewInventoryData, Item)
		
	end
	
	print(NewInventoryData)
	
	Data:UpdateAsync(Player.UserId.."-Inventory", function(CurrentInventoryData)
		
		if NewInventoryData == CurrentInventoryData then
			return CurrentInventoryData
		else
			return NewInventoryData
		end
		
	end)
	
	CanCloseServer = true
	
	
end)

game:BindToClose(function()
	while RunService:IsRunning() and not CanCloseServer do
		task.wait()
	end
	
	
	
end)

Unique Item Id Script

The unique item id is used using HttpService:GenerateGUID(false). When an item is added to the inventory folder it looks for the property stringval “ItemID”. If the value of ItemID is empty then it generates a unique id for it. If it isnt empty it doesn’t.

local HttpService = game:GetService("HttpService")

game.Players.PlayerAdded:Connect(function(Player)
	
	local InventoryFolder = Player:WaitForChild("Inventory")
	
	InventoryFolder.ChildAdded:Connect(function(Child)
		if Child:IsA("StringValue") then
			
			if Child:WaitForChild("ItemID").Value == "" then
				Child.ItemID.Value = HttpService:GenerateGUID(false)
			end
			
		end
	end)
	
end)


Both scripts are ServerScripts
6 Likes