What are you trying to accomplish with your encoder/decoder?
I want to make a game where you can mod it in roblox, my idea for maps was to make a script people cna put in a place, then that script runs through a folder and converts all the parts into a table, then converts that to a json string so it can be copied.
Then in the actual game they can paste that json string and it will load the data as a map.
In that case you should do data compression.
Like checking if the part has default Instance.new() Properties and if they are just donât include it in the JSON, and again I would highly recommend you use Robloxâs API Dump because it would mean your code would support ANY Instance ALWAYS.
Another way you could compress the strings more is not encoding them in Json.
Letâs say you have these properties:
{
Position = Vector3.new(1, 5, 1),
Color = Color3.fromRGB(255, 255, 255)
}
It could also be represented as
"1, 5, 1|255, 255, 255"
Which you could then decode by doing (I think)
local Position = Vector3.new(string.split(string.split(String, "|")[1], ","))
You could further compress this by encoding the numbers into something like Base90
so instead of 255 itâd be something like ZA
idk if im up to that, ill see if i can find one of my friends to do it later
I did the decompression thing u mentioned:
turns into:
" 0|106, 57, 9, |-1, 3.5, -13.000000953674316, 1, 0, 0, 0, 1, 0, 0, 0, 1, |false|Enum.Material.Brick|true|16, 7, 2, |Enum.PartType.Block|true|Default|0|true|false|0|Burnt Sienna|true|true|true|true|Part|"
But now i dont know what property is what
hey it went from 700kb to 300kbs though, and i havnt even done the other compressino things u said
You want to make it ordered by your own property table.
So lets say the order is
Position
Size
Anchored
BrickColor
etc
If Anchored is default then the text would be
Position|Size||BrickColor
Then when decoding it youâd want to ignore values that are nil.
Alright, ill do that. How does base64 or whatever u said work?
Also does brickcolor matter? or can i just use color alone
So, default numbers you have 0-9 (Base10) but with something like Base90 instead of the default 0-9 youâd have your numbers be something like
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890
Each character representing a number.
Hereâs a basic function that should encode/decode strings into Base90.
local EncodeChars = [==[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890-=_+[]{}\;:'"<>/?.!@#$%^&*()]==]
local Base = #EncodeChars
local function EncodeNumber(num)
if num == 0 then
return EncodeChars:sub(1, 1)
end
local encoded = ""
while num > 0 do
local remainder = (num % Base) + 1
encoded = EncodeChars:sub(remainder, remainder) .. encoded
num = math.floor(num / Base)
end
return encoded
end
local function DecodeString(encoded)
local num = 0
for i = 1, #encoded do
local char = encoded:sub(i, i)
local charIndex = EncodeChars:find(char, 1, true)
if not charIndex then
error("Invalid character found in encoded string: " .. char)
end
num = num * Base + (charIndex - 1)
end
return num
end
Brick color does not matter, because youâre already saving the Color3 value.
Now have a defaults table
So i can check through that and see if i need to actualyl care about the property
Is this efficent to do for checking if a property is already the default
Yes, but you should use a for loop on the defaults table.
for Property, DefaultValue in pairs(Proto.Defaults) do
if Part[Property] ~= DefaultValue then
InfoTable[Property] = Part[Property]
else
InfoTable[Property] = ""
end
end
How do i implement this into this script:
local function Decode(Part)
warn("Decoding part: "..Part.Name)
local InfoTable = {}
local Tags = {}
--JSON does notsupport some things, so they are converted to strings/tables.
--Appearance:
--InfoTable.BrickColor = tostring(Part.BrickColor) --Brickcolor is useless to save.
InfoTable.CastShadow = Part.CastShadow
InfoTable.Color = {math.round(Part.Color.R*255), math.round(Part.Color.G*255), math.round(Part.Color.B*255)} --Rounded because floating points
InfoTable.Material = tostring(Part.Material)
InfoTable.Reflectance = Part.Reflectance
InfoTable.Transparency = Part.Transparency
--Data:
InfoTable.Archivable = Part.Archivable
InfoTable.Locked = Part.Locked
InfoTable.Name = Part.Name
--No Parent Required
--Transform
InfoTable.Size = {Part.Size.X, Part.Size.Y, Part.Size.Z}
--InfoTable.CFramePos = {Part.CFrame.Position.X, Part.CFrame.Position.Y, Part.CFrame.Position.Z}
--InfoTable.CFrameRot = {Part.Rotation.X, Part.Rotation.Y, Part.Rotation.Z}
InfoTable.CFrame = {Part.CFrame:GetComponents()}
--Behavior
InfoTable.EnableFluidForces = Part.EnableFluidForces
--Collision
InfoTable.CanCollide = Part.CanCollide
InfoTable.CanQuery = Part.CanQuery
InfoTable.CanTouch = Part.CanTouch
InfoTable.CollisionGroup = Part.CollisionGroup
--Part
InfoTable.Anchored = Part.Anchored
InfoTable.CustomPhysicalProperties = Part.CustomPhysicalProperties
InfoTable.Massless = Part.Massless
InfoTable.RootPriority = Part.RootPriority
InfoTable.Shape = tostring(Part.Shape)
--Tags
for _, V in Part:GetTags() do
table.insert(Tags, V)
end
local FinalTable = {}
table.insert(FinalTable, InfoTable)
table.insert(FinalTable, Tags)
local FinalFinalTable = {}
warn("Finished Decoding: "..Part.Name)
return FinalTable
end
Ideally youâd create a function thatâd convert every Value into a string.
Like
local Conversions = {
Vector3 = function(Vector3)
return Vector3.X..Vector3.Y..Vector3.Z
end
}
etc
You could detect what type the value is with typeof(Value)
CFrame does not come out of this
CFrame isnât part of your defaults table.
i just added it manually, could we maybe start talking about this over PMs? we have gone off topic now