Recently I’ve come into some issues regarding the encoding and saving of instances. There are always of course, fancy, clunky ModuleScripts such as Stravant’s, but his hasn’t been updated in a long, long time. As the creator of several sandbox games, constantly updating the module to each new version of roblox which uses instances that aren’t recorded in the moduleScript is a hassle.
Creating this feature in an environment which has access to the entirety of the API would erase the need for constant updating of ModuleScripts, it would also be a lot faster. Given that the sandbox genre is ever-growing, I feel that this would be a very beneficial feature. Not to mention, in the scheme of things, one that will break literally nothing, and one which would only fix problems.
I’d much rather have a GetMembers function, which would return the entire API for an object. Then you can grab the properties and their types and read-only-ness and determine what you should be saving that way. Once we have an always-up-to-date api function a futureproof InstanceTo/FrontString function would be trivial to write.
For the sake of accesibility to other users I feel like InstanceToString and InstanceFromString functions would be a better option, although GetMembers has been requested very VERY often. I think I’ve seen it more here than any other feature. GetMembers or GetProperties, anyway. I think Stravant even requested it just for this purpose.
I’ve never been aligned with the “let’s add a less powerful feature because it’s easier to use” argument. If people want a feature they should be enabled to create it on their own. Having exact features spoon fed to us is going to do nothing but stifle our own ability to re-use one feature for multiple purposes, bloat the API, and increase our reliance on the engineers to add things that we should just be able to do on our own.
No one is adding classes like Flamethrower or KillOnTouchPart because that’s bad API design. Any good API will deliver resources that you can use to accomplish whatever you want, not just a macro for doing one simple trick.
I don’t agree with that argument either, the thing is though roblox has repeatedly ignored the request to have a getmembers function, so I imagine they just don’t want to do it. Why implement a JSON Encode and Decode function if users, technically speaking, have the ability to implement JSON by themselves using very heavy user-made libraries. The line of what is good and bad API design in the respect that you’re talking about is kind of an arbitrary one. We have for example the ability to create our own tool system but the objects still exist. (Though that’s really just a remnant of early roblox.) I see your point, to be honest I’d like both a GetMembers function and an InstanceTostring, I just feel that the latter is a way of doing things that is partially more consistent with how roblox generally adds things to their API. I’d rather this thread didn’t turn into an argument about API tactics though.
You can’t just stop telling people what you want when you think they’re ignoring you. Nothing gets accomplished that way. I want GetMembers and I want everyone to know, and I want everyone else who wants it to speak up. Nothing will be added if we don’t make it abundantly clear that this is what we need in order to make the games we want to make.
The reason I’m asking for a lower-level API is because we have observed, time and time again, that roblox’s high-level APIs are too specific for every use case and people end up making their own systems anyway. Look at ContextActionService, dialogs, even chat and the leaderboard. By nature a high-level API is designed with a specific use-case in mind, and that just doesn’t mesh with the all-encompassing environment of roblox game development. It is not possible to design a high-level API that makes everyone happy, so the best option is to make a low-level API that enables everyone to make the tools that they want to use.
Because I’d imagine they had to implement that into the engine to actually make the web APIs usable (e.g. methods like Player::GetFriendsOnline) - and exposing those to the users doesn’t require much work since it’s already implemented.
There’s that whole list of Reflection.* classes already existing, which sounds more like what should be exposed. Although the way that’s built up seems like one huge mess to me now, definitely needs work before opening that up to the public.
I’d honestly not bloat the API with a InstanceToString or a GetMembers function for the root Instance class, a proper introspection service sounds more suitable.
I have to agree on the GetMembers stuff: I think access to the API of objects would be much better than InstanceTo/FromString.
In fact, it turns out the metadata is stored in a way that lets you insert it into the game! If you insert the ReflectionMetadata.xml file, it creates ReflectionMetadata objects which you can get the properties, methods, events, etc from.
Why would I prefer ReflectionMetadata access instead of To/FromString? I’ve been using BitBuffer for everything, and have been using it for any and all cases I need to serialize something. I’ve written stuff to serialize any ROBLOX value and written an extendable ‘serializable’ class, and I would love to keep instance serialization in order with how I’m doing everything else.
To be fair though, ROBLOX will do a much better job at serializing things. While I like the consistency of writing my own method, I would also be very happy to have access to the optimizations ROBLOX has made and that it uses for saving/loading places and models, which is a good argument for implementing a To/FromString method in addition to ReflectionMetadata access.
Not really sure if this is a good solution to GetMembers for anybody, but here’s a way I do it in my serialization plugin:
local HttpService = game:GetService("HttpService")
local Dump = nil
repeat
wait(0.5) -- basically what I'm doing here is to keep requesting until I actually get a return.
local Worked = pcall(function() Dump = HttpService:GetAsync("http://anaminus.github.io/rbx/raw/api/latest.txt") end)
until Worked
local Instances = {}
while Dump:find("[^a]?Class .- ") do
local End = Dump:find("[^a]Class .- ",3) or #Dump
local Props = {}
local Sample = Dump:sub(1,End)
local Instance,Parent = Dump:match("[^a]?Class (.-)[%s:]+(.-)%s")
local Next = Sample:find("\n")
local Deprecated = Sample:sub(1,Next-1):match(".+%[(.-)%]$")
if Deprecated ~= nil and Deprecated ~= "deprecated" then
Props.CanSerialize = false
end
if Parent ~= nil and Instances[Parent] ~= nil then
for i,v in pairs(Instances[Parent]) do
if i ~= "CanSerialize" then
Props[i] = v
end
end
end
while Sample:find("%sProperty .- "..Instance.."%..-%s") do
local Start,End = Sample:find("%sProperty .- "..Instance.."%..-%s")
local Type,Prop = Sample:match("%sProperty (.-) "..Instance.."%.(.-)%s")
local Deprecated = Sample:sub(Start,End+30):match("^%sProperty .+ "..Instance.."%..+%s%[(.-)%]")
if not Deprecated then
Props[Prop] = Type
end
Sample = Sample:sub(End+1)
end
Instances[Instance] = Props
Dump = Dump:sub(End+1)
end
for i,v in pairs(Instances) do
if v.CanSerialize == false then
Instances[i] = nil
end
end
-- Here's how you would list all the properties of the Part class.
for i,v in pairs(Instances.Part) do
print(i)
end
I created this a few days ago for another thread, but didn’t upload it until now:
It gets the latest API Dump and reads all classes, properties and enums from it.
It basicly stores for every class the properties as name = type, e.g Anchored = bool for BasePart.
The first time a class is serialized, it’ll calculate all properties for it and cache the result.
For Part, it would also contain the properties of PVInstance, BasePart and Instance. (got them all?)
It can serialize most datatypes (that can be saved), including some of the ParticleEmitter stuff.
I didn’t test it with every property, so eh… you can tell me what I have to fix/add
You can serialize a model, save the result to model.rbxmx and Insert from File it in studio.
(Been there, done that: Serialized the Workspace in a Script Builder and inserted it in studio)
(Note: If you try to do ^, you need to edit the file to “ungroup” the Workspace. Studio doesn’t inserting it)
I’d only want a GetMembers-like API if it actually included every member. Since the engineers want to be super-duper-secret about all the “non-scriptable” members for some reason, it probably isn’t going to happen.
Anyway, I wouldn’t mind a simple serialize-to-binary/xml API, because that would include all the hidden stuff, and I also have a parser for it.
I was considering reading from API dumps as a way to get around the lack of either function, but generally speaking it’s a pretty laborious thing that we’ve been asking for a solution to for a while.
What about the error when you try to require it while it’s in-game instead of requiring the ID? Or is the way it’s set up just not gonna work that way? Doesn’t really matter, just curious