VisualSource is an encoded and compressed source code format which takes information of a script and turns it into condensed executable information.
This documentation documents how VisualSource 3.0 works in detail.
The encryption and data format is pretty much the same. However, the version was bumped to 0000000000000004 and a change was made to add extra data for blocks attached as an else block. It's stored in a new Property that comes after ChildBlocks called ElseChildBlock. What is stored is average block data (see Block data structure for information on that) and if one is not stored, the value stored is nil.
VisualSource uses 3 different data concepts within it's code:
- Objects π¦
- Properties β
- List properties π
Objects start with 2 0x26 characters and following that is the name of the object.
Properties are structured as such:
0x26PROPNAME0x27PROPVAL
List properties are structured as such:
0x26PROPNAME0x27PROPVAL0x27PROPVAL
The "0x27PROPVAL" part is continued until the list ends
These all build up the core structure of how the final source is constructed.
- Editor π¦ - The start of the Editor object, essentially the root of everything.
- CameraPosition β - The XY position where the camera was at on the grid last time the script was saved.
- CameraZoom β - The zoom level of the camera last time the script was saved.
- Block π¦ - The core object of a block. Whenever a new block is serialized, it's added after the previous one every time.
-
Type β - The type of the block (aka the internal name, like SetVariable1)
-
Name β - The name of the block (the visual name in the editor)
-
VisualPosition β - The XY position of the block on the visual grid
-
ChildBlocks π - A list of block names that are connected to the block from first to last.
-
Inputs π - A list of inputs used in the block. Values are repeated until completion. It is stored as such:
- The input name
- The value type that was intended (eg. 2 for variable)
- The value put in
- The type of the value itself (if not a variable, eg. Bool)
-
Outputs π - A list of outputs used in the block. It is stored as such:
- The name of the output
- The value of the output
-
This process continues until all outputs have been logged.
-
- Comment π¦ - A comment (not the actual comment block itself) which wraps around under other blocks
- Position β - The position of the comment on the grid
- Size β - The size of the comment
- Color β - The color of the comment
- Name β - The name of the comment (aka the title)
But before we get into the main process, let's go over how each data type is serialized. There are many different types, that are serialized so let's go over each:
Strings are created if the value is a:
- String
- Choice (eg. an option from a dropdown in the editor)
- Object (object chosen from the game)
- Table (a reference to a table/table itself as a string)
- Function (the function name as a string)
- EventConnection (unsure what this is, probably a connection name)
- Equation (the exact equation from using Solve Equation and stuff) They are typically represented as a string conversion of their value.
Numbers are created if the value is explicitly a number/can be one.
- Number will be 0 if for whatever reason the value put in is bad.
- Negative numbers are formatted too
- Accounts for decimal numbers too including negative decimal numbers.
The result is that the main number and decimal number are converted to hex, and the decimal point is rounded to the nearest thousandth.
Booleans are formatted as either 1 or 0 (1 being true, 0 being false)
BrickColors use the number of the brick color for formatting.
Color3 is converted from Color3 to RGB directly, separated by commas (eg. FF,FF,FF)
The XYZ components are extracted and separated by commas (eg. 1.5,2,-3)
Same thing as Vector3 but extracts the XY components (eg. 1.5,1.5)
The X and Y Scale/Offset values are extracted and separated by commas (eg. 0.5,1A4,0.5,1A4)
All tuple values are extracted and concatenated as a string separated by commas (same way as Color3/Vector3)
VisualSource is decently encrypted, but luckily it's using open-source algorithms, so decrypting/encrypting is not hard.
- Copy the ENTIRE data after
οΏ½0000000000000003οΏ½(the header) - First, use a Base93 decoder and run it on that.
- After, run LibDeflate's deflation decoder on the value and you will get the VisualSource back!
- Take your decoded VisualSource information (MAKE SURE IT IS ENCODED PROPERLY AND DOESNT INCLUDE THE HEADER)
- Run LibDeflate's deflation encoder using the following settings:
{
level = 6,
strategy = "dynamic
}
- Encode the value again with Base93
- Append the header at the start, now you have real VisualSource!