using System; using System.Collections.Generic; using UnityEngine; namespace Mirror { /// /// Component that controls visibility of networked objects based on match id. /// Any object with this component on it will only be visible to other objects in the same match. /// This would be used to isolate players to their respective matches within a single game server instance. /// [DisallowMultipleComponent] [AddComponentMenu("Network/NetworkMatchChecker")] [RequireComponent(typeof(NetworkIdentity))] [HelpURL("https://mirror-networking.com/docs/Components/NetworkMatchChecker.html")] public class NetworkMatchChecker : NetworkVisibility { static readonly Dictionary> matchPlayers = new Dictionary>(); Guid currentMatch = Guid.Empty; [Header("Diagnostics")] [SyncVar] public string currentMatchDebug; /// /// Set this to the same value on all networked objects that belong to a given match /// public Guid matchId { get { return currentMatch; } set { if (currentMatch == value) return; // cache previous match so observers in that match can be rebuilt Guid previousMatch = currentMatch; // Set this to the new match this object just entered ... currentMatch = value; // ... and copy the string for the inspector because Unity can't show Guid directly currentMatchDebug = currentMatch.ToString(); if (previousMatch != Guid.Empty) { // Remove this object from the hashset of the match it just left matchPlayers[previousMatch].Remove(netIdentity); // RebuildObservers of all NetworkIdentity's in the match this object just left RebuildMatchObservers(previousMatch); } if (currentMatch != Guid.Empty) { // Make sure this new match is in the dictionary if (!matchPlayers.ContainsKey(currentMatch)) matchPlayers.Add(currentMatch, new HashSet()); // Add this object to the hashset of the new match matchPlayers[currentMatch].Add(netIdentity); // RebuildObservers of all NetworkIdentity's in the match this object just entered RebuildMatchObservers(currentMatch); } else { // Not in any match now...RebuildObservers will clear and add self netIdentity.RebuildObservers(false); } } } public override void OnStartServer() { if (currentMatch == Guid.Empty) return; if (!matchPlayers.ContainsKey(currentMatch)) matchPlayers.Add(currentMatch, new HashSet()); matchPlayers[currentMatch].Add(netIdentity); // No need to rebuild anything here. // identity.RebuildObservers is called right after this from NetworkServer.SpawnObject } void RebuildMatchObservers(Guid specificMatch) { foreach (NetworkIdentity networkIdentity in matchPlayers[specificMatch]) if (networkIdentity != null) networkIdentity.RebuildObservers(false); } #region Observers /// /// Callback used by the visibility system to determine if an observer (player) can see this object. /// If this function returns true, the network connection will be added as an observer. /// /// Network connection of a player. /// True if the player can see this object. public override bool OnCheckObserver(NetworkConnection conn) { // Not Visible if not in a match if (matchId == Guid.Empty) return false; NetworkMatchChecker networkMatchChecker = conn.identity.GetComponent(); if (networkMatchChecker == null) return false; return networkMatchChecker.matchId == matchId; } /// /// Callback used by the visibility system to (re)construct the set of observers that can see this object. /// Implementations of this callback should add network connections of players that can see this object to the observers set. /// /// The new set of observers for this object. /// True if the set of observers is being built for the first time. public override void OnRebuildObservers(HashSet observers, bool initialize) { if (currentMatch == Guid.Empty) return; foreach (NetworkIdentity networkIdentity in matchPlayers[currentMatch]) if (networkIdentity != null && networkIdentity.connectionToClient != null) observers.Add(networkIdentity.connectionToClient); } #endregion } }