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 PN_stdfloat smooth_node_epsilon = 0.01; 00023 static const double network_time_precision = 100.0; // Matches ClockDelta.py 00024 00025 //////////////////////////////////////////////////////////////////// 00026 // Function: CDistributedSmoothNodeBase::Constructor 00027 // Access: Published 00028 // Description: 00029 //////////////////////////////////////////////////////////////////// 00030 CDistributedSmoothNodeBase:: 00031 CDistributedSmoothNodeBase() { 00032 _repository = NULL; 00033 _is_ai = false; 00034 _ai_id = 0; 00035 00036 #ifdef HAVE_PYTHON 00037 _clock_delta = NULL; 00038 #endif 00039 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 LPoint3 xyz = _node_path.get_pos(); 00097 LVecBase3 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 LPoint3 xyz = _node_path.get_pos(); 00204 LVecBase3 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 LPoint3 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 nassertv(_clock_delta != NULL); 00324 PyObject *clock_delta = PyObject_GetAttrString(_clock_delta, "delta"); 00325 nassertv(clock_delta != NULL); 00326 double delta = PyFloat_AsDouble(clock_delta); 00327 Py_DECREF(clock_delta); 00328 #else 00329 static const double delta = 0.0f; 00330 #endif // HAVE_PYTHON 00331 00332 double local_time = ClockObject::get_global_clock()->get_real_time(); 00333 00334 int network_time = (int)cfloor(((local_time - delta) * network_time_precision) + 0.5); 00335 // Preserves the lower NetworkTimeBits of the networkTime value, 00336 // and extends the sign bit all the way up. 00337 network_time = ((network_time + 0x8000) & 0xFFFF) - 0x8000; 00338 packer.pack_int(network_time); 00339 00340 packer.pop(); 00341 bool pack_ok = packer.end_pack(); 00342 if (pack_ok) { 00343 Datagram dg(packer.get_data(), packer.get_length()); 00344 nassertv(_repository != NULL); 00345 _repository->send_datagram(dg); 00346 00347 } else { 00348 #ifndef NDEBUG 00349 if (packer.had_range_error()) { 00350 ostringstream error; 00351 error << "Node position out of range for DC file: " 00352 << _node_path << " pos = " << _store_xyz 00353 << " hpr = " << _store_hpr 00354 << " zoneId = " << _currL[0]; 00355 00356 #ifdef HAVE_PYTHON 00357 string message = error.str(); 00358 distributed_cat.warning() 00359 << message << "\n"; 00360 PyErr_SetString(PyExc_ValueError, message.c_str()); 00361 #else 00362 nassert_raise(error.str()); 00363 #endif 00364 00365 } else { 00366 const char *message = "Unexpected pack error in DC file."; 00367 #ifdef HAVE_PYTHON 00368 distributed_cat.warning() 00369 << message << "\n"; 00370 PyErr_SetString(PyExc_TypeError, message); 00371 #else 00372 nassert_raise(message); 00373 #endif 00374 } 00375 #endif 00376 } 00377 } 00378 00379 //////////////////////////////////////////////////////////////////// 00380 // Function: CDistributedSmoothNodeBase::set_curr_l 00381 // published function to set current location for 00382 // this object, this location is then sent out along 00383 // with the next position broadcast 00384 // Access: Private 00385 // Description: Appends the timestamp and sends the update. 00386 //////////////////////////////////////////////////////////////////// 00387 void CDistributedSmoothNodeBase:: 00388 set_curr_l(PN_uint64 l) { 00389 _currL[1] = l; 00390 } 00391 00392 void CDistributedSmoothNodeBase:: 00393 print_curr_l() { 00394 cout << "printCurrL: sent l: " << _currL[1] << " last set l: " << _currL[0] << "\n"; 00395 } 00396