So I’m just experimenting with creating an RPG game and want to make weapons that have random modifiers.
I would probably go about this by adding a folder called “Modifiers” into the tool that holds intvalues with names such as “LifeSteal” with the value representing the percent to be stolen.
My problem lies with how I would save these items. I thought about it and only came to the conclusion that I could do it like this:
local inventory = game.Players:FindFirstChild("Inventory")
local invData = {}
for i, item in ipairs(inventory) do
table.insert(invData, item.Name)
for i, modif in ipairs(item:FindFirstChild("Modifiers"):GetChildren()) do
table.insert(invData, modif.Name)
table.insert(invData, modif.Value)
end
end
The reason I say this is a problem is because it just seems inefficient to me, but I’m still pretty new to scripting so I wanted to ask if there is a better way to do this because if not, reading the data seems like it be a pretty extensive task because I’d have to check for the item name, and for each modifier I’d have to make sure it parented to the tool.
Ex:
for i, item in ipairs(invData) do
if itemStorage[item] then
-- clone item to inv/backpack
elseif itemModifiers[item] then
local num = i - 1
if itemStorage:FindFirstChild(invData[num]) then
-- clone modifier to the last item cloned
else
repeat
num = num - 1
until itemStorage:FindFirstChild(invData[num]) ~= nil
-- clone modifier to last item cloned using num
end
else
-- this would be if "item" is a value and would just be assigned to the last modifier
end
end
You should use dictionaries, they work similar to arrays but you can access values via what’s know as “key”.
Dictionaries are slightly more complicated to work in loops. But you will be able to know easier where holds the stats. The code can be done like this:
for i, item in ipairs(inventory) do
invData[item.Name]={} -- invData now acts as a dictionary
local itemData=invData[item.Name] -- referring dictionary, this will not clone
for i, modif in ipairs(item:FindFirstChild("Modifiers"):GetChildren()) do
-- each key in itemData is a modifier name
itemData[modif.Name]=modif.Value
end
end
-- you have to use pairs() instead of ipairs() for dictionaries
for item, modifiers in pairs(invData) do
-- because now you know that every item is an item, you just have to clone it then iterate the modifiers
for name, value in pairs(modifiers) do
-- clone modifier to item
end
end
I’ve considered using attributes and I didn’t think I wanted to at first, but now that you said it it makes more sense to use attributes instead of having a folder that way I can just use :SetAttribute() and not have to worry about parenting the modifier. I guess I didn’t really think enough about that, thanks
Also attributes have less of a performance impact than valuebases since an attribute is just assigning a value to an instance similar to properties whereas value objects take up more memory since it contains many properties and functions derived from instances.
Also if you’re working with arbitrary properties (eg. different weapons have different property names), instance:GetAttributes() returns a dictionary which can be saved to data store as-is (assuming you’re using bools, strings and numbers only).
So if I were to combine what all 3 of you said so far like so;
Saving:
for i, item in ipairs(inventory:GetChildren()) do
invData[item.Name] = {}
local itemData = invData[item.Name]
for i, modif in ipairs(item:GetAttributes()) do
itemData[modif.Name] = modif.Value
end
end
Reading:
for item, modifiers in pairs(invData) do
itemStorage[item]:Clone().Parent = inv
for name, value in pairs(modifiers) do
item:SetAttribute(name, value)
end
end
invData[item.Name] was an empty table then, so it can be used as either array or dictionary. (which later in the code it has been used as a dictionary)
Thank you! That cleared up a lot of my confusion about dictionaries and I don’t plan on using any strings, only numbers so it should be fine for what I’m doing.
Also, if it’s possible to get multiple of the same item, do not use the item’s name as the index, it will cause one item to be overridden by another, only a single item of each type will load.
Instead, try something like so:
local inventoryData = {}
for i, item in ipairs(inventory:GetChildren()) do
local itemData = {}
itemData.Name = item.Name
itemData.Properties = item:GetAttributes()
table.insert(inventoryData, itemData)
end
Then to reference the item in the loading script, do something like
for i,itemInfo in ipairs(loadedInventoryData) do
local newItem = serverStorage:FindFirstChild(itemInfo.Name):Clone()
for propertyName,propertyValue in pairs(itemInfo.Properties) do
newItem:SetAttribute(propertyName, propertyValue)
end
end