Introducing Luau buffer type [Beta]

That’s not quite answering my question… I’m more asking what is it about quaternions that makes them always more optimal for data storage? Axis-angle is also 4 numbers, so that’s not it, but maybe it’s something like “you don’t need as much precision to store the real part of the quaternion” or “it’s faster to convert to/from quaternion than it is to do the same for axis-angle”?

Anyway I was just checking whether there was a real reason to use quaternions over axis-angle, or whether you just forgot / didn’t bother mentioning a viable alternative option. But clearly there is some reason which I am not privy to :slight_smile:

2 Likes

Could you make a basic example how?

How do you know how much bytes something is?

2 Likes

I have a pea brain and had to look into string.pack and string.unpack just to understand how this would be used in development, but for those who are already familiar with it, it looks very promising!

Glad we’re getting some more developer-oriented updates lately :slight_smile:

(and for other pea brains out there, it looks like a way to compress/encrypt data so it takes up less space essentially)

2 Likes

Ah, sorry.

The nice property which quaternions get you is that they’re a naturally symmetrical representation so you can encode all of the components in the same way which avoids unintentionally biasing the distribution of representable values.

4 Likes

I think buffers not having a cursor by default to be a smart choice. If you’ve ever had to create a non-cursor buffer from a cursor buffer, you’d be stoked.

+1

4 Likes

My brain genuinely can’t wrap around how I would make a very efficient writei24 and readi24 function. Are you able to provide this? Thank you so much.

EDIT: figured it out!

local function writei24( b: buffer, offset: number, value: number ): ()
	buffer.writei16( b, offset, value//2^8 )
	buffer.writeu8( b, offset+2, value )
end
local function readi24( b: buffer, offset: number ): number
	return 2^8*buffer.readi16( b, offset ) + buffer.readu8( b, offset + 2 )
end
2 Likes

For signed 24 bit integers the most straightforward way is to just use a temp buffer. The only complication is sign-extending the value:

local TempBuffer = buffer.create(4)

local function writei24(b: buffer, o: number, value: number)
	buffer.writei32(TempBuffer, 0, value)
	-- Chopping off the most significant byte has no affect if the value is
	-- within the i24 range.
	buffer.copy(b, o, TempBuffer, 0, 3)
end

local function readi24(b: buffer, o: number): number
	buffer.copy(TempBuffer, 0, b, o, 3)
	-- Sign extend
	buffer.writeu8(TempBuffer, 3, if buffer.readu8(TempBuffer, 2) >= 128 then 0xFF else 0)
	return buffer.readi32(TempBuffer, 0)
end

EDIT: I’d have to benchmark to see whether your implementation or this is faster. I was trying to avoid the division but the extra branch in my version may make that counterproductive in practice.

4 Likes

Could you make a video documenting the process? Love your vids!

1 Like

Kinda wished buffers were bit-based. I sometimes dont rlly need 8 bit buffers, but smaller than it, but maybe that kind of optimization is too extreme, either way this is gonna be the golden age of networking in roblox!

6 Likes

Regarding both of these, could we see buffer support for MessagingService? This is pretty similar to DataStore support I can imagine, it would be very cool to see. Compression & encoding designed for storage in DataStores and for transmission over MessagingService would be incredibly useful.

I can forsee a lot of interesting tech utilizing buffers over MessagingService as a capability in addition to DataStores alone, because it’d increase the bandwidth we can get and the amount of data we can theoretically send.

It would be interesting to allow cross-server spectating or match previews for example.

5 Likes

This update allows for 8 bit integers. Do you know the optimisation capabilities here? This has to be the best update to come from Roblox that I have ever encountered. It also allows for over 200 variables (technically), since you can use the offset to read and write to different variables. This. Is. Epic.

4 Likes

Are there plans to add API functions for reading/writing varints to buffers (buffer.readvarint/buffer.writevarint)? I feel this would be a very simple solution to people’s compression demands. While implementing these functions on our own is possible, the algorithm is probably not straightforward to most people and a native implementation would be much faster considering Luau lacks bitwise operations.

5 Likes

It’s a value that we can reconfigure to find the best balance, right now we use 1 (the range is -7…22).

If it’s popular enough we might consider adding it.

We have a fix for this ready, but to reduce risk when multiple features are released, we are only going to enable it on Monday.

11 Likes

Introducing in-experience Mesh & Image APIs [Studio Beta]

3 Likes

Please allow us to manipulate single bits. Some functions to read and write numbers of arbitrary bit size would go along nicely with that. Even if hardware doesnt support it, it’s useful. That extra freedom would be great, but it’s also worth noting that this would lend itself to more dynamic code. The current read/write functions are good but I don’t always want bit size hardcoded.

5 Likes

I don’t mean to ask this in a passive aggressive way, but does “cannot currently” imply that attribute implementation is in-the-works or has attribute compatibility been banished to the backburner?

1 Like

I knew about this update already, I was more interested in creating audio with a script too!

Are there plans to allow for buffer.fill to be able to use values larger than 8 bits?
I’m writing a compression utility that needs to be able to write individual bits, my current approach is to split the bits in N bytes and write each byte in a loop, however I had the idea to use buffer.fill in order to fill in the bits all at once getting rid of the loop but to my disappointment buffer.fill only uses the first 8 bits of the value passed to it.

Attribute implementation is not even in the backburner, there are no plans to add it right now.
I guess ‘currently’ was a bad choice of word to use there.

No.
Filling custom repeated sequences of bytes can be implemented similar to how string.rep works: if the pattern is 4 bytes, first you copy 4 bytes to make 8, then you copy 8 to make 16 and so on. Only a few buffer.copy operations are required to fill megabytes of data this way.

1 Like

I just successfully migrated from the BitBuffer module to this luau’s buffer for my network library.
Thank you Luau team. I hope this improves performance.

Server code:

Net.start("test")
Net.writeTimestamp()
Net.writeUInt32(12345)
Net.writeTable({
    abc=true,
    roblox=098765
})
Net.broadcast()

Client code:

Net.onReceive("test",function()
    warn("delay man:", Net.getServerTime()-Net.readTimestamp())
    warn("number:",Net.readUInt32())
    warn("table:",Net.readTable())
end)

Client output:

1 Like