Turn objects into strings! - SerialBit

Superseded by V2, I reccomend using that instead!

About

SerialBit was made with speed and efficiently in mind. It’s made to store objects. For example, lets say a player made a cool build. How would you save it? You can’t store Instances. But, you can store strings. Serialization is the process the process of converting the state of an object into a form that can be persisted or transported. So, in order to save a build, you could use SerialBit, and then happily store your player builds in a datastore, using a compressed string.

See these totally not free model generic huts here?
image
image

Well, the hut on the far left is the original.
The middle, is a model completely rebuilt using SerialBit.
The right, is rebuilt by another serialization module, RbxSerialize

SerialBit was quite accurate, don’t you think?

SerialBit took 0.123 seconds to encode, compress, decode, decompress and then load this model! Without yielding, this would be faster (but you don’t want to crash the server with large models, do you? :wink: )

Infact, heres the string that SerialBit used to create this model.

Serialized string

What kind of cryptic language is this?!?!?! Witchcraft I say!
This string stores all the properties and descendants of the object.

I@jrA1dTC@b|!j03~ER;m9bp7$|GCF4iRF7V>CSOM:=Dsek4oH`x!~~6zV`lK0Bl_56xKw,FAS;zDb~]B;Or.|Pk0k(IvFPs5>S82g.#D7&nJ&Mpl8_jU[.1Jsn(_;2r8?lI:|s<_jQn<~*s3l}bQ~bIPs6,LQ^%LF{id/|;VCa+*][OmrvyR>[__|4eB&yXy)49Aqe=;8^_Mh7{{`Sha92}7e3gUrZg<(25y*fU3*j.@(Nh%>|$zlCVD(|:u9d{l]Ing&nEi{jga&%%B>TW+=l3a?RU&ox*8tAX^js%BV,HAi4fq?<uQt$Ip//?t@?k"Q8yP^rU/3=TrLtW/{<N:?mrQ;?pG([xq8bU]_%,D+"7;mXSmXNb6834.>3xxU`BsyE9yP!t^)]~zYI`eo+vBTD~8PM&wny$LCQ57ssfI0O/9%TCb9HgjED5urAUZ7W!fE>WQ0wCOOeyZvf;kfR5pbQZ)7;CM$ZvgGG>+7N)}.IFIwRXtTH/&<yC.TRrQLOD*r~9$P}pQC^VF<])]P3gN@oDi>^_PW^_N/rg&3R(&_BIr%rJJxSf"iYIXLV"vA@Lz=f`pRWS^C4CN[g5U~9s*4<U)WzB&4$fbdE2Rj>ZC;C%@_/dZD@hi{`(u7fvFBft4[)w7NAMWc]YV[W3<Bhx{3kA#n{6@8mc.Y+!.%4uyszt"oq4OStZmM$BhM]4F,MMg47(BJxJuI9{!JR+8ocJC%mzYx4#=Mf#5U)%u6$y(=gO~j.aev!5xWRaJ0JU*u_8wJ&}PJW2d3o^}?,XeJHF7dz/RHAP;XZ?nX<k"zM}2WCz,m:uFXeQNZub;9XE"5`c/O_nrutfQR9H=Du&bG(Y~Jv@1.o!O<{hFynEP*eve*1F[l(Y0Wy,%Vx@+n~v@UAaVOlWq:lzA8kL235P:bH|&NEWir}F^YniTz,UBQ3R|<MsGLNKLs[;]=(IvV]:18}<T,hN#yv=w_0c6oru!MIeudDi_E2E6|?yqt<%lwTvC]rzY3<^ib`iy%*R%CQ$12/|b,Og&%aFW7_TadAp>lD*Y:OO;LiU;txDtkqBohJ*{tHOA5ZD,J%c>3i]/$Wqi>rbT2+Y$4$WjzZp$zoc!y0_U@Q$vToWO"tyv,743{ob?bi>d/.cnaIG)Kv4>04izNs}3VdHbD&O(,5&_VAzz~SV8FVfAy|SC{3N97?IgffiRLD=NO)}7tKK^>A/YIBapwq|<LFZ^;(tEB+GE*,`e>(ja^J}eeqCwMCL[qt]Bq2,4~".$*HM_=]N~5>oyn{Em!+6<J]{@p)02;`%7N_6mORr;*&N/tjtkt;biO=62<5b8By7NgZrqG=hjD4&{+$gdxNz1JE(Ch*pE@iU|wo&u/qp,TH<gM]?_@q+^3Zb}b05!G2Vkn$)J:cVh#uN*g%ofFTffj"kRmky9X8meF}wfa,4R2xn8V]nLI!w6zX_REO.wj!v)::*Ad0mz:97$4rN)3AoY7eUg@ii2`a}&wu@WP)!FH]^u)ENUVNjnZ%mUcvl?Ifj)R$5Q.fM<B`N.CV*V0=[+Biw&hK$Mju#m*IGynp37PrpSj!JgZt}u@feR1x.=PtuLS`],Pi2.}[2D8ST0&]Q}}]daFyiaMd3Q1Wh!L^mYPI{&}7`Oe7_ePCVBjv~]GCU/]bBbF>x^}S&Bcb*wtL/[i+WOYhBWc$%edL*o,&Ga76f$Gr!0*;7nq0s6N}K@1eb$qgm~_CF+|}5rI*QjoEZVo"vPk]3royu*i>F/7}+Uo<hp7i[~TLQ}IPPF?lZ^ZjF<_1^bYlj_DNWJrmEF)LBzXQQlTZ}4m}~</)EDZ>hg=>VP@|Es4/6{FPnM{QaAH+&gDqGgu77XreieLfmAvaeM.)x6*2u&Z"E#}N~#]*m1}}lOec_|$.v)^"g^)hTch^e|yy9aO#QcC(&3leSCfwBUR.i]e@VBZ4Lat=F9LZb#tEXEFG)A+B&"s2g>9Z]Ds.i`gEQnB<.K?l4TceR?HbN=i`}qo8dDsF?wmoUw*pJ()xQ^X}G&x%]Svnw=oK/svW4&T,(_Lpfr=3J.s=_J|c%Nk1_m1B&)vS+8UMUc?ein:2L3XAyuPf3(4[N>)$J6=BfLc8hpcW[rQ*$w68q7*FdsQZJ8qx&B%y$=S:n]H::#01"0s=K^IzhVVphIZt9=JTO%xA;]S0meQ#65TYo51<ghb^d=g?yPE!i2*:J@=uvUP.0k5+O!m9q5ve%SsJ30Cobwz??.{m9_9lL@0B4uDi=7Q.`E9*Zo;x;$Ug1,fm>f=j1QPO.s7;g:d!%U:jB71cgKlb#}&{@(UOY(!}VL%|,WpFl8Sh|^C03|+_zHD83(3/e"v2c|<a$<Qa@sN(59p,uL31PgSH0vO&Qu_#~WT9Z"Z#zcVZI&!:kul{0gG}%pNQrhe$K^ooya|p)+W&E&a^O,BBfgpv8+ym&!4psov*HKTO/&6PmC*B?xQXs.DFZ$(5[n<]1t_|d^zoTC${9[r}d)|YSZrq`Ouf;Pu4G>;S]ev~X=wW/6&+Bj(TP>n!W*6%gd]:gE$EdE2$lvH5FR4>A~YP84Qv1T5L!%eTNaq8gfLhu@qx]m!TYPv.=H_$@RqVP/S$e1N(JQ=NITsy@z9p9>=O2c$#St#AdcKk&&usBmQ~Woo>&V_9xq**kB9wY3.dQ(W7EbM7a_&dQNg{^]{(U7_`yAkIM;XeEGC3u|YGH+xzdG@VG|V=MBV8y5`(mxpi*q>caIiRhhe7.bWs#C_2;!Vt!<]L1C$.`c6nM[#WQadKf*`JDF^qr%sO4VgX9Ic$8+IO^N#2_.iw.7UH(>gN8z19a.@KH"jlJNzSeFR)j<w/wibC(Ak^R~G(<Z|Lht<<`:lN9I?xgG$|6rVr@.`[5oJRO9uz7429CxJqp#H0UG*)Lp?U0#YTB:PYx{l}=_@k#%u62t/2OkdibvPDX@l}4k)4khi1K^%4(Lv<T/Iv|F=nN@Ubn!Ej<uoDXtDIt#)XRiU36,qnft1Cf!*Hs,?tyPyi9H]CoZWH6Z{DM|Y7i1U9?`}1VP*b>:!G*gKCV4NT<M7fkkwgE8^=vu8k:c*DBahf?T>Z?*%];$*Cl.R6#^OR+,JiIU?/bdhVU}i{Fi=9oDbq^]BRCF*wbn92$wgXERS#O+YNH0x1)FJK,9S@*rq<<Ti%F9bR]K%(`L;ft;@7%a81}9@./K)]r2kT~sl0kMg[v9J)qfb;QYq6E!7S.~U{7Fzl**y+wOh[Ju/j^YXLW<c]F3(6`:gbK.6t0s&BCDw&NNB~+"$V{Hc*<7)A8V_[]2i>krr2)q741_<k2Qo2v!+LhA`Vr!=jtW3_vb5l=d+CM/SSc|Ie&_H,H)2Y>9k4O?=vs(Af7:$<~R0(w?6jy0hn;+WOVbWWLw|ssJw!tx(t)*;`=7B8fGRgq>&>ybp;!1;MvATxs?=O){4Gl1<Bqa_9edm_l^X"V575!#9up2`3.,Si:@&"_#O1[_J!ht~6QPlO/w^A3M%}n]8:P4Ue,P2u<`ex"?{Sa@:q^Vvt^Szkhq_%UQOi:X_8Ky9wTNGR]vJM1!,gvA"U%zlxMVQ*6/[r(;Jb~[=vX)P@!;u0X4>D{#_uEo~)Uk0$U77#4a)Lb4b`p.Pa*@we_6i[^7H!^=zBn747Js}}LgWwS+{lrW,nN=TG88$xXad^Se%wRk~<1ojiINC|vzb9"Pzyv8~&H|v9,B

It also saves a lot of space. RbxSerialize produced a string of 5k characters, while SerialBit produced a string of 3.6k. (That’s quite the difference)

Currently, it’s there’s just two functions. But, I can always add more! What do you think?

SerialBit.serial(Object: Instance): string

Serializes the instance and it’s descendants into a string. This can be loaded into an exact copy with SerialBit.struct

SerialBit.struct(Serial: string): Instance

Instances the model from the serial string. Returns a Model.

SerialBit.reference(Object : Instance) : void

The object passed must have an attribute called “REF_ID”. The descendants of this object must also have an attribute called “REF_CHILD_ID”. When serializing a model with a reference, they must have the exact same attributes, but can have different properties.

Selected the desired object(s) and then run this code in the command bar
local Selection = game:GetService("Selection") local Selected = Selection:Get() for i, v in Selected do local AllObjects = v:GetDescendants() v:SetAttribute("REF_ID", game:GetService("HttpService"):GenerateGUID(0):split("-")[1]) for i = 1, #AllObjects do local Object = AllObjects[i] Object:SetAttribute("REF_CHILD_ID", game:GetService("HttpService"):GenerateGUID(0):split("-")[1]) end end
Example

This is our reference object.
image
image

In our script, we’d add this using SerialBit.reference
image

We would then serialize like normal.
We can also change the properties of the reference object:
image
(hes now tall!)

And when loading the object into the game, it will clone the original reference object, and then apply all of the properties.
You can also use models and basically anything else as references, as long as they have the special attributes.
image
(It worked! But… everything was unanchored :sweat_smile:)

image

If you have any issues, suggestion, or nit-picks, please, leave a post! I’d like to hear from you all. Also, this is one of my first posts! :slight_smile:

Doesn’t support MeshParts or Unions. Unfortunately, MeshParts are impossible to implement without using SpecialMeshes, which, in my opinion, is cheating! Union support may be something in the future :eyes:

31 Likes

That’s interesting! I can’t get my hands on it right now, but it could be useful for things such as exporting data from live games into Studio, or creating dynamic place update systems if this serialization really works.

1 Like

you could check for already existing assets saved in the game and clone them for mesh parts and unions or have a folder for it to check for resources

1 Like

That’s something I could totally implement!

[EDIT: Working on it now.]

Update v1.1.0

Added boolean SerialBit.DebugPrints

Added SerialBit.reference

Instructions on how to use it have been added to the post.

This looks amazing! I’ll definitely check it out.

Why is it that

1 Like

Well, you cant set the MeshId of a MeshPart in scripts. But, you can use SerialBit.reference instead, just with a bit more setup. Hope that helped. :slight_smile:

1 Like

Ah, okay. Never knew that you couldn’t set the MeshId of meshparts. Good to know.

1 Like

the package version is offsale

My bad, I just discovered i dont think you can share packages.

why not release it as a model (not a package)

It is released as a model. I released a package along with it, realised it doesn’t work, then removed it.

Nice work, I’ve abandoned by module due to how busy i am nowadays. I use some super old purelua library for compression and don’t necessarily understand it too much. Hence why now my compression is worse. Anyways there are some isseus like the way you store datatypes. However in some cases storing datatypes in pure text will be smaller. And in some cases it will be significantly bigger. Something i’ve wanted to implement is multiple headers for different encoding methods of datatypes and only use the smallest one. Howerver i never got around to it. The point is, offset this model with extreme decimal percision and with a great offset from the world origin and you will use significantly more memory. Consider storing some datatypes in a raw format.

1 Like

This is very cool and useful for safely storing models in your game with out having to worry too much about game theft.

All we need now is a client script serialization which will prevent client code theft and exploiters from viewing the script. All though running said code might be another challenge in it self too.

Keep up the great work!

1 Like

This module wasn’t for securing your game, but rather, for example, storing player builds. Unfortunately, i dont think anything like this is possible.

1 Like

Hello! First of all, I dont understand the compression module I use either :sweat_smile:. Also, wdym “raw format”

The purpose of the module was to condense everything into a string for storage (eg. Datastore). Do you mean storing it raw as in, like inside a table? That I can totally add as an option of storage, too!

Store all numbers in binary. use string.pack() or some sort of binary stream this will decrease your size significantly.

2 Likes

Thanks for the advice, ill have to research this stuff when I get home

did you implement that for the current update?

I really appreciate the idea!

I already implemented it! It was part of version 1.1.0. If you have any other ideas, tell me!