Panda3D

cDistributedSmoothNodeBase.cxx

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 
 All Classes Functions Variables Enumerations