mas-bandwidth / yojimbo

A network library for client/server games written in C++
BSD 3-Clause "New" or "Revised" License
2.45k stars 238 forks source link

Packing messages into packets #200

Closed cBournhonesque closed 3 months ago

cBournhonesque commented 3 months ago

Hi! I was wondering what your opinion was on how to pack messages into packets.

gafferongames commented 3 months ago

Yojimbo lets you attach blocks of memory on messages.

a) In the reliable channel, these blocks will be sliced up and sent reliably in packets smaller than MTU automatically, and the reliable channel will block any messages to be received after the message with block attach so they arrive after the block send completes, so messages will always be received reliably and in-order.

b) Alternatively, if you need to send a large block of data and it's not too large, eg. 4-8 packets @ MTU worth, you could send it as a big fat unreliable message, and the system will fragment into MTU packets and re-assemble automatically for you, but if any of the fragments are dropped, the whole message is lost.

Basically, a) was designed for you to send down a large block of data on connect, or on load level or whatever on the reliable channel. b) was designed so that when you are sending delta encoded snapshots, it would allow you to go over MTU and it would do fragmentation and reassembly for you automatically, since some routers on the internet drop any packet fragments done at the IP level.

cheers

gafferongames commented 3 months ago

And to answer your question -- I need more information about what you are trying to do. The correct answer depends very much on whether you are using the reliable or unreliable channels to send messages, and what you are trying to achieve.

cBournhonesque commented 3 months ago

My question was not directly related to Yojimbo, sorry about that. (maybe I could send you an email directly if that is a more appropriate channel)? I've been developing a networking library for an ECS game engine as a hobby project: https://github.com/cBournhonesque/lightyear I've read all your articles many times as they provide a great starting point!

One thing i've been struggling is figuring out how messages should fit into packets. I have two types of messages: Actions (Entity spawn/Entity despawn/Component insertion/Component removal) and Updates (Component update). Actions are sent reliably, and Updates are sent unreliably.

Some invariants I'm trying to guarantee:

Currently I achieve this by having lots of individual messages (Actions for entity E1 or Updates for entities [E1, E2]). I'm wondering if I can optimize how messages are packed into packets.

1) Should I just send all Actions in one big message? Even if it's split up into multiple packets, it is sent reliably so it shouldn't be too much of an issue? In general I'm very wary of sending big fragmented packets. 2) Is it recommended to have big individual messages instead of small individual messages to avoid wasting bandwidth on per-packet metadata? 3) How do you solve the problem of having to guarantee that 2 pieces of state arrive together, for example for client-side prediction?