// ---------------------------------------------------------------------------- // // PhotonNetwork Framework for Unity - Copyright (C) 2011 Exit Games GmbH // // // // // developer@exitgames.com // ---------------------------------------------------------------------------- #pragma warning disable 1587 /// \file /// Wraps up smaller classes that don't need their own file. /// /// /// \defgroup publicApi Public API /// \brief Groups the most important classes that you need to understand early on. /// /// \defgroup optionalGui Optional Gui Elements /// \brief Useful GUI elements for PUN. #pragma warning restore 1587 #if UNITY_5 && !UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 #define UNITY_MIN_5_3 #endif using System; using System.Collections.Generic; using ExitGames.Client.Photon; using UnityEngine; using Hashtable = ExitGames.Client.Photon.Hashtable; using SupportClassPun = ExitGames.Client.Photon.SupportClass; /// Defines the OnPhotonSerializeView method to make it easy to implement correctly for observable scripts. /// \ingroup publicApi public interface IPunObservable { /// /// Called by PUN several times per second, so that your script can write and read synchronization data for the PhotonView. /// /// /// This method will be called in scripts that are assigned as Observed component of a PhotonView.
/// PhotonNetwork.sendRateOnSerialize affects how often this method is called.
/// PhotonNetwork.sendRate affects how often packages are sent by this client.
/// /// Implementing this method, you can customize which data a PhotonView regularly synchronizes. /// Your code defines what is being sent (content) and how your data is used by receiving clients. /// /// Unlike other callbacks, OnPhotonSerializeView only gets called when it is assigned /// to a PhotonView as PhotonView.observed script. /// /// To make use of this method, the PhotonStream is essential. It will be in "writing" mode" on the /// client that controls a PhotonView (PhotonStream.isWriting == true) and in "reading mode" on the /// remote clients that just receive that the controlling client sends. /// /// If you skip writing any value into the stream, PUN will skip the update. Used carefully, this can /// conserve bandwidth and messages (which have a limit per room/second). /// /// Note that OnPhotonSerializeView is not called on remote clients when the sender does not send /// any update. This can't be used as "x-times per second Update()". ///
/// \ingroup publicApi void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info); } /// /// This interface is used as definition of all callback methods of PUN, except OnPhotonSerializeView. Preferably, implement them individually. /// /// /// This interface is available for completeness, more than for actually implementing it in a game. /// You can implement each method individually in any MonoMehaviour, without implementing IPunCallbacks. /// /// PUN calls all callbacks by name. Don't use implement callbacks with fully qualified name. /// Example: IPunCallbacks.OnConnectedToPhoton won't get called by Unity's SendMessage(). /// /// PUN will call these methods on any script that implements them, analog to Unity's events and callbacks. /// The situation that triggers the call is described per method. /// /// OnPhotonSerializeView is NOT called like these callbacks! It's usage frequency is much higher and it is implemented in: IPunObservable. /// /// \ingroup publicApi public interface IPunCallbacks { /// /// Called when the initial connection got established but before you can use the server. OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. /// /// /// This callback is only useful to detect if the server can be reached at all (technically). /// Most often, it's enough to implement OnFailedToConnectToPhoton() and OnDisconnectedFromPhoton(). /// /// OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. /// /// When this is called, the low level connection is established and PUN will send your AppId, the user, etc in the background. /// This is not called for transitions from the masterserver to game servers. /// void OnConnectedToPhoton(); /// /// Called when the local user/client left a room. /// /// /// When leaving a room, PUN brings you back to the Master Server. /// Before you can use lobbies and join or create rooms, OnJoinedLobby() or OnConnectedToMaster() will get called again. /// void OnLeftRoom(); /// /// Called after switching to a new MasterClient when the current one leaves. /// /// /// This is not called when this client enters a room. /// The former MasterClient is still in the player list when this method get called. /// void OnMasterClientSwitched(PhotonPlayer newMasterClient); /// /// Called when a CreateRoom() call failed. The parameter provides ErrorCode and message (as array). /// /// /// Most likely because the room name is already in use (some other client was faster than you). /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. /// /// codeAndMsg[0] is short ErrorCode and codeAndMsg[1] is a string debug msg. void OnPhotonCreateRoomFailed(object[] codeAndMsg); /// /// Called when a JoinRoom() call failed. The parameter provides ErrorCode and message (as array). /// /// /// Most likely error is that the room does not exist or the room is full (some other client was faster than you). /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. /// /// codeAndMsg[0] is short ErrorCode and codeAndMsg[1] is string debug msg. void OnPhotonJoinRoomFailed(object[] codeAndMsg); /// /// Called when this client created a room and entered it. OnJoinedRoom() will be called as well. /// /// /// This callback is only called on the client which created a room (see PhotonNetwork.CreateRoom). /// /// As any client might close (or drop connection) anytime, there is a chance that the /// creator of a room does not execute OnCreatedRoom. /// /// If you need specific room properties or a "start signal", it is safer to implement /// OnMasterClientSwitched() and to make the new MasterClient check the room's state. /// void OnCreatedRoom(); /// /// Called on entering a lobby on the Master Server. The actual room-list updates will call OnReceivedRoomListUpdate(). /// /// /// Note: When PhotonNetwork.autoJoinLobby is false, OnConnectedToMaster() will be called and the room list won't become available. /// /// While in the lobby, the roomlist is automatically updated in fixed intervals (which you can't modify). /// The room list gets available when OnReceivedRoomListUpdate() gets called after OnJoinedLobby(). /// void OnJoinedLobby(); /// /// Called after leaving a lobby. /// /// /// When you leave a lobby, [CreateRoom](@ref PhotonNetwork.CreateRoom) and [JoinRandomRoom](@ref PhotonNetwork.JoinRandomRoom) /// automatically refer to the default lobby. /// void OnLeftLobby(); /// /// Called if a connect call to the Photon server failed before the connection was established, followed by a call to OnDisconnectedFromPhoton(). /// /// /// This is called when no connection could be established at all. /// It differs from OnConnectionFail, which is called when an existing connection fails. /// void OnFailedToConnectToPhoton(DisconnectCause cause); /// /// Called when something causes the connection to fail (after it was established), followed by a call to OnDisconnectedFromPhoton(). /// /// /// If the server could not be reached in the first place, OnFailedToConnectToPhoton is called instead. /// The reason for the error is provided as DisconnectCause. /// void OnConnectionFail(DisconnectCause cause); /// /// Called after disconnecting from the Photon server. /// /// /// In some cases, other callbacks are called before OnDisconnectedFromPhoton is called. /// Examples: OnConnectionFail() and OnFailedToConnectToPhoton(). /// void OnDisconnectedFromPhoton(); /// /// Called on all scripts on a GameObject (and children) that have been Instantiated using PhotonNetwork.Instantiate. /// /// /// PhotonMessageInfo parameter provides info about who created the object and when (based off PhotonNetworking.time). /// void OnPhotonInstantiate(PhotonMessageInfo info); /// /// Called for any update of the room-listing while in a lobby (PhotonNetwork.insideLobby) on the Master Server. /// /// /// PUN provides the list of rooms by PhotonNetwork.GetRoomList().
/// Each item is a RoomInfo which might include custom properties (provided you defined those as lobby-listed when creating a room). /// /// Not all types of lobbies provide a listing of rooms to the client. Some are silent and specialized for server-side matchmaking. ///
void OnReceivedRoomListUpdate(); /// /// Called when entering a room (by creating or joining it). Called on all clients (including the Master Client). /// /// /// This method is commonly used to instantiate player characters. /// If a match has to be started "actively", you can call an [PunRPC](@ref PhotonView.RPC) triggered by a user's button-press or a timer. /// /// When this is called, you can usually already access the existing players in the room via PhotonNetwork.playerList. /// Also, all custom properties should be already available as Room.customProperties. Check Room.playerCount to find out if /// enough players are in the room to start playing. /// void OnJoinedRoom(); /// /// Called when a remote player entered the room. This PhotonPlayer is already added to the playerlist at this time. /// /// /// If your game starts with a certain number of players, this callback can be useful to check the /// Room.playerCount and find out if you can start. /// void OnPhotonPlayerConnected(PhotonPlayer newPlayer); /// /// Called when a remote player left the room. This PhotonPlayer is already removed from the playerlist at this time. /// /// /// When your client calls PhotonNetwork.leaveRoom, PUN will call this method on the remaining clients. /// When a remote client drops connection or gets closed, this callback gets executed. after a timeout /// of several seconds. /// void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer); /// /// Called when a JoinRandom() call failed. The parameter provides ErrorCode and message. /// /// /// Most likely all rooms are full or no rooms are available.
/// When using multiple lobbies (via JoinLobby or TypedLobby), another lobby might have more/fitting rooms.
/// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. ///
/// codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. void OnPhotonRandomJoinFailed(object[] codeAndMsg); /// /// Called after the connection to the master is established and authenticated but only when PhotonNetwork.autoJoinLobby is false. /// /// /// If you set PhotonNetwork.autoJoinLobby to true, OnJoinedLobby() will be called instead of this. /// /// You can join rooms and create them even without being in a lobby. The default lobby is used in that case. /// The list of available rooms won't become available unless you join a lobby via PhotonNetwork.joinLobby. /// void OnConnectedToMaster(); /// /// Because the concurrent user limit was (temporarily) reached, this client is rejected by the server and disconnecting. /// /// /// When this happens, the user might try again later. You can't create or join rooms in OnPhotonMaxCcuReached(), cause the client will be disconnecting. /// You can raise the CCU limits with a new license (when you host yourself) or extended subscription (when using the Photon Cloud). /// The Photon Cloud will mail you when the CCU limit was reached. This is also visible in the Dashboard (webpage). /// void OnPhotonMaxCccuReached(); /// /// Called when a room's custom properties changed. The propertiesThatChanged contains all that was set via Room.SetCustomProperties. /// /// /// Since v1.25 this method has one parameter: Hashtable propertiesThatChanged.
/// Changing properties must be done by Room.SetCustomProperties, which causes this callback locally, too. ///
/// void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged); /// /// Called when custom player-properties are changed. Player and the changed properties are passed as object[]. /// /// /// Since v1.25 this method has one parameter: object[] playerAndUpdatedProps, which contains two entries.
/// [0] is the affected PhotonPlayer.
/// [1] is the Hashtable of properties that changed.
/// /// We are using a object[] due to limitations of Unity's GameObject.SendMessage (which has only one optional parameter). /// /// Changing properties must be done by PhotonPlayer.SetCustomProperties, which causes this callback locally, too. /// /// Example:
    /// void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) {
    ///     PhotonPlayer player = playerAndUpdatedProps[0] as PhotonPlayer;
    ///     Hashtable props = playerAndUpdatedProps[1] as Hashtable;
    ///     //...
    /// }
///
/// Contains PhotonPlayer and the properties that changed See remarks. void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps); /// /// Called when the server sent the response to a FindFriends request and updated PhotonNetwork.Friends. /// /// /// The friends list is available as PhotonNetwork.Friends, listing name, online state and /// the room a user is in (if any). /// void OnUpdatedFriendList(); /// /// Called when the custom authentication failed. Followed by disconnect! /// /// /// Custom Authentication can fail due to user-input, bad tokens/secrets. /// If authentication is successful, this method is not called. Implement OnJoinedLobby() or OnConnectedToMaster() (as usual). /// /// During development of a game, it might also fail due to wrong configuration on the server side. /// In those cases, logging the debugMessage is very important. /// /// Unless you setup a custom authentication service for your app (in the [Dashboard](https://www.photonengine.com/dashboard)), /// this won't be called! /// /// Contains a debug message why authentication failed. This has to be fixed during development time. void OnCustomAuthenticationFailed(string debugMessage); /// /// Called when your Custom Authentication service responds with additional data. /// /// /// Custom Authentication services can include some custom data in their response. /// When present, that data is made available in this callback as Dictionary. /// While the keys of your data have to be strings, the values can be either string or a number (in Json). /// You need to make extra sure, that the value type is the one you expect. Numbers become (currently) int64. /// /// Example: void OnCustomAuthenticationResponse(Dictionary<string, object> data) { ... } /// /// void OnCustomAuthenticationResponse(Dictionary data); /// /// Called by PUN when the response to a WebRPC is available. See PhotonNetwork.WebRPC. /// /// /// Important: The response.ReturnCode is 0 if Photon was able to reach your web-service.
/// The content of the response is what your web-service sent. You can create a WebRpcResponse from it.
/// Example: WebRpcResponse webResponse = new WebRpcResponse(operationResponse);
/// /// Please note: Class OperationResponse is in a namespace which needs to be "used":
/// using ExitGames.Client.Photon; // includes OperationResponse (and other classes) /// /// The OperationResponse.ReturnCode by Photon is:
    ///  0 for "OK"
    /// -3 for "Web-Service not configured" (see Dashboard / WebHooks)
    /// -5 for "Web-Service does now have RPC path/name" (at least for Azure)
///
void OnWebRpcResponse(OperationResponse response); /// /// Called when another player requests ownership of a PhotonView from you (the current owner). /// /// /// The parameter viewAndPlayer contains: /// /// PhotonView view = viewAndPlayer[0] as PhotonView; /// /// PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer; /// /// The PhotonView is viewAndPlayer[0] and the requesting player is viewAndPlayer[1]. void OnOwnershipRequest(object[] viewAndPlayer); /// /// Called when the Master Server sent an update for the Lobby Statistics, updating PhotonNetwork.LobbyStatistics. /// /// /// This callback has two preconditions: /// EnableLobbyStatistics must be set to true, before this client connects. /// And the client has to be connected to the Master Server, which is providing the info about lobbies. /// void OnLobbyStatisticsUpdate(); } /// /// Defines all the methods that a Object Pool must implement, so that PUN can use it. /// /// /// To use a Object Pool for instantiation, you can set PhotonNetwork.ObjectPool. /// That is used for all objects, as long as ObjectPool is not null. /// The pool has to return a valid non-null GameObject when PUN calls Instantiate. /// Also, the position and rotation must be applied. /// /// Please note that pooled GameObjects don't get the usual Awake and Start calls. /// OnEnable will be called (by your pool) but the networking values are not updated yet /// when that happens. OnEnable will have outdated values for PhotonView (isMine, etc.). /// You might have to adjust scripts. /// /// PUN will call OnPhotonInstantiate (see IPunCallbacks). This should be used to /// setup the re-used object with regards to networking values / ownership. /// public interface IPunPrefabPool { /// /// This is called when PUN wants to create a new instance of an entity prefab. Must return valid GameObject with PhotonView. /// /// The id of this prefab. /// The position we want the instance instantiated at. /// The rotation we want the instance to take. /// The newly instantiated object, or null if a prefab with was not found. GameObject Instantiate(string prefabId, Vector3 position, Quaternion rotation); /// /// This is called when PUN wants to destroy the instance of an entity prefab. /// /// /// A pool needs some way to find out which type of GameObject got returned via Destroy(). /// It could be a tag or name or anything similar. /// /// The instance to destroy. void Destroy(GameObject gameObject); } namespace Photon { using Hashtable = ExitGames.Client.Photon.Hashtable; /// /// This class adds the property photonView, while logging a warning when your game still uses the networkView. /// public class MonoBehaviour : UnityEngine.MonoBehaviour { /// Cache field for the PhotonView on this GameObject. private PhotonView pvCache = null; /// A cached reference to a PhotonView on this GameObject. /// /// If you intend to work with a PhotonView in a script, it's usually easier to write this.photonView. /// /// If you intend to remove the PhotonView component from the GameObject but keep this Photon.MonoBehaviour, /// avoid this reference or modify this code to use PhotonView.Get(obj) instead. /// public PhotonView photonView { get { if (pvCache == null) { pvCache = PhotonView.Get(this); } return pvCache; } } #if !UNITY_MIN_5_3 /// /// This property is only here to notify developers when they use the outdated value. /// /// /// If Unity 5.x logs a compiler warning "Use the new keyword if hiding was intended" or /// "The new keyword is not required", you may suffer from an Editor issue. /// Try to modify networkView with a if-def condition: /// /// #if UNITY_EDITOR /// new /// #endif /// public PhotonView networkView /// [Obsolete("Use a photonView")] public new PhotonView networkView { get { Debug.LogWarning("Why are you still using networkView? should be PhotonView?"); return PhotonView.Get(this); } } #endif } /// /// This class provides a .photonView and all callbacks/events that PUN can call. Override the events/methods you want to use. /// /// /// By extending this class, you can implement individual methods as override. /// /// Visual Studio and MonoDevelop should provide the list of methods when you begin typing "override". /// Your implementation does not have to call "base.method()". /// /// This class implements IPunCallbacks, which is used as definition of all PUN callbacks. /// Don't implement IPunCallbacks in your classes. Instead, implent PunBehaviour or individual methods. /// /// \ingroup publicApi // the documentation for the interface methods becomes inherited when Doxygen builds it. public class PunBehaviour : Photon.MonoBehaviour, IPunCallbacks { /// /// Called when the initial connection got established but before you can use the server. OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. /// /// /// This callback is only useful to detect if the server can be reached at all (technically). /// Most often, it's enough to implement OnFailedToConnectToPhoton() and OnDisconnectedFromPhoton(). /// /// OnJoinedLobby() or OnConnectedToMaster() are called when PUN is ready. /// /// When this is called, the low level connection is established and PUN will send your AppId, the user, etc in the background. /// This is not called for transitions from the masterserver to game servers. /// public virtual void OnConnectedToPhoton() { } /// /// Called when the local user/client left a room. /// /// /// When leaving a room, PUN brings you back to the Master Server. /// Before you can use lobbies and join or create rooms, OnJoinedLobby() or OnConnectedToMaster() will get called again. /// public virtual void OnLeftRoom() { } /// /// Called after switching to a new MasterClient when the current one leaves. /// /// /// This is not called when this client enters a room. /// The former MasterClient is still in the player list when this method get called. /// public virtual void OnMasterClientSwitched(PhotonPlayer newMasterClient) { } /// /// Called when a CreateRoom() call failed. The parameter provides ErrorCode and message (as array). /// /// /// Most likely because the room name is already in use (some other client was faster than you). /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. /// /// codeAndMsg[0] is a short ErrorCode and codeAndMsg[1] is a string debug msg. public virtual void OnPhotonCreateRoomFailed(object[] codeAndMsg) { } /// /// Called when a JoinRoom() call failed. The parameter provides ErrorCode and message (as array). /// /// /// Most likely error is that the room does not exist or the room is full (some other client was faster than you). /// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. /// /// codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. public virtual void OnPhotonJoinRoomFailed(object[] codeAndMsg) { } /// /// Called when this client created a room and entered it. OnJoinedRoom() will be called as well. /// /// /// This callback is only called on the client which created a room (see PhotonNetwork.CreateRoom). /// /// As any client might close (or drop connection) anytime, there is a chance that the /// creator of a room does not execute OnCreatedRoom. /// /// If you need specific room properties or a "start signal", it is safer to implement /// OnMasterClientSwitched() and to make the new MasterClient check the room's state. /// public virtual void OnCreatedRoom() { } /// /// Called on entering a lobby on the Master Server. The actual room-list updates will call OnReceivedRoomListUpdate(). /// /// /// Note: When PhotonNetwork.autoJoinLobby is false, OnConnectedToMaster() will be called and the room list won't become available. /// /// While in the lobby, the roomlist is automatically updated in fixed intervals (which you can't modify). /// The room list gets available when OnReceivedRoomListUpdate() gets called after OnJoinedLobby(). /// public virtual void OnJoinedLobby() { } /// /// Called after leaving a lobby. /// /// /// When you leave a lobby, [CreateRoom](@ref PhotonNetwork.CreateRoom) and [JoinRandomRoom](@ref PhotonNetwork.JoinRandomRoom) /// automatically refer to the default lobby. /// public virtual void OnLeftLobby() { } /// /// Called if a connect call to the Photon server failed before the connection was established, followed by a call to OnDisconnectedFromPhoton(). /// /// /// This is called when no connection could be established at all. /// It differs from OnConnectionFail, which is called when an existing connection fails. /// public virtual void OnFailedToConnectToPhoton(DisconnectCause cause) { } /// /// Called after disconnecting from the Photon server. /// /// /// In some cases, other callbacks are called before OnDisconnectedFromPhoton is called. /// Examples: OnConnectionFail() and OnFailedToConnectToPhoton(). /// public virtual void OnDisconnectedFromPhoton() { } /// /// Called when something causes the connection to fail (after it was established), followed by a call to OnDisconnectedFromPhoton(). /// /// /// If the server could not be reached in the first place, OnFailedToConnectToPhoton is called instead. /// The reason for the error is provided as DisconnectCause. /// public virtual void OnConnectionFail(DisconnectCause cause) { } /// /// Called on all scripts on a GameObject (and children) that have been Instantiated using PhotonNetwork.Instantiate. /// /// /// PhotonMessageInfo parameter provides info about who created the object and when (based off PhotonNetworking.time). /// public virtual void OnPhotonInstantiate(PhotonMessageInfo info) { } /// /// Called for any update of the room-listing while in a lobby (PhotonNetwork.insideLobby) on the Master Server. /// /// /// PUN provides the list of rooms by PhotonNetwork.GetRoomList().
/// Each item is a RoomInfo which might include custom properties (provided you defined those as lobby-listed when creating a room). /// /// Not all types of lobbies provide a listing of rooms to the client. Some are silent and specialized for server-side matchmaking. ///
public virtual void OnReceivedRoomListUpdate() { } /// /// Called when entering a room (by creating or joining it). Called on all clients (including the Master Client). /// /// /// This method is commonly used to instantiate player characters. /// If a match has to be started "actively", you can call an [PunRPC](@ref PhotonView.RPC) triggered by a user's button-press or a timer. /// /// When this is called, you can usually already access the existing players in the room via PhotonNetwork.playerList. /// Also, all custom properties should be already available as Room.customProperties. Check Room.playerCount to find out if /// enough players are in the room to start playing. /// public virtual void OnJoinedRoom() { } /// /// Called when a remote player entered the room. This PhotonPlayer is already added to the playerlist at this time. /// /// /// If your game starts with a certain number of players, this callback can be useful to check the /// Room.playerCount and find out if you can start. /// public virtual void OnPhotonPlayerConnected(PhotonPlayer newPlayer) { } /// /// Called when a remote player left the room. This PhotonPlayer is already removed from the playerlist at this time. /// /// /// When your client calls PhotonNetwork.leaveRoom, PUN will call this method on the remaining clients. /// When a remote client drops connection or gets closed, this callback gets executed. after a timeout /// of several seconds. /// public virtual void OnPhotonPlayerDisconnected(PhotonPlayer otherPlayer) { } /// /// Called when a JoinRandom() call failed. The parameter provides ErrorCode and message. /// /// /// Most likely all rooms are full or no rooms are available.
/// When using multiple lobbies (via JoinLobby or TypedLobby), another lobby might have more/fitting rooms.
/// PUN logs some info if the PhotonNetwork.logLevel is >= PhotonLogLevel.Informational. ///
/// codeAndMsg[0] is short ErrorCode. codeAndMsg[1] is string debug msg. public virtual void OnPhotonRandomJoinFailed(object[] codeAndMsg) { } /// /// Called after the connection to the master is established and authenticated but only when PhotonNetwork.autoJoinLobby is false. /// /// /// If you set PhotonNetwork.autoJoinLobby to true, OnJoinedLobby() will be called instead of this. /// /// You can join rooms and create them even without being in a lobby. The default lobby is used in that case. /// The list of available rooms won't become available unless you join a lobby via PhotonNetwork.joinLobby. /// public virtual void OnConnectedToMaster() { } /// /// Because the concurrent user limit was (temporarily) reached, this client is rejected by the server and disconnecting. /// /// /// When this happens, the user might try again later. You can't create or join rooms in OnPhotonMaxCcuReached(), cause the client will be disconnecting. /// You can raise the CCU limits with a new license (when you host yourself) or extended subscription (when using the Photon Cloud). /// The Photon Cloud will mail you when the CCU limit was reached. This is also visible in the Dashboard (webpage). /// public virtual void OnPhotonMaxCccuReached() { } /// /// Called when a room's custom properties changed. The propertiesThatChanged contains all that was set via Room.SetCustomProperties. /// /// /// Since v1.25 this method has one parameter: Hashtable propertiesThatChanged.
/// Changing properties must be done by Room.SetCustomProperties, which causes this callback locally, too. ///
/// public virtual void OnPhotonCustomRoomPropertiesChanged(Hashtable propertiesThatChanged) { } /// /// Called when custom player-properties are changed. Player and the changed properties are passed as object[]. /// /// /// Since v1.25 this method has one parameter: object[] playerAndUpdatedProps, which contains two entries.
/// [0] is the affected PhotonPlayer.
/// [1] is the Hashtable of properties that changed.
/// /// We are using a object[] due to limitations of Unity's GameObject.SendMessage (which has only one optional parameter). /// /// Changing properties must be done by PhotonPlayer.SetCustomProperties, which causes this callback locally, too. /// /// Example:
        /// void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) {
        ///     PhotonPlayer player = playerAndUpdatedProps[0] as PhotonPlayer;
        ///     Hashtable props = playerAndUpdatedProps[1] as Hashtable;
        ///     //...
        /// }
///
/// Contains PhotonPlayer and the properties that changed See remarks. public virtual void OnPhotonPlayerPropertiesChanged(object[] playerAndUpdatedProps) { } /// /// Called when the server sent the response to a FindFriends request and updated PhotonNetwork.Friends. /// /// /// The friends list is available as PhotonNetwork.Friends, listing name, online state and /// the room a user is in (if any). /// public virtual void OnUpdatedFriendList() { } /// /// Called when the custom authentication failed. Followed by disconnect! /// /// /// Custom Authentication can fail due to user-input, bad tokens/secrets. /// If authentication is successful, this method is not called. Implement OnJoinedLobby() or OnConnectedToMaster() (as usual). /// /// During development of a game, it might also fail due to wrong configuration on the server side. /// In those cases, logging the debugMessage is very important. /// /// Unless you setup a custom authentication service for your app (in the [Dashboard](https://www.photonengine.com/dashboard)), /// this won't be called! /// /// Contains a debug message why authentication failed. This has to be fixed during development time. public virtual void OnCustomAuthenticationFailed(string debugMessage) { } /// /// Called when your Custom Authentication service responds with additional data. /// /// /// Custom Authentication services can include some custom data in their response. /// When present, that data is made available in this callback as Dictionary. /// While the keys of your data have to be strings, the values can be either string or a number (in Json). /// You need to make extra sure, that the value type is the one you expect. Numbers become (currently) int64. /// /// Example: void OnCustomAuthenticationResponse(Dictionary<string, object> data) { ... } /// /// public virtual void OnCustomAuthenticationResponse(Dictionary data) { } /// /// Called by PUN when the response to a WebRPC is available. See PhotonNetwork.WebRPC. /// /// /// Important: The response.ReturnCode is 0 if Photon was able to reach your web-service. /// The content of the response is what your web-service sent. You can create a WebResponse instance from it. /// Example: WebRpcResponse webResponse = new WebRpcResponse(operationResponse); /// /// Please note: Class OperationResponse is in a namespace which needs to be "used": /// using ExitGames.Client.Photon; // includes OperationResponse (and other classes) /// /// The OperationResponse.ReturnCode by Photon is:
        ///  0 for "OK"
        /// -3 for "Web-Service not configured" (see Dashboard / WebHooks)
        /// -5 for "Web-Service does now have RPC path/name" (at least for Azure)
///
public virtual void OnWebRpcResponse(OperationResponse response) { } /// /// Called when another player requests ownership of a PhotonView from you (the current owner). /// /// /// The parameter viewAndPlayer contains: /// /// PhotonView view = viewAndPlayer[0] as PhotonView; /// /// PhotonPlayer requestingPlayer = viewAndPlayer[1] as PhotonPlayer; /// /// The PhotonView is viewAndPlayer[0] and the requesting player is viewAndPlayer[1]. public virtual void OnOwnershipRequest(object[] viewAndPlayer) { } /// /// Called when the Master Server sent an update for the Lobby Statistics, updating PhotonNetwork.LobbyStatistics. /// /// /// This callback has two preconditions: /// EnableLobbyStatistics must be set to true, before this client connects. /// And the client has to be connected to the Master Server, which is providing the info about lobbies. /// public virtual void OnLobbyStatisticsUpdate() { } } } /// /// Container class for info about a particular message, RPC or update. /// /// \ingroup publicApi public struct PhotonMessageInfo { private readonly int timeInt; public readonly PhotonPlayer sender; public readonly PhotonView photonView; public PhotonMessageInfo(PhotonPlayer player, int timestamp, PhotonView view) { this.sender = player; this.timeInt = timestamp; this.photonView = view; } public double timestamp { get { uint u = (uint)this.timeInt; double t = u; return t / 1000; } } public override string ToString() { return string.Format("[PhotonMessageInfo: Sender='{1}' Senttime={0}]", this.timestamp, this.sender); } } /// Defines Photon event-codes as used by PUN. internal class PunEvent { public const byte RPC = 200; public const byte SendSerialize = 201; public const byte Instantiation = 202; public const byte CloseConnection = 203; public const byte Destroy = 204; public const byte RemoveCachedRPCs = 205; public const byte SendSerializeReliable = 206; // TS: added this but it's not really needed anymore public const byte DestroyPlayer = 207; // TS: added to make others remove all GOs of a player public const byte AssignMaster = 208; // TS: added to assign someone master client (overriding the current) public const byte OwnershipRequest = 209; public const byte OwnershipTransfer = 210; public const byte VacantViewIds = 211; } /// /// This container is used in OnPhotonSerializeView() to either provide incoming data of a PhotonView or for you to provide it. /// /// /// The isWriting property will be true if this client is the "owner" of the PhotonView (and thus the GameObject). /// Add data to the stream and it's sent via the server to the other players in a room. /// On the receiving side, isWriting is false and the data should be read. /// /// Send as few data as possible to keep connection quality up. An empty PhotonStream will not be sent. /// /// Use either Serialize() for reading and writing or SendNext() and ReceiveNext(). The latter two are just explicit read and /// write methods but do about the same work as Serialize(). It's a matter of preference which methods you use. /// /// /// \ingroup publicApi public class PhotonStream { bool write = false; private Queue writeData; private object[] readData; internal byte currentItem = 0; //Used to track the next item to receive. /// /// Creates a stream and initializes it. Used by PUN internally. /// public PhotonStream(bool write, object[] incomingData) { this.write = write; if (incomingData == null) { this.writeData = new Queue(10); } else { this.readData = incomingData; } } public void SetReadStream(object[] incomingData, byte pos = 0) { this.readData = incomingData; this.currentItem = pos; this.write = false; } internal void ResetWriteStream() { writeData.Clear(); } /// If true, this client should add data to the stream to send it. public bool isWriting { get { return this.write; } } /// If true, this client should read data send by another client. public bool isReading { get { return !this.write; } } /// Count of items in the stream. public int Count { get { return (this.isWriting) ? this.writeData.Count : this.readData.Length; } } /// Read next piece of data from the stream when isReading is true. public object ReceiveNext() { if (this.write) { Debug.LogError("Error: you cannot read this stream that you are writing!"); return null; } object obj = this.readData[this.currentItem]; this.currentItem++; return obj; } /// Read next piece of data from the stream without advancing the "current" item. public object PeekNext() { if (this.write) { Debug.LogError("Error: you cannot read this stream that you are writing!"); return null; } object obj = this.readData[this.currentItem]; //this.currentItem++; return obj; } /// Add another piece of data to send it when isWriting is true. public void SendNext(object obj) { if (!this.write) { Debug.LogError("Error: you cannot write/send to this stream that you are reading!"); return; } this.writeData.Enqueue(obj); } /// Turns the stream into a new object[]. public object[] ToArray() { return this.isWriting ? this.writeData.ToArray() : this.readData; } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref bool myBool) { if (this.write) { this.writeData.Enqueue(myBool); } else { if (this.readData.Length > currentItem) { myBool = (bool)this.readData[currentItem]; this.currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref int myInt) { if (write) { this.writeData.Enqueue(myInt); } else { if (this.readData.Length > currentItem) { myInt = (int)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref string value) { if (write) { this.writeData.Enqueue(value); } else { if (this.readData.Length > currentItem) { value = (string)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref char value) { if (write) { this.writeData.Enqueue(value); } else { if (this.readData.Length > currentItem) { value = (char)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref short value) { if (write) { this.writeData.Enqueue(value); } else { if (this.readData.Length > currentItem) { value = (short)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref float obj) { if (write) { this.writeData.Enqueue(obj); } else { if (this.readData.Length > currentItem) { obj = (float)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref PhotonPlayer obj) { if (write) { this.writeData.Enqueue(obj); } else { if (this.readData.Length > currentItem) { obj = (PhotonPlayer)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref Vector3 obj) { if (write) { this.writeData.Enqueue(obj); } else { if (this.readData.Length > currentItem) { obj = (Vector3)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref Vector2 obj) { if (write) { this.writeData.Enqueue(obj); } else { if (this.readData.Length > currentItem) { obj = (Vector2)this.readData[currentItem]; currentItem++; } } } /// /// Will read or write the value, depending on the stream's isWriting value. /// public void Serialize(ref Quaternion obj) { if (write) { this.writeData.Enqueue(obj); } else { if (this.readData.Length > currentItem) { obj = (Quaternion)this.readData[currentItem]; currentItem++; } } } } #if UNITY_5_0 || !UNITY_5 /// Empty implementation of the upcoming HelpURL of Unity 5.1. This one is only for compatibility of attributes. /// http://feedback.unity3d.com/suggestions/override-component-documentation-slash-help-link public class HelpURL : Attribute { public HelpURL(string url) { } } #endif #if !UNITY_MIN_5_3 // in Unity 5.3 and up, we have to use a SceneManager. This section re-implements it for older Unity versions #if UNITY_EDITOR namespace UnityEditor.SceneManagement { /// Minimal implementation of the EditorSceneManager for older Unity, up to v5.2. public class EditorSceneManager { public static int loadedSceneCount { get { return string.IsNullOrEmpty(UnityEditor.EditorApplication.currentScene) ? -1 : 1; } } public static void OpenScene(string name) { UnityEditor.EditorApplication.OpenScene(name); } public static void SaveOpenScenes() { UnityEditor.EditorApplication.SaveScene(); } public static void SaveCurrentModifiedScenesIfUserWantsTo() { UnityEditor.EditorApplication.SaveCurrentSceneIfUserWantsTo(); } } } #endif #endif public class SceneManagerHelper { public static string ActiveSceneName { get { #if UNITY_MIN_5_3 UnityEngine.SceneManagement.Scene s = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); return s.name; #else return Application.loadedLevelName; #endif } } public static int ActiveSceneBuildIndex { get { #if UNITY_MIN_5_3 return UnityEngine.SceneManagement.SceneManager.GetActiveScene().buildIndex; #else return Application.loadedLevel; #endif } } #if UNITY_EDITOR public static string EditorActiveSceneName { get { #if UNITY_MIN_5_3 return UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene().name; #else return System.IO.Path.GetFileNameWithoutExtension(UnityEditor.EditorApplication.currentScene); #endif } } #endif } /// Reads an operation response of a WebRpc and provides convenient access to most common values. /// /// See method PhotonNetwork.WebRpc.
/// Create a WebRpcResponse to access common result values.
/// The operationResponse.OperationCode should be: OperationCode.WebRpc.
///
public class WebRpcResponse { /// Name of the WebRpc that was called. public string Name { get; private set; } /// ReturnCode of the WebService that answered the WebRpc. /// /// 0 is commonly used to signal success.
/// -1 tells you: Got no ReturnCode from WebRpc service.
/// Other ReturnCodes are defined by the individual WebRpc and service. ///
public int ReturnCode { get; private set; } /// Might be empty or null. public string DebugMessage { get; private set; } /// Other key/values returned by the webservice that answered the WebRpc. public Dictionary Parameters { get; private set; } /// An OperationResponse for a WebRpc is needed to read it's values. public WebRpcResponse(OperationResponse response) { object value; response.Parameters.TryGetValue(ParameterCode.UriPath, out value); this.Name = value as string; response.Parameters.TryGetValue(ParameterCode.WebRpcReturnCode, out value); this.ReturnCode = (value != null) ? (byte)value : -1; response.Parameters.TryGetValue(ParameterCode.WebRpcParameters, out value); this.Parameters = value as Dictionary; response.Parameters.TryGetValue(ParameterCode.WebRpcReturnMessage, out value); this.DebugMessage = value as string; } /// Turns the response into an easier to read string. /// String resembling the result. public string ToStringFull() { return string.Format("{0}={2}: {1} \"{3}\"", Name, SupportClassPun.DictionaryToString(Parameters), ReturnCode, DebugMessage); } } /** public class PBitStream { List streamBytes; private int currentByte; private int totalBits = 0; public int ByteCount { get { return BytesForBits(this.totalBits); } } public int BitCount { get { return this.totalBits; } private set { this.totalBits = value; } } public PBitStream() { this.streamBytes = new List(1); } public PBitStream(int bitCount) { this.streamBytes = new List(BytesForBits(bitCount)); } public PBitStream(IEnumerable bytes, int bitCount) { this.streamBytes = new List(bytes); this.BitCount = bitCount; } public static int BytesForBits(int bitCount) { if (bitCount <= 0) { return 0; } return ((bitCount - 1) / 8) + 1; } public void Add(bool val) { int bytePos = this.totalBits / 8; if (bytePos > this.streamBytes.Count-1 || this.totalBits == 0) { this.streamBytes.Add(0); } if (val) { int currentByteBit = 7 - (this.totalBits % 8); this.streamBytes[bytePos] |= (byte)(1 << currentByteBit); } this.totalBits++; } public byte[] ToBytes() { return this.streamBytes.ToArray(); } public int Position { get; set; } public bool GetNext() { if (this.Position > this.totalBits) { throw new Exception("End of PBitStream reached. Can't read more."); } return Get(this.Position++); } public bool Get(int bitIndex) { int byteIndex = bitIndex / 8; int bitInByIndex = 7 - (bitIndex % 8); return ((this.streamBytes[byteIndex] & (byte)(1 << bitInByIndex)) > 0); } public void Set(int bitIndex, bool value) { int byteIndex = bitIndex / 8; int bitInByIndex = 7 - (bitIndex % 8); this.streamBytes[byteIndex] |= (byte)(1 << bitInByIndex); } } **/