NetInput.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright 2016 RWS Inc, All Rights Reserved
  4. //
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of version 2 of the GNU General Public License as published by
  7. // the Free Software Foundation
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License along
  15. // with this program; if not, write to the Free Software Foundation, Inc.,
  16. // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. //
  18. // netinput.h
  19. // Project: RSPiX
  20. //
  21. // History:
  22. // 09/02/97 MJR Started.
  23. //
  24. ////////////////////////////////////////////////////////////////////////////////
  25. #ifndef NETINPUT_H
  26. #define NETINPUT_H
  27. #include "input.h"
  28. ////////////////////////////////////////////////////////////////////////////////
  29. //
  30. // CNetInput handle the buffering of inputs received from other players.
  31. //
  32. // The Net::SEQ values are unsigned, and last I checked were 16-bit values,
  33. // but this same logic would work for 32-bit, too.
  34. //
  35. // The sequence values will increment steadly until they wrap-around. We assume
  36. // that the amount of time that it will take for them to wrap-around is greater
  37. // than the amount of time a network packet can live for and still manage to get
  38. // delivered. With a 16-bit value at 30 frames per second, this allow for over
  39. // 30 minutes -- I doubt a network packet can survive that long.
  40. //
  41. // This class impliments a "sliding window" of input values. The window must
  42. // be at least 3 * Net::MaxAheadSeq in size. (A detailed explanation can be
  43. // found in where that value is defined).
  44. //
  45. // Assuming Net::SEQ ranges from 0 to 65535, the window looks like this:
  46. //
  47. // 0-------------[ooonnnnnn]-----------------------------65535
  48. // ^
  49. // F
  50. //
  51. // The dashes represent values we don't care about -- any values that are
  52. // NOT within the window are ignored.
  53. //
  54. // The "F" represents the current frame number, which determines the overall
  55. // position of the window. This is the LOCAL PLAYER'S frame number, not the
  56. // frame number of the player whose data we are dealing with!
  57. //
  58. // As the frame number increases, the window moves to the right, eventually
  59. // wrapping around and starting over at the left side.
  60. //
  61. // The window contains 3 sets of Net::MaxAheadSeq values. The first set is
  62. // to the left of the current frame number, and is represented by o's. These
  63. // are "old" values we must keep around in case this player drops from the game
  64. // and we are the only player that received (and used!) his input values. In
  65. // that case, we will be asked to supply these values to the other players.
  66. //
  67. // The second two sets are represented by n's, and are new values we might
  68. // have received from this player, but that we haven't yet used.
  69. //
  70. // Inputs may arrive out of order, which means we might get a few values,
  71. // then get a few more values further along in the window but leaving a "hole"
  72. // of unknown values in between. We assume that we'll eventually get those
  73. // values, too, but in the meantime, we can't move our frame number past that
  74. // hole.
  75. //
  76. // In order to properly detect which values we did and did not get, we start
  77. // out with the entire window filled with invalid values, and whenever we move
  78. // the window, we mark any "newly uncovered" values as invalid, too. As we
  79. // receive inputs, we put them in the appropriate spots in the array,
  80. // overwriting the invalid values in the process. Whenever an attempt is made
  81. // to move the frame forward, we check if the value for that frame is valid.
  82. // If so, we can move forward. If not, it means we haven't gotten that value
  83. // yet, so we can't move forward yet.
  84. //
  85. //
  86. // All that cool theory aside, the array is actually implimented in a somewhat
  87. // different manner.
  88. //
  89. // By making it a power of 2 in size (making sure it's at least as
  90. // large as 3 * Net::MaxAheadSeq), everything gets harder to think about, but
  91. // very efficient. Normally, in order to impliment a sliding window buffer,
  92. // you need to slide around the values contained in the buffer as it moves
  93. // forward. By making it a power of 2 in size, we can use simple bit-masks
  94. // to get all the indices into to the buffer to automatically wrap-around as
  95. // needed, and suddenly we don't need to move the values anymore -- instead we
  96. // are changing how we look at the buffer. We are merely moving what we think
  97. // of as the start and end of the buffer around, rather than moving everything
  98. // within the buffer. Kind of hard to explain, but it DOES work!
  99. //
  100. // Let's assume Net::SEQ is only 4-bits, so it ranges from 0 to 15. Now let's
  101. // say Net::MaxAheadSeq is 1, so our buffer needs to 3 times that, but instead
  102. // we go with 4 entries, which is the next power-of-2 after 3. The diagram
  103. // below shows how the various input sequences will map into our buffer. In
  104. // order to arrive at the index into our buffer, we simply take the sequence
  105. // number and mark out all the bits but the bottom 2, which yields a number
  106. // between 0 and 3, and happens to be the correct index into our buffer. The
  107. // diagram shows how our buffer "slides along" without moving the actual
  108. // contents -- instead, it's all just a matter of how you think of it.
  109. //
  110. // 0 1 2 3 4 5 6 7 8 9 A B C D E F
  111. // - - - - - - - - - - - - - - - -
  112. // 0 1 2 3
  113. // 1 2 3 0
  114. // 2 3 0 1
  115. // 3 0 1 2
  116. // 0 1 2 3
  117. //
  118. ////////////////////////////////////////////////////////////////////////////////
  119. class CNetInput
  120. {
  121. //------------------------------------------------------------------------------
  122. // Types, enums, etc.
  123. //------------------------------------------------------------------------------
  124. public:
  125. enum
  126. {
  127. // Maximum total entries (see elsewhere for in-depth explanation)
  128. MaxTotalEntries = 3 * Net::MaxAheadSeq,
  129. // Maxumum new entries (see elsewhere for in-depth explanation)
  130. MaxNewEntries = 2 * Net::MaxAheadSeq,
  131. // Maximum old entries (see elsewhere for in-depth explanation)
  132. MaxOldEntries = 1 * Net::MaxAheadSeq,
  133. // The size must be a power of two, and the mask must correspond to it.
  134. // Remember that this must be at LEAST as large as MaxTotalEntries!
  135. Size = 256,
  136. Mask = Size - 1,
  137. // Invalid input value
  138. Invalid = 0xffffffff
  139. };
  140. //------------------------------------------------------------------------------
  141. // Variables
  142. //------------------------------------------------------------------------------
  143. protected:
  144. UINPUT m_aInputs[Size]; // Inputs
  145. U8 m_aFrameTimes[Size]; // Game time for the frames *SPA
  146. Net::SEQ m_seqFrame; // Local player's current frame number
  147. Net::SEQ m_seqOldest; // Oldest sequence we have
  148. //------------------------------------------------------------------------------
  149. // Functions
  150. //------------------------------------------------------------------------------
  151. public:
  152. ////////////////////////////////////////////////////////////////////////////////
  153. // Constructor
  154. ////////////////////////////////////////////////////////////////////////////////
  155. CNetInput()
  156. {
  157. ASSERT(Size >= MaxTotalEntries);
  158. Reset();
  159. }
  160. ////////////////////////////////////////////////////////////////////////////////
  161. // Destructor
  162. ////////////////////////////////////////////////////////////////////////////////
  163. ~CNetInput()
  164. {
  165. Reset();
  166. }
  167. ////////////////////////////////////////////////////////////////////////////////
  168. // Reset to post-construction state
  169. ////////////////////////////////////////////////////////////////////////////////
  170. void Reset(void)
  171. {
  172. short i = 0;
  173. // Clear the entire window to "invalid" values
  174. for (i = 0; i < Size; i++)
  175. m_aInputs[i] = Invalid;
  176. // Clear the entire window to initail values *SPA !!Eventually should input from prefs!!
  177. for (i = 0; i < Size; i++)
  178. m_aFrameTimes[i] = 100;
  179. // Start the frame at 0. The oldest value always lags by a fixed distance.
  180. m_seqFrame = 0;
  181. m_seqOldest = m_seqFrame - MaxOldEntries;
  182. }
  183. ////////////////////////////////////////////////////////////////////////////////
  184. // Move the frame forward
  185. // IT IS ASSUMED THAT THE CALLER WILL NOT BE STUPID!!!
  186. // Don't ever move the frame forward unless the input for the current frame
  187. // is valid, as reported by GetInput()!
  188. ////////////////////////////////////////////////////////////////////////////////
  189. void IncFrame(void)
  190. {
  191. // Make sure this makes sense!
  192. ASSERT(m_aInputs[m_seqFrame & Mask] != Invalid);
  193. // Invalidate oldest sequence
  194. m_aInputs[m_seqOldest & Mask] = Invalid;
  195. // Move forward
  196. m_seqFrame++;
  197. m_seqOldest++;
  198. }
  199. ////////////////////////////////////////////////////////////////////////////////
  200. // Put a new input value.
  201. // If the specified seq is outside of the "new value window", it is ignored.
  202. ////////////////////////////////////////////////////////////////////////////////
  203. void Put(
  204. Net::SEQ seq,
  205. UINPUT input)
  206. {
  207. // If the seq falls within the "new values" window, we use it. Note that
  208. // the "new values" window starts at the current frame.
  209. // The excessive casting is to make sure the compiler does this all as
  210. // unsigned math and comparisons.
  211. if ((Net::SEQ)(seq - m_seqFrame) < (Net::SEQ)MaxNewEntries)
  212. m_aInputs[seq & Mask] = input;
  213. }
  214. ////////////////////////////////////////////////////////////////////////////////
  215. // Put a new frame time value. *SPA
  216. // If the specified seq is outside of the "new value window", it is ignored.
  217. ////////////////////////////////////////////////////////////////////////////////
  218. void PutFrameTime(
  219. Net::SEQ seq,
  220. U8 frameTime)
  221. {
  222. // If the seq falls within the "new values" window, we use it. Note that
  223. // the "new values" window starts at the current frame.
  224. // The excessive casting is to make sure the compiler does this all as
  225. // unsigned math and comparisons.
  226. if ((Net::SEQ)(seq - m_seqFrame) < (Net::SEQ)MaxNewEntries)
  227. {
  228. m_aFrameTimes[seq & Mask] = frameTime;
  229. }
  230. }
  231. ////////////////////////////////////////////////////////////////////////////////
  232. // Find first invalid value starting at the specified seq and continuing to
  233. // the end of the "new" window.
  234. ////////////////////////////////////////////////////////////////////////////////
  235. Net::SEQ FindFirstInvalid(
  236. Net::SEQ seq)
  237. {
  238. Net::SEQ offset = (Net::SEQ)(seq - m_seqFrame);
  239. while (offset < (Net::SEQ)MaxNewEntries)
  240. {
  241. if (m_aInputs[seq & Mask] == Invalid)
  242. break;
  243. seq++;
  244. offset++;
  245. }
  246. return seq;
  247. }
  248. // This alternative version starts at the current frame
  249. Net::SEQ FindFirstInvalid(void)
  250. {
  251. return FindFirstInvalid(m_seqFrame);
  252. }
  253. ////////////////////////////////////////////////////////////////////////////////
  254. // Get the specified input value.
  255. // A return value of CNetInput::Invalid means that input was not available.
  256. ////////////////////////////////////////////////////////////////////////////////
  257. UINPUT Get(
  258. Net::SEQ seq)
  259. {
  260. // If the seq falls within the total window, we get it. Note that this
  261. // window starts at the oldest value, which is always Net::MaxAheadSeq less
  262. // than the current frame.
  263. // The excessive casting is to make sure the compiler does this all as
  264. // unsigned math and comparisons.
  265. if ((Net::SEQ)(seq - m_seqOldest) < (Net::SEQ)MaxTotalEntries)
  266. return m_aInputs[seq & Mask];
  267. else
  268. return Invalid;
  269. }
  270. ////////////////////////////////////////////////////////////////////////////////
  271. // Get the specified frame time value. *SPA
  272. // A return value of CNetInput::Invalid means that input was not available.
  273. ////////////////////////////////////////////////////////////////////////////////
  274. U8 GetFrameTime(
  275. Net::SEQ seq)
  276. {
  277. // If the seq falls within the total window, we get it. Note that this
  278. // window starts at the oldest value, which is always Net::MaxAheadSeq less
  279. // than the current frame.
  280. // The excessive casting is to make sure the compiler does this all as
  281. // unsigned math and comparisons.
  282. if ((Net::SEQ)(seq - m_seqOldest) < (Net::SEQ)MaxTotalEntries)
  283. return m_aFrameTimes[seq & Mask];
  284. else
  285. return Invalid;
  286. }
  287. ////////////////////////////////////////////////////////////////////////////////
  288. // Get current frame seq
  289. ////////////////////////////////////////////////////////////////////////////////
  290. Net::SEQ GetFrameSeq(void)
  291. {
  292. return m_seqFrame;
  293. }
  294. ////////////////////////////////////////////////////////////////////////////////
  295. // Get oldest frame seq
  296. ////////////////////////////////////////////////////////////////////////////////
  297. Net::SEQ GetOldestSeq(void)
  298. {
  299. return m_seqOldest;
  300. }
  301. };
  302. #endif //NETINPUT_H
  303. ////////////////////////////////////////////////////////////////////////////////
  304. // EOF
  305. ////////////////////////////////////////////////////////////////////////////////