-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Try to preserve metatable information in core.serialize #14360
base: master
Are you sure you want to change the base?
Conversation
would this also fix #13644? |
no, different code. |
With #14369 being reviewed, should I change this to depend on that PR? It turned out that the only "special case" to handle here would be Edit: Another option would be to have the serializer also check |
71787ed
to
24f0eb6
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's a more general abstraction possible that doesn't require special-casing ItemStack
s (or other userdata which we might want to preserve in the future).
We simply need two maps:
- One which maps metatables to named serializers, for example:
[itemstack_mt] = {name = "ItemStack", serializer = ItemStack().to_table}
. The serializer returns a single value (or perhaps a vararg) to be fed to the named function. So serializing an item stack would result in something likeItemStack({name = "default:dirt", count = 42})
. - Another which maps these function names to actual functions, in this case, simply
{ItemStack = ItemStack}
.
So all we need to know for each "class" is a quadruple: Name; metatable / methodtable; serializer (to_*
); deserializer (constructor).
For the case of pure Lua data structures, the serializer can be simply the identity function, and the deserializer only has to set the metatable.
So I think it would make sense to add an extended version, say, core.register_serializable(name, metatable, serializer, deserializer)
. Then you could just do core.register_serializable("ItemStack", itemstack_mt, ItemStack().to_table, ItemStack)
.
core.register_portable_metatable(name, metatable)
would just be convenience for core.register_serializable(name, metatable, function(x) return x end, function(x) return setmetatable(x, metatable) end)
.
(Something like this is what modlib does, but it only does it for userdata (hence the todo 😅). The usage is relatively clean though. Peek at this with a grain of salt, I'd write it a bit differently nowadays.)
I think we should also ask ourselves: Don't we want to expose these metatables in some global variables for convenience? It's a bit nasty to have to obtain an instance to obtain the metatable. See #11639.
This should be doable, although I would prefer to not guarantee the correctness of preserving recursive data structures with custom serializers.
That would make sense IMO, but let's leave that to a different PR. |
Add compact, short information about your PR for easier understanding:
This PR attempts to preserve metatable information in the data serialized by
minetest.serialize
.This PR works by keeping a record of metatables that are assigned to a name. This name is then kept along with the serialized data which can later be used to construct the wanted type during the deserialization process.
Note that there are certain limitations that apply when an object contains a recognized metatable. These limitations will be documented as part of this PR.
Fixes Serialization does not preserve vector metatable #14357.
No, but it may be considered a bugfix depending on whether the issue linked above is considered as a bug.
See linked issue.
To do
This PR is Ready for Review.
core.deserialize
; compatibility is otherwise not guaranteed.How to test
core.serialize
on various data structures and make sure they work.(*) The testcase for ItemStacks is put into the devtest as it appears to be implemented as
userdata
.