123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- // interest management component for custom solutions like
- // distance based, spatial hashing, raycast based, etc.
- using System.Collections.Generic;
- using UnityEngine;
- namespace Mirror
- {
- [DisallowMultipleComponent]
- [HelpURL("https://mirror-networking.gitbook.io/docs/guides/interest-management")]
- public abstract class InterestManagement : InterestManagementBase
- {
- // allocate newObservers helper HashSet
- readonly HashSet<NetworkConnectionToClient> newObservers =
- new HashSet<NetworkConnectionToClient>();
- // rebuild observers for the given NetworkIdentity.
- // Server will automatically spawn/despawn added/removed ones.
- // newObservers: cached hashset to put the result into
- // initialize: true if being rebuilt for the first time
- //
- // IMPORTANT:
- // => global rebuild would be more simple, BUT
- // => local rebuild is way faster for spawn/despawn because we can
- // simply rebuild a select NetworkIdentity only
- // => having both .observers and .observing is necessary for local
- // rebuilds
- //
- // in other words, this is the perfect solution even though it's not
- // completely simple (due to .observers & .observing).
- //
- // Mirror maintains .observing automatically in the background. best of
- // both worlds without any worrying now!
- public abstract void OnRebuildObservers(NetworkIdentity identity, HashSet<NetworkConnectionToClient> newObservers);
- // helper function to trigger a full rebuild.
- // most implementations should call this in a certain interval.
- // some might call this all the time, or only on team changes or
- // scene changes and so on.
- //
- // IMPORTANT: check if NetworkServer.active when using Update()!
- [ServerCallback]
- protected void RebuildAll()
- {
- foreach (NetworkIdentity identity in NetworkServer.spawned.Values)
- {
- NetworkServer.RebuildObservers(identity, false);
- }
- }
- public override void Rebuild(NetworkIdentity identity, bool initialize)
- {
- // clear newObservers hashset before using it
- newObservers.Clear();
- // not force hidden?
- if (identity.visible != Visibility.ForceHidden)
- {
- OnRebuildObservers(identity, newObservers);
- }
- // IMPORTANT: AFTER rebuilding add own player connection in any case
- // to ensure player always sees himself no matter what.
- // -> OnRebuildObservers might clear observers, so we need to add
- // the player's own connection AFTER. 100% fail safe.
- // -> 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 (identity.connectionToClient != null)
- {
- newObservers.Add(identity.connectionToClient);
- }
- bool changed = false;
- // add all newObservers that aren't in .observers yet
- foreach (NetworkConnectionToClient conn in newObservers)
- {
- // only add ready connections.
- // otherwise the player might not be in the world yet or anymore
- if (conn != null && conn.isReady)
- {
- if (initialize || !identity.observers.ContainsKey(conn.connectionId))
- {
- // new observer
- conn.AddToObserving(identity);
- // Debug.Log($"New Observer for {gameObject} {conn}");
- changed = true;
- }
- }
- }
- // remove all old .observers that aren't in newObservers anymore
- foreach (NetworkConnectionToClient conn in identity.observers.Values)
- {
- if (!newObservers.Contains(conn))
- {
- // removed observer
- conn.RemoveFromObserving(identity, false);
- // Debug.Log($"Removed Observer for {gameObject} {conn}");
- changed = true;
- }
- }
- // copy new observers to observers
- if (changed)
- {
- identity.observers.Clear();
- foreach (NetworkConnectionToClient conn in newObservers)
- {
- if (conn != null && conn.isReady)
- identity.observers.Add(conn.connectionId, conn);
- }
- }
- // special case for host mode: we use SetHostVisibility to hide
- // NetworkIdentities that aren't in observer range from host.
- // this is what games like Dota/Counter-Strike do too, where a host
- // does NOT see all players by default. they are in memory, but
- // hidden to the host player.
- //
- // this code is from UNET, it's a bit strange but it works:
- // * it hides newly connected identities in host mode
- // => that part was the intended behaviour
- // * it hides ALL NetworkIdentities in host mode when the host
- // connects but hasn't selected a character yet
- // => this only works because we have no .localConnection != null
- // check. at this stage, localConnection is null because
- // StartHost starts the server first, then calls this code,
- // then starts the client and sets .localConnection. so we can
- // NOT add a null check without breaking host visibility here.
- // * it hides ALL NetworkIdentities in server-only mode because
- // observers never contain the 'null' .localConnection
- // => that was not intended, but let's keep it as it is so we
- // don't break anything in host mode. it's way easier than
- // iterating all identities in a special function in StartHost.
- if (initialize)
- {
- if (!newObservers.Contains(NetworkServer.localConnection))
- {
- SetHostVisibility(identity, false);
- }
- }
- }
- }
- }
|