So there have been numerous posts around the forums of how to make a datastore that can save items. Making such a datastore would have many uses like creating an inventory so I decided to make a tutorial about it.
In order to understand this tutorial you need basic knowledge of the following:
This tutorial will focus on the format of saving items and not on how to retrieve attributes of items as that can be done by making your own functions.
Disclaimer
This tutorial is obviously not using the best practises (for example you would want to use module scripts to recover/update items, retry when data acquisition fails e.t.c) and is only to teach beginners a way to save items in order for them to be able to create their own frameworks for inventories/shops or whatever other system they think of.
When you are saving items it is very likely that you want to save some attributes/properties with them,
First thing to understand is that when you want to save an item you don’t save the item itself but a referance to that item and save it’s attributes/properties along with the referance.
First of all you would want all the obtainable items to be in a folder( When you get more advanced you can put them on multiple folders based on the item’s class for the shake of organization)
Let’s suppose you want to save a sword and that sword has 2 attributes. Them being damage, cooldown. One way you could go about this is creating a table that would contain these attributes. So let’s say I want to save an item called “Sword” with these 2 attributes, I would use the following table.
["Inventory"] = {
["Sword"] = {
["damage"] = 5,
["cooldown"] = 1
}
}
This table allows you to pass the name of the item along with it’s properties. Reason you want to pass the name is that when you recover the data (player joins) you want to know what items he owns and clone them into his inventory(StarterGear) so you would do something like this.
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetDataStore("Inventory")
local RS = game:GetService("ReplicatedStorage")
local data = {}
game.Players.PlayerAdded:Connect(function(plr)
data[plr] = {}
local RecData = {}
local succ,err = pcall(function()
RecData= DS:GetAsync("UserID_"..(plr.userId))
end)
if not RecData then RecData["Inventory"] = {} end
for i,v in pairs(RecData["Inventory"] ) do
data[plr][i] = v
RS.Items[i]:Clone().Parent = plr.StarterGear
RS.Items[i]:Clone().Parent = plr.Backpack
end
end)
Although saving items like this would present problems because you wouldn’t be able to store more than one items (With different stats) with the same name.You can also store items in quantity if you don’t care about items having different stats and being unique but that would limit you a lot and make updating your game a lot harder when it comes to inventory features therefore I don’t recommend it. A way to go arround this is using GUID when saving items. You may ask why use guid and not increment the table? Using guid provides the item with a unique identifier and can provide easier integration of future systems like trading and helps you keep better track of the items. Although this would require 1 extra attribute which would be the item’s name:
["Inventory"] = {
["94b717b2-d54f-4340-a504-bd809ef5bf5c"] = {
["Item"] = "Sword",
["damage"] = 5,
["cooldown"] = 1
}
}
local DSS = game:GetService("DataStoreService")
local DS = DSS:GetDataStore("Inventory")
local RS = game:GetService("ReplicatedStorage")
local data = {}
game.Players.PlayerAdded:Connect(function(plr)
data[plr] = {}
local RecData = {}
local succ,err = pcall(function()
RecData= DS:GetAsync("UserID_"..(plr.userId))
end)
if not RecData then RecData["Inventory"] = {} end
for i,v in pairs(RecData["Inventory"]) do
data[plr][i] = v
RS.Items[v["Item"]]:Clone().Parent = plr.StarterGear
RS.Items[v["Item"]]:Clone().Parent = plr.Backpack
end
end)
Now if you want to Add data you would have a function like the following:
local HttpService = game:GetService("HttpService")
function AddItem(plr,item,damage,cooldown)
data[plr][HttpService:GenerateGUID(false)] = {
["Item"] = item, --Item Name (string)
["damage"] = damage, --integer or float
["cooldown"] = cooldown --integer or float
}
end
game.Players.PlayerRemoving:Connect(function(plr)
local succ,err = pcall(function()
DS:SetAsync("UserID_"..(plr.userId),data[plr]})
end)
data[plr] = nil
end)
Reason we are using a data table is so that you can easily recover damage/durability and other attributes through the use of functions without the need to use GetAsync everytime you want to retrieve something. Also storing inventory data in folders/stringvalues e.t.c is bad practise.
A plugin that I believe will help you a lot if you can afford it is DataStore Editor by @sleitnick as it will help you visualize your datastores. Here are some examples of some of my old datastores using this plugin:
As you get more and more advanced you will be able to organize them into categories for example:
["Progression"] = {
["Level"] = 1,
["EXP"] = 50
},
["Inventory"] = {
["94b717b2-d54f-4340-a504-bd809ef5bf5c"] = {
["Item"] = "Sword",
["damage"] = 5,
["cooldown"] = 1
},
...
}
So let’s say you have added mutliple swords using the AddItem
function your data table would look something like this
["Inventory"] = {
["94b717b2-d54f-4340-a504-bd809ef5bf5c"] = {
["Item"] = "Sword",
["damage"] = 5,
["cooldown"] = 1
},
["ea106a8f-c46a-41db-ab78-30d6f30e332f"] = {
["Item"] = "Sword",
["damage"] = 6,
["cooldown"] = 2
},
["d12f0063-b881-4d53-a485-aae07b0b19e9"] = {
["Item"] = "Sword3",
["damage"] = 2,
["cooldown"] = 8
}
}
When player exits the script would take the whole table above and replace the already existing data with it. If you understand how to save basic items with their attributes you can then save multiple things like Armors, Shields, Part placements using CFrame and other properties.
Thank you for reading. The code above was not tested in studio as it is clearly for demonstration so if you spot any spelling mistakes e.t.c please message me so I can fix them. Leave any feedback bellow.