Release Notes for 441

Notes for Release 441


Client Difference Log

API Changes

Added Property float CylinderHandleAdornment.Angle
Added Property float CylinderHandleAdornment.InnerRadius
Added Property Enum<MeshPartDetailLevel> RenderSettings.MeshPartDetailLevel

Added Function string RunService:GetCoreScriptVersion() {RobloxScriptSecurity}
Added Function bool StudioService:BaseURLHasChineseHost() {RobloxScriptSecurity}

Added Event StudioService.DEPRECATED_OnPublishPlaceToRoblox() {RobloxScriptSecurity}

Added Enum MeshPartDetailLevel
	Added EnumItem MeshPartDetailLevel.DistanceBased : 0
	Added EnumItem MeshPartDetailLevel.Level01 : 1
	Added EnumItem MeshPartDetailLevel.Level02 : 2
	Added EnumItem MeshPartDetailLevel.Level03 : 3
	Added EnumItem MeshPartDetailLevel.Level04 : 4

Added EnumItem RenderFidelity.Performance : 2

Changed the parameters of Event StudioService.OnPublishPlaceToRoblox 
	from: ()
	  to: (bool isOverwritePublish)

(Click here for a syntax highlighted version!)


Wow, I’m certainly excited to see Roblox pushing in the high-end device spectrum. I’m guessing that it still compresses for lower quality settings, but man the detail for high-end computers will be astonishing! Pair that with the surface appearance, and you’ve got real life.

Glad Roblox is also able to push graphically for…showing emotions! Will there be an update where emojis are added to the default chat (not via the plugin that exists, but by default)?

This release note seems like a push in the graphical direction (among other things), and I love it!


Release notes are finally here, let me see what we have today:

It seems interesting with this improvement, but what does this mean with an Emoji implementation? My best guess has to be importing Emojis into text inside a game.

Good news to me with Lua Draggers and asset window are being fixed with those points there, very important to many developers!

Detail to meshes!? Now this is very important for future meshes coming into games that are being made by modelers or usual developers, but how will this work exactly with the level of detail for meshes? Does it improve the quality of the mesh or am I missing something?

Anyway, a nice Release Note update for fixes and improvements, thanks!


Step aside boys. It’s time to implement half those useless projects I’ve been waiting to do.

No more wacky 200iq float packing/unpacking logic with documentation dug up from the ninth circle of hell.

Aaaand meant to reply to the OP.


Nice, that was quick


Really curious about the new emoji implementation, currently some emojis are off by 1-2 pixels, which makes them look off-centered when putting them into text labels. Hopefully, that also gets fixed!

1 Like


Hurray for the maybe 5 people who will use these functions!


Any chance we’ll ever see an LoD system that makes more sense than this? A distance-based LoD system makes less than zero sense as it means large objects that are far from the camera will often be at an LoD that is too low, and small objects that are close to the camera will often have an LoD that is too high.

A screen-based LoD system where LoD is determined by how much of the screen an object takes up, like that of UE4, would make much more sense because it means very large objects, such as a mountain, would retain a high level of detail even from far away.

1 Like

This setting is purely for internal debugging and isn’t meant to reflect the nature of the algorithm used (we don’t exactly use distance-based selection anyway). The more correct name is “Automatic”.


Ah. Regardless though, developers currently have almost zero control over when different LOD levels kick in. Will we ever see this opened up in the future, to the point where we can specify exact distances/screens-sizes where LODs will kick in?


Yes! There are so many applications for string.pack!

I’m working on a custom system for working with massive worlds with 100k+ models. It encodes chunks of map data into binary strings (escaped for StringValues), then decodes and displays only nearby chunks. I’ve been indecisive about the float format and ended up going with this because it’s fast to encode/decode in Lua: string.char(exp, sign + mantissa2, mantissa1, mantissa0)
Encoding/decoding cframes is a bit ridiculous, it’s a relief to not need this:


I’m actually finding it a bit hard to work with in terms of reading. It’s probably fine for set formats, but for stuff that’s arbitrary length (the example I tried was LZ4 compression since that seems like a practical use) it’s a bit awkward.

Incidentally if you’re strapped for space, a lot of CFrames can have their sizes cut down dramatically – Roblox’s binary format just stores an ID for the various axis-aligned rotations and uses that where possible instead of storing the full rotation matrix. It cuts most CFrames down to being a mere 13 bytes instead of 48, though it comes at a cost of non-axis aligned ones being 49 bytes.

Not sure if that would end up being fast but I imagine it would be more space efficient.


We do not currently have plans to expose that, as the behavior will depend on the device the game is running on and user quality settings.

1 Like

These functions work best when the layout is fixed size. LZ4 would not be a good fit, but packing message data for network replication or serialization when you know the exact shape of the message would be.

For client-facing data I use smallest-three quaternion encoding, along with storing ids for the 24 axis aligned angles, which uses less than 10% of the space when storing cframe lists in memory as strings for my data! I decided not to compress in-studio cframe data though, because I’d prefer to keep developer work at high precision; Ideally what the map artist creates would look identical to what the player will see in terms of precision, but I may decide to change the compression down the line. Packing many objects into StringValues instead of parts for representing model positions already shaves 2mb off of my save file. I got undo to work great with StringValues, but team create might not play nicely if two developers edit different objects within the same StringValue chunk. There are ways to make it work, but I don’t really use team create so it’s not a problem.


Is there any chance we will start to see API’s become more binary-string-friendly? It would be great to be able to store compact data in DataStores and send more bits via MessagingService without needing to convert to base 64. I’m currently using this to escape the least-used byte to enable me to store binary strings in StringValues, and I don’t like it:

It’s important for the DataStore API to be robust. Back in 2015 I went with base 64 encoded strings for my game because of undocumented cases that would error.

string.format("%q", binaryString) is also pretty much unusable because it doesn’t properly escape newlines.

I don’t have a repro, but I encountered the most confusing bug a few months ago when I stored invalid utf-8 escaped strings in script source. The game would work because the module’s source was set from a script, but the moment it was opened in the script editor the source would actually change slightly and mess up my binary data. Because of this, string.format("%q", binaryString) should ideally take utf-8 into account instead of always allowing characters 128-255.

I would also request that escaped characters be made more compact: “\000\001\002\003999” -> “\0\1\2\003999”. I have an entire module dedicated to formatting strings this way. +1 if it uses apostrophes when it finds there are more quotes to be escaped.

1 Like

We probably do need to fix quoting of newlines (although that quoting style is compatible with Lua’s string literal syntax so it’s technically correct), but either way this is going to be grossly inefficient compared to either dedicated binary support, or a specialized binary storage format.

Also you really don’t need to unroll loops by that amount :smiley:


Yeah it pushes close to the 200 local limit by unpacking 192 bytes at a time. The performance boost from including the 192 loop was roughly 10% when I measured it last year. I really needed this for my packed-map-data use case, where long strings can be packed extremely often when dragging models. I plan on making my own tools for foliage/models to reduce the need for redundant string updates.

Ran the benchmark again with the new VM and the performance difference is only 2% :+1:

1 Like

I would instinctively do something like

for i=1, #data, 8 do
    local a, b, c, d, e, f, g, h = string.byte(data, i, i + 7)
    freq[1 + (a or 256)] += 1
    freq[1 + (b or 256)] += 1
    freq[1 + (c or 256)] += 1
    freq[1 + (d or 256)] += 1
    freq[1 + (e or 256)] += 1
    freq[1 + (f or 256)] += 1
    freq[1 + (g or 256)] += 1
    freq[1 + (h or 256)] += 1

Although using two loops to avoid or might be slightly worthwhile.