123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254 |
- // --------------------------------------------------------------------------------------------------------------------
- // <copyright file="CullingHandler.cs" company="Exit Games GmbH">
- // Part of: Photon Unity Utilities,
- // </copyright>
- // <summary>
- // Handles the network culling.
- // </summary>
- // <author>developer@exitgames.com</author>
- // --------------------------------------------------------------------------------------------------------------------
- using System.Collections.Generic;
- using UnityEngine;
- using Photon.Pun;
- namespace Photon.Pun.UtilityScripts
- {
- using ExitGames.Client.Photon;
- /// <summary>
- /// Handles the network culling.
- /// </summary>
- [RequireComponent(typeof(PhotonView))]
- public class CullingHandler : MonoBehaviour, IPunObservable
- {
- #region VARIABLES
- private int orderIndex;
- private CullArea cullArea;
- private List<byte> previousActiveCells, activeCells;
- private PhotonView pView;
- private Vector3 lastPosition, currentPosition;
-
-
- // used to limit the number of UpdateInterestGroups calls per second (there is no use to change groups more than a few times per second, even if the Culling algorithm makes it look like that)
- private float timeSinceUpdate;
- // see timeSinceUpdate
- private float timeBetweenUpdatesMin = 0.33f;
- #endregion
- #region UNITY_FUNCTIONS
- /// <summary>
- /// Gets references to the PhotonView component and the cull area game object.
- /// </summary>
- private void OnEnable()
- {
- if (this.pView == null)
- {
- this.pView = GetComponent<PhotonView>();
- if (!this.pView.IsMine)
- {
- return;
- }
- }
- if (this.cullArea == null)
- {
- this.cullArea = FindObjectOfType<CullArea>();
- }
- this.previousActiveCells = new List<byte>(0);
- this.activeCells = new List<byte>(0);
- this.currentPosition = this.lastPosition = transform.position;
- }
- /// <summary>
- /// Initializes the right interest group or prepares the permanent change of the interest Group of the PhotonView component.
- /// </summary>
- private void Start()
- {
- if (!this.pView.IsMine)
- {
- return;
- }
- if (PhotonNetwork.InRoom)
- {
- if (this.cullArea.NumberOfSubdivisions == 0)
- {
- this.pView.Group = this.cullArea.FIRST_GROUP_ID;
- PhotonNetwork.SetInterestGroups(this.cullArea.FIRST_GROUP_ID, true);
- }
- else
- {
- // This is used to continuously update the active group.
- this.pView.ObservedComponents.Add(this);
- }
- }
- }
- /// <summary>
- /// Checks if the player has moved previously and updates the interest groups if necessary.
- /// </summary>
- private void Update()
- {
- if (!this.pView.IsMine)
- {
- return;
- }
- // we'll limit how often this update may run at all (to avoid too frequent changes and flooding the server with SetInterestGroups calls)
- this.timeSinceUpdate += Time.deltaTime;
- if (this.timeSinceUpdate < this.timeBetweenUpdatesMin)
- {
- return;
- }
- this.lastPosition = this.currentPosition;
- this.currentPosition = transform.position;
- // This is a simple position comparison of the current and the previous position.
- // When using Network Culling in a bigger project keep in mind that there might
- // be more transform-related options, e.g. the rotation, or other options to check.
- if (this.currentPosition != this.lastPosition)
- {
- if (this.HaveActiveCellsChanged())
- {
- this.UpdateInterestGroups();
- this.timeSinceUpdate = 0;
- }
- }
- }
- /// <summary>
- /// Drawing informations.
- /// </summary>
- private void OnGUI()
- {
- if (!this.pView.IsMine)
- {
- return;
- }
- string subscribedAndActiveCells = "Inside cells:\n";
- string subscribedCells = "Subscribed cells:\n";
- for (int index = 0; index < this.activeCells.Count; ++index)
- {
- if (index <= this.cullArea.NumberOfSubdivisions)
- {
- subscribedAndActiveCells += this.activeCells[index] + " | ";
- }
- subscribedCells += this.activeCells[index] + " | ";
- }
- GUI.Label(new Rect(20.0f, Screen.height - 120.0f, 200.0f, 40.0f), "<color=white>PhotonView Group: " + this.pView.Group + "</color>", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 });
- GUI.Label(new Rect(20.0f, Screen.height - 100.0f, 200.0f, 40.0f), "<color=white>" + subscribedAndActiveCells + "</color>", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 });
- GUI.Label(new Rect(20.0f, Screen.height - 60.0f, 200.0f, 40.0f), "<color=white>" + subscribedCells + "</color>", new GUIStyle() { alignment = TextAnchor.UpperLeft, fontSize = 16 });
- }
- #endregion
- /// <summary>
- /// Checks if the previously active cells have changed.
- /// </summary>
- /// <returns>True if the previously active cells have changed and false otherwise.</returns>
- private bool HaveActiveCellsChanged()
- {
- if (this.cullArea.NumberOfSubdivisions == 0)
- {
- return false;
- }
- this.previousActiveCells = new List<byte>(this.activeCells);
- this.activeCells = this.cullArea.GetActiveCells(transform.position);
- // If the player leaves the area we insert the whole area itself as an active cell.
- // This can be removed if it is sure that the player is not able to leave the area.
- while (this.activeCells.Count <= this.cullArea.NumberOfSubdivisions)
- {
- this.activeCells.Add(this.cullArea.FIRST_GROUP_ID);
- }
- if (this.activeCells.Count != this.previousActiveCells.Count)
- {
- return true;
- }
- if (this.activeCells[this.cullArea.NumberOfSubdivisions] != this.previousActiveCells[this.cullArea.NumberOfSubdivisions])
- {
- return true;
- }
- return false;
- }
- /// <summary>
- /// Unsubscribes from old and subscribes to new interest groups.
- /// </summary>
- private void UpdateInterestGroups()
- {
- List<byte> disable = new List<byte>(0);
- foreach (byte groupId in this.previousActiveCells)
- {
- if (!this.activeCells.Contains(groupId))
- {
- disable.Add(groupId);
- }
- }
- PhotonNetwork.SetInterestGroups(disable.ToArray(), this.activeCells.ToArray());
- }
- #region IPunObservable implementation
- /// <summary>
- /// This time OnPhotonSerializeView is not used to send or receive any kind of data.
- /// It is used to change the currently active group of the PhotonView component, making it work together with PUN more directly.
- /// Keep in mind that this function is only executed, when there is at least one more player in the room.
- /// </summary>
- public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
- {
- // If the player leaves the area we insert the whole area itself as an active cell.
- // This can be removed if it is sure that the player is not able to leave the area.
- while (this.activeCells.Count <= this.cullArea.NumberOfSubdivisions)
- {
- this.activeCells.Add(this.cullArea.FIRST_GROUP_ID);
- }
- if (this.cullArea.NumberOfSubdivisions == 1)
- {
- this.orderIndex = (++this.orderIndex % this.cullArea.SUBDIVISION_FIRST_LEVEL_ORDER.Length);
- this.pView.Group = this.activeCells[this.cullArea.SUBDIVISION_FIRST_LEVEL_ORDER[this.orderIndex]];
- }
- else if (this.cullArea.NumberOfSubdivisions == 2)
- {
- this.orderIndex = (++this.orderIndex % this.cullArea.SUBDIVISION_SECOND_LEVEL_ORDER.Length);
- this.pView.Group = this.activeCells[this.cullArea.SUBDIVISION_SECOND_LEVEL_ORDER[this.orderIndex]];
- }
- else if (this.cullArea.NumberOfSubdivisions == 3)
- {
- this.orderIndex = (++this.orderIndex % this.cullArea.SUBDIVISION_THIRD_LEVEL_ORDER.Length);
- this.pView.Group = this.activeCells[this.cullArea.SUBDIVISION_THIRD_LEVEL_ORDER[this.orderIndex]];
- }
- }
- #endregion
- }
- }
|