Elaborating on this, it’s kind of a rare confluence of events that causes it anyway. There are so many things that could cause the messages to come separately and then things are fine.
It happens when the serialization message goes out and another message goes out… and all the way through the TCP connection they stay in the same packet and are received as part of the same buffer read on the client so that they are packed into the same byte array.
It’s a somewhat unfortunate part of the message processing design that the entire byte array is unpacked into messages at once… because it means if a message in the first part of the array defines new serialization registrations that its too late for the ones in the rest of the message. array in, messages out… then messages are handled.
Sending serialization messages was not a consideration when this stuff was designed and I was doing my best to keep the existing serialization classes (a big mistake, actually, in the end). Unfortunately, the design is not so easy to fix, either. A message can have the other problem and be split across several reads… untwisting the code that pushes buffers in and gets messages out is not as simple as I would hope.
There are ways around this issue with their own trade offs:
just wait a bit before sending messages to clients after they first connect. Means you can’t use server.broadcast() (which as mentioned is kind of a mistake to have included in the API in the first place). It might also be possible to just wait until the client sends you a message before chattering back. Only real down side here is that it feels a bit hacky. (If the network is horribly backed up it’s still technically possible that messages might buffer together.)
don’t use automatic serializer registration and go back to the “old way” of having to manually register everything. There is a pretty huge downside here as it means it’s very difficult to use the service model since the thing registering the services (the game) would need to know all of the classes to register and do it exactly the same on both client and server. I added the serializer registration message stuff specifically to handle this problem of being able to easily register modular add-on services.
send a message so big that it’s guaranteed to exceed the packet size and by split. Down side here is that you have to send one big empty message and it’s ugly. It would work consistently, though.