[Convert Instances to Scripts] Instance Serializer Plugin

Once upon a time, I made a plugin to convert things into scripts so that I didn’t have to copy properties over manually. Now 4 years later, I’m on the 3rd rewrite, and posting it here.

This plugin, like the title says, converts an instance and its descendants into scripts so that they can be created by a normal script or plugin later down the line. So, for example, if you had a granite cube that was 5x5x5 and was bright red:

Then with the default options it would get converted to this code:

local Part = Instance.new("Part")
Part.BottomSurface = Enum.SurfaceType.Smooth
Part.TopSurface = Enum.SurfaceType.Smooth
Part.Color = Color3.fromRGB(255, 0, 0)
Part.Material = Enum.Material.Granite
Part.Size = Vector3.new(5, 5, 5)

Part.Parent = workspace

Options

There are some options to modify what the output looks like or what gets serialized or not. They’re adjusted by the GUI interface, which looks like this:
image

While the text next to them is at least somewhat informative, a more detailed explanation for each of them can be provided:

Minify output

When this option is selected, the output is minified. This means that as little space as possible is occupied by the output while still keeping it workable and at least somewhat readable. If the serializer was ran with this option, the example code snippet would become:

local a=Instance.new"Part"
a.BottomSurface=0
a.TopSurface=0
a.Color=Color3.fromRGB(255,0,0)
a.Material=832
a.Size=Vector3.new(5,5,5)
a.Parent=workspace

Output modules

By default, the plugin puts the outputted code into a normal Script. With this option turned on though, it’s instead placed in a ModuleScript and returned. There’s no substantial modifications to the code snippet with this option turned on, but for the sake of completion the example would become:

local Part = Instance.new("Part")
Part.BottomSurface = Enum.SurfaceType.Smooth
Part.TopSurface = Enum.SurfaceType.Smooth
Part.Color = Color3.fromRGB(255, 0, 0)
Part.Material = Enum.Material.Granite
Part.Size = Vector3.new(5, 5, 5)

Part.Parent = workspace
return Part

Parent main model

This option defaults to true, and toggles whether the topmost selected Instance is parented or not. If the option were turned off, the example snippet would become:

local Part = Instance.new("Part")
Part.BottomSurface = Enum.SurfaceType.Smooth
Part.TopSurface = Enum.SurfaceType.Smooth
Part.Color = Color3.fromRGB(255, 0, 0)
Part.Material = Enum.Material.Granite
Part.Size = Vector3.new(5, 5, 5)

Serialize restricted properties.

Simply put, this option toggles whether properties that are locked to normal scripts but accessible to plugins and the command bar are serialized. The most obvious use for this is Script.Source, but there are a bunch of locked properties that this option enables the serialization of. If you need to use this option, you’ll know why.

Caveats

This plugin requires very brief HTTP access so that it can load the most recent API dump. Without it, this plugin won’t function. The API dump is loaded from CloneTrooper1019’s client tracker.

Additionally, at the moment script sources have a hard limit of 199,999 characters when set by another script. As a result, sufficiently large models will instead be split into multiple modules and loaded from there.

Extra stuff

This plugin’s source is available here:

If you have any questions or problems, either open an issue there or reply here and I’ll get back to you as soon as possible!

76 Likes

This is very well made. The code is clean and easy to understand, and the plugin is very feature complete, supporting pretty much everything I could think of.

Amazing work. :ok_hand:t2:

5 Likes

@Dekkonot Don’t understand the whole script, but good work.

Studio can make requests directly to rbxcdn.com:

  1. GET https://setup.rbxcdn.com/versionQTStudio to get the latest version.
  2. GET https://setup.rbxcdn.com/$VERSION-API-Dump.json to get the dump.

The only drawback is that this version is the latest, not necessarily the current. @Maximum_ADHD can correct me, but I think the only API to get the current version lives under roblox.com, so it isn’t accessible.

5 Likes

I decided it was better to not rely upon Roblox’s site at all if possible because there’s a chance, however small it may be, that they’ll block requests to rbxcdn. That may be a bit if an irrational worry but it’s still there. I don’t foresee Clone’s client tracker going away or changing format anytime soon (it’s been the same for several years) so I feel comfortable using it.

4 Likes

@Dekkonot Hey, sorry for the reply but I cannot use this plugin? Roblox doesn’t load it, how would I fix this?

Not sure what you mean by it not loading. Do you mean you can’t get it installed or that once you have it installed it isn’t loading?

Once I have it installed, it is not appearing in my plugin menu. @Dekkonot

1 Like

That’s strange. I’m not sure why that would be happening. It sounds like that may be a bug on Roblox’s end.

Try disabling some plugins, you might have too many displayed for this one to show its plugin.

That shouldn’t be the case. I have the plugin installed on my studio and last I checked it worked fine. It’s possible something that Roblox did with plugin Http requests broke it, or I accidentally pushed an update that broke it though. I’ll check later tonight just to be sure though.

@xxpuufflexx @AwesomePIays It should be fixed now. I was making a mistake with how I was uploading the plugin to Roblox, and it resulted in (as predicted by puuffle) the main script not loading. Go ahead and update your plugin.

It looks like certain properties aren’t set when other properties will modify them to what they should be, for instance BasePart.Position isn’t set because BasePart.CFrame will be modified which will modify BasePart.Position. However, it appears that it doesn’t do this for attachments for instance this model (model.rbxm (2.7 KB)) will generate this code:

local Part = Instance.new("Part")
Part.BottomSurface = Enum.SurfaceType.Smooth
Part.TopSurface = Enum.SurfaceType.Smooth
Part.Size = Vector3.new(4, 1, 2)
Part.CFrame = CFrame.new(0, 1, 0, 8.4321634119533e-09, -8.4321634119533e-09, -1, -0.70710682868958, 0.70710670948029, -1.1924880638503e-08, 0.70710670948029, 0.70710682868958, -5.2125306431198e-16)

local Attachment = Instance.new("Attachment")
Attachment.WorldSecondaryAxis = Vector3.new(-0.70710682868958, 0.49999991059303, 0.49999997019768)
Attachment.WorldOrientation = Vector3.new(-44.999996185303, 180, -45.000003814697)
Attachment.CFrame = CFrame.new(0, 1, 0, 8.4321634119533e-09, -8.4321634119533e-09, -1, -0.70710682868958, 0.70710670948029, -1.1924879750325e-08, 0.70710670948029, 0.70710682868958, -8.8817841970013e-16)
Attachment.WorldPosition = Vector3.new(-8.4321634119533e-09, 1.7071067094803, 0.70710682868958)
Attachment.Axis = Vector3.new(8.4321634119533e-09, -0.70710682868958, 0.70710670948029)
Attachment.Rotation = Vector3.new(45.000003814697, -90, 0)
Attachment.WorldCFrame = CFrame.new(-8.4321634119533e-09, 1.7071067094803, 0.70710682868958, -0.70710670948029, -0.70710682868958, 1.4901161193848e-08, -0.49999997019768, 0.49999991059303, 0.70710676908493, -0.50000005960464, 0.49999997019768, -0.70710670948029)
Attachment.SecondaryAxis = Vector3.new(-8.4321634119533e-09, 0.70710670948029, 0.70710682868958)
Attachment.Position = Vector3.new(0, 1, 0)
Attachment.Orientation = Vector3.new(6.8324521862451e-07, -90, -45.000003814697)
Attachment.WorldAxis = Vector3.new(-0.70710670948029, -0.49999997019768, -0.50000005960464)
Attachment.Parent = Part

local Bone = Instance.new("Bone")
Bone.WorldSecondaryAxis = Vector3.new(-8.4321634119533e-09, 0.70710670948029, 0.70710682868958)
Bone.WorldOrientation = Vector3.new(6.8324521862451e-07, -90, -45.000003814697)
Bone.WorldPosition = Vector3.new(0, 1, 0)
Bone.WorldCFrame = CFrame.new(0, 1, 0, 8.4321634119533e-09, -8.4321634119533e-09, -1, -0.70710682868958, 0.70710670948029, -1.1924879750325e-08, 0.70710670948029, 0.70710682868958, -8.8817841970013e-16)
Bone.WorldAxis = Vector3.new(8.4321634119533e-09, -0.70710682868958, 0.70710670948029)
Bone.Transform = CFrame.new(0, 1, 0, 8.4321634119533e-09, -8.4321634119533e-09, -1, -0.70710682868958, 0.70710670948029, -1.1924880638503e-08, 0.70710670948029, 0.70710682868958, -5.2125306431198e-16)
Bone.Parent = Part

Part.Parent = game:GetService("ServerScriptService")
return Part

I only set CFrame on Attachment and Transform on Bone, setting the other rotation/position properties is redundant. This isn’t an issue, but it would make more sense for the redundant properties to not be set (like how it doesn’t set redundant properties of BasePart).

The Minify Option reduces the code size, although I see one area where it could reduce code size further: using single quoted strings or long strings when shorter. So when serializing a string value with the value set to ", instead of generating

local a=Instance.new"StringValue"
a.Value="\""
a.Parent=game:GetService"ServerScriptService"
return a

it would generate

local a=Instance.new"StringValue"
a.Value='"'
a.Parent=game:GetService"ServerScriptService"
return a

This probably doesn’t happen that often, so it’s not very important.

Also, closing the widget with the X at the top right of the widget doesn’t toggle the button in the plugin toolbar like it would when closing the widget by clicking the toolbar button. This isn’t that big of a problem, but it’s worth noting.

I’ll look into fixing that for Attachment – properties are manually restricted, and I don’t use Attachments very often, so I missed those. Thanks for the heads up.

As for the other two, thanks for pointing those out – I’ll make sure they get changed.

This is so useful. Thank you so much. mister!

1 Like

Into one script option please it will be very helpful!

It tries its best to do one script but for extremely large objects it’s not possible due to Roblox’s engine limits – the max settable length of Script.Source is 199,999 characters, so anything beyond that has to be split up.

There’s unfortunately not much I can do about it. :frowning: