
Photon Realtime C# Client - Changelog
Exit Games GmbH - www.photonengine.com - forum.photonengine.com



Version 4.1.7.0 (18. August 2023 - rev7111)
    Added: Class SystemConnectionSummary, which wraps up network-related conditions on the client when it gets created. It relies on Unity's callbacks and requires a ConnectionHandler to be present in the scene (as implementation of a MonoBehaviour getting the callbacks). Check the reference doc for details on how to put it to use.
    Added: LoadBalancingClient.SystemConnectionSummary, created for DisconnectCause.ExceptionOnConnect, DisconnectCause.Exception, DisconnectCause.ServerTimeout and DisconnectCause.ClientTimeout.
    Added: Error logging to each place that creates a SystemConnectionSummary (in LoadBalancingClient).
    Changed: Order of a few switch-cases in LBC.OnStatusChanged() for organizational reasons (the cases which create a SystemConnectionSummary are closer together this way).
    Changed: LBC.DisconnectedCause is reset before calling PhotonPeer.Connect(). This should be set before the connect and not only if Connect() returns true.
    Added: PhotonRealtime.asmdef (and meta file) to Unity SDK. This should be the same for all of our SDKs (PUN, Quantum, Voice).

Version 4.1.6.26 (09. August 2023 - rev7077)
    Changed: Name Server default port for WS is now 80, WSS is 443.
    Changed: client.State = ClientState.Joined is set in GameEnteredOnGameServer() if room-events are suppressed. Otherwise it is now set by event Join. This change aligns the state change with the callback calls.
    Changed: The SummaryToCache will not include a best region, if none of the regions was pinged successfully.
    Added: RegionHandler.BestRegionSummaryPingLimit to ping all regions if the current best region is worse than this limit. Default: 90ms.
    Changed: Demo Particle, GameLogic-class to check the Server Type instead of the client's State, when it entered a room on the Game Server.
    Note: This is affected by the changes we did to set the State from joining to joined! In best case, you would use the callback OnJoinedRoom() which is independent.

Version 4.1.6.25 (05. June 2023 - rev6925)
    No notable changes.

Version 4.1.6.24 (15. May 2023 - rev6894)
    Fixed: Potential NullReferenceException in PingMono.Dispose().

Version 4.1.6.23 (15. March 2023 - rev6743)
    Fixed: Replaced Null-conditional operator for MonoBehaviours and GameObjects. This caused issues with the usage of RegionHandler.emptyMonoBehavior.

Version 4.1.6.22  (21. December 2022 - rev6637)
    Fixed: A casting issue in RoomInfo (and Room) when reading properties.

Version 4.1.6.21  (14. December 2022 - rev6623)
    Changed: Clients never send room or player properties to the Master Server.
    Changed: The values MaxPlayers and PlayerCount for Rooms (RoomInfo and Room class) are now  integer in the client API. Between client and server, byte is still used. You can still only set 0-255 players until further note. This prepares a later change.
    Changed: Event Leave now makes sure the target Player's HasRejoined value is set.
    Changed: RegionHandler so it can be used by multiple connections at the same time.

Version 4.1.6.20  (23. September 2022 - rev6568)
    No notable changes.

Version 4.1.6.19 (12. October 2022 - rev6519)
    No notable changes.

Version 4.1.6.18f2 (23. September 2022 - rev6505)
    Fixed: RegionHandler compatibility when not running in-Unity. MonoBehaviourEmpty is only used conditionally.

Version 4.1.6.18 (20. September 2022 - rev6501)
    Added: RegionHandler.Abort() which enables you to stop region pinging (e.g. when the app goes to background or lost connection). This means the ping result callback is not being called.
    Changed: Unity will always use MonoBehaviourEmpty.Update() to do the callback (set via PingMinimumOfRegions()). This makes sure it is called on the Main Thread.
    Changed: Where MonoBehaviourEmpty.SelfDestroy() is being called (in Abort or when the "finished"-callback was called).
    Changed: The MonoBehaviourEmpty is always created in Unity runtimes.
    Removed: Surplus variable "overtime" in RegionPingCoroutine and RegionPingThreaded.

Version 4.1.6.17 (02. August 2022 - rev6472)
    Added: DisconnectCause.ApplicationQuit. Can be used when your app disconnects on application quit: lbc.Disconnect(DisconnectCause.ApplicationQuit).
    Note: The ConnectionHandler will use this to differentiate a regular disconnect from one that is triggered by Unity / app-quit.

Version 4.1.6.16 (22. June 2022)
    Fixed: Formatting issue in debug logs for WebGL exports.
    Changed: Best Region selection. A weighted ping value is used now. Out of the 5 attempts, the worst is discarded (usually the first) and the best is counted in twice (it is the fastest). In WebGL, HTTP is used to ping servers and when a request didn't finish, the next attempt will be delayed a bit.
    Changed: HTTP Ping class for Best Region selection in WebGL changed from Unity's WWW class to UnityWebRequest.

Version 4.1.6.15 (10. June 2022)
    Changed: Sharding / Clustering support. Clients will no longer connect to a random cluster by default. To do so, make sure to add "/*" to the region code, if your game supports sharding / multiple clusters. This is only done in very high CCU cases.

Version 4.1.6.14 (26. April 2022)
    Added: Warning log if SocketWebTcp could not be found at runtime in Unity WebGL exports.

Version 4.1.6.11 (22. November 2021)
    Changed: For Unity, PhotonEditorUtils.IsPrefab to use the correct prefab stage utility for Unity 2021.2 and up.
    Added: CustomAuthenticationType.Epic to authenticate via Epic Online Services (EOS).
    Added: CustomAuthenticationType.FacebookGaming to authenticate via Facebook Gaming services.

Version 4.1.6.8 (12. October 2021)
    Changed: CustomTypesUnity. The default Quaternion is now Quaternion.identity (which is a legit Quaterion, as opposed to the previously used new Quaternion). Added const values for each type's byte-size.
    Added: Checks to avoid creating a player for actorNumber 0.
    Added: CheckIfOpCanBeSent to OpJoinOrCreateRoom and OpRejoinRoom. Avoids changing state and repeating operation.
    Removed: Surplus checks if the LoadBalancingPeer is non-null. This is done in CheckIfOpCanBeSent(), too.

Version 4.1.6.7 (27. September 2021)
    Replaced: Pointer_stringify with UTF8ToString in WebSocket.jslib. It was removed from newer Emscripten versions and is no longer working when exporting from Unity 2021.2. betas. Replaced with UTF8ToString. Tested in 2018.4.x and a current beta.
    Fixed: Usage of websocketType for console.

Version 4.1.6.6 (17. September 2021)
    Removed: Usage of class EncryptorNative. This needs to be replaced by EncryptorNativeSource where the Native Socket Plugin should be used.
    Changed: The Native Socket Plugin can also be used for UDP on Xbox (not in Editor).
    Removed: CheckConnectSetupXboxOne() as platform requirements were turned into recommendations.
    Changed: For Xbox, order of checked assemblies when getting Type SocketNativeSource. It's more likely to be in Assembly-CSharp.

Version 4.1.6.5 (24. August 2021)
    Updated: The default name server host to "ns.photonengine.io". When using WSS on this, it expects TLS1.2 (Win 7 and old Unity versions may not support this).
    Fixed: Internally used OpJoinRoom() will now send custom room properties (all RoomOptions set) to the Master Server, too. This allows the Master Server to immediately find the room, even if property filtering is used. This was affecting matchmaking with OpJoinOrCreateRoom.

Version 4.1.6.4 (26. July 2021)
    Internal: Added PhotonEditorTools.HasFusion value and added AppSettings.AppIdFusion as well as ClientAppType.Fusion.
    Added: ConnectionHandler.DisconnectAfterKeepAlive to let the fallback thread call Disconnect after the KeepAliveInBackground time. Default: false.
    Changed: ConnectionHandler timer implementation to use a Stopwatch, which is a little more clear about what happens. PUN does not expose this value, so you need to set it in code (change the default).
    Added: Hashtable specific extension methods StripKeysWithNullValues and StripToStringKeys which allocates less.

Version 4.1.6.3 (06. July 2021)
    Added: Handling of ErrorCode Invalid Operation (-2) for Authenticate requests. This becomes a DisconnectCause = OperationNotAllowedInCurrentState.

Version 4.1.6.2 (17. June 2021)
    Changed: The enumeration CustomAuthenticationType was changed to fix naming inconsistencies. Use PlayStation4 and PlayStation5 respectively. Old variants are available as obsolete.

Version 4.1.6.0 (19. May 2021)
    Changed: As tokenless auth is no longer allowed when using a Name Server, there is now an error log and authentication will not be done from the client. This is not happening in the normal workflow but a precaution to detect issues, should something unpredicted happen.
    Changed: SupportLogger formatting of the timestamp to include the minutes (if available). Hours will not be logged (so in the logs, there is a wrap around of log-timestamps after 60 min).

Version 4.1.5.4 (13. April 2021)
    Changed: Connect-methods in the LoadBalancingClient now fail "early" when the peer is already connected. This prevents unintentional modifications of the state and auth token.
    Added: The LoadBalancingClient will now check if the token is available when the AuthMode 'AuthOnce' or 'AuthOnceWss' require it. If it's not available, the client will log an error and prevent the connection attempt. If this happens, the client is already in a bad state and won't connect anyways.

Version 4.1.5.3 (07. April 2021)
    Fixed: Protocol Fallback will now connect correctly when a fixed region is set.
    Changed: ConnectUsingSettings internally sets connectToBestRegion value, based on CloudRegion (equals appSettings.FixedRegion). This avoids pinging when a fixed region is set. Leads to callback OnDisconnected(InvalidRegion).

Version 4.1.5.2 (12. March 2021)
    Changed: Region pinging will now apply port overrides for the Master Server port for UDP and address-based pinging (in the address and the UDP pings).
    Changed: The RegionHandler gets the override port from lbc.ServerPortOverrides.MasterServerPort. If it's 0, the default port 5055 is being used.
    Changed: The LoadBalancingClient.ReplacePortWithAlternative is now static and internal and can be used by the RegionHandler.
    Added: TargetFramework (of the used dll) to SupportLogger output.
    Added: Room.GetPlayer() option to find the Master Client, if the id is 0 (which is commonly used as "owned/controlled by the room, so it requires the Master Client).

Version 4.1.5.1 (09. March 2021)
    Removed: Setting of protocol 1.6 when connecting directly to a Master Server. This was a workaround for older Photon Server SDKs.
    Note: If you host Photon yourself, you can set the LoadBalancingClient.SerializationProtocol to SerializationProtocol.GpBinaryV16, before you connect.
    Changed: OpLeaveRoom will now clear the GameServerAddress and private room-entering cache. This cleans the state and prevents accidental success for ReconnectAndRejoinRoom calls.
    Changed: ReconnectToMaster will check if MasterServerAddress and authToken are known. These are minimum requirements to reconnect to the master (after a connection loss).
    Added: CustomAuthenticationType.Playstation5 (value 12).

Version 4.1.5.0 (23. February 2021)
    Added: LoadBalancingClient.ClientType and related code. Defines which sort of AppId should be expected. The LoadBalancingClient supports Realtime and Voice app types. Default: Realtime.
    Note: This allows using AppSettings for Voice and Realtime clients more easily. ConnectUsingSettings will pick the relevant appid with this info.
    Moved: EncryptionDataParameters class to become an internal class of the LoadBalancingClient (it was not used outside of LBC).
    Removed: Room.StorePlayer was trying to calculate the Master Client (and was wrong about it). This triggered a OnMasterClientSwitched() callback in some cases of rejoining a room.

Version 4.1.4.9 (12. January 2021)
    Internal: EncryptionMode.DatagramEncryptionGCMRandomSequence (12) with .DatagramEncryptionGCM (13).
    Internal: TokenForInit is now an object instead of a string. This also affects the AuthenticationValues class. This enables the server to send a byte[], which is more effective than a string.
    Changed: Exposed all RoomOptions in Room class. Room.PublishUserId, Room.DeleteNullProperties.
    Changed: Room.AutoCleanUp can also be set from room options flag.
    Internal: EnterRoomParams and OpJoinRoom now use a JoinMode (replacing EnterRoomParams.CreateIfNotExists and EnterRoomParams.RejoinOnly).
    Fixed: Unity-specific CustomTypes.cs to actually only compile for Unity.
    Updated: EncryptionMode.DatagramEncryptionGCMRandomSequence (12) with .DatagramEncryptionGCM in the LoadBalancingClient.
    Added: Room.SetExpectedUsers() to let the server know who's also coming (or no longer coming).

Version 4.1.4.8 (30. November 2020)
    Added: Conditional compilation in methods which are only for UNITY_WEBGL and UNITY_XBOXONE. The code needed to compile for any platform, even though it should not run anywhere else.
    Added: Support for UNITY_GAMECORE.
    Added: Parameter checks for GetGameList (and PUN GetCustomRoomList). The operation is not sent unless the parameters are OK.
    Added: SupportLogger.OnDestroy to be removed from callback targets.
    Added: RoomOptions.SuppressPlayerInfo. It can be used to skip join and leave events as well as properties broadcasts in rooms.

Version 4.1.4.7 (25. November 2020)
    Fixed: It was possible to trigger multiple calls of Authenticate by calling ConnectToRegionMaster(region) multiple times while being connected to the Name Server.
    Changed: AuthenticationValues.ToString() to expose less data while showing which values are set.

Version 4.1.4.6 (17. November 2020)
    Added: Unity-specific types will now be registered for de/serialization automatically (in Unity projects) using CustomTypesUnity (in LoadBalancingClient constructor).
    Note: The Player class needs to reference the current room to deserialize, so it is not a serializable type in the Realtime API (but in PUN). Send the Player.ActorNumber instead and the receiver looks up the ActorNumber in the room.
    Changed: The client will now call disconnect if any operation response has a ReturnCode == ErrorCode.OperationLimitReached. The resulting OnDisconnect callback gets the new DisconnectCause.DisconnectByOperationLimit value.
    Added: DisconnectCause.DisconnectByDisconnectMessage. If the server has a "low level" reason to disconnect a client, it can now send a Disconnect Message with some debug info. The LoadBalancingClient will log this message as error and disconnect. When this gets used will be added to the docs.
    Changed: The BroadcastProperties parameter is now always sent to the Game Server, no matter if there are properties. This fixes a recent issue where UserIds were not broadcast in rooms, if no other player properties were used (see v4.1.4.5 changes).
    Changed: UseAlternativeUdpPorts is replaced by ServerPortOverrides, which allow configuration of ports per server (including using no override).
    Changed: UseAlternativeUdpPorts is obsolete and no longer used.
    Changed: LoadBalancingClient.NameServerPortOverride is now named NameServerPortInAppSettings, which is closer to what it resembles. It is overwritten by the ServerPortOverrides if the nameserver port is > 0 there.
    Added: Struct PhotonPortDefinition.
    Added: ReplacePortWithAlternative method to wrap up the replacement as per our address rules.
    Changed: When the client does not connect initially and EnableProtocolFallback is enabled, the ServerPortOverrides are reset and the fallback protocol will use the default ports for the Name Server (defined per protocol).
    Changed: ReconnectAndRejoin() no longer affects the value IsUsingNameServer. This is only about reconnecting.
    Changed: ReconnectAndRejoin() was logging error-level messages for expected situations. Now, there are only warnings in the logs. You can simply check the return value, which is false on error (then you should connect again, as usual).
    Internal: The pool type for paramDictionaryPool, which is used in OpRaiseEvent. It is now a ParameterDictionary, which will wrap some value-types into pooled objects. This helps avoid some memory allocation.
    Internal: ParameterCode.Secret is now .Token to match the server naming.
    Changed: Logging level when OpRaiseEvent fails due to leaving a room. It reports as INFO level, when leaving or disconnecting.
    Added: Error log for Op Authenticate, if the client does not have a token to authenticate on a Master or Game Server. That token comes from the Name Server and should be automatically present and used. Note: The client will send the auth but may fail due to missing token.
    Changed: LoadBalancingClient.Disconnect() now checks if the client was just created or is disconnecting already. Those cases won't trigger a callback, so there is no surplus attempt to disconnect the peer. Also, the State does not change. An INFO level debug message helps detect those cases.

Version 4.1.4.5 (02. September 2020)
    Added: Unity-only ConnectionHandler.StaticReset() to allow entering playmode without domain reload.
    Added: ErrorCode definition for OperationLimitReached (32743). The client will become unable to call any further operations (to safeguard the room/server) and get disconnected soon after. Currently used for SetProperties only.
    Fixed: Region pinging for the case that none of the regions answered anything. Then, all region results caused a callback.
    Added: Support for rooms that suppress room-events.
    Added: Field bool Room.SuppressRoomEvents to allow checking if room events are suppressed.
    Changed: If room events are suppressed, the callbacks OnCreatedRoom() and OnJoinedRoom() are now called by the operation response (not waiting for the suppressed events).
    Renamed: Room.SetRoomFlags() to InternalCacheRoomFlags().
    Changed: When entering a room, the local players NickName property (255) is not sent if NullOrEmpty.
    Changed: LoadBalancingApi should not use Unity.Debug unconditionally.
    Updated: AuthenticationValues reference slightly. Better wording.
    Updated: Token setter to be protected internal. Only needs to be set by Photon LB API.
    Fixed: Csproject files for Chat API and LoadBalancing API. The two projects now import the dll based on the current target framework (dynamic).

Version 4.1.4.4 (6. July 2020)
    Fixed: AppSettings.CopyTo method. It was not copying the new value EnableProtocolFallback yet.
    Fixed: The date of version 4.1.4.3 in this changelog.
    Updated: Error handling in PingWindowsStore.

Version 4.1.4.3 (24. June 2020)
    Added: Check that the Dev Region override is in the list of available regions (from Name Server). If not, the first available region is being used.
    Changed: RegionPinger.Start() now attempts to use a ThreadPool WorkerItem to ping individual regions. Only if that fails, a separate managed Thread is used. This should help avoid running into Thread limits (if any). Builds for NETFX_CORE don't use this.
    Changed: Error handling in PingMono. SocketExceptions were not handled entirely.
    Changed: PhotonPingClasses is no longer used. It's empty and can be removed.
    Changed: Handling of event LobbyStats in case of LoadBalancingPeer.UseByteArraySlicePoolForEvents. This relates to a new option in the PhotonPeer to use pooled memory (wrapped byte[] basically) when incoming events only contain a byte[]. See changes-library.txt and API reference.
    Added: Initial puzzle pieces for WSS Proxy support. This is not yet funtional. To actually use the proxy settings, a special WebSocket implementation is needed.
    Changed: The AppSettings.Port value is now also usable when connecting to a Name Server initially. This allows custom ports on a (custom) Name Server.
    Added: Various details to the SupportLogger output.
    Changed: Callback OnCreatedRoom() is now also triggered by the event Join. This is the same trigger as for JoinOrCreateRoom (if that created a new room).
    Added: Player.HasRejoined value. This is set for the local and remote players and can help define the workflow on ReJoin.
    Added: LoadBalancingClient.EnableProtocolFallback. If enabled, the client will try another protocol if the initial connect to the Name Server fails.
    Added: AppSettings.EnableProtocolFallback with a default of true. Used in ConnectUsingSettings to set the client's value accordingly.
    Internal: Added setting the LoadBalancingClient.Server in Connect and other places, so it should be accurate.
    Added: Checks for connections on WebGL and Xbox One. Settings that can be corrected (to match the platform's requirements) are corrected with a log note. An Exception is thrown, if the settings can't be corrected automatically. This means Connect methods may throw an Exception in some cases, which are to be fixed during development time.

Version 4.1.4.2 (8. May 2020 - rev5519)
    Fixed: EventLeave handling. The IsInactive property is to false before doing the OnPlayerLeftRoom callback.
    Note: Use Player.IsInactive to know the 'reason' for the callback.

Version 4.1.4.0 (27. April 2020 rev5469)
    Fixed: When connecting directly to a Master Server (self hosted), the serialization protocol 1.6 is used (not the detault 1.8). This was changed accidentally in v4.1.3.0 (and thus PUN 2.17).
    Added: Connection state check in CheckIfOpCanBeSent() to fail early if an op can't be sent.
    Updated: WebRPC handling and added an example to the doc of OnWebRpcResponse.
    Added: Logging of OnJoinRoomFailed to SupportLogger.
    Changed: StripKeysWithNullValues to reuse a list of key with null-values. This causes less allocations and garbage to clean. As a downside, the method now runs only for one thread (even for distinct IDictionary instances). This should not be a problem for the expected use case.
    Changed: The LoadBalancingClient.OnStatusChanged will handle StatusCode.SendError as disconnect due to Exception. Log level INFO should log the inner exception when sending.
    Fixed: Cleanup of the RoomReference for the local player object on disconnect. This prevents issues when setting properties, after joining and leaving a room (back on Master Server).
    Internal: LoadBalancingClient.ExpectedProtocol is now a nullable property with private setter. It's used internally (only) to switch to the target transport protocol when Authmode AuthOnceWss is "done".
    Fixed: EventLeave handling. When a player gets removed from the room, the IsInactive property must be set to false before doing the OnPlayerLeftRoom callback. Use Player.IsInactive to know the 'reason' for the callback.

Version 4.1.3.0 (23.03.2020 rev5394)
    Changed: Trying to set empty custom properties Hashtable will fail (return false) and log error.
    Changed: In online mode, trying to set properties while not joined to a room will fail (return false) and log error. Caching local player properties could be allowed though.
    Changed: Player.InternalCacheProperties is now "protected internal" and no longer "public".
    Changed: LoadBalancingClient.OpSetPropertiesOfRoom is now "protected internal" and no longer "public". Use LoadBalancingClient.OpSetCustomPropertiesOfRoom or Room.SetCustomProperties.
    Changed: StatusCode.EncryptionFailedToEstablish will cause disconnection with DisconnectCause.ExceptionOnConnect.
    Changed: Fix for Unity cloud build context to prevent sanitization of server settings, it's not needed and for some reason doesn't detect the current server settings.
    Changed: AppSettings. The NonSerialized attribute is now only used in Unity builds.
    Changed: With the updated Photon library (v4.1.3.0), the encryption can be set to true on any connection, including WSS. It should not be used conditionally for Auth.
    Changed: GetPingImplementation() new sets a default PhotonPingImplementation for UNITY_WEBGL, NETFX_CORE and regular Mono/.Net.
    Internal: New datagram encryption mode DatagramEncryptionGCMRandomSequence (value 12). To be used later on.
    Internal: The SocketWebTcp.SerializationProtocol is now selected by the PhotonSocket with the Peer's current value. It no longer needs to be set.

Version 4.1.2.20 (12. December 2019 - rev5296)
    Added: New callback IErrorInfoCallback.OnErrorInfo when the client receives an ErrorInfo event from the server.
    Changed: RegionPinger use a singleton MonoBehaviourEmpty for coroutine ping in WebGL in Unity.
    Added: LoadBalancingClient.SerializationProtocol property to get or set the binary protocol version. Use this always instead of setting it via LoadBalancingPeer.SerializationProtocolType.
    Added: LoadBalancingClient.ConnectUsingSettings(AppSettings appSettings). This allows Best Region connect, setting a custom name server and much more.
    Changed: Connect() is now ConnectToMasterServer(). Unlike ConnectUsingSettings(), this requires some settings to be done on the client.
    Added: Return parameter for all methods that set properties on the server.
    Note: Room.SetCustomProperties returns bool. If you did override this, your project will have errors, make sure to fix the return type.
    Changed: Failed Authentication will no longer call the OnDisconnected callback twice. This should better align with expectations.
    Internal: Pinging regions via coroutine (when Threads are unavailable) now uses only one GameObject for all pinging.

Version 4.1.2.19 (12. November 2019 - rev5266)
    Fixed: The ExpectedProtocol is now also set for Authmode "AuthOnce" for ConnectToNameServer and ConnectToRegionMaster.
    Changed: Player.ToString() to show ActorNumber and NickName. The PlayerProperties are included in ToStringFull().
    Changed: Logging message for OpAuthenticateOnce (only logged at info level and up).
    Changed: Avoiding a potential nullreference exception on leave of another player.
    Updated: Cluster support. The LoadBalancingClient.CurrentCluster gives access to the current cluster. Region.SetCodeAndCluster() now separates the cluster string properly. See ConnectToRegionMaster, too.
    Fixed: Changing the SupportLogger.Client now skips registering for callbacks, if the new value is null.
    Changed: Logging of SupportLogger.
    Added: LoadBalancingClient.OpJoinRandomOrCreateRoom. This can be used to create a room, should random matchmaking fail. This helps avoid race conditons where players can't find one another.
    Added: Extra null-check in handling of event leave.

Version 4.1.2.17 (9. August 2019 - rev5188)
    Changed: SupportLogger. Traffic stats are enabled by default. The PhotonHandler no longer has to enable this.
    Added: Min/max ping to logged statistics. SupportLogger.TrackValues is invoked to keep track of min/max ping for each connection.
    Fixed: Statistics logging is started on Connect and stopped OnDisconnected().
    Changed: Callback registration.
    Changed: All callback target changes are now queued in one queue and executed in order. This avoids cases where our implementation defined if a callback got added or removed, when a target got added and removed.
    Changed: Duplicate addition and removal is now prevented.
    Changed: The callback containers now know and use the LoadBalancingClient to update the targets. This means they don't need lists for additions and removals anymore.
    Changed: Events will now also update the callback targets before executing the event callback.
    Changed: WebRpcCallbacksContainer is now also a List<i> like the other containers. This is simpler to maintain. The only "custom" callback implementation is that for events. This was an event delegate before and remains one. No change for this.
    Changed: The callbacks to OnDisconnected(reason). On timeout or exception, there is now only one callback which happens after the client/peer is actually disconnected. The peer's status changes (timeout, etc.) are used to identify the reason but don't cause a callback on their own. Previously, you could run into more than one OnDisconnected call and fail to reconnect in the first one.
    Changed: There are now fewer calls of OnDisconnected(). Example: A timeout disconnect caused two calls because signalled the timeout and the second signalled when the client locally finished disconnecting. Now, the DisconnectCause stores the reason and there is only one callback.
    Changed: Internal use of DisconnectCause. It's now set in LBC.Disconnect() and by errors from the Peer. It's reset to "None" before calls to Peer.Connect().
    Removed: DisconnectCause enum values that were obsolete already. DisconnectByServerUserLimit is now MaxCcuReached. TimeoutDisconnect is now ClientTimeout. DisconnectByServer is now ServerTimeout.
    Changed: OnStatusChanged() case Disconnect always sets the CurrentRoom to null. It is no longer used to store the roomname from the Master Server to use on the Game Server.
    Removed: LoadBalancingClient.didAuthenticate, which is no longer needed for the cleaned up logic.
    Changed: WebRpcResponse.ReturnCode -> ResultCode and WebRpcResponse.DebugMessage -> Message.
    Changed: AuthenticationValues.ToString() to include more useful info.
    Changed: Execution order for disconnect on quit. As OnApplicationQuit is followed by OnDisable, PUN now disconnects in OnDisable, if OnApplicationQuit was called previously. This means that you can now send a final message in OnApplicationQuit. It's not guaranteed to arrive anywhere, as the message won't be repeated on loss.
    Removed: PhotonHandler.OnDestroy which was not needed anymore. OnDisable is also called when the app quits, so it's adequate to tear down the thread there.
    Removed: Outdated and unused PingMonoEditor.
    Changed: Random ID for each ping is now truly randomized.
    Changed: Region pinging result logging. Per region, all rtts are available, as well as a previous summary (if any). Pun gets it via RegionHandler.GetResults().

Version 4.1.2.15 (7. June 2019 - rev5137)
    Added: Options for OpFindFriends to filter which rooms should be returned by the server. The default is the same as before but now the friend list may exclude rooms which are not yet on the game server, invisible, closed (or any combination).
    Added: SimulateConnectionLoss(bool) to simplify testing of connection loss. This uses the built-in network simulation to get a client timeout disconnect.
    Removed: EventExt class, which only contained obsolete methods.

Version 4.1.2.14 (6. May 2019 - rev5097)
    Changed: Realtime API changes are now listed in a separate changes file.
    Updated: Demos to make use of Sender and CustomData.

Version 4.1.2.13 (3. May 2019 - rev5086)
    Changed: Renamed ClientState items which ended on "Gameserver" and "Masterserver" to using PascalCase "GameServer" and "MasterServer". The previous names are obsolete to ease upgrading this, if needed.
    Updated: Checks if any given operation can be sent (to the currently connected server) or not. As not all operations are available on all server types, this may help avoid some mismatches.
    Fixed: BroadcastPropsChangeToAll is applied correctly (it wasn't used properly, when false).
    Fixed: When in offline mode, OpSetPropertiesOfActor does not get called (it failed due to not being connected).

Version 4.1.2.11 (15. April 2019 - rev5043)
    Changed: InLobby property is now checking the State == JoinedLobby, which is analog to InRoom.
    Changed: IsConnectedAndReady is now also false for ClientState.DisconnectingFromGameserver, DisconnectingFromMasterserver and DisconnectingFromNameServer.
    Changed: GetGameList check if the filter is null or empty. It's not sent for empty filters.
    Added: Nintendo Switch as CustomAuthenticationType.

Version 4.1.2.10 (11. March 2019 - rev5023)
    Changed: The cached "best region" is cleared whenever a region's pinging finishes. This fixes a potential issue when the BestRegion value is used before the pinging is done. Then, you end up with a wrong selection.
    Changed: PhotonPing now reuses the Socket per region.
    Changed: The RegionHandler now checks #if PING_VIA_COROUTINE to use a coroutine instead of a thread (per region). This is for WebGL exports from Unity.
    Changed: The SupportLogger now uses a Stopwatch to log the time (not depending on Unity's APIs).

Version 4.1.2.1 (31. July 2018 - rev4787)
    Changed: OnStateChangeAction is now named StateChanged and provides a "previous state" value. State changes only trigger the event-call when the value actually changes.
    Renamed: OnEventAction to EventReceived and OnOpResponseAction to OpResponseReceived.
    Added: LoadBalancingClient now has AddCallbackTarget and RemoveCallbackTarget to simplify registering for various callbacks.

Version 4.1.2.0 (3. May 2018 - rev4660)
    Changed: The namespace to the simpler "Photon.Realtime".
    Added: Various callbacks to signal specific situations / events. To get those, a class must implement the interface and be added to a list of "Targets". See: ILoadBalancingCallbacks.
    Added: RegionHandler, which provides methods to ping a list of regions and to find the one with best ping. This moves PUN's "Best Region" feature to the LoadBalancing API.
    Moved: The PhotonPing was part of the dll but is now part of LoadBalancing.
    Added: LoadBalancingClient.UseAlternativeUdpPorts. This way, UDP may use ports of the Steam Multiplayer port-range by simply replacing existing port strings in addresses.
    Changed: RaiseEvent now has an overload, that uses RaiseEventOptions and SendOptions. The old variant is obsolete but will still work.
    Changed: CheckUserOnJoin is now set by default. The RoomOptions.CheckUserOnJoin got removed.
    Added: Client-side checks and limits for OpFindFriends.
    Added: Optional parameter sendAuthCookie to OpLeaveRoom. The app can control what's passed from Photon to a server via WebHook.
    Changes: The room list for lobbies is no longer part of the LoadBalancingClient. Instead, implement the callback for the changed room list.
    Added: AppSettings, a base class to host AppId and some settings for a title. This will help make it available across products. Right now, the LoadBalancingClient is not using it yet.
    Changed: Player.ID is now .ActorNumber, which mirrors the server's naming.
    Fixed: Unity compile defines to support Unity 2018,

Version 4.1.1.18 (19. December 2017 - rev4540)
    Changed: FriendInfo.Name is now "UserId", which is up to date with it's usage.
    Changed: CheckUserOnJoin is now set by default. The RoomOptions.CheckUserOnJoin got removed.

Version 4.1.1.17 (11. October 2017 - rev4465)
    Changed: OperationCode const byte Join = 255 is now marked obsolete. We use "JoinGame" instead.
    Added: DisconnectCause.AuthenticationTicketExpired.
    Fixed: DebugReturn call in Unity WebGL.

Version 4.1.1.15 (17. July 2017 - rev4232)
    Added: LoadBalancingClient.TransportProtocol as shortcut to the use PhotonPeer's TransportProtocol value. This enables setting the protocol easily while not connected.
    Added: LoadBalancingClient.SocketImplementationConfig as shortcut to modify PhotonPeer's SocketImplementationConfig. This enables you to setup which IPhotonSocket implementation to use for which network protocol.
    Changed: LoadBalancingPeer.ConfigUnitySockets() to try to find our websocket implementations in the assembly, making the SocketWebTcpCoroutine and SocketWebTcpThread classes optional.
    Removed: Class "SocketWebTcp" is no longer found by ConfigUnitySockets().

Version 4.1.1.14 (5. July 2017 - rev4191)
    Changed: The ClientState "Uninitialized" is now "PeerCreated". This is the initial state. ConnectedToMaster is now ConnectedToMasterserver (both use the same value).
    Updated: ClientState values descriptions.
    Internal: GameEnteredOnGameServer() first sets the local player's actorNumber, then updates the player lists.

Version 4.1.1.8 (24. February 2017 - rev3873)
    Added: Player.UserId field and code to read published UserIds from the player properties in CacheProperties(). When publishing the UserId in a room (RoomOptions.PublishUserId = true), the UserId becomes available for all players in a room. Good to find/make friends or follow a team player into another room.
    Added: New matchmaking operation: OpGetGameList(typedLobby, sqlFilter). This fetches a list of rooms that match the filter. You can show lists of rooms with specific properties, if needed (or still use OpJoinRandom).
    Fixed: WebFlags properties setters.

Version 4.1.1.7 (16. December 2016)
    Fixed: Demos with persistent (Turnbased) games. The Memory Demo was not setting up rooms correctly (which led to errors joining them) and used a "join" rather than a "rejoin" to get into saved games (getting added to the room once more).

Version 4.1.1.6 (9. December 2016 - rev3801)
    Added: OpJoinRandom will now "remember" to send ExpectedUsers to the Game Server (by caching the value).
    Added: AuthEvent and it's handling. This (internally sent) event can now update the client's token anytime (before that expires).
    Added: LoadBalancingClient.OpChangeGroups().
    Changed: LoadBalancingClient.Disconnect() no longer sets it's own State to Disconnected. It waits till the state-change callback gets called by the lib.

Version 4.1.1.2 (13. September 2016 - rev3652)
    Removed: LoadBalancingClient.PlayerName and Player.Name. Were obsolete for more than a year. There is a NickName and the UserId can be set in the AuthValues.
    Removed: OpJoinRoom() overload with actorNumber. This was obsolete. To enable clients to return to a room, set AuthValues and a userID.
    Changed: LoadBalancingClient no longer overrides the protocol for Unity WebGL. This is done in the LoadBalancingPeer.ConfigUnitySockets().
    Changed: GetNameServerAddress() is the same in Chat and LoadBalancing APIs now.
    Added: DisconnectCause.DisconnectByServerLogic and handling for this case. You can check this DisconnectedCause when the LoadBalancingClient.State is ClientState.Disconnected.
    Added: Hashtable definition to use Photon's own implementation for Windows Store builds (NETFX_CORE). This must be used but it means you to use the same Hashtable definition in all builds (no matter if 8.1 or 10).
    Added: Support for WebGL export in Unity.
    Changed: OnStateChangeAction, OnEventAction and OnOpResponseAction are now events. To register a method in one of those, use += and to deregister you need to use -=. This prevents assigning a new method and de-registering any previously registered ones.

Version 4.1.1.0 (15. August 2016 - rev3536)
    Fixed: Room.ClearExpectedUsers() is now sending it's current, local "expected users" to update the server with "CAS" (Check and Swap). This gives the client an update when the values become valid (which updates the local cache after the roundtrip).
    Added: Support for the 'Server Side Master Client' feature. The Room will read master client updates from the server accordingly. Room.SetMasterClient() enables you to override the server's selection (provided it did not change before your operation gets executed).
    Changed: Option for bool WebForward into the new "WebFlags". This allows fine control of which data is being sent to WebHooks. This affects all SetProperties, OpWebRPC and the RaiseEventOptions.
    Added: WebRPC.cs to the LoadBalancing API folder (was available separately before). It contains WebFlags and WebRpcResponse.

Version 4.1.0.6 (21. June 2016 - rev3376)
    Fixed: LoadBalancingPeer.OpRaiseEvent(...) to send operations (and events) unencrypted again.

Version 4.1.0.2 (21. April 2016 - rev3283)
    Added: Expected Users. This affects the Room, LoadBalancingClient, JoinRoom, JoinOrCreateRoom and CreateRoom.
    Added: null check in Extensions.StripToStringKeys().
    Fixed: FriendInfo.IsInRoom, which returned the opposite of it's naming! Also changed FriendInfo ToString() according to PUN's.
    Added: RoomInfo expectedUsersField, which is updated with room properties (well known ones).
    Added: Room.ExpectedUsers and ClearExpectedUsers() to expose the list of expected players.
    Added: RoomInfo.serverSideMasterClient and masterClientIdField (also updated with well known properties).
    Changed: OpRaiseEvent now re-uses a Dictionary in the LoadBalancingPeer. It uses Clear(), rather than creating a new Dict each time.
    Changed: AuthenticationValues to also use C# properties and and backup-fields. This is guaranteed to work in Unity.
    Updated: EventCode ErrorInfo reference with a link to "WebHooks" doc online.
    Changed: Disconnect handling in the LoadBalancingClient. The client should reset correctly and log info, if it's in a State where a disconnect is a proper error. Note: In some cases like "switching server", a disconnect is expected, so it's not an error then.
    Fixed: PlayerProperties sent to game server will now include well-known properties again. This fixes the "NickName missing" bug.
    Fixed: LoadBalancingClient.State value when the client fails to join or create a game on the Master Server. The state is correctly re-set to ClientState.JoinedLobby or ClientState.ConnectedToMaster.
    Internal: Added private inLobby value, to store if the client was/is in a lobby on the Master Server.
    Fixed: DemoClient (in demo-loadbalancing) now makes use of the Name Server by using: ConnectToRegionMaster("eu").
    Added: DemoClient now has debug output when the connection times out or can't be established.

Version 4.0.5.1 (18. January 2016 - rev3187)
    Added: OpSetCustomPropertiesOfActor() and OpSetCustomPropertiesOfRoom() now check locally, if the client is currently in a room. It must be, to be able to set these properties. An exception exists for setting properties for the local player's actorNumber, but those are better set via LoadBalancingClient.LocalPlayer.

Version 4.0.0.11 (28. October 2015 - rev3093)
    Added: LeaveLobby handling in OnOperationResponse(), which sets the client's state correctly.
    Changed: Order of execution for Ev Join. If user is known (inactive user rejoins), the player's props are read. The actor list is used, if available.
    Changed: RoomOptions to use properties with backup-fields to avoid issues in Unity which has issues with Object Initializer (curly brackets).
    Changed: JoinMode 2 is now "JoinOrRejoin". Was: "Rejoin".
    Added: ErrorCode constant AuthenticationTicketExpired.
    Internal: OpJoinRoom, OpCreateRoom and OpJoinRandomRoom no longer use a (growing) list of properties. Instead, classes were created to "sum up" their parameters. The api for games didn't change.
    Internal: Related to the refactoring of Join/Create, the LoadBalancingClient now creates a Room instance when the client arrived on the GameServer (before, it got created in the initial "create" call).

Version 4.0.0.10 (14. July 2015 - rev2988)
    Updated: Description for IsConnectedAndReady.
    Changed: NameServerAddress to return a fitting address depending on protocol (including WebSocket but not yet RHTTP).
    Updated: The only name server host is now "ns.exitgames.com", which gets turned into a proper address by protocol.
    Changed: LoadBalancingClient.CustomAuthenticationValues is now .AuthValues. You can use those values to identify a user, even if you don't setup an external, custom authentication service.
    Changed: LoadBalancingClient.UserId no longer directly stores the id but puts it into AuthValues. This means, the UserId could also be set via setting AuthValues.
    Changed: The API of AuthenticationValues. There is now the UserId and AddAuthParameter() replaces the less general SetAuthParameters() (which only set specific key/values).
    Changed: PlayerName gets renamed to NickName, so PhotonPlayer.Name becomes .NickName and LoadBalancingClient.Name becomes .NickName, too. The old naming is marked as obsolete.
    Changed: Particle Demo now connects to the Cloud by default (because it's easier to setup and try). You can define your own Master Server (Photon OnPremise) of course.
    Added: GamePropertyKey.MasterClientId (248) and ParameterCode.MasterClientId (203)
    Added: ParameterCode.ExpectedValues (231)
    Added: ParameterCode.SuppressRoomEvents (237)

Version 4.0.0.6 (05. December 2014 - rev2758)
    Added: LoadBalancingClient.OpJoinOrCreateRoom overload which has lobby as parameter. If a room gets created, this defines in which lobby it belongs.
    Changed: LoadBalancingPeer: Added new error code PluginMismatch, documentation for Plugins parameter code.

Version 4.0.0.1 (17. June 2014 - rev2663)
    Added: LoadBalancingClient.OpRaiseEvent(). Now that LoadBalancingClient USES a loadBalancingPeer (and doesn't extend it), things are much easier by offering this method, too!
    Added: LoadBalancingClient.IsConnected and .IsConnectedAndReady to LB API. Going to be part of the API from now on.
    Removed: Unused fields clientId and clientCount.
    Changed: Field for internal use "lastJoinActorNumber" is now private as intended.
    Changed: LoadBalancingClient.Disconnect is now setting it's own state to Disconnected if the connection got closed (as expected).

Version 4.0.0.0 (23. May 2014 - rev2614)
    Changed: LoadBalancingClient.FriendList creation/update is delayed until the server's response is available. This avoids cases where the friends are offline for the moment between requesting the update and getting it. Initially, it is null as before.
    Added: some methods to Player to find next player, etc. Useful for turnbased games to find an opponent.
    Added: LoadBalancingClient.UserId, which is the ID of a user(account). This is used in FindFriends and when you fetch account-related data (like save-games for Turnbased games). Set it before Connect*(). As fallback when empty during connect, the PlayerName is used instead.
    Removed: LoadBalancingPeer.OpSetCustomPropertiesOfActor and OpSetPropertyOfRoom which were too special to be so low level. Could be implemented to LBClient.
    Fixed: OpJoinRandomRoom and OpCreateRoom which didn't reset the ActorNr to claim when entering the room. Depending on previous actions, some calls of those methods did fail when the actorNumber wasn't available.
    Changed: OperationCode.Rpc is now called OperationCode.WebRpc. It's simply much cleaner (considering PUN has RPCs as well but in a different context).
    Changed: WebRpcResponse reading to be able to handle additional data.
    Added: Parameter webForward to: OpSetCustomPropertiesOfRoom and OpSetPropertiesOfRoom. The "old" overloads of these methods are still there, too. If webForward is true, the properties are sent to the WebHooks.