Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
namespace Unity.Netcode
{
internal class SessionConfig
{
/// <summary>
/// The running list of session versions
/// </summary>
public const uint NoFeatureCompatibility = 0;
public const uint BypassFeatureCompatible = 1;
public const uint ServerDistributionCompatible = 2;

// The most current session version (!!!!set this when you increment!!!!!)
public static uint PackageSessionVersion => ServerDistributionCompatible;

internal uint SessionVersion;

public bool ServiceSideDistribution;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense that ServiceSideDistribution is in the ConnectionApproved and ConnectionRequested messages?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It only makes sense because the ConnectionRequestMessage uses it to define the client/package version (unifying the version to a single location) and is not actually serialized where the ConnectionApprovedMessage actually does serialize it when received by the client.



/// <summary>
/// Service to client
/// Set when the client receives a <see cref="ConnectionApprovedMessage"/>
/// </summary>
/// <param name="serviceConfig">the session's settings</param>
public SessionConfig(ServiceConfig serviceConfig)
{
SessionVersion = serviceConfig.SessionVersion;
ServiceSideDistribution = serviceConfig.ServerRedistribution;
}

/// <summary>
/// Can be used to directly set the version.
/// </summary>
/// <remarks>
/// If a client connects that does not support session configuration then
/// this will be invoked. The default values set in the constructor should
/// assume that no features are available.
/// Can also be used for mock/integration testing version handling.
/// </remarks>
/// <param name="version">version to set</param>
public SessionConfig(uint version)
{
SessionVersion = version;
ServiceSideDistribution = false;
}

/// <summary>
/// Client to Service
/// Default package constructor set when <see cref="NetworkManager.Initialize(bool)"/> is invoked.
/// </summary>
public SessionConfig()
{
// The current
SessionVersion = PackageSessionVersion;
ServiceSideDistribution = false;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -563,16 +563,17 @@ private void SendConnectionRequest()
{
var message = new ConnectionRequestMessage
{
CMBServiceConnection = NetworkManager.CMBServiceConnection,
DistributedAuthority = NetworkManager.DistributedAuthorityMode,
// Since only a remote client will send a connection request, we should always force the rebuilding of the NetworkConfig hash value
ConfigHash = NetworkManager.NetworkConfig.GetConfig(false),
ShouldSendConnectionData = NetworkManager.NetworkConfig.ConnectionApproval,
ConnectionData = NetworkManager.NetworkConfig.ConnectionData,
MessageVersions = new NativeArray<MessageVersionData>(MessageManager.MessageHandlers.Length, Allocator.Temp)
};

if (NetworkManager.CMBServiceConnection)
if (NetworkManager.DistributedAuthorityMode)
{
message.ClientConfig.SessionConfig = NetworkManager.SessionConfig;
message.ClientConfig.TickRate = NetworkManager.NetworkConfig.TickRate;
message.ClientConfig.EnableSceneManagement = NetworkManager.NetworkConfig.EnableSceneManagement;
}
Expand Down
18 changes: 18 additions & 0 deletions com.unity.netcode.gameobjects/Runtime/Core/NetworkManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,18 @@ internal static void LogSerializedTypeNotOptimized<T>()
}
#endif

internal SessionConfig SessionConfig;

/// <summary>
/// Used for internal testing purposes
/// </summary>
internal delegate SessionConfig OnGetSessionConfigHandler();
internal OnGetSessionConfigHandler OnGetSessionConfig;
private SessionConfig GetSessionConfig()
{
return OnGetSessionConfig != null ? OnGetSessionConfig.Invoke() : new SessionConfig();
}

internal static bool IsDistributedAuthority;

/// <summary>
Expand Down Expand Up @@ -1179,6 +1191,12 @@ internal void Initialize(bool server)

UpdateTopology();

// Always create a default session config when starting a NetworkManager instance
if (DistributedAuthorityMode)
{
SessionConfig = GetSessionConfig();
}

// Make sure the ServerShutdownState is reset when initializing
if (server)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ namespace Unity.Netcode
{
internal struct ServiceConfig : INetworkSerializable
{
private const int k_AddServerRedistribution = 1;

public uint Version;
public uint SessionVersion;
public bool IsRestoredSession;
public ulong CurrentSessionOwner;
public bool ServerRedistribution;
Expand All @@ -16,25 +14,29 @@ public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReade
{
if (serializer.IsWriter)
{
BytePacker.WriteValueBitPacked(serializer.GetFastBufferWriter(), Version);
BytePacker.WriteValueBitPacked(serializer.GetFastBufferWriter(), SessionVersion);
serializer.SerializeValue(ref IsRestoredSession);
BytePacker.WriteValueBitPacked(serializer.GetFastBufferWriter(), CurrentSessionOwner);

if (Version >= k_AddServerRedistribution)
if (SessionVersion >= SessionConfig.ServerDistributionCompatible)
{
serializer.SerializeValue(ref ServerRedistribution);
}
}
else
{
ByteUnpacker.ReadValueBitPacked(serializer.GetFastBufferReader(), out Version);
ByteUnpacker.ReadValueBitPacked(serializer.GetFastBufferReader(), out SessionVersion);
serializer.SerializeValue(ref IsRestoredSession);
ByteUnpacker.ReadValueBitPacked(serializer.GetFastBufferReader(), out CurrentSessionOwner);

if (Version >= k_AddServerRedistribution)
if (SessionVersion >= SessionConfig.ServerDistributionCompatible)
{
serializer.SerializeValue(ref ServerRedistribution);
}
else
{
ServerRedistribution = false;
}
}
}
}
Expand Down Expand Up @@ -203,11 +205,13 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
if (receivedMessageVersion >= k_AddCMBServiceConfig)
{
reader.ReadNetworkSerializable(out ServiceConfig);
networkManager.SessionConfig = new SessionConfig(ServiceConfig);
}
else
{
reader.ReadValueSafe(out IsRestoredSession);
ByteUnpacker.ReadValueBitPacked(reader, out CurrentSessionOwner);
networkManager.SessionConfig = new SessionConfig(SessionConfig.NoFeatureCompatibility);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,28 @@ namespace Unity.Netcode
/// </summary>
internal struct ClientConfig : INetworkSerializable
{
/// <summary>
/// We start at version 1, where anything less than version 1 on the service side
/// is not bypass feature compatible.
/// </summary>
private const int k_BypassFeatureCompatible = 1;
private const int k_ServerDistributionCompatible = k_BypassFeatureCompatible + 1;
public int Version => k_ServerDistributionCompatible;
public SessionConfig SessionConfig;
public uint SessionVersion => SessionConfig.SessionVersion;
public uint TickRate;
public bool EnableSceneManagement;

// Only gets deserialized but should never be used unless testing
public int RemoteClientVersion;
public uint RemoteClientSessionVersion;

public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
{
// Clients always write
if (serializer.IsWriter)
{
var writer = serializer.GetFastBufferWriter();
BytePacker.WriteValueBitPacked(writer, Version);
BytePacker.WriteValueBitPacked(writer, SessionVersion);
BytePacker.WriteValueBitPacked(writer, TickRate);
writer.WriteValueSafe(EnableSceneManagement);
}
else
{
var reader = serializer.GetFastBufferReader();
ByteUnpacker.ReadValueBitPacked(reader, out RemoteClientVersion);
ByteUnpacker.ReadValueBitPacked(reader, out RemoteClientSessionVersion);
ByteUnpacker.ReadValueBitPacked(reader, out TickRate);
reader.ReadValueSafe(out EnableSceneManagement);
}
Expand All @@ -41,14 +37,16 @@ public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReade

internal struct ConnectionRequestMessage : INetworkMessage
{
internal const string InvalidSessionVersionMessage = "The client version is not compatible with the session version.";

// This version update is unidirectional (client to service) and version
// handling occurs on the service side. This serialized data is never sent
// to a host or server.
private const int k_SendClientConfigToService = 1;
public int Version => k_SendClientConfigToService;

public ulong ConfigHash;
public bool CMBServiceConnection;
public bool DistributedAuthority;
public ClientConfig ClientConfig;

public byte[] ConnectionData;
Expand All @@ -73,7 +71,7 @@ public void Serialize(FastBufferWriter writer, int targetVersion)
// END FORBIDDEN SEGMENT
// ============================================================

if (CMBServiceConnection)
if (DistributedAuthority)
{
writer.WriteNetworkSerializable(ClientConfig);
}
Expand Down Expand Up @@ -121,6 +119,11 @@ public bool Deserialize(FastBufferReader reader, ref NetworkContext context, int
// END FORBIDDEN SEGMENT
// ============================================================

if (networkManager.DAHost)
{
reader.ReadNetworkSerializable(out ClientConfig);
}

if (networkManager.NetworkConfig.ConnectionApproval)
{
if (!reader.TryBeginRead(FastBufferWriter.GetWriteSize(ConfigHash) + FastBufferWriter.GetWriteSize<int>()))
Expand Down Expand Up @@ -183,6 +186,17 @@ public void Handle(ref NetworkContext context)
var networkManager = (NetworkManager)context.SystemOwner;
var senderId = context.SenderId;

// DAHost mocking the service logic to disconnect clients trying to connect with a lower session version
if (networkManager.DAHost)
{
if (ClientConfig.RemoteClientSessionVersion < networkManager.SessionConfig.SessionVersion)
{
//Disconnect with reason
networkManager.ConnectionManager.DisconnectClient(senderId, InvalidSessionVersionMessage);
return;
}
}

if (networkManager.ConnectionManager.PendingClients.TryGetValue(senderId, out PendingClient client))
{
// Set to pending approval to prevent future connection requests from being approved
Expand Down
Loading
Loading