From 6cc2f55ec8127d8fb24073d6ce06267b45345098 Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Mon, 15 Mar 2021 16:54:22 -0500 Subject: [PATCH 01/17] perf: redesign of area of interest The AOI system we inherited from Mirror is poorly designed. It's API requires O(n^2) algorithms, it is highly complex, and it is not flexible enough. This PR implements AOI in a completely different way. The NetworkIdentity objects no longer track visibility, and neither do NetworkPlayer. When the server spawns an object, all it does it raise the Spawned event, the AOI system will subscribe to this event, and then show that object to all the relevant players. Likewise, when a player joins, the AOI will listen for the event and show the relevant objects to the newly created player. In this fashion, we decouple AOI policy from NetworkIdentity and NetworkPlayers. The AOI system can keep the relationship between them in any way that is suitable. In this PR, I implement the simplest InterestManager called GlobalInterestManager. This Interest Manager will just show all objects to all players. Implement the class InterestManager to create any policy desired. I expect to create a Spatial Hashing interest Manager BREAKING CHANGE: Removed NetworkVisibility, extend InterestManager and attach to the ServerObjectManager instead. --- .../Mirage/Components/NetworkMatchChecker.cs | 139 ---------- .../Components/NetworkMatchChecker.cs.meta | 11 - .../Components/NetworkProximityChecker.cs | 103 ------- .../NetworkProximityChecker.cs.meta | 11 - .../Mirage/Components/NetworkSceneChecker.cs | 118 -------- .../Components/NetworkSceneChecker.cs.meta | 11 - .../Editor/NetworkInformationPreview.cs | 7 +- Assets/Mirage/Runtime/INetworkPlayer.cs | 13 +- Assets/Mirage/Runtime/InterestManagement.meta | 8 + .../GlobalInterestManager.cs | 31 +++ .../GlobalInterestManager.cs.meta} | 2 +- .../InterestManagement/InterestManager.cs | 53 ++++ .../InterestManager.cs.meta} | 2 +- Assets/Mirage/Runtime/NetworkIdentity.cs | 244 ++--------------- Assets/Mirage/Runtime/NetworkPlayer.cs | 22 -- Assets/Mirage/Runtime/NetworkVisibility.cs | 32 --- .../Mirage/Runtime/NetworkVisibility.cs.meta | 11 - Assets/Mirage/Runtime/ServerObjectManager.cs | 63 ++--- .../Scripts/ShootingTankBehaviour.cs | 5 +- .../Samples~/Basic/Scenes/Example.unity | 71 ++--- .../Editor/NetworkIdentityCallbackTests.cs | 259 +----------------- .../NetworkIdentityPerformance.cs | 1 - ...dentityPerformanceWithMultipleBehaviour.cs | 1 - .../Runtime/ClientServer/ClientServerSetup.cs | 7 +- .../ClientServer/ServerObjectManagerTests.cs | 2 + .../Runtime/Host/NetworkIdentityTests.cs | 25 +- .../Runtime/NetworkIdentityCallbackTests.cs | 108 -------- .../Tests/Runtime/NetworkMatchCheckerTest.cs | 212 -------------- 28 files changed, 200 insertions(+), 1372 deletions(-) delete mode 100644 Assets/Mirage/Components/NetworkMatchChecker.cs delete mode 100644 Assets/Mirage/Components/NetworkMatchChecker.cs.meta delete mode 100644 Assets/Mirage/Components/NetworkProximityChecker.cs delete mode 100644 Assets/Mirage/Components/NetworkProximityChecker.cs.meta delete mode 100644 Assets/Mirage/Components/NetworkSceneChecker.cs delete mode 100644 Assets/Mirage/Components/NetworkSceneChecker.cs.meta create mode 100644 Assets/Mirage/Runtime/InterestManagement.meta create mode 100644 Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs rename Assets/{Tests/Runtime/NetworkIdentityCallbackTests.cs.meta => Mirage/Runtime/InterestManagement/GlobalInterestManager.cs.meta} (83%) create mode 100644 Assets/Mirage/Runtime/InterestManagement/InterestManager.cs rename Assets/{Tests/Runtime/NetworkMatchCheckerTest.cs.meta => Mirage/Runtime/InterestManagement/InterestManager.cs.meta} (83%) delete mode 100644 Assets/Mirage/Runtime/NetworkVisibility.cs delete mode 100644 Assets/Mirage/Runtime/NetworkVisibility.cs.meta delete mode 100644 Assets/Tests/Runtime/NetworkIdentityCallbackTests.cs delete mode 100644 Assets/Tests/Runtime/NetworkMatchCheckerTest.cs diff --git a/Assets/Mirage/Components/NetworkMatchChecker.cs b/Assets/Mirage/Components/NetworkMatchChecker.cs deleted file mode 100644 index c4e51a71c6e..00000000000 --- a/Assets/Mirage/Components/NetworkMatchChecker.cs +++ /dev/null @@ -1,139 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -namespace Mirage -{ - /// - /// 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; - - public NetworkIdentity Identity => GetComponent(); - - /// - /// 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(Identity); - - // 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(Identity); - - // 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 - Identity.RebuildObservers(false); - } - } - } - - public void Awake() - { - Identity.OnStartServer.AddListener(OnStartServer); - } - - public void OnStartServer() - { - if (currentMatch == Guid.Empty) return; - - if (!matchPlayers.ContainsKey(currentMatch)) - matchPlayers.Add(currentMatch, new HashSet()); - - matchPlayers[currentMatch].Add(Identity); - - // 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(INetworkPlayer player) - { - // Not Visible if not in a match - if (MatchId == Guid.Empty) - return false; - - NetworkMatchChecker networkMatchChecker = player.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 - } -} diff --git a/Assets/Mirage/Components/NetworkMatchChecker.cs.meta b/Assets/Mirage/Components/NetworkMatchChecker.cs.meta deleted file mode 100644 index 7c7d6cfc4f2..00000000000 --- a/Assets/Mirage/Components/NetworkMatchChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1020a74962faada4b807ac5dc053a4cf -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirage/Components/NetworkProximityChecker.cs b/Assets/Mirage/Components/NetworkProximityChecker.cs deleted file mode 100644 index 3788b566586..00000000000 --- a/Assets/Mirage/Components/NetworkProximityChecker.cs +++ /dev/null @@ -1,103 +0,0 @@ -using System.Collections.Generic; -using Mirage.Logging; -using UnityEngine; -using UnityEngine.Profiling; - -namespace Mirage -{ - /// - /// Component that controls visibility of networked objects for players. - /// Any object with this component on it will not be visible to players more than a (configurable) distance away. - /// - [AddComponentMenu("Network/NetworkProximityChecker")] - [RequireComponent(typeof(NetworkIdentity))] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkProximityChecker.html")] - public class NetworkProximityChecker : NetworkVisibility - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkProximityChecker)); - - /// - /// The maximim range that objects will be visible at. - /// - [Tooltip("The maximum range that objects will be visible at.")] - public int VisibilityRange = 10; - - /// - /// How often (in seconds) that this object should update the list of observers that can see it. - /// - [Tooltip("How often (in seconds) that this object should update the list of observers that can see it.")] - public float VisibilityUpdateInterval = 1; - - /// - /// Flag to force this object to be hidden for players. - /// If this object is a player object, it will not be hidden for that player. - /// - [Tooltip("Enable to force this object to be hidden from players.")] - public bool ForceHidden; - - public void Awake() - { - NetIdentity.OnStartServer.AddListener(() => - { - InvokeRepeating(nameof(RebuildObservers), 0, VisibilityUpdateInterval); - }); - - NetIdentity.OnStopServer.AddListener(() => - { - CancelInvoke(nameof(RebuildObservers)); - }); - } - - void RebuildObservers() - { - NetIdentity.RebuildObservers(false); - } - - /// - /// 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(INetworkPlayer player) - { - if (ForceHidden) - return false; - - return Vector3.Distance(player.Identity.transform.position, transform.position) < VisibilityRange; - } - - /// - /// 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 force hidden then return without adding any observers. - if (ForceHidden) - return; - - // 'transform.' calls GetComponent, only do it once - Vector3 position = transform.position; - - // brute force distance check - // -> only player connections can be observers, so it's enough if we - // go through all connections instead of all spawned identities. - // -> compared to UNET's sphere cast checking, this one is orders of - // magnitude faster. if we have 10k monsters and run a sphere - // cast 10k times, we will see a noticeable lag even with physics - // layers. but checking to every connection is fast. - foreach (INetworkPlayer player in Server.Players) - { - // check distance - if (player != null && player.Identity != null && Vector3.Distance(player.Identity.transform.position, position) < VisibilityRange) - { - observers.Add(player); - } - } - } - } -} diff --git a/Assets/Mirage/Components/NetworkProximityChecker.cs.meta b/Assets/Mirage/Components/NetworkProximityChecker.cs.meta deleted file mode 100644 index c5aa1123365..00000000000 --- a/Assets/Mirage/Components/NetworkProximityChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1731d8de2d0c84333b08ebe1e79f4118 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirage/Components/NetworkSceneChecker.cs b/Assets/Mirage/Components/NetworkSceneChecker.cs deleted file mode 100644 index b79b85abdbb..00000000000 --- a/Assets/Mirage/Components/NetworkSceneChecker.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System.Collections.Generic; -using Mirage.Logging; -using UnityEngine; -using UnityEngine.SceneManagement; - -namespace Mirage -{ - /// - /// Component that controls visibility of networked objects between scenes. - /// Any object with this component on it will only be visible to other objects in the same scene - /// This would be used when the server has multiple additive subscenes loaded to isolate players to their respective subscenes - /// - [DisallowMultipleComponent] - [AddComponentMenu("Network/NetworkSceneChecker")] - [RequireComponent(typeof(NetworkIdentity))] - [HelpURL("https://mirror-networking.com/docs/Components/NetworkSceneChecker.html")] - public class NetworkSceneChecker : NetworkVisibility - { - static readonly ILogger logger = LogFactory.GetLogger(typeof(NetworkSceneChecker)); - - /// - /// Flag to force this object to be hidden from all observers. - /// If this object is a player object, it will not be hidden for that client. - /// - [Tooltip("Enable to force this object to be hidden from all observers.")] - public bool forceHidden; - - // Use Scene instead of string scene.name because when additively loading multiples of a subscene the name won't be unique - static readonly Dictionary> sceneCheckerObjects = new Dictionary>(); - - Scene currentScene; - - [Server(error = false)] - void Awake() - { - currentScene = gameObject.scene; - if (logger.LogEnabled()) logger.Log($"NetworkSceneChecker.Awake currentScene: {currentScene}"); - - OnStartServer(); - } - - public void OnStartServer() - { - if (!sceneCheckerObjects.ContainsKey(currentScene)) - sceneCheckerObjects.Add(currentScene, new HashSet()); - - sceneCheckerObjects[currentScene].Add(NetIdentity); - } - - [Server(error = false)] - void Update() - { - if (currentScene == gameObject.scene) - return; - - // This object is in a new scene so observers in the prior scene - // and the new scene need to rebuild their respective observers lists. - - // Remove this object from the hashset of the scene it just left - sceneCheckerObjects[currentScene].Remove(NetIdentity); - - // RebuildObservers of all NetworkIdentity's in the scene this object just left - RebuildSceneObservers(); - - // Set this to the new scene this object just entered - currentScene = gameObject.scene; - - // Make sure this new scene is in the dictionary - if (!sceneCheckerObjects.ContainsKey(currentScene)) - sceneCheckerObjects.Add(currentScene, new HashSet()); - - // Add this object to the hashset of the new scene - sceneCheckerObjects[currentScene].Add(NetIdentity); - - // RebuildObservers of all NetworkIdentity's in the scene this object just entered - RebuildSceneObservers(); - } - - void RebuildSceneObservers() - { - foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene]) - if (networkIdentity != null) - networkIdentity.RebuildObservers(false); - } - - /// - /// 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(INetworkPlayer player) - { - if (forceHidden) - return false; - - return player.Identity.gameObject.scene == gameObject.scene; - } - - /// - /// 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 forceHidden then return without adding any observers. - if (forceHidden) - return; - - // Add everything in the hashset for this object's current scene - foreach (NetworkIdentity networkIdentity in sceneCheckerObjects[currentScene]) - if (networkIdentity != null && networkIdentity.ConnectionToClient != null) - observers.Add(networkIdentity.ConnectionToClient); - } - } -} diff --git a/Assets/Mirage/Components/NetworkSceneChecker.cs.meta b/Assets/Mirage/Components/NetworkSceneChecker.cs.meta deleted file mode 100644 index b451655a379..00000000000 --- a/Assets/Mirage/Components/NetworkSceneChecker.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: b7fdb599e1359924bad6255660370252 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {fileID: 2800000, guid: 7453abfe9e8b2c04a8a47eb536fe21eb, type: 3} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirage/Editor/NetworkInformationPreview.cs b/Assets/Mirage/Editor/NetworkInformationPreview.cs index ee907c7bbed..68442757e58 100644 --- a/Assets/Mirage/Editor/NetworkInformationPreview.cs +++ b/Assets/Mirage/Editor/NetworkInformationPreview.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using UnityEditor; using UnityEngine; +using System.Linq; namespace Mirage { @@ -172,7 +173,9 @@ float DrawNetworkBehaviors(NetworkIdentity identity, float initialX, float Y) float DrawObservers(NetworkIdentity identity, float initialX, float Y) { - if (identity.observers.Count > 0) + IEnumerable observers = identity.Observers; + + if (observers.Any()) { var observerRect = new Rect(initialX, Y + 10, 200, 20); @@ -181,7 +184,7 @@ float DrawObservers(NetworkIdentity identity, float initialX, float Y) observerRect.x += 20; observerRect.y += observerRect.height; - foreach (INetworkPlayer player in identity.observers) + foreach (INetworkPlayer player in observers) { GUI.Label(observerRect, player.Connection.GetEndPointAddress() + ":" + player, styles.ComponentName); observerRect.y += observerRect.height; diff --git a/Assets/Mirage/Runtime/INetworkPlayer.cs b/Assets/Mirage/Runtime/INetworkPlayer.cs index c27be6653ef..f54c04488a3 100644 --- a/Assets/Mirage/Runtime/INetworkPlayer.cs +++ b/Assets/Mirage/Runtime/INetworkPlayer.cs @@ -71,17 +71,6 @@ public interface IMessageHandler : IMessageSender, IMessageReceiver, INotifySend } - /// - /// An object that can observe NetworkIdentities. - /// this is useful for interest management - /// - public interface IVisibilityTracker - { - void AddToVisList(NetworkIdentity identity); - void RemoveFromVisList(NetworkIdentity identity); - void RemoveObservers(); - } - /// /// An object that can own networked objects /// @@ -97,7 +86,7 @@ public interface IObjectOwner /// A connection to a remote endpoint. /// May be from the server to client or from client to server /// - public interface INetworkPlayer : IMessageHandler, IVisibilityTracker, IObjectOwner, IAuthenticatedObject, ISceneLoader + public interface INetworkPlayer : IMessageHandler, IObjectOwner, IAuthenticatedObject, ISceneLoader { IConnection Connection { get; } } diff --git a/Assets/Mirage/Runtime/InterestManagement.meta b/Assets/Mirage/Runtime/InterestManagement.meta new file mode 100644 index 00000000000..47b87ee5126 --- /dev/null +++ b/Assets/Mirage/Runtime/InterestManagement.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60a4aeac526944324921b45b65b50ffa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs new file mode 100644 index 00000000000..bdbc23f996c --- /dev/null +++ b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; + +namespace Mirage.InterestManagement +{ + /// + /// A simple interest manager where all players see all objects + /// + public class GlobalInterestManager : InterestManager + { + public override IEnumerable Observers(NetworkIdentity identity) + { + return ServerObjectManager.Server.Players; + } + + protected override void OnAuthenticated(INetworkPlayer player) + { + foreach (NetworkIdentity identity in ServerObjectManager.SpawnedObjects.Values) + { + ServerObjectManager.ShowForConnection(identity, player); + } + } + + protected override void OnSpawned(NetworkIdentity identity) + { + foreach (INetworkPlayer player in ServerObjectManager.Server.Players) + { + ServerObjectManager.ShowForConnection(identity, player); + } + } + } +} \ No newline at end of file diff --git a/Assets/Tests/Runtime/NetworkIdentityCallbackTests.cs.meta b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs.meta similarity index 83% rename from Assets/Tests/Runtime/NetworkIdentityCallbackTests.cs.meta rename to Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs.meta index 7ecc98c8b6a..33295d3ba9b 100644 --- a/Assets/Tests/Runtime/NetworkIdentityCallbackTests.cs.meta +++ b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: d30db0a07349e4eec880cda9012fbb0a +guid: 5c6ee0ff31a6248959cbb910c2daebf3 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs new file mode 100644 index 00000000000..3a469638382 --- /dev/null +++ b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Mirage.InterestManagement +{ + /// + /// An interest manager is responsible for showing and hiding objects to players + /// based on an area if interest policy. + /// + /// Implement this class to provide a interest management policy and assign + /// it to the + /// + public abstract class InterestManager : MonoBehaviour + { + public ServerObjectManager ServerObjectManager; + + public void Start() + { + if (ServerObjectManager == null) + ServerObjectManager = GetComponent(); + + ServerObjectManager.Spawned.AddListener(OnSpawned); + + NetworkServer server = ServerObjectManager.Server; + if (server == null) + server = GetComponent(); + + server.Authenticated.AddListener(OnAuthenticated); + } + + /// + /// Invoked when a player joins the server + /// It should show all objects relevant to that player + /// + /// + protected abstract void OnAuthenticated(INetworkPlayer player); + + /// + /// Invoked when an object is spawned in the server + /// It should show that object to all relevant players + /// + /// The object just spawned + protected abstract void OnSpawned(NetworkIdentity identity); + + /// + /// Find out all the players that can see an object + /// + /// + /// + public abstract IEnumerable Observers(NetworkIdentity identity); + } +} diff --git a/Assets/Tests/Runtime/NetworkMatchCheckerTest.cs.meta b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs.meta similarity index 83% rename from Assets/Tests/Runtime/NetworkMatchCheckerTest.cs.meta rename to Assets/Mirage/Runtime/InterestManagement/InterestManager.cs.meta index b3c51cf813f..ff5b120d989 100644 --- a/Assets/Tests/Runtime/NetworkMatchCheckerTest.cs.meta +++ b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 2fa0a455ab9b4cf47b9eab0f2b03ce0c +guid: 57b9a2e5882b242a58372f2e02b7c3ff MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/Mirage/Runtime/NetworkIdentity.cs b/Assets/Mirage/Runtime/NetworkIdentity.cs index 4b1318c1c50..8d8bd33bd73 100644 --- a/Assets/Mirage/Runtime/NetworkIdentity.cs +++ b/Assets/Mirage/Runtime/NetworkIdentity.cs @@ -7,6 +7,8 @@ using UnityEngine.Events; using Mirage.Logging; using Mirage.Serialization; +using Mirage.InterestManagement; +using System.Linq; #if UNITY_EDITOR using UnityEditor; #if UNITY_2018_3_OR_NEWER @@ -143,17 +145,34 @@ public sealed class NetworkIdentity : MonoBehaviour /// public bool HasAuthority { get; internal set; } - /// - /// The set of network connections (players) that can see this object. - /// - public readonly HashSet observers = new HashSet(); - /// /// Unique identifier for this particular object instance, used for tracking objects between networked clients and the server. /// This is a unique identifier for this particular GameObject instance. Use it to track GameObjects between networked clients and the server. /// public uint NetId { get; internal set; } + /// + /// Returns list of players that can see this object + /// + /// Returns empty list if the object has not been spawned yet + /// Returns empty list if this is not a server object + public IEnumerable Observers + { + get + { + if (ServerObjectManager == null) + return Enumerable.Empty(); + + InterestManager interestManager = ServerObjectManager.InterestManager; + + if (interestManager == null) + return Enumerable.Empty(); + + return interestManager.Observers(this); + } + } + + /// /// A unique identifier for NetworkIdentity objects within a scene. /// This is used for spawning scene objects on clients. @@ -222,20 +241,6 @@ public NetworkBehaviour[] NetworkBehaviours } } - - NetworkVisibility visibilityCache; - public NetworkVisibility Visibility - { - get - { - if (visibilityCache is null) - { - visibilityCache = GetComponent(); - } - return visibilityCache; - } - } - [SerializeField, HideInInspector] string m_AssetId; @@ -389,15 +394,6 @@ internal void SetClientOwner(INetworkPlayer player) /// public static event ClientAuthorityCallback clientAuthorityCallback; - /// - /// this is used when a connection is destroyed, since the "observers" property is read-only - /// - /// - internal void RemoveObserverInternal(INetworkPlayer player) - { - observers.Remove(player); - } - /// /// hasSpawned should always be false before runtime /// @@ -709,28 +705,6 @@ internal void StopAuthority() OnStopAuthority?.Invoke(); } - /// - /// check if observer can be seen by connection. - /// - /// - /// returns visibility.OnCheckObserver - /// - /// - /// returns true if we have no NetworkVisibility, default objects are visible - /// - /// - /// - /// - /// - internal bool OnCheckObserver(INetworkPlayer player) - { - if (Visibility != null) - { - return Visibility.OnCheckObserver(player); - } - return true; - } - internal void StopClient() { OnStopClient?.Invoke(); @@ -909,170 +883,6 @@ internal void HandleRemoteCall(Skeleton skeleton, int componentIndex, NetworkRea } } - /// - /// Called when NetworkIdentity is destroyed - /// - internal void ClearObservers() - { - foreach (INetworkPlayer player in observers) - { - player.RemoveFromVisList(this); - } - observers.Clear(); - } - - internal void AddObserver(INetworkPlayer player) - { - if (observers.Contains(player)) - { - // if we try to add a connectionId that was already added, then - // we may have generated one that was already in use. - return; - } - - if (logger.LogEnabled()) logger.Log("Added observer " + player.Connection.GetEndPointAddress() + " added for " + gameObject); - observers.Add(player); - player.AddToVisList(this); - - // spawn identity for this conn - ServerObjectManager.ShowForConnection(this, player); - } - - /// - /// Helper function to call OnRebuildObservers in all components - /// HashSet is passed in so we can cache it! - /// Returns true if we have a NetworkVisibility, false otherwise - /// Initialize is true on first rebuild, false on consecutive rebuilds - /// - /// - /// - /// - internal bool GetNewObservers(HashSet observersSet, bool initialize) - { - observersSet.Clear(); - - if (Visibility != null) - { - Visibility.OnRebuildObservers(observersSet, initialize); - return true; - } - - // we have no NetworkVisibility. return false to indicate that we - // should use the default implementation. - return false; - } - - /// - /// Helper function to add all server connections as observers. - /// This is used if none of the components provides their own - /// OnRebuildObservers function. - /// - internal void AddAllReadyServerConnectionsToObservers() - { - // add all server connections - foreach (INetworkPlayer player in Server.Players) - { - if (player.IsReady) - AddObserver(player); - } - - // add local host connection (if any) - if (Server.LocalPlayer != null && Server.LocalPlayer.IsReady) - { - AddObserver(Server.LocalPlayer); - } - } - - static readonly HashSet newObservers = new HashSet(); - - /// - /// This causes the set of players that can see this object to be rebuild. - /// The OnRebuildObservers callback function will be invoked on each NetworkBehaviour. - /// - /// True if this is the first time. - public void RebuildObservers(bool initialize) - { - bool changed = false; - - // call OnRebuildObservers function - bool rebuildOverwritten = GetNewObservers(newObservers, initialize); - - // if player connection: ensure player always see himself no matter what. - // -> fixes https://github.com/vis2k/Mirror/issues/692 where a - // player might teleport out of the ProximityChecker's cast, - // losing the own connection as observer. - if (ConnectionToClient != null && ConnectionToClient.IsReady) - { - newObservers.Add(ConnectionToClient); - } - - // if no NetworkVisibility component, then add all server connections. - if (!rebuildOverwritten) - { - // only add all connections when rebuilding the first time. - // second time we just keep them without rebuilding anything. - if (initialize) - { - AddAllReadyServerConnectionsToObservers(); - } - return; - } - - changed = AddNewObservers(initialize, changed); - - changed = RemoveOldObservers(changed); - - if (changed) - { - observers.Clear(); - foreach (INetworkPlayer player in newObservers) - { - if (player != null && player.IsReady) - observers.Add(player); - } - } - } - - // remove all old .observers that aren't in newObservers anymore - bool RemoveOldObservers(bool changed) - { - foreach (INetworkPlayer player in observers) - { - if (!newObservers.Contains(player)) - { - // removed observer - player.RemoveFromVisList(this); - ServerObjectManager.HideForConnection(this, player); - - if (logger.LogEnabled()) logger.Log("Removed Observer for " + gameObject + " " + player); - changed = true; - } - } - - return changed; - } - - // add all newObservers that aren't in .observers yet - bool AddNewObservers(bool initialize, bool changed) - { - foreach (INetworkPlayer player in newObservers) - { - // only add ready connections. - // otherwise the player might not be in the world yet or anymore - if (player != null && player.IsReady && (initialize || !observers.Contains(player))) - { - // new observer - player.AddToVisList(this); - // spawn identity for this conn - ServerObjectManager.ShowForConnection(this, player); - if (logger.LogEnabled()) logger.Log("New Observer for " + gameObject + " " + player); - changed = true; - } - } - - return changed; - } - /// /// Assign control of an object to a client via the client's NetworkConnection. /// This causes hasAuthority to be set on the client that owns the object, and NetworkBehaviour.OnStartAuthority will be called on that client. This object then will be in the NetworkConnection.clientOwnedObjects list for the connection. @@ -1158,13 +968,11 @@ internal void Reset() ClientObjectManager = null; ConnectionToClient = null; networkBehavioursCache = null; - - ClearObservers(); } internal void ServerUpdate() { - if (observers.Count > 0) + if (Observers.Any()) { SendUpdateVarsMessage(); } @@ -1235,7 +1043,7 @@ internal void SendToRemoteObservers(T msg, bool includeOwner = true, int chan { if (logger.LogEnabled()) logger.Log("Server.SendToObservers id:" + typeof(T)); - if (observers.Count == 0) + if (!Observers.Any()) return; connectionsExcludeSelf.Clear(); diff --git a/Assets/Mirage/Runtime/NetworkPlayer.cs b/Assets/Mirage/Runtime/NetworkPlayer.cs index 0f378077211..2ffdbf4987b 100644 --- a/Assets/Mirage/Runtime/NetworkPlayer.cs +++ b/Assets/Mirage/Runtime/NetworkPlayer.cs @@ -32,9 +32,6 @@ public class NetworkPlayer : INetworkPlayer // Handles network messages on client and server internal delegate void NetworkMessageDelegate(INetworkPlayer player, NetworkReader reader, int channelId); - // internal so it can be tested - private readonly HashSet visList = new HashSet(); - // message handlers for this connection internal readonly Dictionary messageHandlers = new Dictionary(); @@ -207,25 +204,6 @@ public override string ToString() return $"connection({Address})"; } - public void AddToVisList(NetworkIdentity identity) - { - visList.Add(identity); - } - - public void RemoveFromVisList(NetworkIdentity identity) - { - visList.Remove(identity); - } - - public void RemoveObservers() - { - foreach (NetworkIdentity identity in visList) - { - identity.RemoveObserverInternal(this); - } - visList.Clear(); - } - internal void InvokeHandler(int msgType, NetworkReader reader, int channelId) { if (messageHandlers.TryGetValue(msgType, out NetworkMessageDelegate msgDelegate)) diff --git a/Assets/Mirage/Runtime/NetworkVisibility.cs b/Assets/Mirage/Runtime/NetworkVisibility.cs deleted file mode 100644 index 3e94f92c50b..00000000000 --- a/Assets/Mirage/Runtime/NetworkVisibility.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Collections.Generic; -using UnityEngine; - -namespace Mirage -{ - // the name NetworkProximityCheck implies that it's only about objects in - // proximity to the player. But we might have room based, guild based, - // instanced based checks too, so NetworkVisibility is more fitting. - // - // note: we inherit from NetworkBehaviour so we can reuse .netIdentity, etc. - // note: unlike UNET, we only allow 1 proximity checker per NetworkIdentity. - [DisallowMultipleComponent] - public abstract class NetworkVisibility : NetworkBehaviour - { - /// - /// 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 abstract bool OnCheckObserver(INetworkPlayer player); - - /// - /// 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 abstract void OnRebuildObservers(HashSet observers, bool initialize); - - } -} diff --git a/Assets/Mirage/Runtime/NetworkVisibility.cs.meta b/Assets/Mirage/Runtime/NetworkVisibility.cs.meta deleted file mode 100644 index 1e6665899e3..00000000000 --- a/Assets/Mirage/Runtime/NetworkVisibility.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c08f1a030234d49d391d7223a8592f15 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Mirage/Runtime/ServerObjectManager.cs b/Assets/Mirage/Runtime/ServerObjectManager.cs index 3607aa1cdcd..5d15acf08db 100644 --- a/Assets/Mirage/Runtime/ServerObjectManager.cs +++ b/Assets/Mirage/Runtime/ServerObjectManager.cs @@ -6,6 +6,9 @@ using Mirage.Serialization; using UnityEngine; using UnityEngine.Serialization; +using Mirage.Logging; +using Mirage.Serialization; +using Mirage.InterestManagement; namespace Mirage { @@ -61,6 +64,8 @@ public class ServerObjectManager : MonoBehaviour, IServerObjectManager, IObjectL [SerializeField] SpawnEvent _unSpawned = new SpawnEvent(); public SpawnEvent UnSpawned => _unSpawned; + public InterestManager InterestManager; + uint nextNetworkId = 1; uint GetNextNetworkId() => checked(nextNetworkId++); @@ -76,6 +81,15 @@ public bool TryGetIdentity(uint netId, out NetworkIdentity identity) public void Start() { + if (InterestManager == null) + { + InterestManager = gameObject.AddComponent(); + } + if (Server == null) + { + Server = GetComponent(); + } + if (Server != null) { Server.Started.AddListener(SpawnOrActivate); @@ -194,7 +208,7 @@ void StartedHost() /// /// Connection which is adding the player. /// Client associated to the player. - /// Player object spawned for the player. + /// Character object spawned for the player. /// /// Does the previous player remain attached to this connection? /// @@ -219,34 +233,6 @@ public bool ReplaceCharacter(INetworkPlayer player, INetworkClient client, GameO return InternalReplacePlayerForConnection(player, client, character, keepAuthority); } - void SpawnObserversForConnection(INetworkPlayer player) - { - if (logger.LogEnabled()) logger.Log("Spawning " + SpawnedObjects.Count + " objects for conn " + player); - - if (!player.IsReady) - { - // client needs to finish initializing before we can spawn objects - // otherwise it would not find them. - return; - } - - // add connection to each nearby NetworkIdentity's observers, which - // internally sends a spawn message for each one to the connection. - foreach (NetworkIdentity identity in SpawnedObjects.Values) - { - if (identity.gameObject.activeSelf) - { - if (logger.LogEnabled()) logger.Log("Sending spawn message for current server objects name='" + identity.name + "' netId=" + identity.NetId + " sceneId=" + identity.sceneId); - - bool visible = identity.OnCheckObserver(player); - if (visible) - { - identity.AddObserver(player); - } - } - } - } - /// /// When an message handler has received a request from a player, the server calls this to associate the player object with the connection. /// When a player is added for a connection, the client for that connection is made ready automatically. The player object is automatically spawned, so you do not need to call NetworkServer.Spawn for that object. This function is used for "adding" a player, not for "replacing" the player on a connection. If there is already a player on this playerControllerId for this connection, this will fail. @@ -362,13 +348,6 @@ internal bool InternalReplacePlayerForConnection(INetworkPlayer player, INetwork Server.LocalClient.Player.Identity = identity; } - // add connection to observers AFTER the playerController was set. - // by definition, there is nothing to observe if there is no player - // controller. - // - // IMPORTANT: do this in AddCharacter & ReplaceCharacter! - SpawnObserversForConnection(player); - if (logger.LogEnabled()) logger.Log("Replacing playerGameObject object netId: " + character.GetComponent().NetId + " asset ID " + character.GetComponent().AssetId); Respawn(identity); @@ -381,8 +360,7 @@ internal bool InternalReplacePlayerForConnection(INetworkPlayer player, INetwork internal void ShowForConnection(NetworkIdentity identity, INetworkPlayer player) { - if (player.IsReady) - SendSpawnMessage(identity, player); + SendSpawnMessage(identity, player); } internal void HideForConnection(NetworkIdentity identity, INetworkPlayer player) @@ -482,8 +460,6 @@ internal void SpawnObject(GameObject obj, INetworkPlayer ownerPlayer) } if (logger.LogEnabled()) logger.Log("SpawnObject instance ID " + identity.NetId + " asset ID " + identity.AssetId); - - identity.RebuildObservers(true); } internal void SendSpawnMessage(NetworkIdentity identity, INetworkPlayer player) @@ -630,7 +606,6 @@ void DestroyObject(NetworkIdentity identity, bool destroyServerObject) identity.SendToRemoteObservers(new ObjectDestroyMessage { netId = identity.NetId }); - identity.ClearObservers(); if (Server.LocalClientActive) { identity.StopClient(); @@ -745,10 +720,6 @@ public void SetClientReady(INetworkPlayer player) // set ready player.IsReady = true; - - // client is ready to start spawning objects - if (player.Identity != null) - SpawnObserversForConnection(player); } /// @@ -774,8 +745,6 @@ public void SetClientNotReady(INetworkPlayer player) { if (logger.LogEnabled()) logger.Log("PlayerNotReady " + player); player.IsReady = false; - player.RemoveObservers(); - player.Send(new NotReadyMessage()); } } diff --git a/Assets/Mirage/Samples~/AdditiveScenes/Scripts/ShootingTankBehaviour.cs b/Assets/Mirage/Samples~/AdditiveScenes/Scripts/ShootingTankBehaviour.cs index af1f3ea60ed..f6490855cd6 100644 --- a/Assets/Mirage/Samples~/AdditiveScenes/Scripts/ShootingTankBehaviour.cs +++ b/Assets/Mirage/Samples~/AdditiveScenes/Scripts/ShootingTankBehaviour.cs @@ -1,4 +1,5 @@ using UnityEngine; +using System.Linq; namespace Mirage.Examples.Additive { @@ -23,7 +24,7 @@ void Start() void Update() { - if (IsServer && NetIdentity.observers.Count > 0) + if (IsServer && NetIdentity.Observers.Any()) ShootNearestPlayer(); if (IsClient) @@ -36,7 +37,7 @@ void ShootNearestPlayer() GameObject target = null; float distance = 100f; - foreach (INetworkPlayer networkConnection in NetIdentity.observers) + foreach (INetworkPlayer networkConnection in NetIdentity.Observers) { GameObject tempTarget = networkConnection.Identity.gameObject; float tempDistance = Vector3.Distance(tempTarget.transform.position, transform.position); diff --git a/Assets/Mirage/Samples~/Basic/Scenes/Example.unity b/Assets/Mirage/Samples~/Basic/Scenes/Example.unity index 292c115cc5d..1763c0addc7 100644 --- a/Assets/Mirage/Samples~/Basic/Scenes/Example.unity +++ b/Assets/Mirage/Samples~/Basic/Scenes/Example.unity @@ -186,6 +186,7 @@ MonoBehaviour: ClientObjectManager: {fileID: 249891961} ServerObjectManager: {fileID: 249891962} PlayerPrefab: {fileID: 1088833923132447018, guid: 22f1fa3a0aff72b46a371f667bb4fb30, type: 3} + AutoSpawn: 1 startPositionIndex: 0 startPositions: [] playerSpawnMethod: 1 @@ -232,17 +233,17 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: abe6be14204d94224a3e7cd99dd2ea73, type: 3} m_Name: m_EditorClassIdentifier: + Transport: {fileID: 249891954} authenticator: {fileID: 0} - Connected: + _connected: m_PersistentCalls: m_Calls: [] - Authenticated: + _authenticated: m_PersistentCalls: m_Calls: [] - Disconnected: + _disconnected: m_PersistentCalls: m_Calls: [] - Transport: {fileID: 249891954} --- !u!114 &249891959 MonoBehaviour: m_ObjectHideFlags: 0 @@ -256,30 +257,30 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: MaxConnections: 4 - Started: + Listening: 1 + Transport: {fileID: 249891954} + authenticator: {fileID: 0} + _started: m_PersistentCalls: m_Calls: [] - Connected: + _connected: m_PersistentCalls: m_Calls: [] - Authenticated: + _authenticated: m_PersistentCalls: m_Calls: [] - Disconnected: + _disconnected: m_PersistentCalls: m_Calls: [] - Stopped: + _stopped: m_PersistentCalls: m_Calls: [] - OnStartHost: + _onStartHost: m_PersistentCalls: m_Calls: [] - OnStopHost: + _onStopHost: m_PersistentCalls: m_Calls: [] - authenticator: {fileID: 0} - Listening: 1 - Transport: {fileID: 249891954} --- !u!114 &249891960 MonoBehaviour: m_ObjectHideFlags: 0 @@ -294,16 +295,17 @@ MonoBehaviour: m_EditorClassIdentifier: Client: {fileID: 249891958} Server: {fileID: 249891959} - ClientChangeScene: + DontDestroy: 1 + _clientChangeScene: m_PersistentCalls: m_Calls: [] - ClientSceneChanged: + _clientSceneChanged: m_PersistentCalls: m_Calls: [] - ServerChangeScene: + _serverChangeScene: m_PersistentCalls: m_Calls: [] - ServerSceneChanged: + _serverSceneChanged: m_PersistentCalls: m_Calls: [] --- !u!114 &249891961 @@ -320,10 +322,10 @@ MonoBehaviour: m_EditorClassIdentifier: Client: {fileID: 249891958} NetworkSceneManager: {fileID: 249891960} - Spawned: + _spawned: m_PersistentCalls: m_Calls: [] - UnSpawned: + _unSpawned: m_PersistentCalls: m_Calls: [] spawnPrefabs: @@ -342,12 +344,13 @@ MonoBehaviour: m_EditorClassIdentifier: Server: {fileID: 249891959} NetworkSceneManager: {fileID: 249891960} - Spawned: + _spawned: m_PersistentCalls: m_Calls: [] - UnSpawned: + _unSpawned: m_PersistentCalls: m_Calls: [] + InterestManager: {fileID: 0} --- !u!114 &249891963 MonoBehaviour: m_ObjectHideFlags: 0 @@ -361,26 +364,30 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Levels: - - Name: NetworkIdentity + - Name: NetworkClient level: 2 - - Name: ClientObjectManager + - Name: NetworkTime level: 2 - - Name: ServerObjectManager + - Name: NetworkSceneManager level: 2 - - Name: NetworkClient + - Name: NetworkIdentity level: 2 - - Name: NetworkTime + - Name: ClientObjectManager level: 2 - Name: NetworkServer level: 2 - - Name: NetworkSceneManager - level: 2 - Name: NetworkBehaviour level: 2 + - Name: CharacterSpawner + level: 2 + - Name: ServerObjectManager + level: 2 - Name: PlayerSpawner level: 2 - Name: RemoteCallHelper level: 2 + - Name: NetworkBehaviourInspector + level: 2 - Name: EnterPlayModeSettingsCheck level: 2 - Name: NetworkScenePostProcess @@ -413,8 +420,6 @@ MonoBehaviour: level: 2 - Name: WeaverTests level: 4 - - Name: NetworkBehaviourInspector - level: 2 - Name: ChatWindow level: 2 - Name: AdditiveNetworkManager @@ -431,6 +436,10 @@ MonoBehaviour: level: 2 - Name: Tests level: 4 + - Name: WelcomeWindow + level: 2 + - Name: NetworkPlayer + level: 2 --- !u!1 &283483315 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs b/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs index 21be2cdd22a..36fe7e64642 100644 --- a/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs +++ b/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs @@ -14,41 +14,6 @@ public class NetworkIdentityCallbackTests { #region test components - class CheckObserverExceptionNetworkBehaviour : NetworkVisibility - { - public int called; - public INetworkPlayer valuePassed; - public override void OnRebuildObservers(HashSet observers, bool initialize) { } - public override bool OnCheckObserver(INetworkPlayer player) - { - ++called; - valuePassed = player; - throw new Exception("some exception"); - } - } - - class CheckObserverTrueNetworkBehaviour : NetworkVisibility - { - public int called; - public override void OnRebuildObservers(HashSet observers, bool initialize) { } - public override bool OnCheckObserver(INetworkPlayer player) - { - ++called; - return true; - } - } - - class CheckObserverFalseNetworkBehaviour : NetworkVisibility - { - public int called; - public override void OnRebuildObservers(HashSet observers, bool initialize) { } - public override bool OnCheckObserver(INetworkPlayer player) - { - ++called; - return false; - } - } - class SerializeTest1NetworkBehaviour : NetworkBehaviour { public int value; @@ -105,22 +70,6 @@ public override void OnDeserialize(NetworkReader reader, bool initialState) } } - class RebuildObserversNetworkBehaviour : NetworkVisibility - { - public INetworkPlayer observer; - public override bool OnCheckObserver(INetworkPlayer player) { return true; } - public override void OnRebuildObservers(HashSet observers, bool initialize) - { - observers.Add(observer); - } - } - - class RebuildEmptyObserversNetworkBehaviour : NetworkVisibility - { - public override bool OnCheckObserver(INetworkPlayer player) { return true; } - public override void OnRebuildObservers(HashSet observers, bool initialize) { } - } - #endregion GameObject gameObject; @@ -262,26 +211,6 @@ public void SetOverrideClientOwner() Assert.That(identity.ConnectionToClient, Is.EqualTo(original)); } - [Test] - public void RemoveObserverInternal() - { - // call OnStartServer so that observers dict is created - identity.StartServer(); - - // add an observer connection - INetworkPlayer player = Substitute.For(); - identity.observers.Add(player); - - INetworkPlayer player2 = Substitute.For(); - // RemoveObserverInternal with invalid connection should do nothing - identity.RemoveObserverInternal(player2); - Assert.That(identity.observers, Is.EquivalentTo(new[] { player })); - - // RemoveObserverInternal with existing connection should remove it - identity.RemoveObserverInternal(player); - Assert.That(identity.observers, Is.Empty); - } - [Test] public void AssignSceneID() { @@ -466,48 +395,6 @@ public void NotifyAuthorityCallsOnStartStopAuthority() stopAuthFunc.Received(1).Invoke(); } - [Test] - public void OnCheckObserverCatchesException() - { - // add component - gameObject.AddComponent(); - - var connection = new NetworkPlayer(tconn42); - - // should catch the exception internally and not throw it - Assert.Throws(() => - { - identity.OnCheckObserver(connection); - }); - } - - [Test] - public void OnCheckObserverTrue() - { - // create a networkidentity with a component that returns true - // result should still be true. - var gameObjectTrue = new GameObject(); - NetworkIdentity identityTrue = gameObjectTrue.AddComponent(); - CheckObserverTrueNetworkBehaviour compTrue = gameObjectTrue.AddComponent(); - var connection = new NetworkPlayer(tconn42); - Assert.That(identityTrue.OnCheckObserver(connection), Is.True); - Assert.That(compTrue.called, Is.EqualTo(1)); - } - - [Test] - public void OnCheckObserverFalse() - { - // create a networkidentity with a component that returns true and - // one component that returns false. - // result should still be false if any one returns false. - var gameObjectFalse = new GameObject(); - NetworkIdentity identityFalse = gameObjectFalse.AddComponent(); - CheckObserverFalseNetworkBehaviour compFalse = gameObjectFalse.AddComponent(); - var connection = new NetworkPlayer(tconn42); - Assert.That(identityFalse.OnCheckObserver(connection), Is.False); - Assert.That(compFalse.called, Is.EqualTo(1)); - } - [Test] public void OnSerializeAllSafely() { @@ -661,162 +548,18 @@ public void OnStopServerEx() }); } - [Test] - public void AddObserver() - { - identity.Server = server; - // create some connections - var connection1 = new NetworkPlayer(tconn42); - var connection2 = new NetworkPlayer(tconn43); - - // call OnStartServer so that observers dict is created - identity.StartServer(); - - // call AddObservers - identity.AddObserver(connection1); - identity.AddObserver(connection2); - Assert.That(identity.observers, Is.EquivalentTo(new[] { connection1, connection2 })); - - // adding a duplicate connectionId shouldn't overwrite the original - identity.AddObserver(connection1); - Assert.That(identity.observers, Is.EquivalentTo(new[] { connection1, connection2 })); - } - - [Test] - public void ClearObservers() - { - // call OnStartServer so that observers dict is created - identity.StartServer(); - - // add some observers - identity.observers.Add(new NetworkPlayer(tconn42)); - identity.observers.Add(new NetworkPlayer(tconn43)); - - // call ClearObservers - identity.ClearObservers(); - Assert.That(identity.observers.Count, Is.EqualTo(0)); - } - - [Test] public void Reset() { // creates .observers and generates a netId identity.StartServer(); identity.ConnectionToClient = new NetworkPlayer(tconn42); - identity.observers.Add(new NetworkPlayer(tconn42)); + identity.ConnectionToServer = new NetworkPlayer(tconn43); // mark for reset and reset identity.Reset(); Assert.That(identity.NetId, Is.EqualTo(0)); Assert.That(identity.ConnectionToClient, Is.Null); } - - [Test] - public void GetNewObservers() - { - // add components - RebuildObserversNetworkBehaviour comp = gameObject.AddComponent(); - comp.observer = new NetworkPlayer(tconn42); - - // get new observers - var observers = new HashSet(); - bool result = identity.GetNewObservers(observers, true); - Assert.That(result, Is.True); - Assert.That(observers.Count, Is.EqualTo(1)); - Assert.That(observers.Contains(comp.observer), Is.True); - } - - [Test] - public void GetNewObserversClearsHashSet() - { - // get new observers. no observer components so it should just clear - // it and not do anything else - var observers = new HashSet - { - new NetworkPlayer(tconn42) - }; - identity.GetNewObservers(observers, true); - Assert.That(observers.Count, Is.EqualTo(0)); - } - - [Test] - public void GetNewObserversFalseIfNoComponents() - { - // get new observers. no observer components so it should be false - var observers = new HashSet(); - bool result = identity.GetNewObservers(observers, true); - Assert.That(result, Is.False); - } - - // RebuildObservers should always add the own ready connection - // (if any). fixes https://github.com/vis2k/Mirror/issues/692 - [Test] - public void RebuildObserversOnlyAddsOwnPlayerIfReady() - { - // add at least one observers component, otherwise it will just add - // all server connections - gameObject.AddComponent(); - - // add own player connection that isn't ready - (_, NetworkPlayer connection) = PipedConnections(); - identity.ConnectionToClient = connection; - - // call OnStartServer so that observers dict is created - identity.StartServer(); - - // rebuild shouldn't add own player because conn wasn't set ready - identity.RebuildObservers(true); - Assert.That(identity.observers, Does.Not.Contains(identity.ConnectionToClient)); - } - - [Test] - public void RebuildObserversAddsReadyConnectionsIfImplemented() - { - - // add a proximity checker - // one with a ready connection, one with no ready connection, one with null connection - RebuildObserversNetworkBehaviour comp = gameObject.AddComponent(); - comp.observer = Substitute.For(); - comp.observer.IsReady.Returns(true); - - // rebuild observers should add all component's ready observers - identity.RebuildObservers(true); - Assert.That(identity.observers, Is.EquivalentTo(new[] { comp.observer })); - } - - - [Test] - public void RebuildObserversDoesntAddNotReadyConnectionsIfImplemented() - { - // add a proximity checker - // one with a ready connection, one with no ready connection, one with null connection - RebuildObserversNetworkBehaviour comp = gameObject.AddComponent(); - comp.observer = Substitute.For(); - comp.observer.IsReady.Returns(false); - - // rebuild observers should add all component's ready observers - identity.RebuildObservers(true); - Assert.That(identity.observers, Is.Empty); - } - - [Test] - public void RebuildObserversAddsReadyServerConnectionsIfNotImplemented() - { - INetworkPlayer readyConnection = Substitute.For(); - readyConnection.IsReady.Returns(true); - INetworkPlayer notReadyConnection = Substitute.For(); - notReadyConnection.IsReady.Returns(false); - - // add some server connections - server.Players.Add(readyConnection); - server.Players.Add(notReadyConnection); - - // rebuild observers should add all ready server connections - // because no component implements OnRebuildObservers - identity.RebuildObservers(true); - Assert.That(identity.observers, Is.EquivalentTo(new[] { readyConnection })); - } - } } diff --git a/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformance.cs b/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformance.cs index 97d46e00664..df180027eb9 100644 --- a/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformance.cs +++ b/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformance.cs @@ -29,7 +29,6 @@ public void SetUp() gameObject = new GameObject(); identity = gameObject.AddComponent(); identity.ConnectionToClient = Substitute.For(); - identity.observers.Add(identity.ConnectionToClient); health = gameObject.AddComponent(); health.syncMode = SyncMode.Owner; health.syncInterval = 0f; diff --git a/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformanceWithMultipleBehaviour.cs b/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformanceWithMultipleBehaviour.cs index 46edbe855fb..5d0873a57e6 100644 --- a/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformanceWithMultipleBehaviour.cs +++ b/Assets/Tests/Performance/Runtime/NetworkWriter/NetworkIdentityPerformanceWithMultipleBehaviour.cs @@ -21,7 +21,6 @@ public void SetUp() gameObject = new GameObject(); identity = gameObject.AddComponent(); identity.ConnectionToClient = Substitute.For(); - identity.observers.Add(identity.ConnectionToClient); health = new Health[healthCount]; for (int i = 0; i < healthCount; i++) { diff --git a/Assets/Tests/Runtime/ClientServer/ClientServerSetup.cs b/Assets/Tests/Runtime/ClientServer/ClientServerSetup.cs index 4a1643a0288..2583702918e 100644 --- a/Assets/Tests/Runtime/ClientServer/ClientServerSetup.cs +++ b/Assets/Tests/Runtime/ClientServer/ClientServerSetup.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Linq; using Cysharp.Threading.Tasks; +using Mirage.InterestManagement; using UnityEngine; using UnityEngine.TestTools; @@ -18,6 +19,7 @@ public class ClientServerSetup where T : NetworkBehaviour protected NetworkServer server; protected NetworkSceneManager serverSceneManager; protected ServerObjectManager serverObjectManager; + protected InterestManager interestManager; protected GameObject serverPlayerGO; protected NetworkIdentity serverIdentity; protected T serverComponent; @@ -41,7 +43,7 @@ public virtual void ExtraSetup() { } [UnitySetUp] public IEnumerator Setup() => UniTask.ToCoroutine(async () => { - serverGo = new GameObject("server", typeof(NetworkSceneManager), typeof(ServerObjectManager), typeof(NetworkServer)); + serverGo = new GameObject("server", typeof(NetworkSceneManager), typeof(ServerObjectManager), typeof(NetworkServer), typeof(GlobalInterestManager)); clientGo = new GameObject("client", typeof(NetworkSceneManager), typeof(ClientObjectManager), typeof(NetworkClient)); testTransport = serverGo.AddComponent(); @@ -70,6 +72,9 @@ public IEnumerator Setup() => UniTask.ToCoroutine(async () => clientObjectManager.NetworkSceneManager = clientSceneManager; clientObjectManager.Start(); + interestManager = serverGo.GetComponent(); + interestManager.Start(); + ExtraSetup(); // create and register a prefab diff --git a/Assets/Tests/Runtime/ClientServer/ServerObjectManagerTests.cs b/Assets/Tests/Runtime/ClientServer/ServerObjectManagerTests.cs index daacbc331e2..4b92b37512c 100644 --- a/Assets/Tests/Runtime/ClientServer/ServerObjectManagerTests.cs +++ b/Assets/Tests/Runtime/ClientServer/ServerObjectManagerTests.cs @@ -2,6 +2,7 @@ using System.Collections; using System.Linq; using Cysharp.Threading.Tasks; +using Mirage.InterestManagement; using NSubstitute; using NUnit.Framework; using UnityEngine; @@ -20,6 +21,7 @@ public class ServerObjectManagerTest : ClientServerSetup public void SpawnObjectExposeExceptionTest() { var gameObject = new GameObject(); + gameObject.AddComponent(); ServerObjectManager comp = gameObject.AddComponent(); var obj = new GameObject(); diff --git a/Assets/Tests/Runtime/Host/NetworkIdentityTests.cs b/Assets/Tests/Runtime/Host/NetworkIdentityTests.cs index 889f88bc292..d459734d0a4 100644 --- a/Assets/Tests/Runtime/Host/NetworkIdentityTests.cs +++ b/Assets/Tests/Runtime/Host/NetworkIdentityTests.cs @@ -235,29 +235,16 @@ public IEnumerator DestroyOwnedObjectsTest() => UniTask.ToCoroutine(async () => public class NetworkIdentityStartedTests : HostSetup { - #region SetUp - - GameObject gameObject; - NetworkIdentity testIdentity; - - public override void ExtraSetup() - { - gameObject = new GameObject(); - testIdentity = gameObject.AddComponent(); - server.Started.AddListener(() => serverObjectManager.Spawn(gameObject)); - } - - public override void ExtraTearDown() - { - Object.Destroy(gameObject); - } - - #endregion - [UnityTest] public IEnumerator ClientNotNullAfterSpawnInStarted() => UniTask.ToCoroutine(async () => { + var gameObject = new GameObject(); + NetworkIdentity testIdentity = gameObject.AddComponent(); + serverObjectManager.Spawn(gameObject); + await AsyncUtil.WaitUntilWithTimeout(() => testIdentity.Client == client); + + Object.Destroy(gameObject); }); } } diff --git a/Assets/Tests/Runtime/NetworkIdentityCallbackTests.cs b/Assets/Tests/Runtime/NetworkIdentityCallbackTests.cs deleted file mode 100644 index d63ea7c7624..00000000000 --- a/Assets/Tests/Runtime/NetworkIdentityCallbackTests.cs +++ /dev/null @@ -1,108 +0,0 @@ -using System.Collections.Generic; -using NSubstitute; -using NUnit.Framework; -using UnityEngine; -using static Mirage.Tests.LocalConnections; -using Object = UnityEngine.Object; - -namespace Mirage.Tests.Runtime -{ - public class NetworkIdentityCallbackTests - { - #region test components - class RebuildEmptyObserversNetworkBehaviour : NetworkVisibility - { - public override bool OnCheckObserver(INetworkPlayer player) { return true; } - public override void OnRebuildObservers(HashSet observers, bool initialize) { } - } - - - #endregion - - GameObject gameObject; - NetworkIdentity identity; - private NetworkServer server; - private ServerObjectManager serverObjectManager; - private NetworkClient client; - private GameObject networkServerGameObject; - - IConnection tconn42; - IConnection tconn43; - - [SetUp] - public void SetUp() - { - networkServerGameObject = new GameObject(); - server = networkServerGameObject.AddComponent(); - serverObjectManager = networkServerGameObject.AddComponent(); - serverObjectManager.Server = server; - client = networkServerGameObject.AddComponent(); - - gameObject = new GameObject(); - identity = gameObject.AddComponent(); - identity.Server = server; - identity.ServerObjectManager = serverObjectManager; - - tconn42 = Substitute.For(); - tconn43 = Substitute.For(); - } - - [TearDown] - public void TearDown() - { - // set isServer is false. otherwise Destroy instead of - // DestroyImmediate is called internally, giving an error in Editor - Object.DestroyImmediate(gameObject); - Object.DestroyImmediate(networkServerGameObject); - } - - - [Test] - public void AddAllReadyServerConnectionsToObservers() - { - var connection1 = new NetworkPlayer(tconn42) { IsReady = true }; - var connection2 = new NetworkPlayer(tconn43) { IsReady = false }; - // add some server connections - server.Players.Add(connection1); - server.Players.Add(connection2); - - // add a host connection - (_, IConnection localConnection) = PipeConnection.CreatePipe(); - - server.SetLocalConnection(client, localConnection); - server.LocalPlayer.IsReady = true; - - // call OnStartServer so that observers dict is created - identity.StartServer(); - - // add all to observers. should have the two ready connections then. - identity.AddAllReadyServerConnectionsToObservers(); - Assert.That(identity.observers, Is.EquivalentTo(new[] { connection1, server.LocalPlayer })); - - // clean up - server.Disconnect(); - } - - // RebuildObservers should always add the own ready connection - // (if any). fixes https://github.com/vis2k/Mirror/issues/692 - [Test] - public void RebuildObserversAddsOwnReadyPlayer() - { - // add at least one observers component, otherwise it will just add - // all server connections - gameObject.AddComponent(); - - // add own player connection - (_, NetworkPlayer connection) = PipedConnections(); - connection.IsReady = true; - identity.ConnectionToClient = connection; - - // call OnStartServer so that observers dict is created - identity.StartServer(); - - // rebuild should at least add own ready player - identity.RebuildObservers(true); - Assert.That(identity.observers, Does.Contain(identity.ConnectionToClient)); - } - } -} diff --git a/Assets/Tests/Runtime/NetworkMatchCheckerTest.cs b/Assets/Tests/Runtime/NetworkMatchCheckerTest.cs deleted file mode 100644 index dcf31d3b24f..00000000000 --- a/Assets/Tests/Runtime/NetworkMatchCheckerTest.cs +++ /dev/null @@ -1,212 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using NUnit.Framework; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace Mirage.Tests.Runtime -{ - public class NetworkMatchCheckerTest - { - private GameObject serverGO; - private NetworkServer server; - private ServerObjectManager serverObjectManager; - private GameObject player1; - private GameObject player2; - private GameObject player3; - private NetworkMatchChecker player1MatchChecker; - private NetworkMatchChecker player2MatchChecker; - private NetworkPlayer player1Connection; - private NetworkPlayer player2Connection; - private NetworkPlayer player3Connection; - private Dictionary> matchPlayers; - - [SetUp] - public void Setup() - { - serverGO = new GameObject("Network Server", typeof(LoopbackTransport), typeof(NetworkServer), typeof(ServerObjectManager)); - - server = serverGO.GetComponent(); - serverObjectManager = serverGO.GetComponent(); - serverObjectManager.Server = server; - - player1 = new GameObject("TestPlayer1", typeof(NetworkIdentity), typeof(NetworkMatchChecker)); - player2 = new GameObject("TestPlayer2", typeof(NetworkIdentity), typeof(NetworkMatchChecker)); - player3 = new GameObject("TestPlayer3", typeof(NetworkIdentity)); - - - player1.GetComponent().Server = server; - player1.GetComponent().ServerObjectManager = serverObjectManager; - player2.GetComponent().Server = server; - player2.GetComponent().ServerObjectManager = serverObjectManager; - player3.GetComponent().Server = server; - player3.GetComponent().ServerObjectManager = serverObjectManager; - - player1MatchChecker = player1.GetComponent(); - player2MatchChecker = player2.GetComponent(); - - - player1Connection = CreateNetworkConnection(player1); - player2Connection = CreateNetworkConnection(player2); - player3Connection = CreateNetworkConnection(player3); - Dictionary> g = GetMatchPlayersDictionary(); - matchPlayers = g; - } - - static Dictionary> GetMatchPlayersDictionary() - { - Type type = typeof(NetworkMatchChecker); - FieldInfo fieldInfo = type.GetField("matchPlayers", BindingFlags.Static | BindingFlags.NonPublic); - return (Dictionary>)fieldInfo.GetValue(null); - } - - static NetworkPlayer CreateNetworkConnection(GameObject player) - { - (IConnection conn1, IConnection _) = PipeConnection.CreatePipe(); - - var connection = new NetworkPlayer(conn1) - { - Identity = player.GetComponent() - }; - connection.Identity.ConnectionToClient = connection; - connection.IsReady = true; - return connection; - } - - [TearDown] - public void TearDown() - { - Object.DestroyImmediate(player1); - Object.DestroyImmediate(player2); - Object.DestroyImmediate(player3); - - Object.DestroyImmediate(serverGO); - matchPlayers.Clear(); - matchPlayers = null; - } - - static void SetMatchId(NetworkMatchChecker target, Guid guid) - { - // set using reflection so bypass property - FieldInfo field = typeof(NetworkMatchChecker).GetField("currentMatch", BindingFlags.Instance | BindingFlags.NonPublic); - field.SetValue(target, guid); - } - - [Test] - public void OnCheckObserverShouldBeTrueForSameMatchId() - { - string guid = Guid.NewGuid().ToString(); - - SetMatchId(player1MatchChecker, new Guid(guid)); - SetMatchId(player2MatchChecker, new Guid(guid)); - - bool player1Visable = player1MatchChecker.OnCheckObserver(player1Connection); - Assert.IsTrue(player1Visable); - - bool player2Visable = player1MatchChecker.OnCheckObserver(player2Connection); - Assert.IsTrue(player2Visable); - } - - [Test] - public void OnCheckObserverShouldBeFalseForDifferentMatchId() - { - string guid1 = Guid.NewGuid().ToString(); - string guid2 = Guid.NewGuid().ToString(); - - SetMatchId(player1MatchChecker, new Guid(guid1)); - SetMatchId(player2MatchChecker, new Guid(guid2)); - - bool player1VisableToPlayer1 = player1MatchChecker.OnCheckObserver(player1Connection); - Assert.IsTrue(player1VisableToPlayer1); - - bool player2VisableToPlayer1 = player1MatchChecker.OnCheckObserver(player2Connection); - Assert.IsFalse(player2VisableToPlayer1); - - - bool player1VisableToPlayer2 = player2MatchChecker.OnCheckObserver(player1Connection); - Assert.IsFalse(player1VisableToPlayer2); - - bool player2VisableToPlayer2 = player2MatchChecker.OnCheckObserver(player2Connection); - Assert.IsTrue(player2VisableToPlayer2); - } - - [Test] - public void OnCheckObserverShouldBeFalseIfObjectDoesNotHaveNetworkMatchChecker() - { - string guid = Guid.NewGuid().ToString(); - - SetMatchId(player1MatchChecker, new Guid(guid)); - - bool player3Visable = player1MatchChecker.OnCheckObserver(player3Connection); - Assert.IsFalse(player3Visable); - } - - [Test] - public void OnCheckObserverShouldBeFalseForEmptyGuid() - { - string guid = Guid.Empty.ToString(); - - SetMatchId(player1MatchChecker, new Guid(guid)); - SetMatchId(player2MatchChecker, new Guid(guid)); - - bool player1Visable = player1MatchChecker.OnCheckObserver(player1Connection); - Assert.IsFalse(player1Visable); - - bool player2Visable = player1MatchChecker.OnCheckObserver(player2Connection); - Assert.IsFalse(player2Visable); - } - - [Test] - public void SettingMatchIdShouldRebuildObservers() - { - string guidMatch1 = Guid.NewGuid().ToString(); - - // make players join same match - player1MatchChecker.MatchId = new Guid(guidMatch1); - player2MatchChecker.MatchId = new Guid(guidMatch1); - - // check player1's observers contains player 2 - Assert.That(player1MatchChecker.Identity.observers, Contains.Item(player2MatchChecker.ConnectionToClient)); - // check player2's observers contains player 1 - Assert.That(player2MatchChecker.Identity.observers, Contains.Item(player1MatchChecker.ConnectionToClient)); - } - - [Test] - public void ChangingMatchIdShouldRebuildObservers() - { - string guidMatch1 = Guid.NewGuid().ToString(); - string guidMatch2 = Guid.NewGuid().ToString(); - - // make players join same match - player1MatchChecker.MatchId = new Guid(guidMatch1); - player2MatchChecker.MatchId = new Guid(guidMatch1); - - // make player2 join different match - player2MatchChecker.MatchId = new Guid(guidMatch2); - - // check player1's observers does NOT contain player 2 - Assert.That(player1MatchChecker.Identity.observers, !Contains.Item(player2MatchChecker.ConnectionToClient)); - // check player2's observers does NOT contain player 1 - Assert.That(player2MatchChecker.Identity.observers, !Contains.Item(player1MatchChecker.ConnectionToClient)); - } - - [Test] - public void ClearingMatchIdShouldRebuildObservers() - { - string guidMatch1 = Guid.NewGuid().ToString(); - - // make players join same match - player1MatchChecker.MatchId = new Guid(guidMatch1); - player2MatchChecker.MatchId = new Guid(guidMatch1); - - // make player 2 leave match - player2MatchChecker.MatchId = Guid.Empty; - - // check player1's observers does NOT contain player 2 - Assert.That(player1MatchChecker.Identity.observers, !Contains.Item(player2MatchChecker.ConnectionToClient)); - // check player2's observers does NOT contain player 1 - Assert.That(player2MatchChecker.Identity.observers, !Contains.Item(player1MatchChecker.ConnectionToClient)); - } - } -} From cd5fab0875530ff78519df4a579aeb1e531cb38c Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Wed, 17 Mar 2021 14:55:42 -0500 Subject: [PATCH 02/17] host mode now needs to be configured before we spawn objects --- Assets/Mirage/Runtime/NetworkServer.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Assets/Mirage/Runtime/NetworkServer.cs b/Assets/Mirage/Runtime/NetworkServer.cs index 081f9690a73..14cd67cc074 100644 --- a/Assets/Mirage/Runtime/NetworkServer.cs +++ b/Assets/Mirage/Runtime/NetworkServer.cs @@ -261,13 +261,10 @@ public UniTask StartHost(NetworkClient client) Active = true; - client.ConnectHost(this); - - // call OnStartHost AFTER SetupServer. this way we can use - // NetworkServer.Spawn etc. in there too. just like OnStartServer - // is called after the server is actually properly started. OnStartHost?.Invoke(); + client.ConnectHost(this); + logger.Log("NetworkServer StartHost"); return task; } From 93c9f2921a69f9da6c3f03e41281fb1dfe3513f5 Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Wed, 17 Mar 2021 15:08:13 -0500 Subject: [PATCH 03/17] perf: remove linq allocation --- .../InterestManagement/GlobalInterestManager.cs | 2 +- .../Runtime/InterestManagement/InterestManager.cs | 2 +- Assets/Mirage/Runtime/NetworkIdentity.cs | 14 ++++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs index bdbc23f996c..02e5fa0e44d 100644 --- a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs @@ -7,7 +7,7 @@ namespace Mirage.InterestManagement /// public class GlobalInterestManager : InterestManager { - public override IEnumerable Observers(NetworkIdentity identity) + public override IReadOnlyCollection Observers(NetworkIdentity identity) { return ServerObjectManager.Server.Players; } diff --git a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs index 3a469638382..7c0c3ca8237 100644 --- a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs @@ -48,6 +48,6 @@ public void Start() /// /// /// - public abstract IEnumerable Observers(NetworkIdentity identity); + public abstract IReadOnlyCollection Observers(NetworkIdentity identity); } } diff --git a/Assets/Mirage/Runtime/NetworkIdentity.cs b/Assets/Mirage/Runtime/NetworkIdentity.cs index 8d8bd33bd73..e2af17bb470 100644 --- a/Assets/Mirage/Runtime/NetworkIdentity.cs +++ b/Assets/Mirage/Runtime/NetworkIdentity.cs @@ -8,7 +8,6 @@ using Mirage.Logging; using Mirage.Serialization; using Mirage.InterestManagement; -using System.Linq; #if UNITY_EDITOR using UnityEditor; #if UNITY_2018_3_OR_NEWER @@ -151,22 +150,24 @@ public sealed class NetworkIdentity : MonoBehaviour /// public uint NetId { get; internal set; } + private static readonly IReadOnlyCollection emptyList = new List(); + /// /// Returns list of players that can see this object /// /// Returns empty list if the object has not been spawned yet /// Returns empty list if this is not a server object - public IEnumerable Observers + public IReadOnlyCollection Observers { get { if (ServerObjectManager == null) - return Enumerable.Empty(); + return emptyList; InterestManager interestManager = ServerObjectManager.InterestManager; if (interestManager == null) - return Enumerable.Empty(); + return emptyList; return interestManager.Observers(this); } @@ -972,7 +973,8 @@ internal void Reset() internal void ServerUpdate() { - if (Observers.Any()) + + if (Observers.Count > 0) { SendUpdateVarsMessage(); } @@ -1043,7 +1045,7 @@ internal void SendToRemoteObservers(T msg, bool includeOwner = true, int chan { if (logger.LogEnabled()) logger.Log("Server.SendToObservers id:" + typeof(T)); - if (!Observers.Any()) + if (Observers.Count == 0) return; connectionsExcludeSelf.Clear(); From f68864dd3414c7bd02b0a05376b546e5a47d6648 Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Wed, 17 Mar 2021 15:48:32 -0500 Subject: [PATCH 04/17] perf: remove enumerator allocation --- Assets/Mirage/Runtime/NetworkServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Mirage/Runtime/NetworkServer.cs b/Assets/Mirage/Runtime/NetworkServer.cs index 14cd67cc074..732a62efd8e 100644 --- a/Assets/Mirage/Runtime/NetworkServer.cs +++ b/Assets/Mirage/Runtime/NetworkServer.cs @@ -364,7 +364,7 @@ public void SendToAll(T msg, int channelId = Channel.Reliable) SendToMany(Players, msg, channelId); } - public static void SendToMany(IEnumerable players, T msg, int channelId = Channel.Reliable) + public static void SendToMany(L players, T msg, int channelId = Channel.Reliable) where L : IEnumerable { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { From 559528b4f82349ca7a836465ad76888e9d2c4f52 Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Sat, 27 Mar 2021 10:50:48 -0500 Subject: [PATCH 05/17] perf: allocation free send to observers --- .../GlobalInterestManager.cs | 19 ++++++- .../InterestManagement/InterestManager.cs | 53 +++++++++++++++++++ Assets/Mirage/Runtime/NetworkBehaviour.cs | 5 +- Assets/Mirage/Runtime/NetworkIdentity.cs | 34 +----------- Assets/Mirage/Runtime/ServerObjectManager.cs | 2 +- .../Editor/NetworkIdentityCallbackTests.cs | 1 - 6 files changed, 74 insertions(+), 40 deletions(-) diff --git a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs index 02e5fa0e44d..b754c773fa7 100644 --- a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Mirage.InterestManagement { @@ -27,5 +28,21 @@ protected override void OnSpawned(NetworkIdentity identity) ServerObjectManager.ShowForConnection(identity, player); } } + + protected override int Send(NetworkIdentity identity, ArraySegment data, int channelId = 0, INetworkPlayer skip = null) + { + int count = 0; + + foreach (INetworkPlayer player in ServerObjectManager.Server.Players) + { + if (player != skip) + { + // send to all connections, but don't wait for them + player.Send(data, channelId); + count++; + } + } + return count; + } } } \ No newline at end of file diff --git a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs index 7c0c3ca8237..817ccb1a2f5 100644 --- a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Mirage.Serialization; using UnityEngine; namespace Mirage.InterestManagement @@ -49,5 +50,57 @@ public void Start() /// /// public abstract IReadOnlyCollection Observers(NetworkIdentity identity); + + + /// + /// Send a message to all observers of an identity + /// + /// + /// + /// + public virtual void Send(NetworkIdentity identity, T msg, int channelId = Channel.Reliable, INetworkPlayer skip = null) + { + IReadOnlyCollection observers = Observers(identity); + + if (observers.Count == 0) + return; + + using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) + { + // pack message into byte[] once + MessagePacker.Pack(msg, writer); + var segment = writer.ToArraySegment(); + int count = Send(identity, segment, channelId, skip); + + if (count > 0) + NetworkDiagnostics.OnSend(msg, channelId, segment.Count, count); + } + } + + /// + /// Send a message to all observers of an identity + /// + /// Override if you wish to provide + /// an allocation free send method + /// the object that wants to send a message + /// the data to send + /// the channel to send it on + /// a player who should not receive the message + /// Total amounts of messages sent + protected virtual int Send(NetworkIdentity identity, ArraySegment data, int channelId = Channel.Reliable, INetworkPlayer skip = null) + { + int count = 0; + + foreach (INetworkPlayer player in Observers(identity)) + { + if (player != skip) + { + // send to all connections, but don't wait for them + player.Send(data, channelId); + count++; + } + } + return count; + } } } diff --git a/Assets/Mirage/Runtime/NetworkBehaviour.cs b/Assets/Mirage/Runtime/NetworkBehaviour.cs index 0b22a4104e9..f1faae3adfb 100644 --- a/Assets/Mirage/Runtime/NetworkBehaviour.cs +++ b/Assets/Mirage/Runtime/NetworkBehaviour.cs @@ -313,10 +313,7 @@ protected internal void SendRpcInternal(Type invokeClass, string rpcName, Networ payload = writer.ToArraySegment() }; - // The public facing parameter is excludeOwner in [ClientRpc] - // so we negate it here to logically align with SendToReady. - bool includeOwner = !excludeOwner; - NetIdentity.SendToRemoteObservers(message, includeOwner, channelId); + ServerObjectManager.InterestManager.Send(NetIdentity, message, channelId, excludeOwner ? ConnectionToClient : null); } protected internal void SendTargetRpcInternal(INetworkPlayer player, Type invokeClass, string rpcName, NetworkWriter writer, int channelId) diff --git a/Assets/Mirage/Runtime/NetworkIdentity.cs b/Assets/Mirage/Runtime/NetworkIdentity.cs index e2af17bb470..00d857a8113 100644 --- a/Assets/Mirage/Runtime/NetworkIdentity.cs +++ b/Assets/Mirage/Runtime/NetworkIdentity.cs @@ -1017,7 +1017,7 @@ void SendUpdateVarsMessage() if (observersWritten > 0) { varsMessage.payload = observersWriter.ToArraySegment(); - SendToRemoteObservers(varsMessage, false); + ServerObjectManager.InterestManager.Send(this, varsMessage); } // clear dirty bits only for the components that we serialized @@ -1032,38 +1032,6 @@ void SendUpdateVarsMessage() } } - static readonly List connectionsExcludeSelf = new List(100); - - /// - /// Send a message to all the remote observers - /// - /// The message type - /// the message to deliver to to clients - /// Wether the owner should receive this message too - /// the transport channel that should be used to deliver the message - internal void SendToRemoteObservers(T msg, bool includeOwner = true, int channelId = Channel.Reliable) - { - if (logger.LogEnabled()) logger.Log("Server.SendToObservers id:" + typeof(T)); - - if (Observers.Count == 0) - return; - - connectionsExcludeSelf.Clear(); - foreach (INetworkPlayer player in observers) - { - if (player == Server.LocalPlayer) - continue; - - if (includeOwner || ConnectionToClient != player) - { - connectionsExcludeSelf.Add(player); - } - } - - if (connectionsExcludeSelf.Count > 0) - NetworkServer.SendToMany(connectionsExcludeSelf, msg, channelId); - } - /// /// clear all component's dirty bits no matter what /// diff --git a/Assets/Mirage/Runtime/ServerObjectManager.cs b/Assets/Mirage/Runtime/ServerObjectManager.cs index 5d15acf08db..61e957245a8 100644 --- a/Assets/Mirage/Runtime/ServerObjectManager.cs +++ b/Assets/Mirage/Runtime/ServerObjectManager.cs @@ -604,7 +604,7 @@ void DestroyObject(NetworkIdentity identity, bool destroyServerObject) SpawnedObjects.Remove(identity.NetId); identity.ConnectionToClient?.RemoveOwnedObject(identity); - identity.SendToRemoteObservers(new ObjectDestroyMessage { netId = identity.NetId }); + InterestManager.Send(identity, new ObjectDestroyMessage { netId = identity.NetId }); if (Server.LocalClientActive) { diff --git a/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs b/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs index 36fe7e64642..ad4d3a8b83b 100644 --- a/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs +++ b/Assets/Tests/Editor/NetworkIdentityCallbackTests.cs @@ -554,7 +554,6 @@ public void Reset() // creates .observers and generates a netId identity.StartServer(); identity.ConnectionToClient = new NetworkPlayer(tconn42); - identity.ConnectionToServer = new NetworkPlayer(tconn43); // mark for reset and reset identity.Reset(); From f4fe3234b4c881aaef3baf38e39b1d85d4b9bab1 Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Sat, 27 Mar 2021 11:45:54 -0500 Subject: [PATCH 06/17] Users should not touch internal send method --- Assets/Mirage/Runtime/InterestManagement/InterestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs index 817ccb1a2f5..099b350b0fe 100644 --- a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs @@ -58,7 +58,7 @@ public void Start() /// /// /// - public virtual void Send(NetworkIdentity identity, T msg, int channelId = Channel.Reliable, INetworkPlayer skip = null) + protected internal virtual void Send(NetworkIdentity identity, T msg, int channelId = Channel.Reliable, INetworkPlayer skip = null) { IReadOnlyCollection observers = Observers(identity); From bcd708865a5dc25e3f88a0af302980860fa21f44 Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Sat, 27 Mar 2021 12:16:34 -0500 Subject: [PATCH 07/17] perf: Don't send syncvars to local player --- Assets/Mirage/Runtime/NetworkIdentity.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Mirage/Runtime/NetworkIdentity.cs b/Assets/Mirage/Runtime/NetworkIdentity.cs index 00d857a8113..502c970f866 100644 --- a/Assets/Mirage/Runtime/NetworkIdentity.cs +++ b/Assets/Mirage/Runtime/NetworkIdentity.cs @@ -1017,7 +1017,7 @@ void SendUpdateVarsMessage() if (observersWritten > 0) { varsMessage.payload = observersWriter.ToArraySegment(); - ServerObjectManager.InterestManager.Send(this, varsMessage); + ServerObjectManager.InterestManager.Send(this, varsMessage, Channel.Reliable, Server.LocalPlayer); } // clear dirty bits only for the components that we serialized From 29c5afa8ac5b5df154af819f93ace4509b76b80f Mon Sep 17 00:00:00 2001 From: Paul Pacheco Date: Sat, 27 Mar 2021 12:20:04 -0500 Subject: [PATCH 08/17] rpcs and syncvars should never make it to local player --- .../Mirage/Runtime/InterestManagement/GlobalInterestManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs index b754c773fa7..00757dc123e 100644 --- a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs @@ -35,7 +35,7 @@ protected override int Send(NetworkIdentity identity, ArraySegment data, i foreach (INetworkPlayer player in ServerObjectManager.Server.Players) { - if (player != skip) + if (player != skip && player != ServerObjectManager.Server.LocalPlayer) { // send to all connections, but don't wait for them player.Send(data, channelId); From b0a087f6c6840cc6fb3c4272e114a13672e7cf28 Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 16:27:43 +0100 Subject: [PATCH 09/17] updatiing sample scene to be used in test - increased ground to be 100x100 (-50 to +50) - moved camera out - increased scale of prefabs --- .../InterestManagement/Prefabs/Loot.prefab | 22 +-- .../InterestManagement/Prefabs/Npc.prefab | 26 +-- .../InterestManagement/Prefabs/Tank.prefab | 26 +-- .../InterestManagement/Scenes/Scene.unity | 182 +++++++++--------- .../Scenes/Scene/NavMesh.asset | Bin 5444 -> 9348 bytes .../Runtime/InterestManagement.meta | 8 + 6 files changed, 108 insertions(+), 156 deletions(-) create mode 100644 Assets/Tests/Performance/Runtime/InterestManagement.meta diff --git a/Assets/Mirage/Samples~/InterestManagement/Prefabs/Loot.prefab b/Assets/Mirage/Samples~/InterestManagement/Prefabs/Loot.prefab index fece55f83f7..c1b0e537b4c 100644 --- a/Assets/Mirage/Samples~/InterestManagement/Prefabs/Loot.prefab +++ b/Assets/Mirage/Samples~/InterestManagement/Prefabs/Loot.prefab @@ -12,7 +12,6 @@ GameObject: - component: {fileID: 8166229233224018893} - component: {fileID: 5745257042001409199} - component: {fileID: 6411109812051327673} - - component: {fileID: 8918006532685550525} m_Layer: 0 m_Name: Loot m_TagString: Untagged @@ -29,7 +28,7 @@ Transform: m_GameObject: {fileID: 1902385843019246699} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 4.5784225, y: 0.113, z: 0.19971979} - m_LocalScale: {x: 0.2, y: 0.2, z: 0.2} + m_LocalScale: {x: 0.8, y: 0.8, z: 0.8} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -57,7 +56,6 @@ MeshRenderer: m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 m_RayTracingMode: 2 - m_RayTraceProcedural: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -82,7 +80,6 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} --- !u!114 &6411109812051327673 MonoBehaviour: m_ObjectHideFlags: 0 @@ -121,20 +118,3 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] hasSpawned: 0 ---- !u!114 &8918006532685550525 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1902385843019246699} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - VisibilityRange: 3 - VisibilityUpdateInterval: 1 - ForceHidden: 0 diff --git a/Assets/Mirage/Samples~/InterestManagement/Prefabs/Npc.prefab b/Assets/Mirage/Samples~/InterestManagement/Prefabs/Npc.prefab index e0342482461..20694185b52 100644 --- a/Assets/Mirage/Samples~/InterestManagement/Prefabs/Npc.prefab +++ b/Assets/Mirage/Samples~/InterestManagement/Prefabs/Npc.prefab @@ -12,7 +12,6 @@ GameObject: - component: {fileID: 8166229233224018893} - component: {fileID: 5745257042001409199} - component: {fileID: 6411109812051327673} - - component: {fileID: 8918006532685550525} - component: {fileID: -5847114806862335758} - component: {fileID: -5831635982431117221} - component: {fileID: 1157770445662775453} @@ -32,7 +31,7 @@ Transform: m_GameObject: {fileID: 1902385843019246699} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 4.5784225, y: 0.113, z: 0.19971979} - m_LocalScale: {x: 0.1, y: 0.1, z: 0.1} + m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 0 @@ -60,7 +59,6 @@ MeshRenderer: m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 m_RayTracingMode: 2 - m_RayTraceProcedural: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -85,7 +83,6 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} --- !u!114 &6411109812051327673 MonoBehaviour: m_ObjectHideFlags: 0 @@ -106,7 +103,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 1157770445662775453} - m_TargetAssemblyTypeName: Mirage.Examples.InterestManagement.Wander, Mirage.Examples m_MethodName: StartMoving m_Mode: 1 m_Arguments: @@ -118,7 +114,6 @@ MonoBehaviour: m_BoolArgument: 0 m_CallState: 2 - m_Target: {fileID: -5847114806862335758} - m_TargetAssemblyTypeName: UnityEngine.Behaviour, UnityEngine m_MethodName: set_enabled m_Mode: 6 m_Arguments: @@ -148,23 +143,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: [] hasSpawned: 0 ---- !u!114 &8918006532685550525 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1902385843019246699} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - VisibilityRange: 3 - VisibilityUpdateInterval: 1 - ForceHidden: 0 --- !u!195 &-5847114806862335758 NavMeshAgent: m_ObjectHideFlags: 0 @@ -220,4 +198,4 @@ MonoBehaviour: agent: {fileID: -5847114806862335758} bounds: m_Center: {x: 0, y: 0.1, z: 0} - m_Extent: {x: 4.5, y: 0, z: 4.5} + m_Extent: {x: 45, y: 0, z: 45} diff --git a/Assets/Mirage/Samples~/InterestManagement/Prefabs/Tank.prefab b/Assets/Mirage/Samples~/InterestManagement/Prefabs/Tank.prefab index 8c2a216f821..efc70390cd0 100644 --- a/Assets/Mirage/Samples~/InterestManagement/Prefabs/Tank.prefab +++ b/Assets/Mirage/Samples~/InterestManagement/Prefabs/Tank.prefab @@ -15,7 +15,6 @@ GameObject: - component: {fileID: 6900008319038825817} - component: {fileID: 5194388907919410155} - component: {fileID: 114654712548978148} - - component: {fileID: -5216695118302212130} m_Layer: 0 m_Name: Tank m_TagString: Player @@ -32,7 +31,7 @@ Transform: m_GameObject: {fileID: 1916082411674582} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalScale: {x: 2, y: 2, z: 2} m_Children: - {fileID: 7831918942946891954} - {fileID: 6564220120147636086} @@ -61,7 +60,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 114654712548978148} - m_TargetAssemblyTypeName: Mirage.Examples.InterestManagement.Tank, Mirage.Examples m_MethodName: SetRandomName m_Mode: 1 m_Arguments: @@ -182,23 +180,6 @@ MonoBehaviour: rotationSpeed: 80 playerName: nameText: {fileID: 6763574687443798610} ---- !u!114 &-5216695118302212130 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1916082411674582} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 1731d8de2d0c84333b08ebe1e79f4118, type: 3} - m_Name: - m_EditorClassIdentifier: - syncMode: 0 - syncInterval: 0.1 - VisibilityRange: 2 - VisibilityUpdateInterval: 1 - ForceHidden: 0 --- !u!1 &1794225417093723422 GameObject: m_ObjectHideFlags: 0 @@ -246,7 +227,6 @@ MeshRenderer: m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 m_RayTracingMode: 2 - m_RayTraceProcedural: 0 m_RenderingLayerMask: 1 m_RendererPriority: 0 m_Materials: @@ -271,7 +251,6 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} --- !u!102 &6763574687443798610 TextMesh: serializedVersion: 3 @@ -484,6 +463,7 @@ PrefabInstance: m_SourcePrefab: {fileID: 100100000, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} --- !u!4 &7831918942946891954 stripped Transform: - m_CorrespondingSourceObject: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, type: 3} + m_CorrespondingSourceObject: {fileID: 400010, guid: 38b49695fc0a4418bbc350f2366660c5, + type: 3} m_PrefabInstance: {fileID: 7831918942947279416} m_PrefabAsset: {fileID: 0} diff --git a/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity b/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity index e498ca4de52..28ad89804fe 100644 --- a/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity +++ b/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity @@ -43,7 +43,7 @@ RenderSettings: --- !u!157 &3 LightmapSettings: m_ObjectHideFlags: 0 - serializedVersion: 12 + serializedVersion: 11 m_GIWorkflowMode: 1 m_GISettings: serializedVersion: 2 @@ -98,7 +98,7 @@ LightmapSettings: m_TrainingDataDestination: TrainingData m_LightProbeSampleCountMultiplier: 4 m_LightingDataAsset: {fileID: 0} - m_LightingSettings: {fileID: 4890085278179872738, guid: db77943d98409864e94d135eaa5ff138, type: 2} + m_UseShadowmask: 1 --- !u!196 &4 NavMeshSettings: serializedVersion: 2 @@ -118,11 +118,9 @@ NavMeshSettings: manualTileSize: 0 tileSize: 256 accuratePlacement: 0 - maxJobWorkers: 0 - preserveTilesOutsideBounds: 0 debug: m_Flags: 0 - m_NavMeshData: {fileID: 23800000, guid: 0bc607fa2e315482ebe98797e844e11f, type: 2} + m_NavMeshData: {fileID: 23800000, guid: 69a39f5f3ea8247d1ad98ba2df800270, type: 2} --- !u!1 &20677886 GameObject: m_ObjectHideFlags: 0 @@ -175,7 +173,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -288,7 +285,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 88936773} m_LocalRotation: {x: 0, y: 0.92387956, z: -0.38268343, w: 0} - m_LocalPosition: {x: 0, y: 6.5, z: 8} + m_LocalPosition: {x: 0, y: 23.8, z: 24.3} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} @@ -376,7 +373,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -444,7 +440,7 @@ GameObject: - component: {fileID: 559813746} - component: {fileID: 559813747} m_Layer: 0 - m_Name: Mobs + m_Name: NpcSpawner m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -479,7 +475,7 @@ MonoBehaviour: count: 50 bounds: m_Center: {x: 0, y: 0.1, z: 0} - m_Extent: {x: 4.5, y: 0, z: 4.5} + m_Extent: {x: 45, y: 0, z: 45} prefab: {fileID: 6411109812051327673, guid: 943ce394f88b5436ca1beb0c643806d0, type: 3} serverObjectManager: {fileID: 1282001524} --- !u!1 &597109994 @@ -534,7 +530,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -614,7 +609,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -694,7 +688,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -774,7 +767,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -884,7 +876,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 1273045292} - m_TargetAssemblyTypeName: m_MethodName: ReadyButtonHandler m_Mode: 1 m_Arguments: @@ -910,7 +901,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -985,7 +975,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1071,9 +1060,8 @@ GameObject: - component: {fileID: 1107091655} - component: {fileID: 1107091654} - component: {fileID: 1107091653} - - component: {fileID: 1107091657} m_Layer: 0 - m_Name: Ground + m_Name: Ground (100x100) m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -1094,7 +1082,6 @@ MeshRenderer: m_LightProbeUsage: 1 m_ReflectionProbeUsage: 1 m_RayTracingMode: 2 - m_RayTraceProcedural: 0 m_RenderingLayerMask: 4294967295 m_RendererPriority: 0 m_Materials: @@ -1119,7 +1106,6 @@ MeshRenderer: m_SortingLayerID: 0 m_SortingLayer: 0 m_SortingOrder: 0 - m_AdditionalVertexStreams: {fileID: 0} --- !u!64 &1107091654 MeshCollider: m_ObjectHideFlags: 0 @@ -1151,29 +1137,11 @@ Transform: m_GameObject: {fileID: 1107091652} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalPosition: {x: 0, y: 0, z: 0} - m_LocalScale: {x: 1, y: 1, z: 1} + m_LocalScale: {x: 10, y: 1, z: 10} m_Children: [] m_Father: {fileID: 0} m_RootOrder: 1 m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &1107091657 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1107091652} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: a166da186771b475ead457d93b2bd81f, type: 3} - m_Name: - m_EditorClassIdentifier: - count: 500 - bounds: - m_Center: {x: 0, y: 0.1, z: 0} - m_Extent: {x: 4.5, y: 0, z: 4.5} - prefab: {fileID: 6411109812051327673, guid: a9185e00d43994d3d937eaa684c53ff2, type: 3} - serverObjectManager: {fileID: 1282001524} --- !u!1 &1117608592 GameObject: m_ObjectHideFlags: 0 @@ -1234,7 +1202,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1305,7 +1272,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1514,7 +1480,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -1634,7 +1599,8 @@ MonoBehaviour: SceneManager: {fileID: 1282001526} ClientObjectManager: {fileID: 1282001522} ServerObjectManager: {fileID: 1282001524} - PlayerPrefab: {fileID: 114118589361100106, guid: 80382f4d3904f4926bff940b8cb6311a, type: 3} + PlayerPrefab: {fileID: 114118589361100106, guid: 80382f4d3904f4926bff940b8cb6311a, + type: 3} AutoSpawn: 1 startPositionIndex: 0 startPositions: @@ -1686,8 +1652,7 @@ MonoBehaviour: _started: m_PersistentCalls: m_Calls: - - m_Target: {fileID: 1107091657} - m_TargetAssemblyTypeName: Mirage.Examples.InterestManagement.Spawner, Mirage.Examples + - m_Target: {fileID: 2102015267} m_MethodName: Spawn m_Mode: 1 m_Arguments: @@ -1699,7 +1664,6 @@ MonoBehaviour: m_BoolArgument: 0 m_CallState: 2 - m_Target: {fileID: 559813747} - m_TargetAssemblyTypeName: Mirage.Examples.InterestManagement.Spawner, Mirage.Examples m_MethodName: Spawn m_Mode: 1 m_Arguments: @@ -1748,6 +1712,7 @@ MonoBehaviour: _unSpawned: m_PersistentCalls: m_Calls: [] + InterestManager: {fileID: 0} --- !u!114 &1282001525 MonoBehaviour: m_ObjectHideFlags: 0 @@ -1811,50 +1776,62 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Levels: + - Name: NetworkServer + level: 2 + - Name: NetworkTime + level: 2 + - Name: NetworkSceneManager + level: 2 - Name: RemoteCallHelper level: 2 - Name: NetworkBehaviour level: 2 - - Name: ClientObjectManager + - Name: ServerObjectManager level: 2 - - Name: NetworkClient + - Name: NetworkIdentity level: 2 - - Name: NetworkTime + - Name: ClientObjectManager level: 2 - Name: CharacterSpawner level: 2 - - Name: NetworkIdentity - level: 2 - - Name: ServerObjectManager + - Name: NetworkClient level: 2 - - Name: NetworkServer + - Name: PlayerSpawner level: 2 - - Name: NetworkSceneManager + - Name: SyncPositionBehaviour + level: 0 + - Name: SnapshotBuffer + level: 0 + - Name: NetworkProximityChecker level: 2 - - Name: NetworkBehaviourInspector + - Name: ZoneHandler level: 2 - - Name: PlayerSpawner + - Name: NetworkAnimator level: 2 - - Name: EnterPlayModeSettingsCheck + - Name: AdditiveNetworkManager level: 2 - Name: NetworkScenePostProcess level: 2 + - Name: NetworkWriterPool + level: 2 - Name: NetworkConnection level: 2 - Name: NetworkReaderExtensions level: 2 - - Name: NetworkWriterPool - level: 2 - Name: NetworkReaderPool level: 2 - Name: BasicAuthenticator level: 2 - Name: NetworkRigidbody level: 2 - - Name: NetworkProximityChecker + - Name: EnterPlayModeSettingsCheck level: 2 - - Name: NetworkAnimator + - Name: SceneDrawer level: 2 + - Name: NetworkBehaviourInspector + level: 2 + - Name: InterpolationTime + level: 0 - Name: NetworkSceneChecker level: 2 - Name: Reward @@ -1869,12 +1846,6 @@ MonoBehaviour: level: 4 - Name: ChatWindow level: 2 - - Name: AdditiveNetworkManager - level: 2 - - Name: ZoneHandler - level: 2 - - Name: SceneDrawer - level: 2 - Name: NetworkDiscovery level: 2 - Name: NetworkDiscoveryBase`2 @@ -1885,8 +1856,14 @@ MonoBehaviour: level: 4 - Name: WelcomeWindow level: 2 + - Name: MessageBroker + level: 2 - Name: NetworkPlayer level: 2 + - Name: SyncVarReceiver + level: 2 + - Name: NetworkWorld + level: 2 --- !u!1 &1458789072 GameObject: m_ObjectHideFlags: 0 @@ -2066,7 +2043,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 0.392} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2207,7 +2183,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2322,6 +2297,55 @@ Transform: m_Father: {fileID: 0} m_RootOrder: 2 m_LocalEulerAnglesHint: {x: 50, y: 150, z: 0} +--- !u!1 &2102015266 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2102015269} + - component: {fileID: 2102015267} + m_Layer: 0 + m_Name: LootSpawner + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &2102015267 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2102015266} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a166da186771b475ead457d93b2bd81f, type: 3} + m_Name: + m_EditorClassIdentifier: + count: 500 + bounds: + m_Center: {x: 0, y: 0.1, z: 0} + m_Extent: {x: 45, y: 0, z: 45} + prefab: {fileID: 6411109812051327673, guid: a9185e00d43994d3d937eaa684c53ff2, type: 3} + serverObjectManager: {fileID: 1282001524} +--- !u!4 &2102015269 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2102015266} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 11 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!114 &695766753322977103 MonoBehaviour: m_ObjectHideFlags: 0 @@ -2355,7 +2379,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2474,7 +2497,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 0.078431375} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2549,7 +2571,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 0.5} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2618,7 +2639,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2670,7 +2690,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2757,7 +2776,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 695766753322977103} - m_TargetAssemblyTypeName: m_MethodName: StopButtonHandler m_Mode: 1 m_Arguments: @@ -2802,7 +2820,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -2889,7 +2906,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 695766753322977103} - m_TargetAssemblyTypeName: m_MethodName: StartClientButtonHandler m_Mode: 1 m_Arguments: @@ -2934,7 +2950,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -3031,7 +3046,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -3111,7 +3125,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -3198,7 +3211,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 695766753322977103} - m_TargetAssemblyTypeName: m_MethodName: StartServerOnlyButtonHandler m_Mode: 1 m_Arguments: @@ -3224,7 +3236,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -3304,7 +3315,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 695766753322977103} - m_TargetAssemblyTypeName: m_MethodName: OnNetworkAddressInputUpdate m_Mode: 1 m_Arguments: @@ -3426,7 +3436,6 @@ MonoBehaviour: m_PersistentCalls: m_Calls: - m_Target: {fileID: 695766753322977103} - m_TargetAssemblyTypeName: m_MethodName: StartHostButtonHandler m_Mode: 1 m_Arguments: @@ -3471,7 +3480,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 1, g: 1, b: 1, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -3509,7 +3517,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: @@ -3701,7 +3708,6 @@ MonoBehaviour: m_Material: {fileID: 0} m_Color: {r: 0.19607843, g: 0.19607843, b: 0.19607843, a: 1} m_RaycastTarget: 1 - m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} m_Maskable: 1 m_OnCullStateChanged: m_PersistentCalls: diff --git a/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene/NavMesh.asset b/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene/NavMesh.asset index 3acffc80e7884117f6ba1c24763179df0d46214e..410cbc84af9ba1822ab371a73e525981cb393c07 100644 GIT binary patch literal 9348 zcmc(kU2t7h7035YZW2W-4T6H89uTl#slEN6tHXMA#o&Pc~856<|c56+}@d|}WR@xdAO!5JK%93C7Wd@%n1YwvaL`N+v_ z>uC3I*4bzO_TFp%_u3yf#h4p+8gs`>#+V!N-z45<+t$jSEjzYUb{wymf3L2tmP#o6 zJIU(m_pd$FIP=Q&za5Eg9=_|`<9~V`r8E7;^bsTNGA2TkRr!d-iYb|rIoEHZpOs8h zMhUy*qlx@le2kY(#5em(^FH%u^nE+Z*&Z&zBUqbCXt4$Te;%J7!ef0z7Q(Xs9eDe$ z{{bnBF=)E~LE%wcA>02@j+e~KeI{zV{yB#A#{c15`}Fv)$?=kzfWEgOn)CY+@`zq+ z!uU!R%nu)O&S9yV)rnG&(c@%BGfrsPXkmDuud$c`>a`t~6-op`$ zOIiOLQ9it)l)lpbhsnEG_+$8{fA)VpdDN{?GG+0!4Sya|1(|KmAcHXW2bi-+1ik>dl>{sokC{%$JZuQ`5m0sn#HpDf@%a{QJ8e$Me* z3;0hR|5O40x#OQM;1?YKOaXt#aj$^?&hgs{_#YkTK2NU?JHLN*{Ido81IOK&M0e{Z%Ed~4y$G=d(f9&|yH8{_2od2S~vIaj3e!=l=YjC!I z$MNk2{11-vtk2F5+yBLJ#wg4G0k#1b4_@Xz@(9Kyo?kp4Zg3p;oY`1a$~N|VycL}1 z({A!8$Bd&Z=O#)Tkg;CvUwll+l4wj`yUYQ!P-=YEe+194iC}FaPu}07 zC{A-bzfz4;v@Ux9Hcd;g51JUhQW`sVzy{{!TaYmArPKTFR4mvTIP|4fiq zVO+}IKfFiN{s$#~^w0P`B;13wsbq#y@%u80)A6%h<9DclYy2M0aeKc$>+~Hak6>Iv zd`j4}@$ZXAP`;kNNpfwBx9X=p#{bbAXQ_$Kz(3dbRE`hG{Ja6q`I#2(!P>dc{6Msu4=l|;{PS3yPs^2f*s{dGy zTmQdw{^xQ$?SH<2tN);YtN-IUJ|ySY1^DMmT@ViA689(1w_iEV->K>Ov**{Z!Fj&a z$RpPnuk7z<#32*E^!;#xyxSb@`^|gkTjN*HaeF`f4RyGG8p1tTn|S^vw*6{jKNQX<=SmgYiwqhku6{ zgWPJQP zGMNthPd^-V7RUV1HCaf*KyyKxbsTfdnN9^g8tq3N0)2$`RO1GYt4mDS7W-^UkIAv zkyA^YB*{LW^6fUU&=$x_;Yj1Z9fbq>;7EO zz(`Zt#)4zZ3$eg?enIAex-W9=up0hS$HZ9)=TfUv3o#;d5+~AW69(~=E;rg*ZqBo4KL!}Ik&zV`B6GMkpXz3Gh9#U7OvOo4GkDKF za{M^`9jY}?bj-+d*h&;Qztf@LW`E<&c~}>s#w?pKb||ycDj z!qgX;NHQ?$TfgaZQ|avO3vqQfE>dnQGR& z)yO$Gzjtk&<%o4JMJMYa4y7y6$+o?8vJR5Qb2O=wK(#^hXf|)P**aHKC+D%3PL5x7 zV(q4MCbi8R9glTt-o;bO*U*V>%Mr|F#B`$2%`C89p_h&Di94q>J%e`fP+WuFnNo_3Sy0y&a zEw}sAw$JJ;N34IT`;%1%ZFM$VHzjqlVlSPpGtr5$%DS~>D^E!rP&BfF1PmYc2HmObbB#Gv!Q|mCF(P;*wa)j!ap_BVls`QPkM?Yl^) zjRWr$o7}x3I+NN+-Ms>qTF;27?%S)gZaE%JMLHc9ozSKCis&R$ZDiTJ_IKf&E ziga@Pz%HKg{i*ScwI%lCsOH(P>SsQ)ZvU_QQ?(Z9)ctA4tM})G>XbEUb#?cr?n$=M zJnJNNns|41=h)5#?Rxu@|3|NPN}fYJYkTR$STCYip0^mM{e8>dMee+fb&_#?T0N=t zEOl)A?*2q|C@n{L$7_jsoANpx!2NmoI@z|DPS?NaZHbA zI^9@ZJoWyJ;~8tyJ;}G`t@iHuL~r^#fpc{E@#Ot^Y4K$LNDtzv;xF9M-@NHQ9(ed-Ihy{i`%lT1-X>ARODiv?oQj0z0}=VXu-<} z0t$u)W8#xZNrag8!NezhFex#<5b#BOFi{^&Fg_U`j1N9o&;Pr1=c7tv9GIQ+{pQU7 zJLi0tnG#jsAX<mN3i3(^eM}e6 zJ;pyA&uqgZ)Xs5^b8x7`z2Lzt#1n~eUO2&#b0iL4F7jQ%&miCXgpTC<*!LAa5yxD^ zBlI2n?%+0b?&oVwfLO!&)!-B0VSOHBjI-be_zHdK%mWX=qe6d>+u#ovUJ;6aK6o7d zm7(|-fb$7H%5m!WA2d8l1-4J}i5MR;yh8Y&;x_VKXz>e*FS7UtiZ8bKM~W}8_!Y&M zTKrSRAGY}CiZ8SHRmC5%_%+3AE&i?I%Pszc;+XHUZn6%)DE^qmu|83s$1VP+;wvm3 zWoP)WwD?@bpHRGvy%sWC%jbG#tN5%A@T^=%3FeretHJpMzr=H=L-92hKdd;`YpMUB z;!jz;p!iygzoB@Y#V;!Uw8cMGyuO5EKjHmH#2+i+mzZBwyrG1{|C-{B7XMyx>^V9w z`2VapYNz?{%;xgO#uwTE9>6Xa^L)PIykAmv99*vJrOdJJnv8#VU2ih};dT8CIG@m8 z%^FyDSVNl)kJ2q(j~n?O_MR<**Rp?w7{@qsjPF*9wj=Z`AM_!eoyt*x}^V)B5omY?H zQvXAx|AOIR{R0-)`Y&2s>mM{+)@@YP?GSiyXWb5i$EWI}-@iw|`9!{-um%LtBo zhWDkc#dW?pi|c%c443-1mHw-ShxPLo*ZTNYsivuTw7ze6RE+x{tdDvY1xJ0NbbiKQ*X#6zpop_PG!OBeMIwI5 zbzZMoT<7(=;Zk3((>Dwc>%VDntshui>%V1qgl_TsqMq}@JUeB${I1aNqth1G`fpoY z>z}dsX4c2JoHd;L<+^QUj`?=Z@NmEHSX}q}uElk~=M9gD^~HY!h<@?iiery+Y`0q& zOgO$n9UXptOKZyWbNSX`-^~`hTy`5}dfU9TyCcCyhvN^jA^bY>ZokvFBU|vDY|@3B zlImvfg4RVtXlHs&H|CMSNA>ql|QpU@6x&u5I&3V_M zjFT-o>FsVh-Q}HdDX9&~QE&Y@hv^Eo0K=9Pbfd^ewWysR2&>5B2@i7?ercYEBt?XKrj&qxj ziTL=~`HAtdF??%_!?xvp=>uDC_q?Oo$6ZSDE@#vW#D%h%HLX_;Y62 zl-s{prFp{b?s*C^k!R2T%kk1YaYyIId2rq`XKl;eq|Y>Y^3&0Pe`b^?{Gzn@Kjo=& zEbZ%`#}i&8#uNEsJkdsO$V=PuIyKJ7Z^{R+Z#kY6R0i Date: Mon, 29 Mar 2021 16:28:05 +0100 Subject: [PATCH 10/17] Performance test setup for IM --- .../InterestManagementPerformanceBase.cs | 85 +++++++++++++++++++ .../InterestManagementPerformanceBase.cs.meta | 11 +++ 2 files changed, 96 insertions(+) create mode 100644 Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs create mode 100644 Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs.meta diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs new file mode 100644 index 00000000000..7a198130a8f --- /dev/null +++ b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs @@ -0,0 +1,85 @@ +using System.Collections; +using Cysharp.Threading.Tasks; +using NUnit.Framework; +using UnityEditor.SceneManagement; +using UnityEngine; +using UnityEngine.SceneManagement; +using UnityEngine.TestTools; +using static UnityEngine.Object; + +namespace Mirage.Tests.Performance.Runtime +{ + [Category("Performance"), Category("InterestManagement")] + public class InterestManagementPerformanceBase + { + const string testScene = "Assets/Examples/InterestManagement/Scenes/Scene.unity"; + const int clientCount = 10; + + private NetworkServer server; + private LoopbackTransport transport; + private UniTask serverTask; + IConnection[] clients; + + [UnitySetUp] + public IEnumerator Setup() + { + yield return EditorSceneManager.LoadSceneAsyncInPlayMode(testScene, new LoadSceneParameters(LoadSceneMode.Single)); + + // wait 1 frame for start to be called + yield return null; + + server = FindObjectOfType(); + transport = server.gameObject.AddComponent(); + server.Transport = transport; + + bool started = false; + server.MaxConnections = clientCount; + + yield return SetupInterestManagement(server); + + server.Started.AddListener(() => started = true); + serverTask = server.ListenAsync(); + + // wait for start + while (!started) { yield return null; } + + // connect N clients + clients = new IConnection[clientCount]; + for (int i = 0; i < clientCount; i++) + { + UniTask.Awaiter task = transport.ConnectAsync(default).GetAwaiter(); + // wait for connect + while (!task.IsCompleted) { yield return null; } + clients[i] = task.GetResult(); + } + } + + /// + /// Called before server starts + /// + /// + /// + protected virtual IEnumerator SetupInterestManagement(NetworkServer server) { yield return null; } + + + [UnityTearDown] + public IEnumerator TearDown() + { + server.Disconnect(); + yield return serverTask.ToCoroutine(); + + // open new scene so that old one is destroyed + SceneManager.CreateScene("empty", new CreateSceneParameters(LocalPhysicsMode.None)); + yield return EditorSceneManager.UnloadSceneAsync(testScene); + + yield return new WaitForSeconds(5); + + } + + [UnityTest] + public IEnumerator RunsWithoutErrors() + { + yield return new WaitForSeconds(5); + } + } +} diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs.meta b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs.meta new file mode 100644 index 00000000000..00a3f8c04bf --- /dev/null +++ b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cdeed5527b67c0d409c8cec60b474974 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From f4a95af9083c39f613c033f912026ebbebb57221 Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 16:32:08 +0100 Subject: [PATCH 11/17] GlobalInterestManagement test --- ...GlobalInterestManagementPerformanceTest.cs | 16 ++++++++++++++ ...lInterestManagementPerformanceTest.cs.meta | 11 ++++++++++ .../InterestManagementPerformanceBase.cs | 21 ++++++++++++++----- 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs create mode 100644 Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs.meta diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs b/Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs new file mode 100644 index 00000000000..f13f0b3975a --- /dev/null +++ b/Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs @@ -0,0 +1,16 @@ +using System.Collections; +using Mirage.InterestManagement; + +namespace Mirage.Tests.Performance.Runtime +{ + public class GlobalInterestManagementPerformanceTest : InterestManagementPerformanceBase + { + protected override IEnumerator SetupInterestManagement(NetworkServer server) + { + server.gameObject.AddComponent(); + + // wait frame for setup + yield return null; + } + } +} diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs.meta b/Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs.meta new file mode 100644 index 00000000000..79ee9dfcd5c --- /dev/null +++ b/Assets/Tests/Performance/Runtime/InterestManagement/GlobalInterestManagementPerformanceTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: acb1d132c83ee844397a28c8809f1970 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs index 7a198130a8f..e488ee947e3 100644 --- a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs +++ b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs @@ -1,5 +1,6 @@ using System.Collections; using Cysharp.Threading.Tasks; +using Mirage.InterestManagement; using NUnit.Framework; using UnityEditor.SceneManagement; using UnityEngine; @@ -10,7 +11,7 @@ namespace Mirage.Tests.Performance.Runtime { [Category("Performance"), Category("InterestManagement")] - public class InterestManagementPerformanceBase + public abstract class InterestManagementPerformanceBase { const string testScene = "Assets/Examples/InterestManagement/Scenes/Scene.unity"; const int clientCount = 10; @@ -35,6 +36,10 @@ public IEnumerator Setup() bool started = false; server.MaxConnections = clientCount; + removeExistingIM(); + // wait frame for destroy + yield return null; + yield return SetupInterestManagement(server); server.Started.AddListener(() => started = true); @@ -54,12 +59,21 @@ public IEnumerator Setup() } } + private void removeExistingIM() + { + InterestManager[] existing = server.GetComponents(); + for (int i = 0; i < existing.Length; i++) + { + Destroy(existing[i]); + } + } + /// /// Called before server starts /// /// /// - protected virtual IEnumerator SetupInterestManagement(NetworkServer server) { yield return null; } + protected abstract IEnumerator SetupInterestManagement(NetworkServer server); [UnityTearDown] @@ -71,9 +85,6 @@ public IEnumerator TearDown() // open new scene so that old one is destroyed SceneManager.CreateScene("empty", new CreateSceneParameters(LocalPhysicsMode.None)); yield return EditorSceneManager.UnloadSceneAsync(testScene); - - yield return new WaitForSeconds(5); - } [UnityTest] From 5a6750563a6d7b18bd239756d8d4f0ded1ce3ee8 Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 16:32:19 +0100 Subject: [PATCH 12/17] format --- Assets/Mirage/Runtime/InterestManagement/InterestManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs index 099b350b0fe..268f07196f9 100644 --- a/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/InterestManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using Mirage.Serialization; using UnityEngine; @@ -58,7 +58,7 @@ public void Start() /// /// /// - protected internal virtual void Send(NetworkIdentity identity, T msg, int channelId = Channel.Reliable, INetworkPlayer skip = null) + protected internal virtual void Send(NetworkIdentity identity, T msg, int channelId = Channel.Reliable, INetworkPlayer skip = null) { IReadOnlyCollection observers = Observers(identity); From cb835666f12567387cdb9aeb2d7c9e46c11961a8 Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 17:02:33 +0100 Subject: [PATCH 13/17] DistanceConstantSight IM --- .../DistanceConstantSightInterestManager.cs | 106 ++++++++++++++++++ ...stanceConstantSightInterestManager.cs.meta | 11 ++ .../GlobalInterestManager.cs | 4 +- ...stanceInterestManagementPerformanceTest.cs | 16 +++ ...eInterestManagementPerformanceTest.cs.meta | 11 ++ .../InterestManagementPerformanceBase.cs | 38 +++++++ 6 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs create mode 100644 Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs.meta create mode 100644 Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs create mode 100644 Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs.meta diff --git a/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs new file mode 100644 index 00000000000..1c2131900c6 --- /dev/null +++ b/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using UnityEngine; + +namespace Mirage.InterestManagement +{ + /// + /// Brute force distance check on all objects, all players have same sight distance + /// + public class DistanceConstantSightInterestManager : InterestManager + { + public float SightDistnace = 10; + + List temp = new List(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + static bool fastInDistanceXZ(Vector3 a, Vector3 b, float sqRange) + { + float dx = a.x - b.x; + float dz = a.z - b.z; + float sqDist = dx * dx + dz * dz; + return sqDist < sqRange; + } + + public override IReadOnlyCollection Observers(NetworkIdentity identity) + { + if (identity == null) { return Array.Empty(); } + + Vector3 A = identity.transform.position; + float sqRange = SightDistnace * SightDistnace; + temp.Clear(); + foreach (INetworkPlayer player in ServerObjectManager.Server.Players) + { + if (player.Identity == null) { continue; } + + Vector3 B = player.Identity.transform.position; + + if (fastInDistanceXZ(A, B, sqRange)) + { + temp.Add(player); + } + } + + return temp; + } + + + protected override void OnAuthenticated(INetworkPlayer player) + { + // no owned object, nothing to see + if (player.Identity == null) { return; } + + Vector3 B = player.Identity.transform.position; + float sqRange = SightDistnace * SightDistnace; + + foreach (NetworkIdentity identity in ServerObjectManager.SpawnedObjects.Values) + { + Vector3 A = identity.transform.position; + + if (fastInDistanceXZ(A, B, sqRange)) + { + ServerObjectManager.ShowForConnection(identity, player); + } + } + } + + protected override void OnSpawned(NetworkIdentity identity) + { + // does object have owner? + if (identity.ConnectionToClient != null) + { + OnAuthenticated(identity.ConnectionToClient); + } + + Vector3 A = identity.transform.position; + float sqRange = SightDistnace * SightDistnace; + + foreach (INetworkPlayer player in ServerObjectManager.Server.Players) + { + Vector3 B = player.Identity.transform.position; + + if (fastInDistanceXZ(A, B, sqRange)) + { + ServerObjectManager.ShowForConnection(identity, player); + } + } + } + + protected override int Send(NetworkIdentity identity, ArraySegment data, int channelId = 0, INetworkPlayer skip = null) + { + int count = 0; + + foreach (INetworkPlayer player in Observers(identity)) + { + if (player != skip && player != ServerObjectManager.Server.LocalPlayer) + { + // send to all connections, but don't wait for them + player.Send(data, channelId); + count++; + } + } + return count; + } + } +} diff --git a/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs.meta b/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs.meta new file mode 100644 index 00000000000..fe2ca35c766 --- /dev/null +++ b/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 148b6d8bf29cc414d84e02409895ffbe +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs index 00757dc123e..6751af4ef1d 100644 --- a/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/GlobalInterestManager.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; namespace Mirage.InterestManagement @@ -45,4 +45,4 @@ protected override int Send(NetworkIdentity identity, ArraySegment data, i return count; } } -} \ No newline at end of file +} diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs b/Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs new file mode 100644 index 00000000000..d5caf287bc2 --- /dev/null +++ b/Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs @@ -0,0 +1,16 @@ +using System.Collections; +using Mirage.InterestManagement; + +namespace Mirage.Tests.Performance.Runtime +{ + public class DistanceInterestManagementPerformanceTest : InterestManagementPerformanceBase + { + protected override IEnumerator SetupInterestManagement(NetworkServer server) + { + server.gameObject.AddComponent(); + + // wait frame for setup + yield return null; + } + } +} diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs.meta b/Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs.meta new file mode 100644 index 00000000000..e32abdbf496 --- /dev/null +++ b/Assets/Tests/Performance/Runtime/InterestManagement/DistanceInterestManagementPerformanceTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fe1105f348351c74daf737341e020cb4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs index e488ee947e3..dd08912a7b8 100644 --- a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs +++ b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs @@ -1,3 +1,4 @@ +using System; using System.Collections; using Cysharp.Threading.Tasks; using Mirage.InterestManagement; @@ -10,6 +11,43 @@ namespace Mirage.Tests.Performance.Runtime { + [Ignore("NotImplemented")] + public class SpatialHashInterestManagementPerformanceTest : InterestManagementPerformanceBase + { + protected override IEnumerator SetupInterestManagement(NetworkServer server) + { + throw new NotImplementedException(); + //server.gameObject.AddComponent(); + + // wait frame for setup + yield return null; + } + } + [Ignore("NotImplemented")] + public class GridAndDistanceInterestManagementPerformanceTest : InterestManagementPerformanceBase + { + protected override IEnumerator SetupInterestManagement(NetworkServer server) + { + throw new NotImplementedException(); + //server.gameObject.AddComponent(); + + // wait frame for setup + yield return null; + } + } + + [Ignore("NotImplemented")] + public class QuadTreeInterestManagementPerformanceTest : InterestManagementPerformanceBase + { + protected override IEnumerator SetupInterestManagement(NetworkServer server) + { + throw new NotImplementedException(); + //server.gameObject.AddComponent(); + + // wait frame for setup + yield return null; + } + } [Category("Performance"), Category("InterestManagement")] public abstract class InterestManagementPerformanceBase { From 462ceb2d220e079ca0bac5393799d4a9409b3dbf Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 17:30:16 +0100 Subject: [PATCH 14/17] trying to fiix wander error --- .../Samples~/InterestManagement/Scripts/Wander.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Assets/Mirage/Samples~/InterestManagement/Scripts/Wander.cs b/Assets/Mirage/Samples~/InterestManagement/Scripts/Wander.cs index 9f3d333b66e..5b2ce0ce6a8 100644 --- a/Assets/Mirage/Samples~/InterestManagement/Scripts/Wander.cs +++ b/Assets/Mirage/Samples~/InterestManagement/Scripts/Wander.cs @@ -1,5 +1,4 @@ -using System.Collections; -using System.Collections.Generic; +using System.Collections; using UnityEngine; using UnityEngine.AI; @@ -10,11 +9,17 @@ public class Wander : MonoBehaviour public NavMeshAgent agent; public Bounds bounds; + private Coroutine coroutine; // Start is called before the first frame update public void StartMoving() { - StartCoroutine(Move()); + coroutine = StartCoroutine(Move()); + } + + private void OnDestroy() + { + StopCoroutine(coroutine); } public IEnumerator Move() @@ -31,6 +36,7 @@ public IEnumerator Move() agent.destination = position; yield return new WaitForSeconds(Random.Range(1.0f, 5.0f)); + if (!agent.isActiveAndEnabled) { yield break; } } } } From 665609f7ed699e3102cf2e01e09afd2823b0510f Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 17:30:29 +0100 Subject: [PATCH 15/17] adding spawn counts to test --- .../InterestManagementPerformanceBase.cs | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs index dd08912a7b8..5532d2df069 100644 --- a/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs +++ b/Assets/Tests/Performance/Runtime/InterestManagement/InterestManagementPerformanceBase.cs @@ -1,8 +1,10 @@ using System; using System.Collections; using Cysharp.Threading.Tasks; +using Mirage.Examples.InterestManagement; using Mirage.InterestManagement; using NUnit.Framework; +using Unity.PerformanceTesting; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; @@ -52,7 +54,12 @@ protected override IEnumerator SetupInterestManagement(NetworkServer server) public abstract class InterestManagementPerformanceBase { const string testScene = "Assets/Examples/InterestManagement/Scenes/Scene.unity"; - const int clientCount = 10; + const string NpcSpawnerName = "NpcSpawner"; + const string LootSpawnerName = "LootSpawner"; + const int clientCount = 100; + const int stationaryCount = 3500; + const int movingCount = 500; + private NetworkServer server; private LoopbackTransport transport; @@ -66,6 +73,9 @@ public IEnumerator Setup() // wait 1 frame for start to be called yield return null; + GameObject.Find(LootSpawnerName).GetComponent().count = stationaryCount; + GameObject.Find(NpcSpawnerName).GetComponent().count = movingCount; + server = FindObjectOfType(); transport = server.gameObject.AddComponent(); @@ -130,5 +140,23 @@ public IEnumerator RunsWithoutErrors() { yield return new WaitForSeconds(5); } + + [UnityTest, Performance] + public IEnumerator FramePerformance() + { + SampleGroup[] sampleGroups = + { + new SampleGroup("Observers", SampleUnit.Microsecond), + new SampleGroup("OnAuthenticated", SampleUnit.Microsecond), + new SampleGroup("OnSpawned", SampleUnit.Microsecond), + }; + + yield return Measure.Frames() + .ProfilerMarkers(sampleGroups) + .WarmupCount(5) + .MeasurementCount(300) + .Run(); + } + } } From e2d89f3fae986a90d1e59c7732e969633119dc9f Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 17:30:43 +0100 Subject: [PATCH 16/17] bad distance check as baseline --- .../DistanceConstantSightInterestManager.cs | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs b/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs index 1c2131900c6..cc04ce1588d 100644 --- a/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs +++ b/Assets/Mirage/Runtime/InterestManagement/DistanceConstantSightInterestManager.cs @@ -10,7 +10,90 @@ namespace Mirage.InterestManagement /// public class DistanceConstantSightInterestManager : InterestManager { + private class NetIdComparer : IEqualityComparer + { + public bool Equals(NetworkIdentity x, NetworkIdentity y) + { + return x.NetId == y.NetId; + } + + public int GetHashCode(NetworkIdentity obj) + { + return (int)obj.NetId; + } + } + public float SightDistnace = 10; + public float UpdateInterval = 0; + float nextUpdate = 0; + + public void Update() + { + if (nextUpdate < Time.time) + { + rebuild(); + nextUpdate += UpdateInterval; + } + } + + Dictionary> lastFrame = new Dictionary>(); + Dictionary> nextFrame = new Dictionary>(); + + private void rebuild() + { + foreach (NetworkIdentity identity in ServerObjectManager.SpawnedObjects.Values) + { + IReadOnlyCollection observers = Observers(identity); + foreach (INetworkPlayer player in observers) + { + if (!nextFrame.TryGetValue(player, out HashSet nextSet)) + { + nextSet = new HashSet(new NetIdComparer()); + nextFrame[player] = nextSet; + } + + nextSet.Add(identity); + } + } + + foreach (INetworkPlayer player in ServerObjectManager.Server.Players) + { + if (!lastFrame.TryGetValue(player, out HashSet lastSet)) + { + lastSet = new HashSet(new NetIdComparer()); + lastFrame[player] = lastSet; + } + if (!nextFrame.TryGetValue(player, out HashSet nextSet)) + { + nextSet = new HashSet(new NetIdComparer()); + nextFrame[player] = nextSet; + } + + + foreach (NetworkIdentity identity in lastSet) + { + if (!nextSet.Contains(identity)) + { + ServerObjectManager.HideForConnection(identity, player); + } + } + foreach (NetworkIdentity identity in nextSet) + { + if (!lastSet.Contains(identity)) + { + ServerObjectManager.ShowForConnection(identity, player); + } + } + + // reset collections + lastSet.Clear(); + foreach (NetworkIdentity identity in nextSet) + { + lastSet.Add(identity); + } + nextSet.Clear(); + } + } List temp = new List(); From ec8854614ff00aea54090db1e9a1744c741204f6 Mon Sep 17 00:00:00 2001 From: James Frowen Date: Mon, 29 Mar 2021 18:00:33 +0100 Subject: [PATCH 17/17] adding distance IM --- .../InterestManagement/Scenes/Scene.unity | 32 ++++++++++++++----- 1 file changed, 24 insertions(+), 8 deletions(-) diff --git a/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity b/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity index 28ad89804fe..2d170d793b7 100644 --- a/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity +++ b/Assets/Mirage/Samples~/InterestManagement/Scenes/Scene.unity @@ -1524,6 +1524,7 @@ GameObject: - component: {fileID: 1282001522} - component: {fileID: 1282001524} - component: {fileID: 1282001527} + - component: {fileID: 1282001528} m_Layer: 0 m_Name: NetworkManager m_TagString: Untagged @@ -1776,25 +1777,27 @@ MonoBehaviour: m_Name: m_EditorClassIdentifier: Levels: - - Name: NetworkServer + - Name: NetworkClient level: 2 - Name: NetworkTime level: 2 - - Name: NetworkSceneManager - level: 2 - Name: RemoteCallHelper level: 2 - Name: NetworkBehaviour level: 2 - - Name: ServerObjectManager + - Name: CharacterSpawner + level: 2 + - Name: NetworkSceneManager level: 2 - Name: NetworkIdentity level: 2 - Name: ClientObjectManager level: 2 - - Name: CharacterSpawner + - Name: ServerObjectManager level: 2 - - Name: NetworkClient + - Name: NetworkServer + level: 2 + - Name: NetworkBehaviourInspector level: 2 - Name: PlayerSpawner level: 2 @@ -1828,8 +1831,6 @@ MonoBehaviour: level: 2 - Name: SceneDrawer level: 2 - - Name: NetworkBehaviourInspector - level: 2 - Name: InterpolationTime level: 0 - Name: NetworkSceneChecker @@ -1864,6 +1865,21 @@ MonoBehaviour: level: 2 - Name: NetworkWorld level: 2 +--- !u!114 &1282001528 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1282001517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 148b6d8bf29cc414d84e02409895ffbe, type: 3} + m_Name: + m_EditorClassIdentifier: + ServerObjectManager: {fileID: 0} + SightDistnace: 10 + UpdateInterval: 0 --- !u!1 &1458789072 GameObject: m_ObjectHideFlags: 0