397 lines
12 KiB
C++
397 lines
12 KiB
C++
// Filename: cDistributedSmoothNodeBase.cxx
|
|
// Created by: drose (03Sep04)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "cDistributedSmoothNodeBase.h"
|
|
#include "cConnectionRepository.h"
|
|
#include "dcField.h"
|
|
#include "dcClass.h"
|
|
#include "dcmsgtypes.h"
|
|
#include "config_distributed.h"
|
|
|
|
static const PN_stdfloat smooth_node_epsilon = 0.01;
|
|
static const double network_time_precision = 100.0; // Matches ClockDelta.py
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::Constructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CDistributedSmoothNodeBase::
|
|
CDistributedSmoothNodeBase() {
|
|
_repository = NULL;
|
|
_is_ai = false;
|
|
_ai_id = 0;
|
|
|
|
#ifdef HAVE_PYTHON
|
|
_clock_delta = NULL;
|
|
#endif
|
|
|
|
_currL[0] = 0;
|
|
_currL[1] = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::Destructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
CDistributedSmoothNodeBase::
|
|
~CDistributedSmoothNodeBase() {
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::initialize
|
|
// Access: Published
|
|
// Description: Initializes the internal structures from some
|
|
// constructs that are normally stored only in Python.
|
|
// Also reads the current node's pos & hpr values in
|
|
// preparation for transmitting them via one of the
|
|
// broadcast_pos_hpr_*() methods.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
initialize(const NodePath &node_path, DCClass *dclass, CHANNEL_TYPE do_id) {
|
|
_node_path = node_path;
|
|
_dclass = dclass;
|
|
_do_id = do_id;
|
|
|
|
nassertv(!_node_path.is_empty());
|
|
|
|
_store_xyz = _node_path.get_pos();
|
|
_store_hpr = _node_path.get_hpr();
|
|
_store_stop = false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::send_everything
|
|
// Access: Published
|
|
// Description: Broadcasts the current pos/hpr in its complete form.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
send_everything() {
|
|
_currL[0] = _currL[1];
|
|
d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2],
|
|
_store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_full
|
|
// Access: Published
|
|
// Description: Examines the complete pos/hpr information to see
|
|
// which of the six elements have changed, and
|
|
// broadcasts the appropriate messages.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
broadcast_pos_hpr_full() {
|
|
LPoint3 xyz = _node_path.get_pos();
|
|
LVecBase3 hpr = _node_path.get_hpr();
|
|
|
|
int flags = 0;
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
|
|
_store_xyz[0] = xyz[0];
|
|
flags |= F_new_x;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
|
|
_store_xyz[1] = xyz[1];
|
|
flags |= F_new_y;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_xyz[2], xyz[2], smooth_node_epsilon)) {
|
|
_store_xyz[2] = xyz[2];
|
|
flags |= F_new_z;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
|
|
_store_hpr[0] = hpr[0];
|
|
flags |= F_new_h;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_hpr[1], hpr[1], smooth_node_epsilon)) {
|
|
_store_hpr[1] = hpr[1];
|
|
flags |= F_new_p;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_hpr[2], hpr[2], smooth_node_epsilon)) {
|
|
_store_hpr[2] = hpr[2];
|
|
flags |= F_new_r;
|
|
}
|
|
|
|
if (_currL[0] != _currL[1]) {
|
|
// location (zoneId) has changed, send out all info
|
|
// copy over 'set' location over to 'sent' location
|
|
_currL[0] = _currL[1];
|
|
// Any other change
|
|
_store_stop = false;
|
|
d_setSmPosHprL(_store_xyz[0], _store_xyz[1], _store_xyz[2],
|
|
_store_hpr[0], _store_hpr[1], _store_hpr[2], _currL[0]);
|
|
|
|
} else if (flags == 0) {
|
|
// No change. Send one and only one "stop" message.
|
|
if (!_store_stop) {
|
|
_store_stop = true;
|
|
d_setSmStop();
|
|
}
|
|
|
|
} else if (only_changed(flags, F_new_h)) {
|
|
// Only change in H.
|
|
_store_stop = false;
|
|
d_setSmH(_store_hpr[0]);
|
|
|
|
} else if (only_changed(flags, F_new_z)) {
|
|
// Only change in Z.
|
|
_store_stop = false;
|
|
d_setSmZ(_store_xyz[2]);
|
|
|
|
} else if (only_changed(flags, F_new_x | F_new_y)) {
|
|
// Only change in X, Y
|
|
_store_stop = false;
|
|
d_setSmXY(_store_xyz[0], _store_xyz[1]);
|
|
|
|
} else if (only_changed(flags, F_new_x | F_new_z)) {
|
|
// Only change in X, Z
|
|
_store_stop = false;
|
|
d_setSmXZ(_store_xyz[0], _store_xyz[2]);
|
|
|
|
} else if (only_changed(flags, F_new_x | F_new_y | F_new_z)) {
|
|
// Only change in X, Y, Z
|
|
_store_stop = false;
|
|
d_setSmPos(_store_xyz[0], _store_xyz[1], _store_xyz[2]);
|
|
|
|
} else if (only_changed(flags, F_new_h | F_new_p | F_new_r)) {
|
|
// Only change in H, P, R
|
|
_store_stop = false;
|
|
d_setSmHpr(_store_hpr[0], _store_hpr[1], _store_hpr[2]);
|
|
|
|
} else if (only_changed(flags, F_new_x | F_new_y | F_new_h)) {
|
|
// Only change in X, Y, H
|
|
_store_stop = false;
|
|
d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
|
|
|
|
} else if (only_changed(flags, F_new_x | F_new_y | F_new_z | F_new_h)) {
|
|
// Only change in X, Y, Z, H
|
|
_store_stop = false;
|
|
d_setSmXYZH(_store_xyz[0], _store_xyz[1], _store_xyz[2], _store_hpr[0]);
|
|
|
|
} else {
|
|
// Any other change
|
|
_store_stop = false;
|
|
d_setSmPosHpr(_store_xyz[0], _store_xyz[1], _store_xyz[2],
|
|
_store_hpr[0], _store_hpr[1], _store_hpr[2]);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_xyh
|
|
// Access: Published
|
|
// Description: Examines only X, Y, and H of the pos/hpr information,
|
|
// and broadcasts the appropriate messages.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
broadcast_pos_hpr_xyh() {
|
|
LPoint3 xyz = _node_path.get_pos();
|
|
LVecBase3 hpr = _node_path.get_hpr();
|
|
|
|
int flags = 0;
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
|
|
_store_xyz[0] = xyz[0];
|
|
flags |= F_new_x;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
|
|
_store_xyz[1] = xyz[1];
|
|
flags |= F_new_y;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_hpr[0], hpr[0], smooth_node_epsilon)) {
|
|
_store_hpr[0] = hpr[0];
|
|
flags |= F_new_h;
|
|
}
|
|
|
|
if (flags == 0) {
|
|
// No change. Send one and only one "stop" message.
|
|
if (!_store_stop) {
|
|
_store_stop = true;
|
|
d_setSmStop();
|
|
}
|
|
|
|
} else if (only_changed(flags, F_new_h)) {
|
|
// Only change in H.
|
|
_store_stop = false;
|
|
d_setSmH(_store_hpr[0]);
|
|
|
|
} else if (only_changed(flags, F_new_x | F_new_y)) {
|
|
// Only change in X, Y
|
|
_store_stop = false;
|
|
d_setSmXY(_store_xyz[0], _store_xyz[1]);
|
|
|
|
} else {
|
|
// Any other change.
|
|
_store_stop = false;
|
|
d_setSmXYH(_store_xyz[0], _store_xyz[1], _store_hpr[0]);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::broadcast_pos_hpr_xy
|
|
// Access: Published
|
|
// Description: Examines only X and Y of the pos/hpr information,
|
|
// and broadcasts the appropriate messages.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
broadcast_pos_hpr_xy() {
|
|
LPoint3 xyz = _node_path.get_pos();
|
|
|
|
int flags = 0;
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_xyz[0], xyz[0], smooth_node_epsilon)) {
|
|
_store_xyz[0] = xyz[0];
|
|
flags |= F_new_x;
|
|
}
|
|
|
|
if (!IS_THRESHOLD_EQUAL(_store_xyz[1], xyz[1], smooth_node_epsilon)) {
|
|
_store_xyz[1] = xyz[1];
|
|
flags |= F_new_y;
|
|
}
|
|
|
|
if (flags == 0) {
|
|
// No change. Send one and only one "stop" message.
|
|
if (!_store_stop) {
|
|
_store_stop = true;
|
|
d_setSmStop();
|
|
}
|
|
|
|
} else {
|
|
// Any other change.
|
|
_store_stop = false;
|
|
d_setSmXY(_store_xyz[0], _store_xyz[1]);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::begin_send_update
|
|
// Access: Private
|
|
// Description: Fills up the packer with the data appropriate for
|
|
// sending an update on the indicated field name, up
|
|
// until the arguments.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
begin_send_update(DCPacker &packer, const string &field_name) {
|
|
DCField *field = _dclass->get_field_by_name(field_name);
|
|
nassertv(field != (DCField *)NULL);
|
|
|
|
if (_is_ai) {
|
|
|
|
packer.raw_pack_uint8(1);
|
|
packer.RAW_PACK_CHANNEL(_do_id);
|
|
packer.RAW_PACK_CHANNEL(_ai_id);
|
|
//packer.raw_pack_uint8('A');
|
|
packer.raw_pack_uint16(STATESERVER_OBJECT_SET_FIELD);
|
|
packer.raw_pack_uint32(_do_id);
|
|
packer.raw_pack_uint16(field->get_number());
|
|
|
|
} else {
|
|
packer.raw_pack_uint16(CLIENT_OBJECT_SET_FIELD);
|
|
packer.raw_pack_uint32(_do_id);
|
|
packer.raw_pack_uint16(field->get_number());
|
|
}
|
|
|
|
packer.begin_pack(field);
|
|
packer.push();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::finish_send_update
|
|
// Access: Private
|
|
// Description: Appends the timestamp and sends the update.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
finish_send_update(DCPacker &packer) {
|
|
#ifdef HAVE_PYTHON
|
|
nassertv(_clock_delta != NULL);
|
|
PyObject *clock_delta = PyObject_GetAttrString(_clock_delta, "delta");
|
|
nassertv(clock_delta != NULL);
|
|
double delta = PyFloat_AsDouble(clock_delta);
|
|
Py_DECREF(clock_delta);
|
|
#else
|
|
static const double delta = 0.0f;
|
|
#endif // HAVE_PYTHON
|
|
|
|
double local_time = ClockObject::get_global_clock()->get_real_time();
|
|
|
|
int network_time = (int)cfloor(((local_time - delta) * network_time_precision) + 0.5);
|
|
// Preserves the lower NetworkTimeBits of the networkTime value,
|
|
// and extends the sign bit all the way up.
|
|
network_time = ((network_time + 0x8000) & 0xFFFF) - 0x8000;
|
|
packer.pack_int(network_time);
|
|
|
|
packer.pop();
|
|
bool pack_ok = packer.end_pack();
|
|
if (pack_ok) {
|
|
Datagram dg(packer.get_data(), packer.get_length());
|
|
nassertv(_repository != NULL);
|
|
_repository->send_datagram(dg);
|
|
|
|
} else {
|
|
#ifndef NDEBUG
|
|
if (packer.had_range_error()) {
|
|
ostringstream error;
|
|
error << "Node position out of range for DC file: "
|
|
<< _node_path << " pos = " << _store_xyz
|
|
<< " hpr = " << _store_hpr
|
|
<< " zoneId = " << _currL[0];
|
|
|
|
#ifdef HAVE_PYTHON
|
|
string message = error.str();
|
|
distributed_cat.warning()
|
|
<< message << "\n";
|
|
PyErr_SetString(PyExc_ValueError, message.c_str());
|
|
#else
|
|
nassert_raise(error.str());
|
|
#endif
|
|
|
|
} else {
|
|
const char *message = "Unexpected pack error in DC file.";
|
|
#ifdef HAVE_PYTHON
|
|
distributed_cat.warning()
|
|
<< message << "\n";
|
|
PyErr_SetString(PyExc_TypeError, message);
|
|
#else
|
|
nassert_raise(message);
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: CDistributedSmoothNodeBase::set_curr_l
|
|
// published function to set current location for
|
|
// this object, this location is then sent out along
|
|
// with the next position broadcast
|
|
// Access: Private
|
|
// Description: Appends the timestamp and sends the update.
|
|
////////////////////////////////////////////////////////////////////
|
|
void CDistributedSmoothNodeBase::
|
|
set_curr_l(PN_uint64 l) {
|
|
_currL[1] = l;
|
|
}
|
|
|
|
void CDistributedSmoothNodeBase::
|
|
print_curr_l() {
|
|
cout << "printCurrL: sent l: " << _currL[1] << " last set l: " << _currL[0] << "\n";
|
|
}
|
|
|