Panda3D
|
00001 // Filename: cDistributedSmoothNodeBase.cxx 00002 // Created by: drose (03Sep04) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "cDistributedSmoothNodeBase.h" 00016 #include "cConnectionRepository.h" 00017 #include "dcField.h" 00018 #include "dcClass.h" 00019 #include "dcmsgtypes.h" 00020 #include "config_distributed.h" 00021 00022 static const float smooth_node_epsilon = 0.01; 00023 static const double network_time_precision = 100.0; // Matches ClockDelta.py 00024 00025 CConnectionRepository *CDistributedSmoothNodeBase::_repository = NULL; 00026 bool CDistributedSmoothNodeBase::_is_ai; 00027 CHANNEL_TYPE CDistributedSmoothNodeBase::_ai_id; 00028 00029 #ifdef HAVE_PYTHON 00030 PyObject *CDistributedSmoothNodeBase::_clock_delta = NULL; 00031 #endif 00032 00033 //////////////////////////////////////////////////////////////////// 00034 // Function: CDistributedSmoothNodeBase::Constructor 00035 // Access: Published 00036 // Description: 00037 //////////////////////////////////////////////////////////////////// 00038 CDistributedSmoothNodeBase:: 00039 CDistributedSmoothNodeBase() { 00040 _currL[0] = 0; 00041 _currL[1] = 0; 00042 } 00043 00044 //////////////////////////////////////////////////////////////////// 00045 // Function: CDistributedSmoothNodeBase::Destructor 00046 // Access: Published 00047 // Description: 00048 //////////////////////////////////////////////////////////////////// 00049 CDistributedSmoothNodeBase:: 00050 ~CDistributedSmoothNodeBase() { 00051 } 00052 00053 //////////////////////////////////////////////////////////////////// 00054 // Function: CDistributedSmoothNodeBase::initialize 00055 // Access: Published 00056 // Description: Initializes the internal structures from some 00057 // constructs that are normally stored only in Python. 00058 // Also reads the current node's pos & hpr values in 00059 // preparation for transmitting them via one of the 00060 // broadcast_pos_hpr_*() methods. 00061 //////////////////////////////////////////////////////////////////// 00062 void CDistributedSmoothNodeBase:: 00063 initialize(const NodePath &node_path, DCClass *dclass, CHANNEL_TYPE do_id) { 00064 _node_path = node_path; 00065 _dclass = dclass; 00066 _do_id = do_id; 00067 00068 nassertv(!_node_path.is_empty()); 00069 00070 _store_xyz = _node_path.get_pos(); 00071 _store_hpr = _node_path.get_hpr(); 00072 _store_stop = false; 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: CDistributedSmoothNodeBase::send_everything 00077 // Access: Published 00078 // Description: Broadcasts the current pos/hpr in its complete form. 00079 //////////////////////////////////////////////////////////////////// 00080 void CDistributedSmoothNodeBase:: 00081 send_everything() { 00082 _currL[0] = _currL[1]; 00083 d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2], 00084 _store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]); 00085 } 00086 00087 //////////////////////////////////////////////////////////////////// 00088 // Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_full 00089 // Access: Published 00090 // Description: Examines the complete pos/hpr information to see 00091 // which of the six elements have changed, and 00092 // broadcasts the appropriate messages. 00093 //////////////////////////////////////////////////////////////////// 00094 void CDistributedSmoothNodeBase:: 00095 broadcast_pos_hpr_full() { 00096 LPoint3f xyz = _node_path.get_pos(); 00097 LVecBase3f hpr = _node_path.get_hpr(); 00098 00099 int flags = 0; 00100 00101 if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) { 00102 _store_xyz[0] = xyz[0]; 00103 flags |= F_new_x; 00104 } 00105 00106 if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) { 00107 _store_xyz[1] = xyz[1]; 00108 flags |= F_new_y; 00109 } 00110 00111 if (!IS_THRESHOLD_EQUAL(_store_xyz[2], xyz[2], smooth_node_epsilon)) { 00112 _store_xyz[2] = xyz[2]; 00113 flags |= F_new_z; 00114 } 00115 00116 if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) { 00117 _store_hpr[0] = hpr[0]; 00118 flags |= F_new_h; 00119 } 00120 00121 if (!IS_THRESHOLD_EQUAL(_store_hpr[1], hpr[1], smooth_node_epsilon)) { 00122 _store_hpr[1] = hpr[1]; 00123 flags |= F_new_p; 00124 } 00125 00126 if (!IS_THRESHOLD_EQUAL(_store_hpr[2], hpr[2], smooth_node_epsilon)) { 00127 _store_hpr[2] = hpr[2]; 00128 flags |= F_new_r; 00129 } 00130 00131 if (_currL[0] != _currL[1]) { 00132 // location (zoneId) has changed, send out all info 00133 // copy over 'set' location over to 'sent' location 00134 _currL[0] = _currL[1]; 00135 // Any other change 00136 _store_stop = false; 00137 d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2], 00138 _store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]); 00139 00140 } else if (flags == 0) { 00141 // No change. Send one and only one "stop" message. 00142 if (!_store_stop) { 00143 _store_stop = true; 00144 d_setSmStop(); 00145 } 00146 00147 } else if (only_changed(flags, F_new_h)) { 00148 // Only change in H. 00149 _store_stop = false; 00150 d_setSmH(_store_hpr[0]); 00151 00152 } else if (only_changed(flags, F_new_z)) { 00153 // Only change in Z. 00154 _store_stop = false; 00155 d_setSmZ(_store_xyz[2]); 00156 00157 } else if (only_changed(flags, F_new_x | F_new_y)) { 00158 // Only change in X, Y 00159 _store_stop = false; 00160 d_setSmXY(_store_xyz[0], _store_xyz[1]); 00161 00162 } else if (only_changed(flags, F_new_x | F_new_z)) { 00163 // Only change in X, Z 00164 _store_stop = false; 00165 d_setSmXZ(_store_xyz[0], _store_xyz[2]); 00166 00167 } else if (only_changed(flags, F_new_x | F_new_y | F_new_z)) { 00168 // Only change in X, Y, Z 00169 _store_stop = false; 00170 d_setSmPos(_store_xyz[0], _store_xyz[1], _store_xyz[2]); 00171 00172 } else if (only_changed(flags, F_new_h | F_new_p | F_new_r)) { 00173 // Only change in H, P, R 00174 _store_stop = false; 00175 d_setSmHpr(_store_hpr[0], _store_hpr[1], _store_hpr[2]); 00176 00177 } else if (only_changed(flags, F_new_x | F_new_y | F_new_h)) { 00178 // Only change in X, Y, H 00179 _store_stop = false; 00180 d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]); 00181 00182 } else if (only_changed(flags, F_new_x | F_new_y | F_new_z | F_new_h)) { 00183 // Only change in X, Y, Z, H 00184 _store_stop = false; 00185 d_setSmXYZH(_store_xyz[0], _store_xyz[1], _store_xyz[2], _store_hpr[0]); 00186 00187 } else { 00188 // Any other change 00189 _store_stop = false; 00190 d_setSmPosHpr(_store_xyz[0], _store_xyz[1], _store_xyz[2], 00191 _store_hpr[0], _store_hpr[1], _store_hpr[2]); 00192 } 00193 } 00194 00195 //////////////////////////////////////////////////////////////////// 00196 // Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_xyh 00197 // Access: Published 00198 // Description: Examines only X, Y, and H of the pos/hpr information, 00199 // and broadcasts the appropriate messages. 00200 //////////////////////////////////////////////////////////////////// 00201 void CDistributedSmoothNodeBase:: 00202 broadcast_pos_hpr_xyh() { 00203 LPoint3f xyz = _node_path.get_pos(); 00204 LVecBase3f hpr = _node_path.get_hpr(); 00205 00206 int flags = 0; 00207 00208 if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) { 00209 _store_xyz[0] = xyz[0]; 00210 flags |= F_new_x; 00211 } 00212 00213 if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) { 00214 _store_xyz[1] = xyz[1]; 00215 flags |= F_new_y; 00216 } 00217 00218 if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) { 00219 _store_hpr[0] = hpr[0]; 00220 flags |= F_new_h; 00221 } 00222 00223 if (flags == 0) { 00224 // No change. Send one and only one "stop" message. 00225 if (!_store_stop) { 00226 _store_stop = true; 00227 d_setSmStop(); 00228 } 00229 00230 } else if (only_changed(flags, F_new_h)) { 00231 // Only change in H. 00232 _store_stop = false; 00233 d_setSmH(_store_hpr[0]); 00234 00235 } else if (only_changed(flags, F_new_x | F_new_y)) { 00236 // Only change in X, Y 00237 _store_stop = false; 00238 d_setSmXY(_store_xyz[0], _store_xyz[1]); 00239 00240 } else { 00241 // Any other change. 00242 _store_stop = false; 00243 d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]); 00244 } 00245 } 00246 00247 //////////////////////////////////////////////////////////////////// 00248 // Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_xy 00249 // Access: Published 00250 // Description: Examines only X and Y of the pos/hpr information, 00251 // and broadcasts the appropriate messages. 00252 //////////////////////////////////////////////////////////////////// 00253 void CDistributedSmoothNodeBase:: 00254 broadcast_pos_hpr_xy() { 00255 LPoint3f xyz = _node_path.get_pos(); 00256 00257 int flags = 0; 00258 00259 if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) { 00260 _store_xyz[0] = xyz[0]; 00261 flags |= F_new_x; 00262 } 00263 00264 if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) { 00265 _store_xyz[1] = xyz[1]; 00266 flags |= F_new_y; 00267 } 00268 00269 if (flags == 0) { 00270 // No change. Send one and only one "stop" message. 00271 if (!_store_stop) { 00272 _store_stop = true; 00273 d_setSmStop(); 00274 } 00275 00276 } else { 00277 // Any other change. 00278 _store_stop = false; 00279 d_setSmXY(_store_xyz[0], _store_xyz[1]); 00280 } 00281 } 00282 00283 //////////////////////////////////////////////////////////////////// 00284 // Function: CDistributedSmoothNodeBase::begin_send_update 00285 // Access: Private 00286 // Description: Fills up the packer with the data appropriate for 00287 // sending an update on the indicated field name, up 00288 // until the arguments. 00289 //////////////////////////////////////////////////////////////////// 00290 void CDistributedSmoothNodeBase:: 00291 begin_send_update(DCPacker &packer, const string &field_name) { 00292 DCField *field = _dclass->get_field_by_name(field_name); 00293 nassertv(field != (DCField *)NULL); 00294 00295 if (_is_ai) { 00296 00297 packer.raw_pack_uint8(1); 00298 packer.RAW_PACK_CHANNEL(_do_id); 00299 packer.RAW_PACK_CHANNEL(_ai_id); 00300 //packer.raw_pack_uint8('A'); 00301 packer.raw_pack_uint16(STATESERVER_OBJECT_UPDATE_FIELD); 00302 packer.raw_pack_uint32(_do_id); 00303 packer.raw_pack_uint16(field->get_number()); 00304 00305 } else { 00306 packer.raw_pack_uint16(CLIENT_OBJECT_UPDATE_FIELD); 00307 packer.raw_pack_uint32(_do_id); 00308 packer.raw_pack_uint16(field->get_number()); 00309 } 00310 00311 packer.begin_pack(field); 00312 packer.push(); 00313 } 00314 00315 //////////////////////////////////////////////////////////////////// 00316 // Function: CDistributedSmoothNodeBase::finish_send_update 00317 // Access: Private 00318 // Description: Appends the timestamp and sends the update. 00319 //////////////////////////////////////////////////////////////////// 00320 void CDistributedSmoothNodeBase:: 00321 finish_send_update(DCPacker &packer) { 00322 #ifdef HAVE_PYTHON 00323 PyObject *clock_delta = PyObject_GetAttrString(_clock_delta, "delta"); 00324 nassertv(clock_delta != NULL); 00325 double delta = PyFloat_AsDouble(clock_delta); 00326 Py_DECREF(clock_delta); 00327 #else 00328 static const double delta = 0.0f; 00329 #endif // HAVE_PYTHON 00330 00331 double local_time = ClockObject::get_global_clock()->get_real_time(); 00332 00333 int network_time = (int)cfloor(((local_time - delta) * network_time_precision) + 0.5); 00334 // Preserves the lower NetworkTimeBits of the networkTime value, 00335 // and extends the sign bit all the way up. 00336 network_time = ((network_time + 0x8000) & 0xFFFF) - 0x8000; 00337 packer.pack_int(network_time); 00338 00339 packer.pop(); 00340 bool pack_ok = packer.end_pack(); 00341 if (pack_ok) { 00342 Datagram dg(packer.get_data(), packer.get_length()); 00343 _repository->send_datagram(dg); 00344 00345 } else { 00346 #ifndef NDEBUG 00347 if (packer.had_range_error()) { 00348 ostringstream error; 00349 error << "Node position out of range for DC file: " 00350 << _node_path << " pos = " << _store_xyz 00351 << " hpr = " << _store_hpr 00352 << " zoneId = " << _currL[0]; 00353 00354 #ifdef HAVE_PYTHON 00355 string message = error.str(); 00356 distributed_cat.warning() 00357 << message << "\n"; 00358 PyErr_SetString(PyExc_ValueError, message.c_str()); 00359 #else 00360 nassert_raise(error.str()); 00361 #endif 00362 00363 } else { 00364 const char *message = "Unexpected pack error in DC file."; 00365 #ifdef HAVE_PYTHON 00366 distributed_cat.warning() 00367 << message << "\n"; 00368 PyErr_SetString(PyExc_TypeError, message); 00369 #else 00370 nassert_raise(message); 00371 #endif 00372 } 00373 #endif 00374 } 00375 } 00376 00377 //////////////////////////////////////////////////////////////////// 00378 // Function: CDistributedSmoothNodeBase::set_curr_l 00379 // published function to set current location for 00380 // this object, this location is then sent out along 00381 // with the next position broadcast 00382 // Access: Private 00383 // Description: Appends the timestamp and sends the update. 00384 //////////////////////////////////////////////////////////////////// 00385 void CDistributedSmoothNodeBase:: 00386 set_curr_l(PN_uint64 l) { 00387 _currL[1] = l; 00388 } 00389 00390 void CDistributedSmoothNodeBase:: 00391 print_curr_l() { 00392 cout << "printCurrL: sent l: " << _currL[1] << " last set l: " << _currL[0] << "\n"; 00393 } 00394