Extensions.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. // ----------------------------------------------------------------------------
  2. // <copyright file="Extensions.cs" company="Exit Games GmbH">
  3. // Photon Extensions - Copyright (C) 2018 Exit Games GmbH
  4. // </copyright>
  5. // <summary>
  6. // Provides some helpful methods and extensions for Hashtables, etc.
  7. // </summary>
  8. // <author>developer@photonengine.com</author>
  9. // ----------------------------------------------------------------------------
  10. #if UNITY_4_7 || UNITY_5 || UNITY_5_3_OR_NEWER
  11. #define SUPPORTED_UNITY
  12. #endif
  13. namespace Photon.Realtime
  14. {
  15. using System.Collections;
  16. using System.Collections.Generic;
  17. using ExitGames.Client.Photon;
  18. #if SUPPORTED_UNITY
  19. using UnityEngine;
  20. using Debug = UnityEngine.Debug;
  21. #endif
  22. #if SUPPORTED_UNITY || NETFX_CORE
  23. using Hashtable = ExitGames.Client.Photon.Hashtable;
  24. using SupportClass = ExitGames.Client.Photon.SupportClass;
  25. #endif
  26. /// <summary>
  27. /// This static class defines some useful extension methods for several existing classes (e.g. Vector3, float and others).
  28. /// </summary>
  29. public static class Extensions
  30. {
  31. /// <summary>
  32. /// Merges all keys from addHash into the target. Adds new keys and updates the values of existing keys in target.
  33. /// </summary>
  34. /// <param name="target">The IDictionary to update.</param>
  35. /// <param name="addHash">The IDictionary containing data to merge into target.</param>
  36. public static void Merge(this IDictionary target, IDictionary addHash)
  37. {
  38. if (addHash == null || target.Equals(addHash))
  39. {
  40. return;
  41. }
  42. foreach (object key in addHash.Keys)
  43. {
  44. target[key] = addHash[key];
  45. }
  46. }
  47. /// <summary>
  48. /// Merges keys of type string to target Hashtable.
  49. /// </summary>
  50. /// <remarks>
  51. /// Does not remove keys from target (so non-string keys CAN be in target if they were before).
  52. /// </remarks>
  53. /// <param name="target">The target IDictionary passed in plus all string-typed keys from the addHash.</param>
  54. /// <param name="addHash">A IDictionary that should be merged partly into target to update it.</param>
  55. public static void MergeStringKeys(this IDictionary target, IDictionary addHash)
  56. {
  57. if (addHash == null || target.Equals(addHash))
  58. {
  59. return;
  60. }
  61. foreach (object key in addHash.Keys)
  62. {
  63. // only merge keys of type string
  64. if (key is string)
  65. {
  66. target[key] = addHash[key];
  67. }
  68. }
  69. }
  70. /// <summary>Helper method for debugging of IDictionary content, including type-information. Using this is not performant.</summary>
  71. /// <remarks>Should only be used for debugging as necessary.</remarks>
  72. /// <param name="origin">Some Dictionary or Hashtable.</param>
  73. /// <returns>String of the content of the IDictionary.</returns>
  74. public static string ToStringFull(this IDictionary origin)
  75. {
  76. return SupportClass.DictionaryToString(origin, false);
  77. }
  78. /// <summary>Helper method for debugging of List<T> content. Using this is not performant.</summary>
  79. /// <remarks>Should only be used for debugging as necessary.</remarks>
  80. /// <param name="data">Any List<T> where T implements .ToString().</param>
  81. /// <returns>A comma-separated string containing each value's ToString().</returns>
  82. public static string ToStringFull<T>(this List<T> data)
  83. {
  84. if (data == null) return "null";
  85. string[] sb = new string[data.Count];
  86. for (int i = 0; i < data.Count; i++)
  87. {
  88. object o = data[i];
  89. sb[i] = (o != null) ? o.ToString() : "null";
  90. }
  91. return string.Join(", ", sb);
  92. }
  93. /// <summary>Helper method for debugging of object[] content. Using this is not performant.</summary>
  94. /// <remarks>Should only be used for debugging as necessary.</remarks>
  95. /// <param name="data">Any object[].</param>
  96. /// <returns>A comma-separated string containing each value's ToString().</returns>
  97. public static string ToStringFull(this object[] data)
  98. {
  99. if (data == null) return "null";
  100. string[] sb = new string[data.Length];
  101. for (int i = 0; i < data.Length; i++)
  102. {
  103. object o = data[i];
  104. sb[i] = (o != null) ? o.ToString() : "null";
  105. }
  106. return string.Join(", ", sb);
  107. }
  108. /// <summary>
  109. /// This method copies all string-typed keys of the original into a new Hashtable.
  110. /// </summary>
  111. /// <remarks>
  112. /// Does not recurse (!) into hashes that might be values in the root-hash.
  113. /// This does not modify the original.
  114. /// </remarks>
  115. /// <param name="original">The original IDictonary to get string-typed keys from.</param>
  116. /// <returns>New Hashtable containing only string-typed keys of the original.</returns>
  117. public static Hashtable StripToStringKeys(this IDictionary original)
  118. {
  119. Hashtable target = new Hashtable();
  120. if (original != null)
  121. {
  122. foreach (object key in original.Keys)
  123. {
  124. if (key is string)
  125. {
  126. target[key] = original[key];
  127. }
  128. }
  129. }
  130. return target;
  131. }
  132. /// <summary>
  133. /// This method copies all string-typed keys of the original into a new Hashtable.
  134. /// </summary>
  135. /// <remarks>
  136. /// Does not recurse (!) into hashes that might be values in the root-hash.
  137. /// This does not modify the original.
  138. /// </remarks>
  139. /// <param name="original">The original IDictonary to get string-typed keys from.</param>
  140. /// <returns>New Hashtable containing only string-typed keys of the original.</returns>
  141. public static Hashtable StripToStringKeys(this Hashtable original)
  142. {
  143. Hashtable target = new Hashtable();
  144. if (original != null)
  145. {
  146. foreach (DictionaryEntry entry in original)
  147. {
  148. if (entry.Key is string)
  149. {
  150. target[entry.Key] = original[entry.Key];
  151. }
  152. }
  153. }
  154. return target;
  155. }
  156. /// <summary>Used by StripKeysWithNullValues.</summary>
  157. /// <remarks>
  158. /// By making keysWithNullValue a static variable to clear before using, allocations only happen during the warm-up phase
  159. /// as the list needs to grow. Once it hit the high water mark for keys you need to remove.
  160. /// </remarks>
  161. private static readonly List<object> keysWithNullValue = new List<object>();
  162. /// <summary>Removes all keys with null values.</summary>
  163. /// <remarks>
  164. /// Photon properties are removed by setting their value to null. Changes the original IDictionary!
  165. /// Uses lock(keysWithNullValue), which should be no problem in expected use cases.
  166. /// </remarks>
  167. /// <param name="original">The IDictionary to strip of keys with null value.</param>
  168. public static void StripKeysWithNullValues(this IDictionary original)
  169. {
  170. lock (keysWithNullValue)
  171. {
  172. keysWithNullValue.Clear();
  173. foreach (DictionaryEntry entry in original)
  174. {
  175. if (entry.Value == null)
  176. {
  177. keysWithNullValue.Add(entry.Key);
  178. }
  179. }
  180. for (int i = 0; i < keysWithNullValue.Count; i++)
  181. {
  182. var key = keysWithNullValue[i];
  183. original.Remove(key);
  184. }
  185. }
  186. }
  187. /// <summary>Removes all keys with null values.</summary>
  188. /// <remarks>
  189. /// Photon properties are removed by setting their value to null. Changes the original IDictionary!
  190. /// Uses lock(keysWithNullValue), which should be no problem in expected use cases.
  191. /// </remarks>
  192. /// <param name="original">The IDictionary to strip of keys with null value.</param>
  193. public static void StripKeysWithNullValues(this Hashtable original)
  194. {
  195. lock (keysWithNullValue)
  196. {
  197. keysWithNullValue.Clear();
  198. foreach (DictionaryEntry entry in original)
  199. {
  200. if (entry.Value == null)
  201. {
  202. keysWithNullValue.Add(entry.Key);
  203. }
  204. }
  205. for (int i = 0; i < keysWithNullValue.Count; i++)
  206. {
  207. var key = keysWithNullValue[i];
  208. original.Remove(key);
  209. }
  210. }
  211. }
  212. /// <summary>
  213. /// Checks if a particular integer value is in an int-array.
  214. /// </summary>
  215. /// <remarks>This might be useful to look up if a particular actorNumber is in the list of players of a room.</remarks>
  216. /// <param name="target">The array of ints to check.</param>
  217. /// <param name="nr">The number to lookup in target.</param>
  218. /// <returns>True if nr was found in target.</returns>
  219. public static bool Contains(this int[] target, int nr)
  220. {
  221. if (target == null)
  222. {
  223. return false;
  224. }
  225. for (int index = 0; index < target.Length; index++)
  226. {
  227. if (target[index] == nr)
  228. {
  229. return true;
  230. }
  231. }
  232. return false;
  233. }
  234. }
  235. }