Panda3D
cDistributedSmoothNodeBase.cxx
Go to the documentation of this file.
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 
15 #include "cConnectionRepository.h"
16 #include "dcField.h"
17 #include "dcClass.h"
18 #include "dcmsgtypes.h"
19 #include "config_distributed.h"
20 
21 static const PN_stdfloat smooth_node_epsilon = 0.01;
22 static const double network_time_precision = 100.0; // Matches ClockDelta.py
23 
24 /**
25  *
26  */
27 CDistributedSmoothNodeBase::
28 CDistributedSmoothNodeBase() {
29  _repository = nullptr;
30  _is_ai = false;
31  _ai_id = 0;
32 
33 #ifdef HAVE_PYTHON
34  _clock_delta = nullptr;
35 #endif
36 
37  _currL[0] = 0;
38  _currL[1] = 0;
39 }
40 
41 /**
42  *
43  */
44 CDistributedSmoothNodeBase::
45 ~CDistributedSmoothNodeBase() {
46 }
47 
48 /**
49  * Initializes the internal structures from some constructs that are normally
50  * stored only in Python. Also reads the current node's pos & hpr values in
51  * preparation for transmitting them via one of the broadcast_pos_hpr_*()
52  * methods.
53  */
55 initialize(const NodePath &node_path, DCClass *dclass, CHANNEL_TYPE do_id) {
56  _node_path = node_path;
57  _dclass = dclass;
58  _do_id = do_id;
59 
60  nassertv(!_node_path.is_empty());
61 
62  _store_xyz = _node_path.get_pos();
63  _store_hpr = _node_path.get_hpr();
64  _store_stop = false;
65 }
66 
67 /**
68  * Broadcasts the current pos/hpr in its complete form.
69  */
72  _currL[0] = _currL[1];
73  d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2],
74  _store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]);
75 }
76 
77 /**
78  * Examines the complete pos/hpr information to see which of the six elements
79  * have changed, and broadcasts the appropriate messages.
80  */
83  LPoint3 xyz = _node_path.get_pos();
84  LVecBase3 hpr = _node_path.get_hpr();
85 
86  int flags = 0;
87 
88  if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
89  _store_xyz[0] = xyz[0];
90  flags |= F_new_x;
91  }
92 
93  if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
94  _store_xyz[1] = xyz[1];
95  flags |= F_new_y;
96  }
97 
98  if (!IS_THRESHOLD_EQUAL(_store_xyz[2], xyz[2], smooth_node_epsilon)) {
99  _store_xyz[2] = xyz[2];
100  flags |= F_new_z;
101  }
102 
103  if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
104  _store_hpr[0] = hpr[0];
105  flags |= F_new_h;
106  }
107 
108  if (!IS_THRESHOLD_EQUAL(_store_hpr[1], hpr[1], smooth_node_epsilon)) {
109  _store_hpr[1] = hpr[1];
110  flags |= F_new_p;
111  }
112 
113  if (!IS_THRESHOLD_EQUAL(_store_hpr[2], hpr[2], smooth_node_epsilon)) {
114  _store_hpr[2] = hpr[2];
115  flags |= F_new_r;
116  }
117 
118  if (_currL[0] != _currL[1]) {
119  // location (zoneId) has changed, send out all info copy over 'set'
120  // location over to 'sent' location
121  _currL[0] = _currL[1];
122  // Any other change
123  _store_stop = false;
124  d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2],
125  _store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]);
126 
127  } else if (flags == 0) {
128  // No change. Send one and only one "stop" message.
129  if (!_store_stop) {
130  _store_stop = true;
131  d_setSmStop();
132  }
133 
134  } else if (only_changed(flags, F_new_h)) {
135  // Only change in H.
136  _store_stop = false;
137  d_setSmH(_store_hpr[0]);
138 
139  } else if (only_changed(flags, F_new_z)) {
140  // Only change in Z.
141  _store_stop = false;
142  d_setSmZ(_store_xyz[2]);
143 
144  } else if (only_changed(flags, F_new_x | F_new_y)) {
145  // Only change in X, Y
146  _store_stop = false;
147  d_setSmXY(_store_xyz[0], _store_xyz[1]);
148 
149  } else if (only_changed(flags, F_new_x | F_new_z)) {
150  // Only change in X, Z
151  _store_stop = false;
152  d_setSmXZ(_store_xyz[0], _store_xyz[2]);
153 
154  } else if (only_changed(flags, F_new_x | F_new_y | F_new_z)) {
155  // Only change in X, Y, Z
156  _store_stop = false;
157  d_setSmPos(_store_xyz[0], _store_xyz[1], _store_xyz[2]);
158 
159  } else if (only_changed(flags, F_new_h | F_new_p | F_new_r)) {
160  // Only change in H, P, R
161  _store_stop = false;
162  d_setSmHpr(_store_hpr[0], _store_hpr[1], _store_hpr[2]);
163 
164  } else if (only_changed(flags, F_new_x | F_new_y | F_new_h)) {
165  // Only change in X, Y, H
166  _store_stop = false;
167  d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
168 
169  } else if (only_changed(flags, F_new_x | F_new_y | F_new_z | F_new_h)) {
170  // Only change in X, Y, Z, H
171  _store_stop = false;
172  d_setSmXYZH(_store_xyz[0], _store_xyz[1], _store_xyz[2], _store_hpr[0]);
173 
174  } else {
175  // Any other change
176  _store_stop = false;
177  d_setSmPosHpr(_store_xyz[0], _store_xyz[1], _store_xyz[2],
178  _store_hpr[0], _store_hpr[1], _store_hpr[2]);
179  }
180 }
181 
182 /**
183  * Examines only X, Y, and H of the pos/hpr information, and broadcasts the
184  * appropriate messages.
185  */
188  LPoint3 xyz = _node_path.get_pos();
189  LVecBase3 hpr = _node_path.get_hpr();
190 
191  int flags = 0;
192 
193  if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
194  _store_xyz[0] = xyz[0];
195  flags |= F_new_x;
196  }
197 
198  if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
199  _store_xyz[1] = xyz[1];
200  flags |= F_new_y;
201  }
202 
203  if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
204  _store_hpr[0] = hpr[0];
205  flags |= F_new_h;
206  }
207 
208  if (flags == 0) {
209  // No change. Send one and only one "stop" message.
210  if (!_store_stop) {
211  _store_stop = true;
212  d_setSmStop();
213  }
214 
215  } else if (only_changed(flags, F_new_h)) {
216  // Only change in H.
217  _store_stop = false;
218  d_setSmH(_store_hpr[0]);
219 
220  } else if (only_changed(flags, F_new_x | F_new_y)) {
221  // Only change in X, Y
222  _store_stop = false;
223  d_setSmXY(_store_xyz[0], _store_xyz[1]);
224 
225  } else {
226  // Any other change.
227  _store_stop = false;
228  d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
229  }
230 }
231 
232 /**
233  * Examines only X and Y of the pos/hpr information, and broadcasts the
234  * appropriate messages.
235  */
238  LPoint3 xyz = _node_path.get_pos();
239 
240  int flags = 0;
241 
242  if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
243  _store_xyz[0] = xyz[0];
244  flags |= F_new_x;
245  }
246 
247  if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
248  _store_xyz[1] = xyz[1];
249  flags |= F_new_y;
250  }
251 
252  if (flags == 0) {
253  // No change. Send one and only one "stop" message.
254  if (!_store_stop) {
255  _store_stop = true;
256  d_setSmStop();
257  }
258 
259  } else {
260  // Any other change.
261  _store_stop = false;
262  d_setSmXY(_store_xyz[0], _store_xyz[1]);
263  }
264 }
265 
266 /**
267  * Fills up the packer with the data appropriate for sending an update on the
268  * indicated field name, up until the arguments.
269  */
270 void CDistributedSmoothNodeBase::
271 begin_send_update(DCPacker &packer, const std::string &field_name) {
272  DCField *field = _dclass->get_field_by_name(field_name);
273  nassertv(field != nullptr);
274 
275  if (_is_ai) {
276 
277  packer.raw_pack_uint8(1);
278  packer.RAW_PACK_CHANNEL(_do_id);
279  packer.RAW_PACK_CHANNEL(_ai_id);
280  // packer.raw_pack_uint8('A');
281  packer.raw_pack_uint16(STATESERVER_OBJECT_SET_FIELD);
282  packer.raw_pack_uint32(_do_id);
283  packer.raw_pack_uint16(field->get_number());
284 
285  } else {
286  packer.raw_pack_uint16(CLIENT_OBJECT_SET_FIELD);
287  packer.raw_pack_uint32(_do_id);
288  packer.raw_pack_uint16(field->get_number());
289  }
290 
291  packer.begin_pack(field);
292  packer.push();
293 }
294 
295 /**
296  * Appends the timestamp and sends the update.
297  */
298 void CDistributedSmoothNodeBase::
299 finish_send_update(DCPacker &packer) {
300 #ifdef HAVE_PYTHON
301  nassertv(_clock_delta != nullptr);
302  PyObject *clock_delta = PyObject_GetAttrString(_clock_delta, "delta");
303  nassertv(clock_delta != nullptr);
304  double delta = PyFloat_AsDouble(clock_delta);
305  Py_DECREF(clock_delta);
306 #else
307  static const double delta = 0.0f;
308 #endif // HAVE_PYTHON
309 
310  double local_time = ClockObject::get_global_clock()->get_real_time();
311 
312  int network_time = (int)cfloor(((local_time - delta) * network_time_precision) + 0.5);
313  // Preserves the lower NetworkTimeBits of the networkTime value, and extends
314  // the sign bit all the way up.
315  network_time = ((network_time + 0x8000) & 0xFFFF) - 0x8000;
316  packer.pack_int(network_time);
317 
318  packer.pop();
319  bool pack_ok = packer.end_pack();
320  if (pack_ok) {
321  Datagram dg(packer.get_data(), packer.get_length());
322  nassertv(_repository != nullptr);
323  _repository->send_datagram(dg);
324 
325  } else {
326 #ifndef NDEBUG
327  if (packer.had_range_error()) {
328  std::ostringstream error;
329  error << "Node position out of range for DC file: "
330  << _node_path << " pos = " << _store_xyz
331  << " hpr = " << _store_hpr
332  << " zoneId = " << _currL[0];
333 
334 #ifdef HAVE_PYTHON
335  std::string message = error.str();
336  distributed_cat.warning()
337  << message << "\n";
338  PyErr_SetString(PyExc_ValueError, message.c_str());
339 #else
340  nassert_raise(error.str());
341 #endif
342 
343  } else {
344  const char *message = "Unexpected pack error in DC file.";
345 #ifdef HAVE_PYTHON
346  distributed_cat.warning()
347  << message << "\n";
348  PyErr_SetString(PyExc_TypeError, message);
349 #else
350  nassert_raise(message);
351 #endif
352  }
353 #endif
354  }
355 }
356 
357 /**
358  * Appends the timestamp and sends the update.
359  */
361 set_curr_l(uint64_t l) {
362  _currL[1] = l;
363 }
364 
365 void CDistributedSmoothNodeBase::
366 print_curr_l() {
367  std::cout << "printCurrL: sent l: " << _currL[1] << " last set l: " << _currL[0] << "\n";
368 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool send_datagram(const Datagram &dg)
Queues the indicated datagram for sending to the server.
void set_curr_l(uint64_t l)
Appends the timestamp and sends the update.
void initialize(const NodePath &node_path, DCClass *dclass, CHANNEL_TYPE do_id)
Initializes the internal structures from some constructs that are normally stored only in Python.
void send_everything()
Broadcasts the current pos/hpr in its complete form.
void broadcast_pos_hpr_xyh()
Examines only X, Y, and H of the pos/hpr information, and broadcasts the appropriate messages.
void broadcast_pos_hpr_full()
Examines the complete pos/hpr information to see which of the six elements have changed,...
void broadcast_pos_hpr_xy()
Examines only X and Y of the pos/hpr information, and broadcasts the appropriate messages.
get_real_time
Returns the actual number of seconds elapsed since the ClockObject was created, or since it was last ...
Definition: clockObject.h:92
static ClockObject * get_global_clock()
Returns a pointer to the global ClockObject.
Definition: clockObject.I:215
Defines a particular DistributedClass as read from an input .dc file.
Definition: dcClass.h:44
DCField * get_field_by_name(const std::string &name) const
Returns a pointer to the DCField that shares the indicated name.
Definition: dcClass.cxx:201
A single field of a Distributed Class, either atomic or molecular.
Definition: dcField.h:37
int get_number() const
Returns a unique index number associated with this field.
Definition: dcField.I:19
This class can be used for packing a series of numeric and string data into a binary stream,...
Definition: dcPacker.h:34
void push()
Marks the beginning of a nested series of fields.
Definition: dcPacker.cxx:411
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
bool had_range_error() const
Returns true if there has been an range validation error since the most recent call to begin(); in pa...
Definition: dcPacker.I:553
void pack_int(int value)
Packs the indicated numeric or string value into the stream.
Definition: dcPacker.I:153
void raw_pack_uint32(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:758
void raw_pack_uint16(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:749
void raw_pack_uint8(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:740
void pop()
Marks the end of a nested series of fields.
Definition: dcPacker.cxx:495
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:641
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:583
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition: nodePath.h:159
LVecBase3 get_hpr() const
Retrieves the rotation component of the transform.
Definition: nodePath.cxx:1110
LPoint3 get_pos() const
Retrieves the translation component of the transform.
Definition: nodePath.cxx:1044
bool is_empty() const
Returns true if the NodePath contains no nodes.
Definition: nodePath.I:188
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.