I have encountered an issue while using the DataStoreService. When I save a table to the datastore using SetAsync(), I find that I am getting an incomplete table when GetAsync().
Here is the code that I am using:
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")
local buffUnit = {
playerId = nil,
buffId = 0,
value = 0,
calType = "" add, multiple
}
buffUnit.__index = buffUnit
local test = {}
setmetatable(test, buffUnit)
playerData:SetAsync("test", test)
local downLoadTest = playerData:GetAsync("test")
print(downLoadTest.playerId) -- nil
It seems that attributes in the metatable don’t really belong to the child table. However, OOP performs better in many situations. Is there any convenient way to save a table with a metatable?
Although I don’t see what scenario you’d have where a metatable would need to change so significantly as to be saved anyway. Usually the metatables you use are boilerplate enough that you’d be able to apply them to specific types of table/information storage.
If you need to save some external attributes, including those that could be contained in a metatable, you can serialise in a similar way as normal table values/game data.
Thanks for replying, buddy! Here’s the situation: I have two types of animals, each with a name, HP, speed, etc. To represent them, I created a metatable like this:
local animal = {
name = "not set",
hp = 100,
speed = 10
}
animal.__index = animal
then i have a rabbit and a tiger:
local rabbit = setmetatable({}, animal)
rabbit.ownerId = 123
local tiger = setmetatable({}, animal)
tiger.targetId = 213
However, when a player leaves the game and I try to save either the rabbit or the tiger, its name, HP, and speed are lost.
And now I know that setmetatable() doesn’t really copy attributes from parent tables to child tables, but rather ‘rents’ them.
I don’t think metatables are necessary for what you want to do. In Java or C++ the sort of inheritance you’re describing makes perfect sense in most scenarios, but in Lua that’s not necessarily the case.
(mainly due to objects being a type in and of themselves, rather than pseudo-objects in Lua) - this isn’t to say you shouldn’t use them, just be adequately discerning
Either way, if you did want to do this you’d have to serialise the data in some way so you could reapply the correct metatables. i.e save a keyword for the animal which can then be used to apply the correct metatable. Any saved data could then be applied to the metatable also.
Metatables used in this way are meant to save memory by using the same values and methods for many objects you’re making. But, your using it in a way that will cause bugs because these are all independant variables to the animals that are being used as global variables. So you don’t need metatables for this.
Okay, I’m fairly new to Lua and Roblox, before this, I only knew some Python. But now, I feel more confident using metatables in a proper way. Thank you very much!
Hmm, python. This is what your script would look like in python:
# Why does the devforum make python look ugly 🤨
class Animal:
Name = "Untitled"
Health = 100
Speed = 10
class Rabbit:
def __init__(self, id):
self.OwnerId = id
def __setattr__(self, i, v):
setattr(Animal, i, v)
def __getattr__(self, i):
return getattr(Animal, i)
a = Rabbit(123)
a.Name = "Spots"
b = Rabbit(123)
b.Name = "Furry"
print("My first pet is", a.Name) #: My first pet is Furry
print("My second pet is", b.Name) #: My second pet is Furry
From some dumb python executor:
This is happening because the properties are not inherited, but are still being used. In lua, this would be what you want:
local Animal = {}
Animal.__index = Animal
function Animal.new(id)
local self = {}
self.Type = id
self.Name = "Untitled"
self.Health = 100
self.Speed = 10
return setmetatable(self, Animal)
end
local a = Animal.new("Rabbit")
a.Name = "Spots"
local b = Animal.new("Rabbit")
b.Name = "Furry"
print(a.Name) --> Spots
print(b.Name) --> Furry