Emergency 20 Dokumentation  4.2.0
DataCacheItemHelper.h
Go to the documentation of this file.
1 // Copyright (C) 2012-2018 Promotion Software GmbH
2 
3 
4 //[-------------------------------------------------------]
5 //[ Header guard ]
6 //[-------------------------------------------------------]
7 #pragma once
8 
9 
10 //[-------------------------------------------------------]
11 //[ Includes ]
12 //[-------------------------------------------------------]
14 
16 #include <qsf/math/EulerAngles.h>
17 
18 #include <glm/gtc/quaternion.hpp>
19 
20 
21 //[-------------------------------------------------------]
22 //[ Local defines ]
23 //[-------------------------------------------------------]
24 // This define is used to enable the cache debug logging (per cache entry logging how many bits where written/read to/from BitStream )
25 // This debug logging are used to find out what went wrong on the client side. Mostly in conjunction with game recorder/player data
26 //#define ENABLE_MULTIPLAYER_CACHE_DEBUG 1
27 
28 
29 //[-------------------------------------------------------]
30 //[ Namespace ]
31 //[-------------------------------------------------------]
32 namespace em5
33 {
34  namespace multiplayer
35  {
36  namespace detail
37  {
38 
39 
40  //[-------------------------------------------------------]
41  //[ Methods ]
42  //[-------------------------------------------------------]
43  template<typename T>
44  static void writeChanges(const bool valueChanged, const T& newValue, qsf::game::BitStream& bitStream)
45  {
46  // Write if data has changed
47  bitStream.write(valueChanged);
48  if (valueChanged)
49  {
50  // Write changed value
51  bitStream.write(newValue);
52  }
53  }
54 
55  template<typename T>
56  static void writeChanges(const bool valueChanged, const T& newValue, size_t bitCount, qsf::game::BitStream& bitStream)
57  {
58  // Write if data has changed
59  bitStream.write(valueChanged);
60  if (valueChanged)
61  {
62  // Write changed value
63  bitStream.write(newValue, bitCount);
64  }
65  }
66 
67  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
68  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
69  template<>
70  static void writeChanges(const bool valueChanged, const glm::vec2& newValue, qsf::game::BitStream& bitStream)
71  {
72  // Write if data has changed
73  bitStream.write(valueChanged);
74  if (valueChanged)
75  {
76  // Write changed value
77  bitStream.write(newValue.x);
78  bitStream.write(newValue.y);
79  }
80  }
81 
82  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
83  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
84  template<>
85  static void writeChanges(const bool valueChanged, const glm::vec3& newValue, qsf::game::BitStream& bitStream)
86  {
87  // Write if data has changed
88  bitStream.write(valueChanged);
89  if (valueChanged)
90  {
91  // Write changed value
92  bitStream.write(newValue.x);
93  bitStream.write(newValue.y);
94  bitStream.write(newValue.z);
95  }
96  }
97 
98  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
99  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
100  template<>
101  static void writeChanges(const bool valueChanged, const glm::quat& newValue, qsf::game::BitStream& bitStream)
102  {
103  // Write if data has changed
104  bitStream.write(valueChanged);
105  if (valueChanged)
106  {
107  // Write changed value
108  bitStream.write(newValue.x);
109  bitStream.write(newValue.y);
110  bitStream.write(newValue.z);
111  bitStream.write(newValue.w);
112  }
113  }
114 
115  template<typename T>
116  static bool checkForChanges(const T& newValue, T& currentValue)
117  {
118  bool valueChanged = newValue != currentValue;
119  if (valueChanged)
120  {
121  // Save changed data
122  currentValue = newValue;
123  }
124 
125  return valueChanged;
126  }
127 
128  template<typename T>
129  static bool checkChangedAndWrite(const T& newValue, T& currentValue, qsf::game::BitStream& bitStream, bool force)
130  {
131  bool valueChanged = newValue != currentValue || force;
132  // Write if data has changed
133  bitStream.write(valueChanged);
134  if (valueChanged)
135  {
136  // Save changed data
137  currentValue = newValue;
138 
139  // Write changed value
140  bitStream.write(newValue);
141  }
142 
143  return valueChanged;
144  }
145 
146  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
147  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
148  template<>
149  static bool checkChangedAndWrite(const glm::vec2& newValue, glm::vec2& currentValue, qsf::game::BitStream& bitStream, bool force)
150  {
151  bool valueChanged = newValue != currentValue || force;
152  // Write if data has changed
153  bitStream.write(valueChanged);
154  if (valueChanged)
155  {
156  // Save changed data
157  currentValue = newValue;
158 
159  // Write changed value
160  bitStream.write(newValue.x);
161  bitStream.write(newValue.y);
162  }
163 
164  return valueChanged;
165  }
166 
167  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
168  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
169  template<>
170  static bool checkChangedAndWrite(const glm::vec3& newValue, glm::vec3& currentValue, qsf::game::BitStream& bitStream, bool force)
171  {
172  bool valueChanged = newValue != currentValue || force;
173  // Write if data has changed
174  bitStream.write(valueChanged);
175  if (valueChanged)
176  {
177  // Save changed data
178  currentValue = newValue;
179 
180  // Write changed value
181  bitStream.write(newValue.x);
182  bitStream.write(newValue.y);
183  bitStream.write(newValue.z);
184  }
185 
186  return valueChanged;
187  }
188 
189  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
190  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
191  template<>
192  static bool checkChangedAndWrite(const glm::quat& newValue, glm::quat& currentValue, qsf::game::BitStream& bitStream, bool force)
193  {
194  bool valueChanged = newValue != currentValue || force;
195  // Write if data has changed
196  bitStream.write(valueChanged);
197  if (valueChanged)
198  {
199  // Save changed data
200  currentValue = newValue;
201 
202  // Write changed value
203  bitStream.write(newValue.x);
204  bitStream.write(newValue.y);
205  bitStream.write(newValue.z);
206  bitStream.write(newValue.w);
207  }
208 
209  return valueChanged;
210  }
211 
212  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
213  static bool checkChanged(const qsf::game::BitStream& bitStream)
214  {
215  // Read if data has changed
216  bool haveData = false;
217  if (!bitStream.read(haveData))
218  {
219  QSF_ERROR("DataCacheItem: could not read changed state from stream", QSF_REACT_THROW);
220  }
221 
222  return haveData;
223  }
224 
225  template<typename T>
226  static bool checkChangedAndRead(const qsf::game::BitStream& bitStream, T& currentValue)
227  {
228  // Read if data has changed
229  bool haveData = false;
230  bitStream.read(haveData);
231 
232  if (haveData)
233  {
234  // Try read the value and save it on success
235  T newValue;
236  if (bitStream.read(newValue))
237  {
238  currentValue = newValue;
239  }
240  else
241  {
242  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
243  }
244  }
245 
246  // Return if data has changed
247  return haveData;
248  }
249 
250  template<typename T>
251  static bool checkChangedAndRead(const qsf::game::BitStream& bitStream, size_t bitCount, T& currentValue)
252  {
253  // Read if data has changed
254  bool haveData = false;
255  bitStream.read(haveData);
256 
257  if (haveData)
258  {
259  // Try read the value and save it on success
260  T newValue;
261  if (bitStream.read(newValue, bitCount))
262  {
263  currentValue = newValue;
264  }
265  else
266  {
267  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
268  }
269  }
270 
271  // Return if data has changed
272  return haveData;
273  }
274 
275  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
276  template<>
277  static bool checkChangedAndRead(const qsf::game::BitStream& bitStream, glm::vec2& currentValue)
278  {
279  // Read if data has changed
280  bool haveData = false;
281  bitStream.read(haveData);
282 
283  if (haveData)
284  {
285  // Try read the value and save it on success
286  glm::vec2 newValue;
287  if (!bitStream.read(newValue.x))
288  {
289  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
290  }
291 
292  if (!bitStream.read(newValue.y))
293  {
294  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
295  }
296 
297  currentValue = newValue;
298  }
299 
300  // Return if data has changed
301  return haveData;
302  }
303 
304  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
305  template<>
306  static bool checkChangedAndRead(const qsf::game::BitStream& bitStream, glm::vec3& currentValue)
307  {
308  // Read if data has changed
309  bool haveData = false;
310  bitStream.read(haveData);
311 
312  if (haveData)
313  {
314  // Try read the value and save it on success
315  glm::vec3 newValue;
316  if (!bitStream.read(newValue.x))
317  {
318  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
319  }
320 
321  if (!bitStream.read(newValue.y))
322  {
323  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
324  }
325 
326  if (!bitStream.read(newValue.z))
327  {
328  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
329  }
330 
331  currentValue = newValue;
332  }
333 
334  // Return if data has changed
335  return haveData;
336  }
337 
338  // TODO(ca) Got a warning here: "explicit specialization cannot have storage class"... this looks like a specialized function template... have you tried overloading instead?
339  template<>
340  static bool checkChangedAndRead(const qsf::game::BitStream& bitStream, glm::quat& currentValue)
341  {
342  // Read if data has changed
343  bool haveData = false;
344  bitStream.read(haveData);
345 
346  if (haveData)
347  {
348  // Try read the value and save it on success
349  glm::quat newValue;
350  if (!bitStream.read(newValue.x))
351  {
352  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
353  }
354 
355  if (!bitStream.read(newValue.y))
356  {
357  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
358  }
359 
360  if (!bitStream.read(newValue.z))
361  {
362  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
363  }
364 
365  if (!bitStream.read(newValue.w))
366  {
367  QSF_ERROR("DataCacheItem: could not read value from stream", QSF_REACT_THROW);
368  }
369 
370  currentValue = newValue;
371  }
372 
373  // Return if data has changed
374  return haveData;
375  }
376 
377  // TODO(ca) Unused local function
378  /*
379  static bool checkChangedAndWritePosition(const glm::vec3& newValue, glm::vec3& currentValue, qsf::game::BitStream& bitStream, bool force)
380  {
381  // Positions are stored as 16bit signed values (0.1 meters precision)
382 
383  int16 newValueX = static_cast<int16>(newValue.x*10);
384  int16 newValueY = static_cast<int16>(newValue.y*10);
385  int16 newValueZ = static_cast<int16>(newValue.z*10);
386 
387  int16 currentValueX = static_cast<int16>(currentValue.x*10);
388  int16 currentValueY = static_cast<int16>(currentValue.y*10);
389  int16 currentValueZ = static_cast<int16>(currentValue.z*10);
390 
391  bool xValueChanged = newValueX != currentValueX || force;
392  bool yValueChanged = newValueY != currentValueY || force;
393  bool zValueChanged = newValueZ != currentValueZ || force;
394 
395  if (xValueChanged || yValueChanged || zValueChanged)
396  {
397  // Save changed data
398  currentValue = newValue;
399  }
400 
401  bitStream.write(xValueChanged);
402  if (xValueChanged)
403  {
404  // Write changed value
405  bitStream.write(newValueX);
406  }
407 
408  bitStream.write(yValueChanged);
409  if (yValueChanged)
410  {
411  // Write changed value
412  bitStream.write(newValueY);
413  }
414 
415  bitStream.write(zValueChanged);
416  if (zValueChanged)
417  {
418  // Write changed value
419  bitStream.write(newValueZ);
420  }
421 
422  return xValueChanged || yValueChanged || zValueChanged;
423  }
424  */
425 
426  // TODO(ca) Unused local function
427  /*
428  static bool checkChangedAndReadPosition(const qsf::game::BitStream& bitStream, glm::vec3& currentValue)
429  {
430  // Positions are stored as 16bit signed values (0.1 meters precision)
431  bool result = false;
432  // Check and read x value
433  int16 xValue;
434  if (checkChangedAndRead(bitStream, xValue))
435  {
436  result = true;
437  currentValue.x = static_cast<float>(xValue/10.0f);
438  }
439 
440  // Check and read y value
441  int16 yValue;
442  if (checkChangedAndRead(bitStream, yValue))
443  {
444  result = true;
445  currentValue.y = static_cast<float>(yValue/10.0f);
446  }
447 
448  // Check and read y value
449  int16 zValue;
450  if (checkChangedAndRead(bitStream, zValue))
451  {
452  result = true;
453  currentValue.z = static_cast<float>(zValue/10.0f);
454  }
455 
456  return result;
457  }
458  */
459 
460  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
461  static float unwrapEulerAngle(int8 wrappedAngle)
462  {
463  return static_cast<float>(wrappedAngle * 360.0f / 256.0f);
464  }
465 
466  // TODO(ca) This causes a 'Unused function' warning due to static storage class - please find a better solution
467  static int8 wrapEulerAngle(float angle)
468  {
469  return static_cast<int8>(angle * 256 / 360);
470  }
471 
472  // TODO(ca) Unused local function
473  /*
474  static bool checkChangedAndWriteRotation(const glm::quat& newValue, glm::quat& currentValue, qsf::game::BitStream& bitStream, bool force)
475  {
476  // Rotation are stored as 8bit signed values (as euler angles, -180 - 180)
477  glm::vec3 newEulerAngles = glm::degrees(qsf::EulerAngles::quaternionToEuler(newValue));
478  glm::vec3 currentEulerAngles = glm::degrees(qsf::EulerAngles::quaternionToEuler(currentValue));
479 
480  int8 newValueX = wrapEulerAngle(newEulerAngles.x);
481  int8 newValueY = wrapEulerAngle(newEulerAngles.y);
482  int8 newValueZ = wrapEulerAngle(newEulerAngles.z);
483 
484  int8 currentValueX = wrapEulerAngle(currentEulerAngles.x);
485  int8 currentValueY = wrapEulerAngle(currentEulerAngles.y);
486  int8 currentValueZ = wrapEulerAngle(currentEulerAngles.z);
487 
488  bool xValueChanged = newValueX != currentValueX || force;
489  bool yValueChanged = newValueY != currentValueY || force;
490  bool zValueChanged = newValueZ != currentValueZ || force;
491 
492  if (xValueChanged || yValueChanged || zValueChanged)
493  {
494  // Save changed data
495  currentValue = newValue;
496  }
497 
498  bitStream.write(xValueChanged);
499  if (xValueChanged)
500  {
501  // Write changed value
502  bitStream.write(newValueX);
503  }
504 
505  bitStream.write(yValueChanged);
506  if (yValueChanged)
507  {
508  // Write changed value
509  bitStream.write(newValueY);
510  }
511 
512  bitStream.write(zValueChanged);
513  if (zValueChanged)
514  {
515  // Write changed value
516  bitStream.write(newValueZ);
517  }
518 
519  return xValueChanged || yValueChanged || currentValueZ;
520  }
521  */
522 
523  // TODO(ca) Unused local function
524  /*
525  static bool checkChangedAndReadRotation(const qsf::game::BitStream& bitStream, glm::quat& currentValue)
526  {
527  // Positions are stored as 8bit signed values (as euler angles, -180 - 180)
528  bool result = false;
529  glm::vec3 eulerAngles = glm::degrees(qsf::EulerAngles::quaternionToEuler(currentValue));
530 
531  // Check and read x value
532  int8 xValue;
533  if (checkChangedAndRead(bitStream, xValue))
534  {
535  result = true;
536  eulerAngles.x = unwrapEulerAngle(xValue);
537  }
538 
539  // Check and read y value
540  int8 yValue;
541  if (checkChangedAndRead(bitStream, yValue))
542  {
543  result = true;
544  eulerAngles.y = unwrapEulerAngle(yValue);
545  }
546 
547  // Check and read y value
548  int8 zValue;
549  if (checkChangedAndRead(bitStream, zValue))
550  {
551  result = true;
552  eulerAngles.z = unwrapEulerAngle(zValue);
553  }
554 
555  if (result)
556  {
557  currentValue = qsf::EulerAngles::eulerToQuaternion(glm::radians(eulerAngles));
558  }
559 
560  return result;
561  }
562  */
563  }
564 
565 
566 //[-------------------------------------------------------]
567 //[ Namespace ]
568 //[-------------------------------------------------------]
569  } // multiplayer
570 } // em5
Definition: ActionPriority.h:13
signed char int8
Definition: PlatformTypes.h:174
#define QSF_REACT_THROW
Definition: ErrorHandling.h:203
Game bit stream class (just a wrapper for linnet bit stream)
Definition: BitStream.h:40
Definition: Main.h:42
bool read(bool &value) const
void write(bool value)
#define QSF_ERROR(explanation, reaction)
Definition: ErrorHandling.h:132