lucaspoffo / renet

Server/Client network library for multiplayer games with authentication and connection management made with Rust
Apache License 2.0
620 stars 65 forks source link

Streaming API to write messages #111

Open Shatur opened 9 months ago

Shatur commented 9 months ago

Currently in order to send a message, I need to pass anything that converts into Bytes. But this prevents users from re-using the memory. Bytes cheaply clonable, but can't grow, so users can't use it a buffer for snapshots. Vec<u8> can be used as a buffer for snapshots, but it needs to be cloned to send (because conversion from Vec<u8> to Bytes implemented only from owning value). Maybe provide a streaming API instead where you write messages directly into Renet's message buffer?

lucaspoffo commented 9 months ago

Can you show an example of how the API would look. Not sure if I 100% understand it

Shatur commented 9 months ago

It would be great to have a concept of buffers inside Renet. Buffer is just Vec<u8>. Buffers can be "available" (the buffer is already acknowledged in reliable channel or was sent on an unreliable channel) or "in use" (the opposite of "available"). When user wants to write a message it requests a buffer from Renet. If all buffers are "in use", Renet just returns new Vec<u8>. If there is a buffer marked as "available" - Renet returns it as an owned value. Users writes data to this buffer and puts it back to Renet to any channel. Renet accepts this buffer and marks it as "in use" internally. After sending (or after the data becomes acknowledged for reliable channels) the buffer becomes "available" and next time user ask for a buffer, Renet will return it.

lucaspoffo commented 8 months ago

This seems to be an allocation problem. Since we use Bytes, we mostly delegate to it. Some related discussions/PR in the Bytes crate:

Shatur commented 8 months ago

we mostly delegate to it.

The way Renet uses it, there is not much help from Bytes. User can preallocate BytesMut to write something, but after calling freeze to convert it into Bytes there is no way to write something else into it again. SharedBuf would help in this case, but it have a cost. With the API I proposing there is no significant overhead. And we could keep convenient send_message and just add the passed Vec<u8> to the list of buffers "in use".

Shatur commented 7 months ago

After some thinking I have an alternative proposal: Copy all data passed to send_message and use buffers under the hood (reuse the memory). This approach is much simpler and still solves the problem I having.