fivem
fivem copied to clipboard
Exports does not return metatable attached to the table
Description: Exports does not return metatable attached to the table
Repro:
- Create a class on a resource and inherit from that class and also add an export for the inherited class
Player = {
health = 100,
new = function(self, o)
o = o or {}
setmetatable(o, {__index = self})
return o
end
}
Police = Player:new({
armor = 100,
})
console.log(Police.armor, Police.health)
-- Result will be 100, 100
exports("Police", function()
return Police
end)
- On other resource call the export and try to fetch inherited class
Police = expoorts.base:Police()
console.log(police.armor, police.health)
-- Result will be 100, nil and if you try to get metatable will be also nil
getmetatable(Police) --> result will be nill
Expected behavior: exports should return metatable attached to the table
Returning an object with just the original metatable replicated by function references would be weird: what meaning would a metatable have in other ScRTs? This'd need a lot of thought which comes down to the original concept of allowing 'meta-refs' which are just proxy objects where every field access is a metatable-like callback marshaling back to the original ScRT.
Instead of relying on this being 'expected', it would be possible to return a closed wrapper object with just getter funcrefs, as the same would have to happen when using a metatable anyway.
Wouldn't "table/object marshaling loses metatable" or something similar make more sense as a title?
While initially meta-refs seemed logical, I believe the whole initial point of needing to share classes between resources is incorrect. Unless you want to import them (through the manifest file, as in LUA for example), sharing execution contexts in this specific case isn’t a great design choice.
IMO, and as an alternative, I would suggest having the two resources agree on a mutual definition and simply think of their communication as an API, where you remotely call different methods that interact with that class. In sum, exporting police
would simply become export(“PoliceArmor”)
, export(“callMethodXInPolice”)
or simply export(“Police”)
returning a serialised version of the class, similarly to routes.
(Related to https://forum.cfx.re/t/exporting-a-class-between-two-resources/2066783/4)