using System; using System.Collections.Generic; using UnityEngine; using System.Linq; using Unity.Collections; namespace Unity.Netcode { /// /// The configuration object used to start server, client and hosts /// [Serializable] public class NetworkConfig { /// /// The protocol version. Different versions doesn't talk to each other. /// [Tooltip("Use this to make two builds incompatible with each other")] public ushort ProtocolVersion = 0; /// /// The transport hosts the sever uses /// [Tooltip("The NetworkTransport to use")] public NetworkTransport NetworkTransport = null; /// /// The default player prefab /// [Tooltip("When set, NetworkManager will automatically create and spawn the assigned player prefab. This can be overridden by adding it to the NetworkPrefabs list and selecting override.")] public GameObject PlayerPrefab; /// /// A list of prefabs that can be dynamically spawned. /// [SerializeField] [Tooltip("The prefabs that can be spawned across the network")] internal List NetworkPrefabs = new List(); /// /// This dictionary provides a quick way to check and see if a NetworkPrefab has a NetworkPrefab override. /// Generated at runtime and OnValidate /// internal Dictionary NetworkPrefabOverrideLinks = new Dictionary(); internal Dictionary OverrideToNetworkPrefab = new Dictionary(); /// /// The tickrate of network ticks. This value controls how often netcode runs user code and sends out data. /// [Tooltip("The tickrate. This value controls how often netcode runs user code and sends out data. The value is in 'ticks per seconds' which means a value of 50 will result in 50 ticks being executed per second or a fixed delta time of 0.02.")] public uint TickRate = 30; /// /// The amount of seconds to wait for handshake to complete before timing out a client /// [Tooltip("The amount of seconds to wait for the handshake to complete before the client times out")] public int ClientConnectionBufferTimeout = 10; /// /// Whether or not to use connection approval /// [Tooltip("Whether or not to force clients to be approved before they connect")] public bool ConnectionApproval = false; /// /// The data to send during connection which can be used to decide on if a client should get accepted /// [Tooltip("The connection data sent along with connection requests")] public byte[] ConnectionData = new byte[0]; /// /// If your logic uses the NetworkTime, this should probably be turned off. If however it's needed to maximize accuracy, this is recommended to be turned on /// [Tooltip("Enable this to re-sync the NetworkTime after the initial sync")] public bool EnableTimeResync = false; /// /// If time re-sync is turned on, this specifies the interval between syncs in seconds. /// [Tooltip("The amount of seconds between re-syncs of NetworkTime, if enabled")] public int TimeResyncInterval = 30; /// /// Whether or not to ensure that NetworkVariables can be read even if a client accidentally writes where its not allowed to. This costs some CPU and bandwidth. /// [Tooltip("Ensures that NetworkVariables can be read even if a client accidental writes where its not allowed to. This will cost some CPU time and bandwidth")] public bool EnsureNetworkVariableLengthSafety = false; /// /// Enables scene management. This will allow network scene switches and automatic scene difference corrections upon connect. /// SoftSynced scene objects wont work with this disabled. That means that disabling SceneManagement also enables PrefabSync. /// [Tooltip("Enables scene management. This will allow network scene switches and automatic scene difference corrections upon connect.\n" + "SoftSynced scene objects wont work with this disabled. That means that disabling SceneManagement also enables PrefabSync.")] public bool EnableSceneManagement = true; /// /// Whether or not the netcode should check for differences in the prefabs at connection. /// If you dynamically add prefabs at runtime, turn this OFF /// [Tooltip("Whether or not the netcode should check for differences in the prefab lists at connection")] public bool ForceSamePrefabs = true; /// /// If true, NetworkIds will be reused after the NetworkIdRecycleDelay. /// [Tooltip("If true, NetworkIds will be reused after the NetworkIdRecycleDelay")] public bool RecycleNetworkIds = true; /// /// The amount of seconds a NetworkId has to be unused in order for it to be reused. /// [Tooltip("The amount of seconds a NetworkId has to unused in order for it to be reused")] public float NetworkIdRecycleDelay = 120f; /// /// Decides how many bytes to use for Rpc messaging. Leave this to 2 bytes unless you are facing hash collisions /// [Tooltip("The maximum amount of bytes to use for RPC messages.")] public HashSize RpcHashSize = HashSize.VarIntFourBytes; /// /// The amount of seconds to wait for all clients to load or unload a requested scene /// [Tooltip("The amount of seconds to wait for all clients to load or unload a requested scene (only when EnableSceneManagement is enabled)")] public int LoadSceneTimeOut = 120; /// /// The amount of time a message should be buffered if the asset or object needed to process it doesn't exist yet. If the asset is not added/object is not spawned within this time, it will be dropped. /// [Tooltip("The amount of time a message should be buffered if the asset or object needed to process it doesn't exist yet. If the asset is not added/object is not spawned within this time, it will be dropped")] public float SpawnTimeout = 1f; /// /// Whether or not to enable network logs. /// public bool EnableNetworkLogs = true; public const int RttAverageSamples = 5; // number of RTT to keep an average of (plus one) public const int RttWindowSize = 64; // number of slots to use for RTT computations (max number of in-flight packets) /// /// Returns a base64 encoded version of the configuration /// /// public string ToBase64() { NetworkConfig config = this; var writer = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp); using (writer) { writer.WriteValueSafe(config.ProtocolVersion); writer.WriteValueSafe(config.TickRate); writer.WriteValueSafe(config.ClientConnectionBufferTimeout); writer.WriteValueSafe(config.ConnectionApproval); writer.WriteValueSafe(config.LoadSceneTimeOut); writer.WriteValueSafe(config.EnableTimeResync); writer.WriteValueSafe(config.EnsureNetworkVariableLengthSafety); writer.WriteValueSafe(config.RpcHashSize); writer.WriteValueSafe(ForceSamePrefabs); writer.WriteValueSafe(EnableSceneManagement); writer.WriteValueSafe(RecycleNetworkIds); writer.WriteValueSafe(NetworkIdRecycleDelay); writer.WriteValueSafe(EnableNetworkLogs); // Allocates return Convert.ToBase64String(writer.ToArray()); } } /// /// Sets the NetworkConfig data with that from a base64 encoded version /// /// The base64 encoded version public void FromBase64(string base64) { NetworkConfig config = this; byte[] binary = Convert.FromBase64String(base64); using var reader = new FastBufferReader(binary, Allocator.Temp); using (reader) { reader.ReadValueSafe(out config.ProtocolVersion); reader.ReadValueSafe(out config.TickRate); reader.ReadValueSafe(out config.ClientConnectionBufferTimeout); reader.ReadValueSafe(out config.ConnectionApproval); reader.ReadValueSafe(out config.LoadSceneTimeOut); reader.ReadValueSafe(out config.EnableTimeResync); reader.ReadValueSafe(out config.EnsureNetworkVariableLengthSafety); reader.ReadValueSafe(out config.RpcHashSize); reader.ReadValueSafe(out config.ForceSamePrefabs); reader.ReadValueSafe(out config.EnableSceneManagement); reader.ReadValueSafe(out config.RecycleNetworkIds); reader.ReadValueSafe(out config.NetworkIdRecycleDelay); reader.ReadValueSafe(out config.EnableNetworkLogs); } } private ulong? m_ConfigHash = null; /// /// Gets a SHA256 hash of parts of the NetworkConfig instance /// /// /// public ulong GetConfig(bool cache = true) { if (m_ConfigHash != null && cache) { return m_ConfigHash.Value; } var writer = new FastBufferWriter(MessagingSystem.NON_FRAGMENTED_MESSAGE_MAX_SIZE, Allocator.Temp, int.MaxValue); using (writer) { writer.WriteValueSafe(ProtocolVersion); writer.WriteValueSafe(NetworkConstants.PROTOCOL_VERSION); if (ForceSamePrefabs) { var sortedDictionary = NetworkPrefabOverrideLinks.OrderBy(x => x.Key); foreach (var sortedEntry in sortedDictionary) { writer.WriteValueSafe(sortedEntry.Key); } } writer.WriteValueSafe(TickRate); writer.WriteValueSafe(ConnectionApproval); writer.WriteValueSafe(ForceSamePrefabs); writer.WriteValueSafe(EnableSceneManagement); writer.WriteValueSafe(EnsureNetworkVariableLengthSafety); writer.WriteValueSafe(RpcHashSize); if (cache) { m_ConfigHash = XXHash.Hash64(writer.ToArray()); return m_ConfigHash.Value; } return XXHash.Hash64(writer.ToArray()); } } /// /// Compares a SHA256 hash with the current NetworkConfig instances hash /// /// /// public bool CompareConfig(ulong hash) { return hash == GetConfig(); } } }