Update FishNet

This commit is contained in:
2026-04-07 03:11:52 +07:00
parent 9675b7b31d
commit ba7513d478
869 changed files with 3675 additions and 2764 deletions
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ClientConnectionBroadcast.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Editor/ServerManagerEditor.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/KickReasons.cs
uploadId: 866910
uploadId: 892096
@@ -93,7 +93,7 @@ namespace FishNet.Managing.Server
CollectionCaches<NetworkConnection>.Store(connCache);
CollectionCaches<NetworkObject>.Store(nobCache);
}
/// <summary>
/// Indicates that a networkObserver component should be updated regularly. This is done automatically.
/// </summary>
@@ -105,7 +105,7 @@ namespace FishNet.Managing.Server
else
_timedNetworkObservers.Add(networkObject);
}
/// <summary>
/// Indicates that a networkObserver component no longer needs to be updated regularly. This is done automatically.
/// </summary>
@@ -375,10 +375,10 @@ namespace FishNet.Managing.Server
NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, _writer.GetArraySegment(), nc);
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
if (NetworkTrafficStatistics != null)
NetworkTrafficStatistics.AddOutboundPacketIdData(PacketId.BulkSpawnOrDespawn, string.Empty, _writer.Length, gameObject: null, asServer: true);
#endif
#endif
_writer.Clear();
@@ -399,36 +399,36 @@ namespace FishNet.Managing.Server
return;
_writer.Clear();
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
PacketId trafficPacketId;
#endif
#endif
conn.UpdateHashGridPositions(!timedOnly);
// If observer state changed then write changes.
ObserverStateChange osc = nob.RebuildObservers(conn, timedOnly);
if (osc == ObserverStateChange.Added)
{
WriteSpawn(nob, _writer, conn);
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
trafficPacketId = PacketId.ObjectSpawn;
#endif
#endif
}
else if (osc == ObserverStateChange.Removed)
{
nob.InvokeOnServerDespawn(conn);
WriteDespawn(nob, nob.GetDefaultDespawnType(), _writer);
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
trafficPacketId = PacketId.ObjectDespawn;
#endif
#endif
}
else
{
return;
}
#if DEVELOPMENT && !UNITY_SERVER
#if DEVELOPMENT && !UNITY_SERVER
if (NetworkTrafficStatistics != null)
NetworkTrafficStatistics.AddOutboundPacketIdData(trafficPacketId, string.Empty, _writer.Length, gameObject: null, asServer: true);
#endif
#endif
NetworkManager.TransportManager.SendToClient((byte)Channel.Reliable, _writer.GetArraySegment(), conn);
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Observers.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.Parsing.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/Object/ServerObjects.cs
uploadId: 866910
uploadId: 892096
@@ -129,7 +129,7 @@ namespace FishNet.Managing.Server
}
PooledWriter writer = WriterPool.Retrieve();
BroadcastsSerializers.WriteBroadcast(NetworkManager, writer, message, ref channel);
BroadcastsSerializers.WriteBroadcast(writer, message);
ArraySegment<byte> segment = writer.GetArraySegment();
AddOutboundNetworkTraffic<T>(segment.Count);
@@ -156,7 +156,7 @@ namespace FishNet.Managing.Server
bool failedAuthentication = false;
PooledWriter writer = WriterPool.Retrieve();
BroadcastsSerializers.WriteBroadcast(NetworkManager, writer, message, ref channel);
BroadcastsSerializers.WriteBroadcast(writer, message);
ArraySegment<byte> segment = writer.GetArraySegment();
int sentBytes = 0;
@@ -349,7 +349,7 @@ namespace FishNet.Managing.Server
bool failedAuthentication = false;
PooledWriter writer = WriterPool.Retrieve();
BroadcastsSerializers.WriteBroadcast(NetworkManager, writer, message, ref channel);
BroadcastsSerializers.WriteBroadcast(writer, message);
ArraySegment<byte> segment = writer.GetArraySegment();
int sentBytes = 0;
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.Broadcast.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.QOL.cs
uploadId: 866910
uploadId: 892096
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.RpcLinks.cs
uploadId: 866910
uploadId: 892096
@@ -218,10 +218,6 @@ namespace FishNet.Managing.Server
/// </summary>
private float _nextTimeoutCheckTime;
/// <summary>
/// Used to read splits.
/// </summary>
private SplitReader _splitReader = new();
/// <summary>
/// </summary>
private NetworkTrafficStatistics _networkTrafficStatistics;
#if DEVELOPMENT
@@ -611,46 +607,44 @@ namespace FishNet.Managing.Server
{
//Sanity check to make sure transports are following proper types/ranges.
int id = args.ConnectionId;
if (id < 0 || id > NetworkConnection.MAXIMUM_CLIENTID_VALUE)
if (id < 0)
{
Kick(args.ConnectionId, KickReason.UnexpectedProblem, LoggingType.Error, $"The transport you are using supplied an invalid connection Id of {id}. Connection Id values must range between 0 and {NetworkConnection.MAXIMUM_CLIENTID_VALUE}. The client has been disconnected.");
return;
}
//Valid Id.
else
//If started then add to authenticated clients.
if (args.ConnectionState == RemoteConnectionState.Started)
{
//If started then add to authenticated clients.
if (args.ConnectionState == RemoteConnectionState.Started)
NetworkManager.Log($"Remote connection started for Id {id}.");
NetworkConnection conn = new(NetworkManager, id, args.TransportIndex, true);
Clients.Add(args.ConnectionId, conn);
_clientsList.Add(conn);
OnRemoteConnectionState?.Invoke(conn, args);
//Do nothing else until the client sends it's version.
}
//If stopping.
else if (args.ConnectionState == RemoteConnectionState.Stopped)
{
/* If client's connection is found then clean
* them up from server. */
if (Clients.TryGetValueIL2CPP(id, out NetworkConnection conn))
{
NetworkManager.Log($"Remote connection started for Id {id}.");
NetworkConnection conn = new(NetworkManager, id, args.TransportIndex, true);
Clients.Add(args.ConnectionId, conn);
_clientsList.Add(conn);
conn.SetDisconnecting(true);
OnRemoteConnectionState?.Invoke(conn, args);
Clients.Remove(id);
_clientsList.Remove(conn);
Objects.ClientDisconnected(conn);
BroadcastClientConnectionChange(false, conn);
//Return predictedObjectIds.
Queue<int> pqId = conn.PredictedObjectIds;
while (pqId.Count > 0)
Objects.CacheObjectId(pqId.Dequeue());
//Do nothing else until the client sends it's version.
}
//If stopping.
else if (args.ConnectionState == RemoteConnectionState.Stopped)
{
/* If client's connection is found then clean
* them up from server. */
if (Clients.TryGetValueIL2CPP(id, out NetworkConnection conn))
{
conn.SetDisconnecting(true);
OnRemoteConnectionState?.Invoke(conn, args);
Clients.Remove(id);
_clientsList.Remove(conn);
Objects.ClientDisconnected(conn);
BroadcastClientConnectionChange(false, conn);
//Return predictedObjectIds.
Queue<int> pqId = conn.PredictedObjectIds;
while (pqId.Count > 0)
Objects.CacheObjectId(pqId.Dequeue());
conn.ResetState();
NetworkManager.Log($"Remote connection stopped for Id {id}.");
}
conn.ResetState();
NetworkManager.Log($"Remote connection stopped for Id {id}.");
}
}
}
@@ -717,6 +711,14 @@ namespace FishNet.Managing.Server
//Not from a valid connection. Should not be possible.
if (args.ConnectionId < 0)
return;
/* Connection isn't available. This should never happen.
* Force an immediate disconnect. */
if (!Clients.TryGetValueIL2CPP(args.ConnectionId, out NetworkConnection connection))
{
Kick(args.ConnectionId, KickReason.UnexpectedProblem, LoggingType.Error, $"ConnectionId {args.ConnectionId} not found within Clients. Connection will be kicked immediately.");
return;
}
ArraySegment<byte> segment;
if (NetworkManager.TransportManager.HasIntermediateLayer)
@@ -735,7 +737,7 @@ namespace FishNet.Managing.Server
//If over MTU kick client immediately.
if (segment.Count > channelMtu)
{
ExceededMTUKick();
ExceededMTUKick(segment.Count, channelMtu);
return;
}
@@ -761,30 +763,35 @@ namespace FishNet.Managing.Server
#endif
//Skip packetId.
reader.ReadPacketId();
int expectedMessages;
_splitReader.GetHeader(reader, out expectedMessages);
//If here split message is to be read into splitReader.
_splitReader.Write(tick, reader, expectedMessages);
/* If fullMessage returns 0 count then the split
* has not written fully yet. Otherwise, if there is
* data within then reinitialize reader with the
* full message. */
ArraySegment<byte> fullMessage = _splitReader.GetFullMessage();
if (fullMessage.Count == 0)
int expectedMessages = reader.ReadInt32();
if (!connection.TryGetSplitReader(expectedMessages, out SplitReader splitReader))
{
//Intentionally a normal log rather than error to prevent spam from client attacks.
NetworkManager.Log($"Something went wrong when trying to get the [{nameof(splitReader)}] for connection [{connection.ToString()}].");
connection.Kick(KickReason.UnusualActivity);
return;
/* If here then all data has been received.
* It's possible the client could have exceeded
* maximum MTU but not the maximum number of splits.
* This is because the length of each split
* is not written, so we don't know how much data of the
* final message actually belonged to the split vs
* unrelated data added afterwards. We're going to cut
* the client some slack in this situation for the sake
* of keeping things simple. */
}
if (!splitReader.Write(reader))
{
//Intentionally a normal log rather than error to prevent spam from client attacks.
NetworkManager.Log($"Something went wrong when trying to write a split message for connection [{connection.ToString()}].");
connection.Kick(KickReason.UnusualActivity);
return;
}
//This will return true if the full message has been written.
if (!splitReader.TryGetFullMessage(out ArraySegment<byte> fullMessage))
return;
reader.Initialize(fullMessage, NetworkManager, dataSource);
//Once here the split reader can be returned.
connection.StoreSplitReader();
}
//Parse reader.
@@ -794,64 +801,55 @@ namespace FishNet.Managing.Server
#if DEVELOPMENT
NetworkManager.PacketIdHistory.ReceivedPacket(packetId, packetFromServer: false);
#endif
NetworkConnection conn;
/* Connection isn't available. This should never happen.
* Force an immediate disconnect. */
if (!Clients.TryGetValueIL2CPP(args.ConnectionId, out conn))
{
Kick(args.ConnectionId, KickReason.UnexpectedProblem, LoggingType.Error, $"ConnectionId {args.ConnectionId} not found within Clients. Connection will be kicked immediately.");
return;
}
conn.LocalTick.Update(timeManager, tick, EstimatedTick.OldTickOption.Discard);
conn.PacketTick.Update(timeManager, tick, EstimatedTick.OldTickOption.SetLastRemoteTick);
connection.LocalTick.Update(timeManager, tick, EstimatedTick.OldTickOption.Discard);
connection.PacketTick.Update(timeManager, tick, EstimatedTick.OldTickOption.SetLastRemoteTick);
/* If connection isn't authenticated and isn't a broadcast
* then disconnect client. If a broadcast then process
* normally; client may still become disconnected if the broadcast
* does not allow to be called while not authenticated. */
if (!conn.IsAuthenticated && packetId != PacketId.Version && packetId != PacketId.Broadcast)
if (!connection.IsAuthenticated && packetId != PacketId.Version && packetId != PacketId.Broadcast)
{
conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent packetId {packetId} without being authenticated. Connection will be kicked immediately.");
connection.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {connection.ClientId} sent packetId {packetId} without being authenticated. Connection will be kicked immediately.");
return;
}
if (packetId == PacketId.Replicate)
{
Objects.ParseReplicateRpc(reader, conn, args.Channel);
Objects.ParseReplicateRpc(reader, connection, args.Channel);
}
else if (packetId == PacketId.ServerRpc)
{
Objects.ParseServerRpc(reader, conn, args.Channel);
Objects.ParseServerRpc(reader, connection, args.Channel);
}
else if (packetId == PacketId.ObjectSpawn)
{
if (!GetAllowPredictedSpawning())
{
conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
connection.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {connection.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
return;
}
Objects.ReadSpawn(reader, conn);
Objects.ReadSpawn(reader, connection);
}
else if (packetId == PacketId.ObjectDespawn)
{
if (!GetAllowPredictedSpawning())
{
conn.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {conn.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
connection.Kick(KickReason.ExploitAttempt, LoggingType.Common, $"ConnectionId {connection.ClientId} sent a predicted spawn while predicted spawning is not enabled. Connection will be kicked immediately.");
return;
}
Objects.ReadDespawn(reader, conn);
Objects.ReadDespawn(reader, connection);
}
else if (packetId == PacketId.Broadcast)
{
ParseBroadcast(reader, conn, args.Channel);
ParseBroadcast(reader, connection, args.Channel);
}
else if (packetId == PacketId.PingPong)
{
ParsePingPong(reader, conn);
ParsePingPong(reader, connection);
}
else if (packetId == PacketId.Version)
{
ParseVersion(reader, conn, args.TransportIndex);
ParseVersion(reader, connection, args.TransportIndex);
}
else
{
@@ -880,9 +878,9 @@ namespace FishNet.Managing.Server
#endif
//Kicks connection for exceeding MTU.
void ExceededMTUKick()
void ExceededMTUKick(int sentCount, int maximumCount)
{
Kick(args.ConnectionId, KickReason.ExploitExcessiveData, LoggingType.Common, $"ConnectionId {args.ConnectionId} sent a message larger than allowed amount. Connection will be kicked immediately.");
Kick(args.ConnectionId, KickReason.ExploitExcessiveData, LoggingType.Common, $"ConnectionId {args.ConnectionId} sent a message of {sentCount} bytes while the maximum allowed amount is {maximumCount}. Connection will be kicked immediately.");
}
}
@@ -13,6 +13,6 @@ AssetOrigin:
serializedVersion: 1
productId: 207815
packageName: 'FishNet: Networking Evolved'
packageVersion: 4.6.22R
packageVersion: 4.7.1R
assetPath: Assets/FishNet/Runtime/Managing/Server/ServerManager.cs
uploadId: 866910
uploadId: 892096