mirror of
https://github.com/Facepunch/sbox-public.git
synced 2026-04-19 13:59:22 -04:00
**Broadcast** now encodes the wire payload just once and sends the same bytes to every recipient, before we did one redundant compression per connection. This primarily reduces CPU load on the server/host. **Chunking** Large messages are now compressed before chunking rather than after. Resulting in slightly smaller payloads. The receiver now decompresses a single reassembled payload instead of decompressing every chunk independently, significantly reducing CPU load on receiving clients. **Refactor** Chunking and compression are now low-level wire concerns handled by Connection rather than being mixed into the high-level message types. The old `InternalMessageType.Chunk` enum is removed; chunk framing uses a dedicated wire flag byte alongside `FlagRaw` and `FlagCompressed`. **Results (Chunking changes)** Synthetic data, results on real payloads may differ. Benchmarks (1000 GOs / 2000 components, ~1MB payload, 500 iterations): Wire size (chunk-first-then-compress): 275KB Wire size (compress-first): 259KB (5.7% smaller) Send chunk-first: 0.85 ms/op (old) Send compress-first: 0.88 ms/op (new) Recv chunk-first: 1.16 ms/op (old) Recv compress-first: 0.34 ms/op (new, 3.4x faster)
82 lines
2.7 KiB
C#
82 lines
2.7 KiB
C#
namespace Sandbox.Network;
|
|
|
|
internal partial class NetworkSystem
|
|
{
|
|
/// <summary>
|
|
/// Send a message to all connections. You can optionally pass in a filter to determine who actually receives the message.
|
|
/// </summary>
|
|
/// <param name="msg">The message to send.</param>
|
|
/// <param name="minimumState">The minumum state the connection must be to receive the message.</param>
|
|
/// <param name="filter">If specified, the connection must pass this filter to receive the message.</param>
|
|
/// <param name="flags">Network message flags that may dictate how the message is sent.</param>
|
|
public void Broadcast( ByteStream msg, Connection.ChannelState minimumState = Connection.ChannelState.Snapshot, Connection.Filter? filter = null, NetFlags flags = NetFlags.Reliable )
|
|
{
|
|
IEnumerable<Connection> availableConnections = Networking.IsHost ? _connections : Connection.All;
|
|
|
|
if ( Connection is not null )
|
|
{
|
|
availableConnections = availableConnections
|
|
.Append( Connection )
|
|
.Distinct();
|
|
}
|
|
|
|
// Encode once so every recipient gets the same wire bytes without re-compressing per connection.
|
|
var compressed = Connection.EncodeStream( msg );
|
|
|
|
foreach ( var c in availableConnections )
|
|
{
|
|
if ( c == Connection.Local ) continue;
|
|
if ( c.State < minimumState ) continue;
|
|
if ( filter.HasValue && !filter.Value.IsRecipient( c ) ) continue;
|
|
c.Send( compressed, flags );
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Broadcast a packed message to all connections.
|
|
/// </summary>
|
|
internal void Broadcast<T>( T msg, Connection.ChannelState minimumState = Connection.ChannelState.Snapshot,
|
|
Connection.Filter? filter = null, NetFlags flags = NetFlags.Reliable )
|
|
{
|
|
var bs = ByteStream.Create( 32 );
|
|
|
|
bs.Write( InternalMessageType.Packed );
|
|
TypeLibrary.ToBytes( msg, ref bs );
|
|
|
|
Broadcast( bs, minimumState );
|
|
|
|
bs.Dispose();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get a list of connections that meet a specific criteria.
|
|
/// </summary>
|
|
/// <param name="minimumState">The minumum state the connection must be to receive the message.</param>
|
|
/// <param name="filter">If specified, the connection must pass this filter to receive the message.</param>
|
|
public IEnumerable<Connection> GetFilteredConnections( Connection.ChannelState minimumState = Connection.ChannelState.Snapshot, Connection.Filter? filter = null )
|
|
{
|
|
IEnumerable<Connection> availableConnections = Networking.IsHost ? _connections : Connection.All;
|
|
|
|
if ( Connection is not null )
|
|
{
|
|
availableConnections = availableConnections
|
|
.Append( Connection )
|
|
.Distinct();
|
|
}
|
|
|
|
foreach ( var c in availableConnections )
|
|
{
|
|
if ( c == Connection.Local )
|
|
continue;
|
|
|
|
if ( c.State < minimumState )
|
|
continue;
|
|
|
|
if ( filter.HasValue && !filter.Value.IsRecipient( c ) )
|
|
continue;
|
|
|
|
yield return c;
|
|
}
|
|
}
|
|
}
|