cDistributedSmoothNodeBase.cxx 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file cDistributedSmoothNodeBase.cxx
  10. * @author drose
  11. * @date 2004-09-03
  12. */
  13. #include "cDistributedSmoothNodeBase.h"
  14. #include "cConnectionRepository.h"
  15. #include "dcField.h"
  16. #include "dcClass.h"
  17. #include "dcmsgtypes.h"
  18. #include "config_distributed.h"
  19. static const PN_stdfloat smooth_node_epsilon = 0.01;
  20. static const double network_time_precision = 100.0; // Matches ClockDelta.py
  21. /**
  22. *
  23. */
  24. CDistributedSmoothNodeBase::
  25. CDistributedSmoothNodeBase() {
  26. _repository = nullptr;
  27. _is_ai = false;
  28. _ai_id = 0;
  29. #ifdef HAVE_PYTHON
  30. _clock_delta = nullptr;
  31. #endif
  32. _currL[0] = 0;
  33. _currL[1] = 0;
  34. }
  35. /**
  36. *
  37. */
  38. CDistributedSmoothNodeBase::
  39. ~CDistributedSmoothNodeBase() {
  40. }
  41. /**
  42. * Initializes the internal structures from some constructs that are normally
  43. * stored only in Python. Also reads the current node's pos & hpr values in
  44. * preparation for transmitting them via one of the broadcast_pos_hpr_*()
  45. * methods.
  46. */
  47. void CDistributedSmoothNodeBase::
  48. initialize(const NodePath &node_path, DCClass *dclass, CHANNEL_TYPE do_id) {
  49. _node_path = node_path;
  50. _dclass = dclass;
  51. _do_id = do_id;
  52. nassertv(!_node_path.is_empty());
  53. _store_xyz = _node_path.get_pos();
  54. _store_hpr = _node_path.get_hpr();
  55. _store_stop = false;
  56. }
  57. /**
  58. * Broadcasts the current pos/hpr in its complete form.
  59. */
  60. void CDistributedSmoothNodeBase::
  61. send_everything() {
  62. _currL[0] = _currL[1];
  63. d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2],
  64. _store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]);
  65. }
  66. /**
  67. * Examines the complete pos/hpr information to see which of the six elements
  68. * have changed, and broadcasts the appropriate messages.
  69. */
  70. void CDistributedSmoothNodeBase::
  71. broadcast_pos_hpr_full() {
  72. LPoint3 xyz = _node_path.get_pos();
  73. LVecBase3 hpr = _node_path.get_hpr();
  74. int flags = 0;
  75. if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
  76. _store_xyz[0] = xyz[0];
  77. flags |= F_new_x;
  78. }
  79. if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
  80. _store_xyz[1] = xyz[1];
  81. flags |= F_new_y;
  82. }
  83. if (!IS_THRESHOLD_EQUAL(_store_xyz[2], xyz[2], smooth_node_epsilon)) {
  84. _store_xyz[2] = xyz[2];
  85. flags |= F_new_z;
  86. }
  87. if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
  88. _store_hpr[0] = hpr[0];
  89. flags |= F_new_h;
  90. }
  91. if (!IS_THRESHOLD_EQUAL(_store_hpr[1], hpr[1], smooth_node_epsilon)) {
  92. _store_hpr[1] = hpr[1];
  93. flags |= F_new_p;
  94. }
  95. if (!IS_THRESHOLD_EQUAL(_store_hpr[2], hpr[2], smooth_node_epsilon)) {
  96. _store_hpr[2] = hpr[2];
  97. flags |= F_new_r;
  98. }
  99. if (_currL[0] != _currL[1]) {
  100. // location (zoneId) has changed, send out all info copy over 'set'
  101. // location over to 'sent' location
  102. _currL[0] = _currL[1];
  103. // Any other change
  104. _store_stop = false;
  105. d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2],
  106. _store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]);
  107. } else if (flags == 0) {
  108. // No change. Send one and only one "stop" message.
  109. if (!_store_stop) {
  110. _store_stop = true;
  111. d_setSmStop();
  112. }
  113. } else if (only_changed(flags, F_new_h)) {
  114. // Only change in H.
  115. _store_stop = false;
  116. d_setSmH(_store_hpr[0]);
  117. } else if (only_changed(flags, F_new_z)) {
  118. // Only change in Z.
  119. _store_stop = false;
  120. d_setSmZ(_store_xyz[2]);
  121. } else if (only_changed(flags, F_new_x | F_new_y)) {
  122. // Only change in X, Y
  123. _store_stop = false;
  124. d_setSmXY(_store_xyz[0], _store_xyz[1]);
  125. } else if (only_changed(flags, F_new_x | F_new_z)) {
  126. // Only change in X, Z
  127. _store_stop = false;
  128. d_setSmXZ(_store_xyz[0], _store_xyz[2]);
  129. } else if (only_changed(flags, F_new_x | F_new_y | F_new_z)) {
  130. // Only change in X, Y, Z
  131. _store_stop = false;
  132. d_setSmPos(_store_xyz[0], _store_xyz[1], _store_xyz[2]);
  133. } else if (only_changed(flags, F_new_h | F_new_p | F_new_r)) {
  134. // Only change in H, P, R
  135. _store_stop = false;
  136. d_setSmHpr(_store_hpr[0], _store_hpr[1], _store_hpr[2]);
  137. } else if (only_changed(flags, F_new_x | F_new_y | F_new_h)) {
  138. // Only change in X, Y, H
  139. _store_stop = false;
  140. d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
  141. } else if (only_changed(flags, F_new_x | F_new_y | F_new_z | F_new_h)) {
  142. // Only change in X, Y, Z, H
  143. _store_stop = false;
  144. d_setSmXYZH(_store_xyz[0], _store_xyz[1], _store_xyz[2], _store_hpr[0]);
  145. } else {
  146. // Any other change
  147. _store_stop = false;
  148. d_setSmPosHpr(_store_xyz[0], _store_xyz[1], _store_xyz[2],
  149. _store_hpr[0], _store_hpr[1], _store_hpr[2]);
  150. }
  151. }
  152. /**
  153. * Examines only X, Y, and H of the pos/hpr information, and broadcasts the
  154. * appropriate messages.
  155. */
  156. void CDistributedSmoothNodeBase::
  157. broadcast_pos_hpr_xyh() {
  158. LPoint3 xyz = _node_path.get_pos();
  159. LVecBase3 hpr = _node_path.get_hpr();
  160. int flags = 0;
  161. if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
  162. _store_xyz[0] = xyz[0];
  163. flags |= F_new_x;
  164. }
  165. if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
  166. _store_xyz[1] = xyz[1];
  167. flags |= F_new_y;
  168. }
  169. if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
  170. _store_hpr[0] = hpr[0];
  171. flags |= F_new_h;
  172. }
  173. if (flags == 0) {
  174. // No change. Send one and only one "stop" message.
  175. if (!_store_stop) {
  176. _store_stop = true;
  177. d_setSmStop();
  178. }
  179. } else if (only_changed(flags, F_new_h)) {
  180. // Only change in H.
  181. _store_stop = false;
  182. d_setSmH(_store_hpr[0]);
  183. } else if (only_changed(flags, F_new_x | F_new_y)) {
  184. // Only change in X, Y
  185. _store_stop = false;
  186. d_setSmXY(_store_xyz[0], _store_xyz[1]);
  187. } else {
  188. // Any other change.
  189. _store_stop = false;
  190. d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
  191. }
  192. }
  193. /**
  194. * Examines only X and Y of the pos/hpr information, and broadcasts the
  195. * appropriate messages.
  196. */
  197. void CDistributedSmoothNodeBase::
  198. broadcast_pos_hpr_xy() {
  199. LPoint3 xyz = _node_path.get_pos();
  200. int flags = 0;
  201. if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
  202. _store_xyz[0] = xyz[0];
  203. flags |= F_new_x;
  204. }
  205. if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
  206. _store_xyz[1] = xyz[1];
  207. flags |= F_new_y;
  208. }
  209. if (flags == 0) {
  210. // No change. Send one and only one "stop" message.
  211. if (!_store_stop) {
  212. _store_stop = true;
  213. d_setSmStop();
  214. }
  215. } else {
  216. // Any other change.
  217. _store_stop = false;
  218. d_setSmXY(_store_xyz[0], _store_xyz[1]);
  219. }
  220. }
  221. /**
  222. * Fills up the packer with the data appropriate for sending an update on the
  223. * indicated field name, up until the arguments.
  224. */
  225. void CDistributedSmoothNodeBase::
  226. begin_send_update(DCPacker &packer, const std::string &field_name) {
  227. DCField *field = _dclass->get_field_by_name(field_name);
  228. nassertv(field != nullptr);
  229. if (_is_ai) {
  230. packer.raw_pack_uint8(1);
  231. packer.RAW_PACK_CHANNEL(_do_id);
  232. packer.RAW_PACK_CHANNEL(_ai_id);
  233. // packer.raw_pack_uint8('A');
  234. packer.raw_pack_uint16(STATESERVER_OBJECT_SET_FIELD);
  235. packer.raw_pack_uint32(_do_id);
  236. packer.raw_pack_uint16(field->get_number());
  237. } else {
  238. packer.raw_pack_uint16(CLIENT_OBJECT_SET_FIELD);
  239. packer.raw_pack_uint32(_do_id);
  240. packer.raw_pack_uint16(field->get_number());
  241. }
  242. packer.begin_pack(field);
  243. packer.push();
  244. }
  245. /**
  246. * Appends the timestamp and sends the update.
  247. */
  248. void CDistributedSmoothNodeBase::
  249. finish_send_update(DCPacker &packer) {
  250. #ifdef HAVE_PYTHON
  251. nassertv(_clock_delta != nullptr);
  252. PyObject *clock_delta = PyObject_GetAttrString(_clock_delta, "delta");
  253. nassertv(clock_delta != nullptr);
  254. double delta = PyFloat_AsDouble(clock_delta);
  255. Py_DECREF(clock_delta);
  256. #else
  257. static const double delta = 0.0f;
  258. #endif // HAVE_PYTHON
  259. double local_time = ClockObject::get_global_clock()->get_real_time();
  260. int network_time = (int)cfloor(((local_time - delta) * network_time_precision) + 0.5);
  261. // Preserves the lower NetworkTimeBits of the networkTime value, and extends
  262. // the sign bit all the way up.
  263. network_time = ((network_time + 0x8000) & 0xFFFF) - 0x8000;
  264. packer.pack_int(network_time);
  265. packer.pop();
  266. bool pack_ok = packer.end_pack();
  267. if (pack_ok) {
  268. Datagram dg(packer.get_data(), packer.get_length());
  269. nassertv(_repository != nullptr);
  270. _repository->send_datagram(dg);
  271. } else {
  272. #ifndef NDEBUG
  273. if (packer.had_range_error()) {
  274. std::ostringstream error;
  275. error << "Node position out of range for DC file: "
  276. << _node_path << " pos = " << _store_xyz
  277. << " hpr = " << _store_hpr
  278. << " zoneId = " << _currL[0];
  279. #ifdef HAVE_PYTHON
  280. std::string message = error.str();
  281. distributed_cat.warning()
  282. << message << "\n";
  283. PyErr_SetString(PyExc_ValueError, message.c_str());
  284. #else
  285. nassert_raise(error.str());
  286. #endif
  287. } else {
  288. const char *message = "Unexpected pack error in DC file.";
  289. #ifdef HAVE_PYTHON
  290. distributed_cat.warning()
  291. << message << "\n";
  292. PyErr_SetString(PyExc_TypeError, message);
  293. #else
  294. nassert_raise(message);
  295. #endif
  296. }
  297. #endif
  298. }
  299. }
  300. /**
  301. * Appends the timestamp and sends the update.
  302. */
  303. void CDistributedSmoothNodeBase::
  304. set_curr_l(uint64_t l) {
  305. _currL[1] = l;
  306. }
  307. void CDistributedSmoothNodeBase::
  308. print_curr_l() {
  309. std::cout << "printCurrL: sent l: " << _currL[1] << " last set l: " << _currL[0] << "\n";
  310. }