It is useless, because you’re wasting data by saving them as nested tables, instead of just the values themselves. You should only use tables when you need to use them, like saving owned cars and plots.
@Katrist it’s useless for the computer yes. Very handy for human readability though.
@LeCrabCurry You can do
return profile.Data["PlayerStats"]["Health"]
The two strings can be configurable parameters of your get function.
This is what comments are for though, it’s just added complexity having to comb through a table to find the data you really want to retrieve.
function PlrDataHandler:Set(player, key, value) -- key = {"PlayerStats", "Health"}
would making a path like this work? if so how would I incorporate this into my script to find the profile.Data[data1][data2][data3]
, etc
You would do something like this (index is a more suitable name):
function PlrDataHandler:Set(player, index, key, value)
--[[
Index = table name
Key = value name
Value = key's new value
]]
local profile = GetProfile(player)
assert(profile.Data[index][key], string.format("Data does not exist for key %s", key))
assert(type(profile.Data[index][key]) == type(value))
profile.Data[index][key] = value
local valueOBJ = player:FindFirstChild(key, true)
if valueOBJ then
valueOBJ.Value = value
end
end
But what if I want to include more data? such as Inventory = {Item = {Stats = {"A","B","C"}}}
I was thinking of using some sort of loop, for example if the path was {“Inventory”, “Item”, “Stats”, “A”}, then I’d loop through it
function FindPath(path) -- path = {"Inventory", "Item", "Stats", "A"}
local currentPath = profile.Data
for i, v in pairs(path) do
currentPath = currentPath[path[i]]
end
return currentPath -- profile.Data[Inventory]["Item"]["Stats"]["A"]
end
Apologies for not formatting since its just a mockup code I wrote right now, but in theory would this work?
Actually, you can get values nested in tables. You’d have do a deep search, which is possible by modifying the deep clone code in the docs, which I have done here:
local Data = {
["PlayerStats"] = {
["Chakra"] = 0,
["Strength"] = 0,
["Health"] = 0,
},
["Levels"] = {
["Level"] = 1,
["Exp"] = 0,
["Points"] = 0,
}
}
local function setValue(tbl, key, value)
for k, v in pairs(tbl) do
if type(v) == "table" then
v = setValue(v, key, value)
end
if k == key then
tbl[k] = value
end
end
end
setValue(Data, "Points", 5) -- Sets the value of Points to 5
This should work, do a test with a print statement after setting a value and see if it updated.
Never said it wasn’t possible. I’m saying that it’s highly impractical to do so, because you’re wasting time combing through tables to reach just 1 value.
Would thus work?
function FindPath(path) – path = {“Inventory”, “Item”, “Stats”, “A”}
local currentPath = profile.Data
for i, v in pairs(path) do
currentPath = currentPath[path[i]]
end
return currentPath -- profile.Data[Inventory]["Item"]["Stats"]["A"]
end
You’re only returning the value in that function, so you wouldn’t be able to mutate that value after. You’re close though.
hm I see, so then what should I do? use table.concat? or would that not apply here
You can just set the value in that function. You could also use a recursive search like @ltsmrsky did.
You said his method is impractical, why is that? Will it take a lot of memory?
I had the same issue but I fixed it by creating a function that lets you access tables like you can access the workspace (PlayerStats.Weapons.Weapon):
GetData({"PlayerStats", "Weapons", "Weapon"}) --// Returns DatastoreProfile.PlayerStats.Weapons.Weapon
If you get what I mean. I’m not home right now so I can’t reply with a script.
Edit:
function SearchTable(Table, directory)
local Int = 0;
while Int < #directory do
Table = Table[directory[Int + 1]];
Int += 1;
end;
return Table;
end;
function RetrieveData(Player, directory)
local ReturnData = SearchTable(Profiles[Player].Data, directory);
if ReturnData ~= nil then
return ReturnData;
else
warn("Data not found.");
return nil;
end;
end;
Yes, it takes a lot more memory and a lot more time to search for the data.
This is similar to the mockup I made, but also wouldn’t the function just return the value of the index we are trying to search for?
Nope, it returns an editable index.
Example:
local Players = game:GetService("Players");
local Client: Player = Players[Player];
local ClientData = DataManager:RetrieveData(Client, {"Data", "PlayerStats"});
ClientData.Chakra += 1;
ClientData.Strength += 1;
ClientData.Health += 10;
I’ve used your function, but now I’m getting an error.
ServerScriptService.DataHandler:113: profile does not exist for 2231850740
function GetProfile(plr)
assert(profiles[plr], string.format("profile does not exist for %s", plr.UserId))
return(profiles[plr])
end
Also when I print profiles it returns an empty table. Though I’m not sure if this is because of the table combing system I added or it’s something else…
On the scale you’re working at you won’t notice any difference.
Minute (useless) optimizations should be more important than code readability.
It’s not impractical at all.
What do you mean by “table combining system”, could you elaborate?
And has this error occured before?