Instance Integer Identifiers

With the recent introduction of buffer types, I’ve started work on a library called Zap which takes a network description and outputs efficient luau that packs all data into buffers. The biggest issue I’ve encountered is sending instances through buffers.

How are instances currently sent over remotes?

Through a lot of research, time, and effort, people smarter than me have concluded that instances are sent over remotes as 4 bytes. While we don’t have access to how the engine is doing this, I guess that the engine has a unqiue 4 byte identifier or integer for each instance in a game.

How can we send instances over buffers?

It’s quite simple really, buffers have the buffer.writeu32 function which writes a 4 byte integer to a buffer. The only issue is that we have no method of getting this unique number to write to buffers.

Proposed Solution

My proposed solution is a new property, Instance.Id. The exact naming could be debated, Id, UniqueId, or SharedId - it doesn’t really matter. Another important API would be the ability to take these identifiers and retrieve the instance they corrospond to, I suggest game:GetInstanceFromId(Id: number): Instance?.

The keen eyed among you might question the ? after the method’s return. Instances that do not exist at the destination exist as nil when recieved by remotes. This new API would have the same behavior: if an instance identifier does not exist, it would return nil.

Alternatives

My current solution to this problem is to send a table along with my buffer. This table stores all the instances that need to be sent, and the buffer stores the index of the instance in that table. This solution will likely turn out to be quite buggy with optional instance types, as arrays can sometimes truncate after the first nil. Additionally, this uses 3 extra bytes per instance, and 2 bytes per fire.

43 Likes

This is plugin security, but would this be useful if it was accessible to you?

GetDebugId Documentation

7 Likes

This would actually be quite useful for syncing local instances en-masse when normal replication isn’t optimal.

That’s for plugins to arbitrarily distinguish instances with, and the generated Id isn’t shared between server/client boundaries afaik.

4 Likes

It is!.. in a weird way. The Ids are formatted as 1_234567, with the first number changing depending on the side of the boundary the function was called from. 0 for server, and 1 for client. Here’s an example just from calling it on a few instances from both sides.
image
The only reason the id would change is if you were to call GetDebugId on an instance that has the NotReplicated tag.

I think GetDebugId would fit the OP’s use case if the security was de-elevated.

4 Likes

Roblox has an internal UniqueId property they’re starting to use for this purpose. It’s currently represented as a 128-bit integer, which means it’d be impossible to store properly in Luau.

I would prefer Roblox not simply expose this, since sending 16 bytes per Instance is a waste. It makes sense on a global scale, but per-place there’s never going to be 2^32 instances, let alone 2^128.

7 Likes

This sounds like something used to identify instances universally, not something meant for temporary use in experiences. For instances to be encoded over remotes as 4 bytes some kind of temporary identifier likely exists.

2 Likes

This is exactly what I’m looking for, except not as a string but as a number. Also the ability to take this number and reverse the process, getting an instance from it.

3 Likes

It’s not, it’s only guaranteed to be unique across games. In practice it’s a UUID so it will be unique, but nobody complains if you upload two things that have overlapping UniqueIds.

I agree that something more temporary would be better though, I’m just mentioning something that already exists if an engineer wants to look at prior work.

4 Likes

I’d rather keep DebugIds studio-only. We’re not even sure they exist on a live server. Plus, it’s impossible to guarantee a client won’t have a conflicting local instance this way (studio most likely compensates for this though).

Since the primary use case is for networking, why not expose a new method solely for getting the replicated id?

Instance:GetReplicatedId(): number?

Returns the u32 id used internally for the instance with remotes.
Returns nil if the instance is unreplicated or is local.

game:GetInstanceFromReplicatedId(id: number): Instance?

Returns the instance the u32 id is for.
Returns nil if the id doesn’t match any replicated instance on the machine.

There’s no point in exposing it as a property since it’s always constant, and with an optional return it becomes more obvious that some instances can’t have ids.

9 Likes

I’d just like to add an additional usecase for a partial version of this:

With the introduction of actors, messaging between different parts of a game is more relevant than ever before. The engine’s own serdes systems are atrociously slow and space inefficient, a general purpose serdes function written in luau can drastically outperform the engine’s.

Allowing users to encode instances into buffers improves the ability for developers to efficiently pass data between actors.

1 Like

I’d like to add on to this, currently I have a module Introducing: AttributeUtil! that allows storing Instances as an attribute, currently I have to serialized it in a custom way so if Roblox adds this it would make things like these a lot easier

4 Likes

There is that, but then there’s also this
image

Whatever that should translate to

It’s the same thing when you use newproxy()
image

thing is Instances lose that if you send them through server, so a unique ID would be more useful to allow something like better Explorer Debuggers on the Roblox Client

That is the only purpose.

1 Like

Those are memory addresses which are fundamentally different from the value returned from GetDebugId, those will always change and will not be static because memory addresses always changes

1 Like

GetDebugId used to be accessible by a lower security, then it was increased.

But that alone is going to be useless if I can’t use the DebugId to return an Instance back.

1 Like

After the latest update this quietly appeared on every instance, related and intended…?

RobloxStudioBeta_YtRZrx8rzi

UniqueId as I understand it is an identifier that is unique for instances across all of roblox, and is intended for use with UGC. As such it is large to provide space for all these instances. If the provided api for this feature request cannot achieve the same or less bandwidth usage (4 bytes), then it doesn’t fulfill the needs of this feature request.

2 Likes

aaaand it’s gone :person_shrugging:

nah, I am kidding

There’s FFlagMakeUniqueIDVisibleInPropertiesWidget

If you set it to true, you will get this thing back. However, you can not use it with scripts.

And whatever happened here, I have no clue

image

but it just had the same UniqueId, sooo uhh yeah

 

I think this has to do with getting crashes

OP wants to encode a unique id (probably incrementing and decrementing) every time a instance is added/removed. Yes, you can use collection service, but you’d have to do something hacky like

CollectionService:GetTagged(“ID”)[1]

Remember that a character is one byte and is more expensive to use then integers.

You cannot get the instance from a attribute on an instance either.

1 Like

Heya folks! We have rolled back showing UniqueIDs for now as there was an unforeseen issue causing them to be editable. We will be reintroducing this feature once it is resolved, thanks for your patience!

7 Likes

I have to point out that this property doesn’t solve this feature request.

There is a 4-byte identifier shared across client and server which is used to replicate instances by passing that identifier through.

We want that, not a UUID. A true UUID isn’t suitable for intensive replication: that is 4x the bandwidth, as UUIDs are 128-bit numbers, thus making them 16 bytes. This is specifically needed for replication

4 Likes