Release Notes for 394

Notes for Release 394


Client Difference Log

API Changes

Added Property bool PluginAction.Checked {RobloxScriptSecurity} [<📁> Load-only] [NotReplicated]

Added Function void GuiService:InspectPlayerFromUserIdWithCtx(int64 userId, string ctx) {RobloxScriptSecurity}
Added Function bool Humanoid:PlayEmoteById(string emoteName, int64 emoteId) {RobloxScriptSecurity} [Yields]
Added Function void MarketplaceService:SignalPromptBundlePurchaseFinished(Instance player, int64 bundleId, bool success) {RobloxScriptSecurity}

Added Event GuiService.InspectPlayerFromUserIdWithCtxRequest(int64 userId, string ctx) {RobloxScriptSecurity}
Added Event MarketplaceService.PromptBundlePurchaseFinished(Instance player, int64 bundleId, bool wasPurchased) {RobloxScriptSecurity}

Added EnumItem InfoType.Bundle : 4

(Click here for a syntax highlighted version!)


All around, a nice bunch of bug fixes. Glad to see these pesky bugs getting removed.

Always good to have a confirmation for this type of stuff.

This should prevent a lot of problems people had with characters having different sizes / looking different between the server and the client.

Glad to see that Rthro is getting more consistent. It’s always been a problem that different packages or bundles will have different weights or sizes, making certain bugs appear for certain avatars. Still, I wish the weight of other items such as packages were consistent, but it’s always good to take a step in the right direction.

It’s always great to have more Lua functions!

With that, thanks to the teams that pushed these fixes out, and have a good day!


What is the difference bewteen table.unpack and the global variable unpack? Will the global variable unpack be deprecated in favour of table.unpack, or is the latter preferred over the former?


There is no difference; Lua 5.2 removes global unpack but we obviously can’t do that so both will continue to function.


Will only one be optimized because you want to make it the idiom?

We currently don’t plan to heavily optimize either; I expect that if we do, we’ll treat them equally. The real point of this update is table.pack, and table.unpack went along for the ride.


So as a general rule, we should treat the global as deprecated?

I’m curious about table.pack. Doesn’t that just make an array from the arguments with a field n indicating length? How is it useful?

1 Like

It’s useful in cases where you want to marshal the function argument calls across a network boundary as a table, or just store them for later.

You can use {...}, but the problem is that if you have any nil arguments in the function, the size of this table will be hard to compute (because of the quirks of # when dealing with arrays-with-holes).

You can compute the size using select('#', ...) yourself of course. But that’s pretty obscure.

Instead you can use table.pack as a convenience method that’s also going to be slightly faster.

Added Function void MarketplaceService:SignalPromptBundlePurchaseFinished(Instance player, int64 bundleId, bool success) {RobloxScriptSecurity}
Added Event MarketplaceService.PromptBundlePurchaseFinished(Instance player, int64 bundleId, bool wasPurchased) {RobloxScriptSecurity}

Question: Will you purchase Rthro bundles, non-Rthro bundles, or both using this?

The API for purchasing bundles should be unlocked eventually, I hope.


“Mixed” tables with string keys or nil array spaces can’t be marshalled/replicated last I checked?

I would consider table.pack’s result pretty obscure, as an “n” field isn’t used anywhere else in the API. unpack also doesn’t check for “n” (thankfully), so one would need to write table.unpack(t, 1, t.n) to get this to work, which is obscure in its own way.

This is not true if a custom packing function is optimized to not create a table in the case where the tuple length is 1 and isn’t already a table (creating a table is a whole lot slower than a type check). Storing the length at the beginning of the array as {select("#", ...), ...} would also use a bit less memory than using the hash part of the array (assuming the table doesn’t need to be reallocated to the nearest 2^n in the case of a trailing tuple.)

I love seeing improvements to the Lua API and I’m sure table.pack is convenient for a handful of devs, but it’s pretty obscure even though it’s in vanilla Lua.

1 Like

This is talking about manual implementations, not builtin - builtin mechanisms indeed don’t support mixed tables.

You’re making a lot of assumptions that may or may not be correct. Storing the length at the beginning of the array is a bit of a hack, and allocating the table the way you suggest still results in two allocations because the size isn’t known up front (so you create the table with 1 element and then grow it to the final size).

The .n in table.unpack fwiw is - as far as I know - a homage to the original Lua behavior that was deprecated in 5.1 where .n could store the array length. But .n is clearly documented in table.pack semantics, whereas select trick is something you have to learn… somehow… by reading the entire Lua reference manual I guess?

Anyway, if you don’t like table.pack - don’t use it. But it’s a builtin function in Lua 5.2 and it complements unpack reasonably well. Our general goal is that if there are features in later versions of Lua that are useful to the community, and are easy for us to pull in - we will do so. At this point we’ve added most of the 5.2+ library functionality (utf8 and bit32 included), and these just complete the set.


Okay that’s fair. I think I’m just eager to see a non-standard method like table.find implemented, as it would greatly improve my game’s performance in many cases.

Pack is useful with var ret because you cannot do
local …=f()

So you have to do one thing with the var ret, either:
local t={f()}—but table size is incorrect because of nil values
local n=select(‘#’,f())—but then you miss the args

So what I’ve been doing until table.pack becomes available is implementing my own pack to let me get the size and ret:
local t=pack(f())
local n=t.n

Edit: not sure if I should have replied to you

1 Like

Does that mean you’re open to adding other 5.2+ things, like string.pack or hex/unicode string escapes? I believe those are basically all that are missing that aren’t fundamental changes to the language.

Please file feature requests for this and we can take a look. On string.pack specifically I looked at this briefly and wasn’t sure if we should take it as is - there are parts of this API for example that behave differently on 32-bit vs 64-bit systems which isn’t ideal. But if there’s a need for this we can figure out if we need to adapt this to get more consistent behavior.

Looked at string.pack again and we’ll need to think about it. It seems super useful, but we’d need to substantially alter the spec to make all platform-dependent formats they have there fixed-size, and apparently that’s like half of the formats. :-/ As a result our version will very likely be incompatible with native version in terms of produced data. Might still be useful but not sure.

Even with those changes it would probably still be useful, though I’m not sure how much effort it would take to implement those changes and to document them.