|
@@ -16,25 +16,13 @@
|
|
|
#include "dcAtomicField.h"
|
|
#include "dcAtomicField.h"
|
|
|
#include "hashGenerator.h"
|
|
#include "hashGenerator.h"
|
|
|
#include "dcindent.h"
|
|
#include "dcindent.h"
|
|
|
-#include "dcmsgtypes.h"
|
|
|
|
|
-
|
|
|
|
|
-#include "datagram.h"
|
|
|
|
|
-#include "datagramIterator.h"
|
|
|
|
|
|
|
|
|
|
#include "dcClassParameter.h"
|
|
#include "dcClassParameter.h"
|
|
|
#include <algorithm>
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-#include "py_panda.h"
|
|
|
|
|
-#endif
|
|
|
|
|
-
|
|
|
|
|
-using std::ostream;
|
|
|
|
|
-using std::ostringstream;
|
|
|
|
|
using std::string;
|
|
using std::string;
|
|
|
|
|
|
|
|
#ifdef WITHIN_PANDA
|
|
#ifdef WITHIN_PANDA
|
|
|
-#include "pStatTimer.h"
|
|
|
|
|
-
|
|
|
|
|
#ifndef CPPPARSER
|
|
#ifndef CPPPARSER
|
|
|
PStatCollector DCClass::_update_pcollector("App:Show code:readerPollTask:Update");
|
|
PStatCollector DCClass::_update_pcollector("App:Show code:readerPollTask:Update");
|
|
|
PStatCollector DCClass::_generate_pcollector("App:Show code:readerPollTask:Generate");
|
|
PStatCollector DCClass::_generate_pcollector("App:Show code:readerPollTask:Generate");
|
|
@@ -89,10 +77,7 @@ DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) :
|
|
|
_number = -1;
|
|
_number = -1;
|
|
|
_constructor = nullptr;
|
|
_constructor = nullptr;
|
|
|
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
- _class_def = nullptr;
|
|
|
|
|
- _owner_class_def = nullptr;
|
|
|
|
|
-#endif
|
|
|
|
|
|
|
+ _python_class_defs = nullptr;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -108,11 +93,6 @@ DCClass::
|
|
|
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
|
for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
|
|
|
delete (*fi);
|
|
delete (*fi);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
- Py_XDECREF(_class_def);
|
|
|
|
|
- Py_XDECREF(_owner_class_def);
|
|
|
|
|
-#endif
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -338,7 +318,7 @@ inherits_from_bogus_class() const {
|
|
|
* Write a string representation of this instance to <out>.
|
|
* Write a string representation of this instance to <out>.
|
|
|
*/
|
|
*/
|
|
|
void DCClass::
|
|
void DCClass::
|
|
|
-output(ostream &out) const {
|
|
|
|
|
|
|
+output(std::ostream &out) const {
|
|
|
if (_is_struct) {
|
|
if (_is_struct) {
|
|
|
out << "struct";
|
|
out << "struct";
|
|
|
} else {
|
|
} else {
|
|
@@ -349,678 +329,11 @@ output(ostream &out) const {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Returns true if the DCClass object has an associated Python class
|
|
|
|
|
- * definition, false otherwise.
|
|
|
|
|
- */
|
|
|
|
|
-bool DCClass::
|
|
|
|
|
-has_class_def() const {
|
|
|
|
|
- return (_class_def != nullptr);
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Sets the class object associated with this DistributedClass. This object
|
|
|
|
|
- * will be used to construct new instances of the class.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-set_class_def(PyObject *class_def) {
|
|
|
|
|
- Py_XINCREF(class_def);
|
|
|
|
|
- Py_XDECREF(_class_def);
|
|
|
|
|
- _class_def = class_def;
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Returns the class object that was previously associated with this
|
|
|
|
|
- * DistributedClass. This will return a new reference to the object.
|
|
|
|
|
- */
|
|
|
|
|
-PyObject *DCClass::
|
|
|
|
|
-get_class_def() const {
|
|
|
|
|
- if (_class_def == nullptr) {
|
|
|
|
|
- Py_INCREF(Py_None);
|
|
|
|
|
- return Py_None;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Py_INCREF(_class_def);
|
|
|
|
|
- return _class_def;
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Returns true if the DCClass object has an associated Python owner class
|
|
|
|
|
- * definition, false otherwise.
|
|
|
|
|
- */
|
|
|
|
|
-bool DCClass::
|
|
|
|
|
-has_owner_class_def() const {
|
|
|
|
|
- return (_owner_class_def != nullptr);
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Sets the owner class object associated with this DistributedClass. This
|
|
|
|
|
- * object will be used to construct new owner instances of the class.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-set_owner_class_def(PyObject *owner_class_def) {
|
|
|
|
|
- Py_XINCREF(owner_class_def);
|
|
|
|
|
- Py_XDECREF(_owner_class_def);
|
|
|
|
|
- _owner_class_def = owner_class_def;
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Returns the owner class object that was previously associated with this
|
|
|
|
|
- * DistributedClass. This will return a new reference to the object.
|
|
|
|
|
- */
|
|
|
|
|
-PyObject *DCClass::
|
|
|
|
|
-get_owner_class_def() const {
|
|
|
|
|
- if (_owner_class_def == nullptr) {
|
|
|
|
|
- Py_INCREF(Py_None);
|
|
|
|
|
- return Py_None;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- Py_INCREF(_owner_class_def);
|
|
|
|
|
- return _owner_class_def;
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Extracts the update message out of the packer and applies it to the
|
|
|
|
|
- * indicated object by calling the appropriate method.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-receive_update(PyObject *distobj, DatagramIterator &di) const {
|
|
|
|
|
-#ifdef WITHIN_PANDA
|
|
|
|
|
- PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
|
|
|
|
|
-#endif
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
- const char *data = (const char *)di.get_datagram().get_data();
|
|
|
|
|
- packer.set_unpack_data(data + di.get_current_index(),
|
|
|
|
|
- di.get_remaining_size(), false);
|
|
|
|
|
-
|
|
|
|
|
- int field_id = packer.raw_unpack_uint16();
|
|
|
|
|
- DCField *field = get_field_by_index(field_id);
|
|
|
|
|
- if (field == nullptr) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm
|
|
|
|
|
- << "Received update for field " << field_id << ", not in class "
|
|
|
|
|
- << get_name();
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- packer.begin_unpack(field);
|
|
|
|
|
- field->receive_update(packer, distobj);
|
|
|
|
|
- packer.end_unpack();
|
|
|
|
|
-
|
|
|
|
|
- di.skip_bytes(packer.get_num_unpacked_bytes());
|
|
|
|
|
-
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Processes a big datagram that includes all of the "required" fields that
|
|
|
|
|
- * are sent along with a normal "generate with required" message. This is all
|
|
|
|
|
- * of the atomic fields that are marked "broadcast required".
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-receive_update_broadcast_required(PyObject *distobj, DatagramIterator &di) const {
|
|
|
|
|
-#ifdef WITHIN_PANDA
|
|
|
|
|
- PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
|
|
|
|
|
-#endif
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
- const char *data = (const char *)di.get_datagram().get_data();
|
|
|
|
|
- packer.set_unpack_data(data + di.get_current_index(),
|
|
|
|
|
- di.get_remaining_size(), false);
|
|
|
|
|
-
|
|
|
|
|
- int num_fields = get_num_inherited_fields();
|
|
|
|
|
- for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
|
|
|
|
|
- DCField *field = get_inherited_field(i);
|
|
|
|
|
- if (field->as_molecular_field() == nullptr &&
|
|
|
|
|
- field->is_required() && field->is_broadcast()) {
|
|
|
|
|
- packer.begin_unpack(field);
|
|
|
|
|
- field->receive_update(packer, distobj);
|
|
|
|
|
- if (!packer.end_unpack()) {
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- di.skip_bytes(packer.get_num_unpacked_bytes());
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Processes a big datagram that includes all of the "required" fields that
|
|
|
|
|
- * are sent along with a normal "generate with required" message. This is all
|
|
|
|
|
- * of the atomic fields that are marked "broadcast ownrecv". Should be used
|
|
|
|
|
- * for 'owner-view' objects.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-receive_update_broadcast_required_owner(PyObject *distobj,
|
|
|
|
|
- DatagramIterator &di) const {
|
|
|
|
|
-#ifdef WITHIN_PANDA
|
|
|
|
|
- PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
|
|
|
|
|
-#endif
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
- const char *data = (const char *)di.get_datagram().get_data();
|
|
|
|
|
- packer.set_unpack_data(data + di.get_current_index(),
|
|
|
|
|
- di.get_remaining_size(), false);
|
|
|
|
|
-
|
|
|
|
|
- int num_fields = get_num_inherited_fields();
|
|
|
|
|
- for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
|
|
|
|
|
- DCField *field = get_inherited_field(i);
|
|
|
|
|
- if (field->as_molecular_field() == nullptr &&
|
|
|
|
|
- field->is_required() && (field->is_ownrecv() || field->is_broadcast())) {
|
|
|
|
|
- packer.begin_unpack(field);
|
|
|
|
|
- field->receive_update(packer, distobj);
|
|
|
|
|
- if (!packer.end_unpack()) {
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- di.skip_bytes(packer.get_num_unpacked_bytes());
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Processes a big datagram that includes all of the "required" fields that
|
|
|
|
|
- * are sent when an avatar is created. This is all of the atomic fields that
|
|
|
|
|
- * are marked "required", whether they are broadcast or not.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-receive_update_all_required(PyObject *distobj, DatagramIterator &di) const {
|
|
|
|
|
-#ifdef WITHIN_PANDA
|
|
|
|
|
- PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
|
|
|
|
|
-#endif
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
- const char *data = (const char *)di.get_datagram().get_data();
|
|
|
|
|
- packer.set_unpack_data(data + di.get_current_index(),
|
|
|
|
|
- di.get_remaining_size(), false);
|
|
|
|
|
-
|
|
|
|
|
- int num_fields = get_num_inherited_fields();
|
|
|
|
|
- for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
|
|
|
|
|
- DCField *field = get_inherited_field(i);
|
|
|
|
|
- if (field->as_molecular_field() == nullptr &&
|
|
|
|
|
- field->is_required()) {
|
|
|
|
|
- packer.begin_unpack(field);
|
|
|
|
|
- field->receive_update(packer, distobj);
|
|
|
|
|
- if (!packer.end_unpack()) {
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- di.skip_bytes(packer.get_num_unpacked_bytes());
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Processes a datagram that lists some additional fields that are broadcast
|
|
|
|
|
- * in one chunk.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-receive_update_other(PyObject *distobj, DatagramIterator &di) const {
|
|
|
|
|
-#ifdef WITHIN_PANDA
|
|
|
|
|
- PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
|
|
|
|
|
-#endif
|
|
|
|
|
- int num_fields = di.get_uint16();
|
|
|
|
|
- for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
|
|
|
|
|
- receive_update(distobj, di);
|
|
|
|
|
- }
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Processes an update for a named field from a packed value blob.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-direct_update(PyObject *distobj, const string &field_name,
|
|
|
|
|
- const vector_uchar &value_blob) {
|
|
|
|
|
- DCField *field = get_field_by_name(field_name);
|
|
|
|
|
- nassertv_always(field != nullptr);
|
|
|
|
|
-
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
- packer.set_unpack_data(value_blob);
|
|
|
|
|
- packer.begin_unpack(field);
|
|
|
|
|
- field->receive_update(packer, distobj);
|
|
|
|
|
- packer.end_unpack();
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Processes an update for a named field from a packed datagram.
|
|
|
|
|
- */
|
|
|
|
|
-void DCClass::
|
|
|
|
|
-direct_update(PyObject *distobj, const string &field_name,
|
|
|
|
|
- const Datagram &datagram) {
|
|
|
|
|
- DCField *field = get_field_by_name(field_name);
|
|
|
|
|
- nassertv_always(field != nullptr);
|
|
|
|
|
-
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
- packer.set_unpack_data((const char *)datagram.get_data(), datagram.get_length(), false);
|
|
|
|
|
- packer.begin_unpack(field);
|
|
|
|
|
- field->receive_update(packer, distobj);
|
|
|
|
|
- packer.end_unpack();
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Looks up the current value of the indicated field by calling the
|
|
|
|
|
- * appropriate get*() function, then packs that value into the datagram. This
|
|
|
|
|
- * field is presumably either a required field or a specified optional field,
|
|
|
|
|
- * and we are building up a datagram for the generate-with-required message.
|
|
|
|
|
- *
|
|
|
|
|
- * Returns true on success, false on failure.
|
|
|
|
|
- */
|
|
|
|
|
-bool DCClass::
|
|
|
|
|
-pack_required_field(Datagram &datagram, PyObject *distobj,
|
|
|
|
|
- const DCField *field) const {
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
- packer.begin_pack(field);
|
|
|
|
|
- if (!pack_required_field(packer, distobj, field)) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- if (!packer.end_pack()) {
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- datagram.append_data(packer.get_data(), packer.get_length());
|
|
|
|
|
- return true;
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Looks up the current value of the indicated field by calling the
|
|
|
|
|
- * appropriate get*() function, then packs that value into the packer. This
|
|
|
|
|
- * field is presumably either a required field or a specified optional field,
|
|
|
|
|
- * and we are building up a datagram for the generate-with-required message.
|
|
|
|
|
- *
|
|
|
|
|
- * Returns true on success, false on failure.
|
|
|
|
|
- */
|
|
|
|
|
-bool DCClass::
|
|
|
|
|
-pack_required_field(DCPacker &packer, PyObject *distobj,
|
|
|
|
|
- const DCField *field) const {
|
|
|
|
|
- const DCParameter *parameter = field->as_parameter();
|
|
|
|
|
- if (parameter != nullptr) {
|
|
|
|
|
- // This is the easy case: to pack a parameter, we just look on the class
|
|
|
|
|
- // object for the data element.
|
|
|
|
|
- string field_name = field->get_name();
|
|
|
|
|
-
|
|
|
|
|
- if (!PyObject_HasAttrString(distobj, (char *)field_name.c_str())) {
|
|
|
|
|
- // If the attribute is not defined, but the field has a default value
|
|
|
|
|
- // specified, quietly pack the default value.
|
|
|
|
|
- if (field->has_default_value()) {
|
|
|
|
|
- packer.pack_default_value();
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // If there is no default value specified, it's an error.
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "Data element " << field_name
|
|
|
|
|
- << ", required by dc file for dclass " << get_name()
|
|
|
|
|
- << ", not defined on object";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- PyObject *result =
|
|
|
|
|
- PyObject_GetAttrString(distobj, (char *)field_name.c_str());
|
|
|
|
|
- nassertr(result != nullptr, false);
|
|
|
|
|
-
|
|
|
|
|
- // Now pack the value into the datagram.
|
|
|
|
|
- bool pack_ok = parameter->pack_args(packer, result);
|
|
|
|
|
- Py_DECREF(result);
|
|
|
|
|
-
|
|
|
|
|
- return pack_ok;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (field->as_molecular_field() != nullptr) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "Cannot pack molecular field " << field->get_name()
|
|
|
|
|
- << " for generate";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- const DCAtomicField *atom = field->as_atomic_field();
|
|
|
|
|
- nassertr(atom != nullptr, false);
|
|
|
|
|
-
|
|
|
|
|
- // We need to get the initial value of this field. There isn't a good,
|
|
|
|
|
- // robust way to get this; presently, we just mangle the "setFoo()" name of
|
|
|
|
|
- // the required field into "getFoo()" and call that.
|
|
|
|
|
- string setter_name = atom->get_name();
|
|
|
|
|
-
|
|
|
|
|
- if (setter_name.empty()) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "Required field is unnamed!";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (atom->get_num_elements() == 0) {
|
|
|
|
|
- // It sure doesn't make sense to have a required field with no parameters.
|
|
|
|
|
- // What data, exactly, is required?
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "Required field " << setter_name << " has no parameters!";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- string getter_name = setter_name;
|
|
|
|
|
- if (setter_name.substr(0, 3) == "set") {
|
|
|
|
|
- // If the original method started with "set", we mangle this directly to
|
|
|
|
|
- // "get".
|
|
|
|
|
- getter_name[0] = 'g';
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // Otherwise, we add a "get" prefix, and capitalize the next letter.
|
|
|
|
|
- getter_name = "get" + setter_name;
|
|
|
|
|
- getter_name[3] = toupper(getter_name[3]);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Now we have to look up the getter on the distributed object and call it.
|
|
|
|
|
- if (!PyObject_HasAttrString(distobj, (char *)getter_name.c_str())) {
|
|
|
|
|
- // As above, if there's no getter but the field has a default value
|
|
|
|
|
- // specified, quietly pack the default value.
|
|
|
|
|
- if (field->has_default_value()) {
|
|
|
|
|
- packer.pack_default_value();
|
|
|
|
|
- return true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Otherwise, with no default value it's an error.
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "Distributed class " << get_name()
|
|
|
|
|
- << " doesn't have getter named " << getter_name
|
|
|
|
|
- << " to match required field " << setter_name;
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- PyObject *func =
|
|
|
|
|
- PyObject_GetAttrString(distobj, (char *)getter_name.c_str());
|
|
|
|
|
- nassertr(func != nullptr, false);
|
|
|
|
|
-
|
|
|
|
|
- PyObject *empty_args = PyTuple_New(0);
|
|
|
|
|
- PyObject *result = PyObject_CallObject(func, empty_args);
|
|
|
|
|
- Py_DECREF(empty_args);
|
|
|
|
|
- Py_DECREF(func);
|
|
|
|
|
- if (result == nullptr) {
|
|
|
|
|
- // We don't set this as an exception, since presumably the Python method
|
|
|
|
|
- // itself has already triggered a Python exception.
|
|
|
|
|
- std::cerr << "Error when calling " << getter_name << "\n";
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (atom->get_num_elements() == 1) {
|
|
|
|
|
- // In this case, we expect the getter to return one object, which we wrap
|
|
|
|
|
- // up in a tuple.
|
|
|
|
|
- PyObject *tuple = PyTuple_New(1);
|
|
|
|
|
- PyTuple_SET_ITEM(tuple, 0, result);
|
|
|
|
|
- result = tuple;
|
|
|
|
|
-
|
|
|
|
|
- } else {
|
|
|
|
|
- // Otherwise, it had better already be a sequence or tuple of some sort.
|
|
|
|
|
- if (!PySequence_Check(result)) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "Since dclass " << get_name() << " method " << setter_name
|
|
|
|
|
- << " is declared to have multiple parameters, Python function "
|
|
|
|
|
- << getter_name << " must return a list or tuple.\n";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Now pack the arguments into the datagram.
|
|
|
|
|
- bool pack_ok = atom->pack_args(packer, result);
|
|
|
|
|
- Py_DECREF(result);
|
|
|
|
|
-
|
|
|
|
|
- return pack_ok;
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Generates a datagram containing the message necessary to send an update for
|
|
|
|
|
- * the indicated distributed object from the client.
|
|
|
|
|
- */
|
|
|
|
|
-Datagram DCClass::
|
|
|
|
|
-client_format_update(const string &field_name, DOID_TYPE do_id,
|
|
|
|
|
- PyObject *args) const {
|
|
|
|
|
- DCField *field = get_field_by_name(field_name);
|
|
|
|
|
- if (field == nullptr) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "No field named " << field_name << " in class " << get_name()
|
|
|
|
|
- << "\n";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return field->client_format_update(do_id, args);
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Generates a datagram containing the message necessary to send an update for
|
|
|
|
|
- * the indicated distributed object from the AI.
|
|
|
|
|
- */
|
|
|
|
|
-Datagram DCClass::
|
|
|
|
|
-ai_format_update(const string &field_name, DOID_TYPE do_id,
|
|
|
|
|
- CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, PyObject *args) const {
|
|
|
|
|
- DCField *field = get_field_by_name(field_name);
|
|
|
|
|
- if (field == nullptr) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "No field named " << field_name << " in class " << get_name()
|
|
|
|
|
- << "\n";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return field->ai_format_update(do_id, to_id, from_id, args);
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Generates a datagram containing the message necessary to send an update,
|
|
|
|
|
- * using the indicated msg type for the indicated distributed object from the
|
|
|
|
|
- * AI.
|
|
|
|
|
- */
|
|
|
|
|
-Datagram DCClass::
|
|
|
|
|
-ai_format_update_msg_type(const string &field_name, DOID_TYPE do_id,
|
|
|
|
|
- CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, int msg_type, PyObject *args) const {
|
|
|
|
|
- DCField *field = get_field_by_name(field_name);
|
|
|
|
|
- if (field == nullptr) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "No field named " << field_name << " in class " << get_name()
|
|
|
|
|
- << "\n";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return field->ai_format_update_msg_type(do_id, to_id, from_id, msg_type, args);
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Generates a datagram containing the message necessary to generate a new
|
|
|
|
|
- * distributed object from the client. This requires querying the object for
|
|
|
|
|
- * the initial value of its required fields.
|
|
|
|
|
- *
|
|
|
|
|
- * optional_fields is a list of fieldNames to generate in addition to the
|
|
|
|
|
- * normal required fields.
|
|
|
|
|
- *
|
|
|
|
|
- * This method is only called by the CMU implementation.
|
|
|
|
|
- */
|
|
|
|
|
-Datagram DCClass::
|
|
|
|
|
-client_format_generate_CMU(PyObject *distobj, DOID_TYPE do_id,
|
|
|
|
|
- ZONEID_TYPE zone_id,
|
|
|
|
|
- PyObject *optional_fields) const {
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
-
|
|
|
|
|
- packer.raw_pack_uint16(CLIENT_OBJECT_GENERATE_CMU);
|
|
|
|
|
-
|
|
|
|
|
- packer.raw_pack_uint32(zone_id);
|
|
|
|
|
- packer.raw_pack_uint16(_number);
|
|
|
|
|
- packer.raw_pack_uint32(do_id);
|
|
|
|
|
-
|
|
|
|
|
- // Specify all of the required fields.
|
|
|
|
|
- int num_fields = get_num_inherited_fields();
|
|
|
|
|
- for (int i = 0; i < num_fields; ++i) {
|
|
|
|
|
- DCField *field = get_inherited_field(i);
|
|
|
|
|
- if (field->is_required() && field->as_molecular_field() == nullptr) {
|
|
|
|
|
- packer.begin_pack(field);
|
|
|
|
|
- if (!pack_required_field(packer, distobj, field)) {
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
- packer.end_pack();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Also specify the optional fields.
|
|
|
|
|
- int num_optional_fields = 0;
|
|
|
|
|
- if (PyObject_IsTrue(optional_fields)) {
|
|
|
|
|
- num_optional_fields = PySequence_Size(optional_fields);
|
|
|
|
|
- }
|
|
|
|
|
- packer.raw_pack_uint16(num_optional_fields);
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < num_optional_fields; i++) {
|
|
|
|
|
- PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
|
|
|
|
|
-#if PY_MAJOR_VERSION >= 3
|
|
|
|
|
- string field_name = PyUnicode_AsUTF8(py_field_name);
|
|
|
|
|
-#else
|
|
|
|
|
- string field_name = PyString_AsString(py_field_name);
|
|
|
|
|
-#endif
|
|
|
|
|
- Py_XDECREF(py_field_name);
|
|
|
|
|
-
|
|
|
|
|
- DCField *field = get_field_by_name(field_name);
|
|
|
|
|
- if (field == nullptr) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "No field named " << field_name << " in class " << get_name()
|
|
|
|
|
- << "\n";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
- packer.raw_pack_uint16(field->get_number());
|
|
|
|
|
- packer.begin_pack(field);
|
|
|
|
|
- if (!pack_required_field(packer, distobj, field)) {
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
- packer.end_pack();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return Datagram(packer.get_data(), packer.get_length());
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
-#ifdef HAVE_PYTHON
|
|
|
|
|
-/**
|
|
|
|
|
- * Generates a datagram containing the message necessary to generate a new
|
|
|
|
|
- * distributed object from the AI. This requires querying the object for the
|
|
|
|
|
- * initial value of its required fields.
|
|
|
|
|
- *
|
|
|
|
|
- * optional_fields is a list of fieldNames to generate in addition to the
|
|
|
|
|
- * normal required fields.
|
|
|
|
|
- */
|
|
|
|
|
-Datagram DCClass::
|
|
|
|
|
-ai_format_generate(PyObject *distobj, DOID_TYPE do_id,
|
|
|
|
|
- DOID_TYPE parent_id, ZONEID_TYPE zone_id,
|
|
|
|
|
- CHANNEL_TYPE district_channel_id, CHANNEL_TYPE from_channel_id,
|
|
|
|
|
- PyObject *optional_fields) const {
|
|
|
|
|
- DCPacker packer;
|
|
|
|
|
-
|
|
|
|
|
- packer.raw_pack_uint8(1);
|
|
|
|
|
- packer.RAW_PACK_CHANNEL(district_channel_id);
|
|
|
|
|
- packer.RAW_PACK_CHANNEL(from_channel_id);
|
|
|
|
|
- // packer.raw_pack_uint8('A');
|
|
|
|
|
-
|
|
|
|
|
- bool has_optional_fields = (PyObject_IsTrue(optional_fields) != 0);
|
|
|
|
|
-
|
|
|
|
|
- if (has_optional_fields) {
|
|
|
|
|
- packer.raw_pack_uint16(STATESERVER_CREATE_OBJECT_WITH_REQUIRED_OTHER);
|
|
|
|
|
- } else {
|
|
|
|
|
- packer.raw_pack_uint16(STATESERVER_CREATE_OBJECT_WITH_REQUIRED);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- packer.raw_pack_uint32(do_id);
|
|
|
|
|
- // Parent is a bit overloaded; this parent is not about inheritance, this
|
|
|
|
|
- // one is about the visibility container parent, i.e. the zone parent:
|
|
|
|
|
- packer.raw_pack_uint32(parent_id);
|
|
|
|
|
- packer.raw_pack_uint32(zone_id);
|
|
|
|
|
- packer.raw_pack_uint16(_number);
|
|
|
|
|
-
|
|
|
|
|
- // Specify all of the required fields.
|
|
|
|
|
- int num_fields = get_num_inherited_fields();
|
|
|
|
|
- for (int i = 0; i < num_fields; ++i) {
|
|
|
|
|
- DCField *field = get_inherited_field(i);
|
|
|
|
|
- if (field->is_required() && field->as_molecular_field() == nullptr) {
|
|
|
|
|
- packer.begin_pack(field);
|
|
|
|
|
- if (!pack_required_field(packer, distobj, field)) {
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
- packer.end_pack();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- // Also specify the optional fields.
|
|
|
|
|
- if (has_optional_fields) {
|
|
|
|
|
- int num_optional_fields = PySequence_Size(optional_fields);
|
|
|
|
|
- packer.raw_pack_uint16(num_optional_fields);
|
|
|
|
|
-
|
|
|
|
|
- for (int i = 0; i < num_optional_fields; ++i) {
|
|
|
|
|
- PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
|
|
|
|
|
-#if PY_MAJOR_VERSION >= 3
|
|
|
|
|
- string field_name = PyUnicode_AsUTF8(py_field_name);
|
|
|
|
|
-#else
|
|
|
|
|
- string field_name = PyString_AsString(py_field_name);
|
|
|
|
|
-#endif
|
|
|
|
|
- Py_XDECREF(py_field_name);
|
|
|
|
|
-
|
|
|
|
|
- DCField *field = get_field_by_name(field_name);
|
|
|
|
|
- if (field == nullptr) {
|
|
|
|
|
- ostringstream strm;
|
|
|
|
|
- strm << "No field named " << field_name << " in class " << get_name()
|
|
|
|
|
- << "\n";
|
|
|
|
|
- nassert_raise(strm.str());
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- packer.raw_pack_uint16(field->get_number());
|
|
|
|
|
-
|
|
|
|
|
- packer.begin_pack(field);
|
|
|
|
|
- if (!pack_required_field(packer, distobj, field)) {
|
|
|
|
|
- return Datagram();
|
|
|
|
|
- }
|
|
|
|
|
- packer.end_pack();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return Datagram(packer.get_data(), packer.get_length());
|
|
|
|
|
-}
|
|
|
|
|
-#endif // HAVE_PYTHON
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* Write a string representation of this instance to <out>.
|
|
* Write a string representation of this instance to <out>.
|
|
|
*/
|
|
*/
|
|
|
void DCClass::
|
|
void DCClass::
|
|
|
-output(ostream &out, bool brief) const {
|
|
|
|
|
|
|
+output(std::ostream &out, bool brief) const {
|
|
|
output_instance(out, brief, "", "", "");
|
|
output_instance(out, brief, "", "", "");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -1029,7 +342,7 @@ output(ostream &out, bool brief) const {
|
|
|
* stream.
|
|
* stream.
|
|
|
*/
|
|
*/
|
|
|
void DCClass::
|
|
void DCClass::
|
|
|
-write(ostream &out, bool brief, int indent_level) const {
|
|
|
|
|
|
|
+write(std::ostream &out, bool brief, int indent_level) const {
|
|
|
indent(out, indent_level);
|
|
indent(out, indent_level);
|
|
|
if (_is_struct) {
|
|
if (_is_struct) {
|
|
|
out << "struct";
|
|
out << "struct";
|
|
@@ -1089,7 +402,7 @@ write(ostream &out, bool brief, int indent_level) const {
|
|
|
* stream.
|
|
* stream.
|
|
|
*/
|
|
*/
|
|
|
void DCClass::
|
|
void DCClass::
|
|
|
-output_instance(ostream &out, bool brief, const string &prename,
|
|
|
|
|
|
|
+output_instance(std::ostream &out, bool brief, const string &prename,
|
|
|
const string &name, const string &postname) const {
|
|
const string &name, const string &postname) const {
|
|
|
if (_is_struct) {
|
|
if (_is_struct) {
|
|
|
out << "struct";
|
|
out << "struct";
|