PhotonStreamQueue.cs 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. // ----------------------------------------------------------------------------
  2. // <copyright file="PhotonStreamQueue.cs" company="Exit Games GmbH">
  3. // PhotonNetwork Framework for Unity - Copyright (C) 2018 Exit Games GmbH
  4. // </copyright>
  5. // <summary>
  6. // Contains the PhotonStreamQueue.
  7. // </summary>
  8. // <author>developer@exitgames.com</author>
  9. // ----------------------------------------------------------------------------
  10. namespace Photon.Pun
  11. {
  12. using System.Collections.Generic;
  13. using UnityEngine;
  14. /// <summary>
  15. /// The PhotonStreamQueue helps you poll object states at higher frequencies than what
  16. /// PhotonNetwork.SendRate dictates and then sends all those states at once when
  17. /// Serialize() is called.
  18. /// On the receiving end you can call Deserialize() and then the stream will roll out
  19. /// the received object states in the same order and timeStep they were recorded in.
  20. /// </summary>
  21. public class PhotonStreamQueue
  22. {
  23. private int m_SampleRate;
  24. private int m_SampleCount;
  25. private int m_ObjectsPerSample = -1;
  26. private float m_LastSampleTime = -Mathf.Infinity;
  27. private int m_LastFrameCount = -1;
  28. private int m_NextObjectIndex = -1;
  29. private List<object> m_Objects = new List<object>();
  30. private bool m_IsWriting;
  31. /// <summary>
  32. /// Initializes a new instance of the <see cref="PhotonStreamQueue"/> class.
  33. /// </summary>
  34. /// <param name="sampleRate">How many times per second should the object states be sampled</param>
  35. public PhotonStreamQueue(int sampleRate)
  36. {
  37. this.m_SampleRate = sampleRate;
  38. }
  39. private void BeginWritePackage()
  40. {
  41. //If not enough time has passed since the last sample, we don't want to write anything
  42. if (Time.realtimeSinceStartup < this.m_LastSampleTime + 1f / this.m_SampleRate)
  43. {
  44. this.m_IsWriting = false;
  45. return;
  46. }
  47. if (this.m_SampleCount == 1)
  48. {
  49. this.m_ObjectsPerSample = this.m_Objects.Count;
  50. //Debug.Log( "Setting m_ObjectsPerSample to " + m_ObjectsPerSample );
  51. }
  52. else if (this.m_SampleCount > 1)
  53. {
  54. if (this.m_Objects.Count / this.m_SampleCount != this.m_ObjectsPerSample)
  55. {
  56. Debug.LogWarning("The number of objects sent via a PhotonStreamQueue has to be the same each frame");
  57. Debug.LogWarning("Objects in List: " + this.m_Objects.Count + " / Sample Count: " + this.m_SampleCount + " = " + this.m_Objects.Count / this.m_SampleCount + " != " + this.m_ObjectsPerSample);
  58. }
  59. }
  60. this.m_IsWriting = true;
  61. this.m_SampleCount++;
  62. this.m_LastSampleTime = Time.realtimeSinceStartup;
  63. /*if( m_SampleCount > 1 )
  64. {
  65. Debug.Log( "Check: " + m_Objects.Count + " / " + m_SampleCount + " = " + ( m_Objects.Count / m_SampleCount ) + " = " + m_ObjectsPerSample );
  66. }*/
  67. }
  68. /// <summary>
  69. /// Resets the PhotonStreamQueue. You need to do this whenever the amount of objects you are observing changes
  70. /// </summary>
  71. public void Reset()
  72. {
  73. this.m_SampleCount = 0;
  74. this.m_ObjectsPerSample = -1;
  75. this.m_LastSampleTime = -Mathf.Infinity;
  76. this.m_LastFrameCount = -1;
  77. this.m_Objects.Clear();
  78. }
  79. /// <summary>
  80. /// Adds the next object to the queue. This works just like PhotonStream.SendNext
  81. /// </summary>
  82. /// <param name="obj">The object you want to add to the queue</param>
  83. public void SendNext(object obj)
  84. {
  85. if (Time.frameCount != this.m_LastFrameCount)
  86. {
  87. this.BeginWritePackage();
  88. }
  89. this.m_LastFrameCount = Time.frameCount;
  90. if (this.m_IsWriting == false)
  91. {
  92. return;
  93. }
  94. this.m_Objects.Add(obj);
  95. }
  96. /// <summary>
  97. /// Determines whether the queue has stored any objects
  98. /// </summary>
  99. public bool HasQueuedObjects()
  100. {
  101. return this.m_NextObjectIndex != -1;
  102. }
  103. /// <summary>
  104. /// Receives the next object from the queue. This works just like PhotonStream.ReceiveNext
  105. /// </summary>
  106. /// <returns></returns>
  107. public object ReceiveNext()
  108. {
  109. if (this.m_NextObjectIndex == -1)
  110. {
  111. return null;
  112. }
  113. if (this.m_NextObjectIndex >= this.m_Objects.Count)
  114. {
  115. this.m_NextObjectIndex -= this.m_ObjectsPerSample;
  116. }
  117. return this.m_Objects[this.m_NextObjectIndex++];
  118. }
  119. /// <summary>
  120. /// Serializes the specified stream. Call this in your OnPhotonSerializeView method to send the whole recorded stream.
  121. /// </summary>
  122. /// <param name="stream">The PhotonStream you receive as a parameter in OnPhotonSerializeView</param>
  123. public void Serialize(PhotonStream stream)
  124. {
  125. // TODO: find a better solution for this:
  126. // the "if" is a workaround for packages which have only 1 sample/frame. in that case, SendNext didn't set the obj per sample.
  127. if (this.m_Objects.Count > 0 && this.m_ObjectsPerSample < 0)
  128. {
  129. this.m_ObjectsPerSample = this.m_Objects.Count;
  130. }
  131. stream.SendNext(this.m_SampleCount);
  132. stream.SendNext(this.m_ObjectsPerSample);
  133. for (int i = 0; i < this.m_Objects.Count; ++i)
  134. {
  135. stream.SendNext(this.m_Objects[i]);
  136. }
  137. //Debug.Log( "Serialize " + m_SampleCount + " samples with " + m_ObjectsPerSample + " objects per sample. object count: " + m_Objects.Count + " / " + ( m_SampleCount * m_ObjectsPerSample ) );
  138. this.m_Objects.Clear();
  139. this.m_SampleCount = 0;
  140. }
  141. /// <summary>
  142. /// Deserializes the specified stream. Call this in your OnPhotonSerializeView method to receive the whole recorded stream.
  143. /// </summary>
  144. /// <param name="stream">The PhotonStream you receive as a parameter in OnPhotonSerializeView</param>
  145. public void Deserialize(PhotonStream stream)
  146. {
  147. this.m_Objects.Clear();
  148. this.m_SampleCount = (int) stream.ReceiveNext();
  149. this.m_ObjectsPerSample = (int) stream.ReceiveNext();
  150. for (int i = 0; i < this.m_SampleCount * this.m_ObjectsPerSample; ++i)
  151. {
  152. this.m_Objects.Add(stream.ReceiveNext());
  153. }
  154. if (this.m_Objects.Count > 0)
  155. {
  156. this.m_NextObjectIndex = 0;
  157. }
  158. else
  159. {
  160. this.m_NextObjectIndex = -1;
  161. }
  162. //Debug.Log( "Deserialized " + m_SampleCount + " samples with " + m_ObjectsPerSample + " objects per sample. object count: " + m_Objects.Count + " / " + ( m_SampleCount * m_ObjectsPerSample ) );
  163. }
  164. }
  165. }