RoomInfo.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. // ----------------------------------------------------------------------------
  2. // <copyright file="RoomInfo.cs" company="Exit Games GmbH">
  3. // Loadbalancing Framework for Photon - Copyright (C) 2018 Exit Games GmbH
  4. // </copyright>
  5. // <summary>
  6. // This class resembles info about available rooms, as sent by the Master
  7. // server's lobby. Consider all values as readonly.
  8. // </summary>
  9. // <author>developer@photonengine.com</author>
  10. // ----------------------------------------------------------------------------
  11. #if UNITY_4_7 || UNITY_5 || UNITY_5_3_OR_NEWER
  12. #define SUPPORTED_UNITY
  13. #endif
  14. namespace Photon.Realtime
  15. {
  16. using System;
  17. using System.Collections;
  18. using ExitGames.Client.Photon;
  19. #if SUPPORTED_UNITY || NETFX_CORE
  20. using Hashtable = ExitGames.Client.Photon.Hashtable;
  21. using SupportClass = ExitGames.Client.Photon.SupportClass;
  22. #endif
  23. /// <summary>
  24. /// A simplified room with just the info required to list and join, used for the room listing in the lobby.
  25. /// The properties are not settable (IsOpen, MaxPlayers, etc).
  26. /// </summary>
  27. /// <remarks>
  28. /// This class resembles info about available rooms, as sent by the Master server's lobby.
  29. /// Consider all values as readonly. None are synced (only updated by events by server).
  30. /// </remarks>
  31. public class RoomInfo
  32. {
  33. /// <summary>Used in lobby, to mark rooms that are no longer listed (for being full, closed or hidden).</summary>
  34. public bool RemovedFromList;
  35. /// <summary>Backing field for property.</summary>
  36. private Hashtable customProperties = new Hashtable();
  37. /// <summary>Backing field for property.</summary>
  38. protected int maxPlayers = 0;
  39. /// <summary>Backing field for property.</summary>
  40. protected int emptyRoomTtl = 0;
  41. /// <summary>Backing field for property.</summary>
  42. protected int playerTtl = 0;
  43. /// <summary>Backing field for property.</summary>
  44. protected string[] expectedUsers;
  45. /// <summary>Backing field for property.</summary>
  46. protected bool isOpen = true;
  47. /// <summary>Backing field for property.</summary>
  48. protected bool isVisible = true;
  49. /// <summary>Backing field for property. False unless the GameProperty is set to true (else it's not sent).</summary>
  50. protected bool autoCleanUp = true;
  51. /// <summary>Backing field for property.</summary>
  52. protected string name;
  53. /// <summary>Backing field for master client id (actorNumber). defined by server in room props and ev leave.</summary>
  54. public int masterClientId;
  55. /// <summary>Backing field for property.</summary>
  56. protected string[] propertiesListedInLobby;
  57. /// <summary>Read-only "cache" of custom properties of a room. Set via Room.SetCustomProperties (not available for RoomInfo class!).</summary>
  58. /// <remarks>All keys are string-typed and the values depend on the game/application.</remarks>
  59. /// <see cref="Room.SetCustomProperties"/>
  60. public Hashtable CustomProperties
  61. {
  62. get
  63. {
  64. return this.customProperties;
  65. }
  66. }
  67. /// <summary>The name of a room. Unique identifier for a room/match (per AppId + game-Version).</summary>
  68. public string Name
  69. {
  70. get
  71. {
  72. return this.name;
  73. }
  74. }
  75. /// <summary>
  76. /// Count of players currently in room. This property is overwritten by the Room class (used when you're in a Room).
  77. /// </summary>
  78. public int PlayerCount { get; private set; }
  79. /// <summary>
  80. /// The limit of players for this room. This property is shown in lobby, too.
  81. /// If the room is full (players count == maxplayers), joining this room will fail.
  82. /// </summary>
  83. /// <remarks>
  84. /// As part of RoomInfo this can't be set.
  85. /// As part of a Room (which the player joined), the setter will update the server and all clients.
  86. /// </remarks>
  87. public int MaxPlayers
  88. {
  89. get
  90. {
  91. return this.maxPlayers;
  92. }
  93. }
  94. /// <summary>
  95. /// Defines if the room can be joined.
  96. /// This does not affect listing in a lobby but joining the room will fail if not open.
  97. /// If not open, the room is excluded from random matchmaking.
  98. /// Due to racing conditions, found matches might become closed even while you join them.
  99. /// Simply re-connect to master and find another.
  100. /// Use property "IsVisible" to not list the room.
  101. /// </summary>
  102. /// <remarks>
  103. /// As part of RoomInfo this can't be set.
  104. /// As part of a Room (which the player joined), the setter will update the server and all clients.
  105. /// </remarks>
  106. public bool IsOpen
  107. {
  108. get
  109. {
  110. return this.isOpen;
  111. }
  112. }
  113. /// <summary>
  114. /// Defines if the room is listed in its lobby.
  115. /// Rooms can be created invisible, or changed to invisible.
  116. /// To change if a room can be joined, use property: open.
  117. /// </summary>
  118. /// <remarks>
  119. /// As part of RoomInfo this can't be set.
  120. /// As part of a Room (which the player joined), the setter will update the server and all clients.
  121. /// </remarks>
  122. public bool IsVisible
  123. {
  124. get
  125. {
  126. return this.isVisible;
  127. }
  128. }
  129. /// <summary>
  130. /// Constructs a RoomInfo to be used in room listings in lobby.
  131. /// </summary>
  132. /// <param name="roomName">Name of the room and unique ID at the same time.</param>
  133. /// <param name="roomProperties">Properties for this room.</param>
  134. protected internal RoomInfo(string roomName, Hashtable roomProperties)
  135. {
  136. this.InternalCacheProperties(roomProperties);
  137. this.name = roomName;
  138. }
  139. /// <summary>
  140. /// Makes RoomInfo comparable (by name).
  141. /// </summary>
  142. public override bool Equals(object other)
  143. {
  144. RoomInfo otherRoomInfo = other as RoomInfo;
  145. return (otherRoomInfo != null && this.Name.Equals(otherRoomInfo.name));
  146. }
  147. /// <summary>
  148. /// Accompanies Equals, using the name's HashCode as return.
  149. /// </summary>
  150. /// <returns></returns>
  151. public override int GetHashCode()
  152. {
  153. return this.name.GetHashCode();
  154. }
  155. /// <summary>Returns most interesting room values as string.</summary>
  156. /// <returns>Summary of this RoomInfo instance.</returns>
  157. public override string ToString()
  158. {
  159. return string.Format("Room: '{0}' {1},{2} {4}/{3} players.", this.name, this.isVisible ? "visible" : "hidden", this.isOpen ? "open" : "closed", this.maxPlayers, this.PlayerCount);
  160. }
  161. /// <summary>Returns most interesting room values as string, including custom properties.</summary>
  162. /// <returns>Summary of this RoomInfo instance.</returns>
  163. public string ToStringFull()
  164. {
  165. return string.Format("Room: '{0}' {1},{2} {4}/{3} players.\ncustomProps: {5}", this.name, this.isVisible ? "visible" : "hidden", this.isOpen ? "open" : "closed", this.maxPlayers, this.PlayerCount, this.customProperties.ToStringFull());
  166. }
  167. /// <summary>Copies "well known" properties to fields (IsVisible, etc) and caches the custom properties (string-keys only) in a local hashtable.</summary>
  168. /// <param name="propertiesToCache">New or updated properties to store in this RoomInfo.</param>
  169. protected internal virtual void InternalCacheProperties(Hashtable propertiesToCache)
  170. {
  171. if (propertiesToCache == null || propertiesToCache.Count == 0 || this.customProperties.Equals(propertiesToCache))
  172. {
  173. return;
  174. }
  175. // check of this game was removed from the list. in that case, we don't
  176. // need to read any further properties
  177. // list updates will remove this game from the game listing
  178. if (propertiesToCache.ContainsKey(GamePropertyKey.Removed))
  179. {
  180. this.RemovedFromList = (bool)propertiesToCache[GamePropertyKey.Removed];
  181. if (this.RemovedFromList)
  182. {
  183. return;
  184. }
  185. }
  186. // fetch the "well known" properties of the room, if available
  187. if (propertiesToCache.ContainsKey(GamePropertyKey.MaxPlayers))
  188. {
  189. this.maxPlayers = Convert.ToInt32(propertiesToCache[GamePropertyKey.MaxPlayers]);
  190. }
  191. if (propertiesToCache.ContainsKey(GamePropertyKey.IsOpen))
  192. {
  193. this.isOpen = (bool)propertiesToCache[GamePropertyKey.IsOpen];
  194. }
  195. if (propertiesToCache.ContainsKey(GamePropertyKey.IsVisible))
  196. {
  197. this.isVisible = (bool)propertiesToCache[GamePropertyKey.IsVisible];
  198. }
  199. if (propertiesToCache.ContainsKey(GamePropertyKey.PlayerCount))
  200. {
  201. this.PlayerCount = Convert.ToInt32(propertiesToCache[GamePropertyKey.PlayerCount]);
  202. }
  203. if (propertiesToCache.ContainsKey(GamePropertyKey.CleanupCacheOnLeave))
  204. {
  205. this.autoCleanUp = (bool)propertiesToCache[GamePropertyKey.CleanupCacheOnLeave];
  206. }
  207. if (propertiesToCache.ContainsKey(GamePropertyKey.MasterClientId))
  208. {
  209. this.masterClientId = (int)propertiesToCache[GamePropertyKey.MasterClientId];
  210. }
  211. if (propertiesToCache.ContainsKey(GamePropertyKey.PropsListedInLobby))
  212. {
  213. this.propertiesListedInLobby = propertiesToCache[GamePropertyKey.PropsListedInLobby] as string[];
  214. }
  215. if (propertiesToCache.ContainsKey((byte)GamePropertyKey.ExpectedUsers))
  216. {
  217. this.expectedUsers = (string[])propertiesToCache[GamePropertyKey.ExpectedUsers];
  218. }
  219. if (propertiesToCache.ContainsKey((byte)GamePropertyKey.EmptyRoomTtl))
  220. {
  221. this.emptyRoomTtl = (int)propertiesToCache[GamePropertyKey.EmptyRoomTtl];
  222. }
  223. if (propertiesToCache.ContainsKey((byte)GamePropertyKey.PlayerTtl))
  224. {
  225. this.playerTtl = (int)propertiesToCache[GamePropertyKey.PlayerTtl];
  226. }
  227. // merge the custom properties (from your application) to the cache (only string-typed keys will be kept)
  228. this.customProperties.MergeStringKeys(propertiesToCache);
  229. this.customProperties.StripKeysWithNullValues();
  230. }
  231. }
  232. }