Panda3D
Loading...
Searching...
No Matches
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
16#include "dcField.h"
17#include "dcClass.h"
18#include "dcmsgtypes.h"
19#include "config_distributed.h"
20
21static const PN_stdfloat smooth_node_epsilon = 0.01;
22static const double network_time_precision = 100.0; // Matches ClockDelta.py
23
24/**
25 *
26 */
27CDistributedSmoothNodeBase::
28CDistributedSmoothNodeBase() {
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 */
44CDistributedSmoothNodeBase::
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 */
55initialize(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 */
270void CDistributedSmoothNodeBase::
271begin_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 */
298void CDistributedSmoothNodeBase::
299finish_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 */
361set_curr_l(uint64_t l) {
362 _currL[1] = l;
363}
364
365void CDistributedSmoothNodeBase::
366print_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.
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.
LPoint3 get_pos() const
Retrieves the translation component of the transform.
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.