So I am making an inventory system and have it properly saving each instance with a weapon ID and its own special stats (damage, rarity, quality etc) but when I want to remove an item from a players inventory, I have no way of identifying which one of said item is the exact one they want to remove.
Say a player tries to delete a common iron sword with 2 damage. I want to make sure that one is deleted instead of another iron sword with different stats he might have. I figured I could accomplish this by creating a GUID for each unique instance of a weapon and then store it both in data service and the physical object and just compare the two when deleting but I believe that the data footprint of that might be too large if there are too many weapons. Does anyone have any alternatives?
Here is an example of what an item would be saved as
The problem is that each instance of the weapon is different, even if it is the same base weapon. Because of this, just deleting items based off the weapon ID won’t work.
Before the runtime ends, I convert each stat or unique quality to a string, integer, or table and store it that way. I’ve already achieved that but am now trying to find a way to correctly distinguish between each saved instance (now portrayed as strings, integers, or tables like in my example) to delete or equip a certain one
You can still use a GUID, but you don’t need to store it. Assuming all your interactions with the object don’t care about maintaining a reference between serialization and deserialization steps, then when you serialize it, just don’t include a GUID. When you deserialize it, generate a new GUID.
Similarly, if you wanted to avoid a GUID, you could use a reference to the model for the same reason. This is possibly even preferable, since it saves a lookup when you need to access the model from the data object in memory.
Saving instances is especially hard because they dont have a specific UniqueId as of right now. You can try setting an attribute to each item but that has caused me problems before. Can I get a little bit more context on what you are going for here? Are thr instances you are attempting to save pre-made or made in-game
You defeat an enemy twice. The first time he drops a Iron sword (ID:1, Rarity: Common) and the second time he drops a iron sword again but with (ID:1, Rarity: Rare). I can properly save these values to datastore service and load them back in in bulk but if i need to access one specific version of an item that a player obtained, say the Rare sword, I cant figure out a way to
I’m not sure what your serialization/deserialization steps look like, but I imagine something like this:
local DataStoreService = game:GetService("DataStoreService")
local ServerStorage = game:GetService("ServerStorage")
local dataStore = DataStoreService:GetDataStore("Inventory")
local ITEM_STORAGE_FOLDER = ServerStorage.ItemStorageFolder
local inventoryByPlayer = {
-- [player1] = { -- Example inventory
-- [swordModel1] = {
-- itemType = "Sword",
-- damage = 10,
-- instance = swordModel1
-- },
-- [swordModel2] = {
-- itemType = "Sword",
-- damage = 50,
-- instance = swordModel2
-- }
-- },
}
local function saveInventory(player)
local serializedItemData = {}
for _, itemData in inventoryByPlayer[player] do
table.insert(serializedItemData, itemData)
end
dataStore:SetAsync(player.UserId, serializedItemData)
end
local function loadInventory(player)
local inventory = {}
local serializedInventory = dataStore:GetAsync(player.UserId)
for _, itemData in serializedInventory do
local itemModel = ITEM_STORAGE_FOLDER:FindFirstChild(itemData.itemType):Clone()
itemData.instance = itemModel
inventory[itemModel] = itemData
end
return inventory
end
… obviously with better data handling practices than this example
You can save each item with a UUID. When loading in you can loop through the inventory to equip the items, you just have to save the model name, find the model, clone it and place it in the inventory. The UUID would only be used to distinguish 2 of the same swords obtained
Yeah that’s fine, the instance is a value which will just be nil when saved to data, effectively making that instance key/value pair disappear from the saved data. But we don’t care, because it gets populated with a new instance when deserialized.
The data is all serialized and unserialized through int values, string values, and the weapon’s model (which is only used for the viewport frames and is identical to all others as you can see)
Instance is a clone of some prefab/template item somewhere. The point is it’s a unique instance you could then go on to modify, like set the color of the sword based on damage property or something.
If your items aren’t customized individually, but rather are classed by a category (like itemType + itemRarity) you can consider each of those categories to be a unique type, and that allows you to store your inventory as a count which is very efficient. You can then have a lookup table of data for each category, like look up damage for a RareSword from some constant centralized table, for example.
When deserializing, you can generate unique guids for each object and use that as the item reference in your code. Here’s a relevant example
local DataStoreService = game:GetService("DataStoreService")
local HttpService = game:GetService("HttpService")
local ServerStorage = game:GetService("ServerStorage")
local dataStore = DataStoreService:GetDataStore("Inventory")
local GUI_OBJECT_TEMPLATE_FOLDER = ServerStorage.GuiObjectTemplateFolder
local STATS_BY_ITEM_TYPE = {
CommonSword = {
DamageMultiplier = 0,
HP = 10,
AttackSpeed = 0
},
RareSword = {
DamageMultiplier = 2,
HP = 100,
AttackSpeed = 20
},
}
local inventoryByPlayer = {
-- [player1] = { -- Example inventory
-- CommonSword = { guid1, guid2 },
-- RareSword = { guid3 },
-- },
}
local function saveInventory(player)
local inventory = inventoryByPlayer[player]
local serializedItemData = {}
for itemType, itemGuids in inventory do
serializedItemData[itemType] = #itemGuids
end
dataStore:SetAsync(player.UserId, serializedItemData)
end
local function loadInventory(player)
local serializedInventory = dataStore:GetAsync(player.UserId)
local inventory = {}
for itemType, itemCount in serializedInventory do
local itemGuids = {}
for _ = 1, itemCount do
table.insert(itemGuids, HttpService:GenerateGuid(false))
end
inventory[itemType] = itemGuids
end
return inventory
end
local guiObjectsByGuid = {
-- [guid1] = guiObject1,
-- [guid2] = guiObject2,
}
local function drawInventory(inventory)
local isGuidInInventory = {}
-- Draw new items
for itemType, itemGuids in inventory do
for _, guid in itemGuids do
isGuidInInventory[guid] = true
local existingGuiObejct = guiObjectsByGuid[guid]
if not existingGuiObejct then
local guiObjectTemplate = GUI_OBJECT_TEMPLATE_FOLDER[itemType]
local guiObject = guiObjectTemplate:Clone()
guiObject.TextLabel.DamageMultiplier.Text = STATS_BY_ITEM_TYPE[itemType].DamageMultiplier
guiObjectsByGuid[guid] = guiObject
end
end
end
-- Destroy items no longer in inventory
for guid, guiObject in guiObjectsByGuid do
if not isGuidInInventory[guid] then
guiObject:Destroy()
guiObjectsByGuid[guid] = nil
end
end
end