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