Panda3D
dcClass.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file dcClass.cxx
10  * @author drose
11  * @date 2000-10-05
12  */
13 
14 #include "dcClass.h"
15 #include "dcFile.h"
16 #include "dcAtomicField.h"
17 #include "hashGenerator.h"
18 #include "dcindent.h"
19 #include "dcmsgtypes.h"
20 
21 #include "dcClassParameter.h"
22 #include <algorithm>
23 
24 #ifdef HAVE_PYTHON
25 #include "py_panda.h"
26 #endif
27 
28 using std::ostream;
29 using std::ostringstream;
30 using std::string;
31 
32 #ifdef WITHIN_PANDA
33 #include "pStatTimer.h"
34 
35 #ifndef CPPPARSER
36 PStatCollector DCClass::_update_pcollector("App:Show code:readerPollTask:Update");
37 PStatCollector DCClass::_generate_pcollector("App:Show code:readerPollTask:Generate");
38 #endif // CPPPARSER
39 
40 ConfigVariableBool dc_multiple_inheritance
41 ("dc-multiple-inheritance", true,
42  PRC_DESC("Set this true to support multiple inheritance in the dc file. "
43  "If this is false, the old way, multiple inheritance is not "
44  "supported, but field numbers will be numbered sequentially, "
45  "which may be required to support old code that assumed this."));
46 
47 ConfigVariableBool dc_virtual_inheritance
48 ("dc-virtual-inheritance", true,
49  PRC_DESC("Set this true to support proper virtual inheritance in the "
50  "dc file, so that diamond-of-death type constructs can be used. "
51  "This also enables shadowing (overloading) of inherited method "
52  "names from a base class."));
53 
54 ConfigVariableBool dc_sort_inheritance_by_file
55 ("dc-sort-inheritance-by-file", true,
56  PRC_DESC("This is a temporary hack. This should be true if you are using "
57  "version 1.42 of the otp_server.exe binary, which sorted inherited "
58  "fields based on the order of the classes within the DC file, "
59  "rather than based on the order in which the references are made "
60  "within the class."));
61 
62 
63 #endif // WITHIN_PANDA
64 
65 class SortFieldsByIndex {
66 public:
67  inline bool operator ()(const DCField *a, const DCField *b) const {
68  return a->get_number() < b->get_number();
69  }
70 };
71 
72 /**
73  *
74  */
75 DCClass::
76 DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) :
77 #ifdef WITHIN_PANDA
78  _class_update_pcollector(_update_pcollector, name),
79  _class_generate_pcollector(_generate_pcollector, name),
80 #endif
81  _dc_file(dc_file),
82  _name(name),
83  _is_struct(is_struct),
84  _bogus_class(bogus_class)
85 {
86  _number = -1;
87  _constructor = nullptr;
88 
89 #ifdef HAVE_PYTHON
90  _class_def = nullptr;
91  _owner_class_def = nullptr;
92 #endif
93 }
94 
95 /**
96  *
97  */
98 DCClass::
99 ~DCClass() {
100  if (_constructor != nullptr) {
101  delete _constructor;
102  }
103 
104  Fields::iterator fi;
105  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
106  delete (*fi);
107  }
108 
109 #ifdef HAVE_PYTHON
110  Py_XDECREF(_class_def);
111  Py_XDECREF(_owner_class_def);
112 #endif
113 }
114 
115 /**
116  *
117  */
118 DCClass *DCClass::
119 as_class() {
120  return this;
121 }
122 
123 /**
124  *
125  */
126 const DCClass *DCClass::
127 as_class() const {
128  return this;
129 }
130 
131 /**
132  * Returns the number of base classes this class inherits from.
133  */
134 int DCClass::
136  return _parents.size();
137 }
138 
139 /**
140  * Returns the nth parent class this class inherits from.
141  */
143 get_parent(int n) const {
144  nassertr(n >= 0 && n < (int)_parents.size(), nullptr);
145  return _parents[n];
146 }
147 
148 /**
149  * Returns true if this class has a constructor method, false if it just uses
150  * the default constructor.
151  */
152 bool DCClass::
154  return (_constructor != nullptr);
155 }
156 
157 /**
158  * Returns the constructor method for this class if it is defined, or NULL if
159  * the class uses the default constructor.
160  */
163  return _constructor;
164 }
165 
166 /**
167  * Returns the number of fields defined directly in this class, ignoring
168  * inheritance.
169  */
170 int DCClass::
171 get_num_fields() const {
172  return _fields.size();
173 }
174 
175 /**
176  * Returns the nth field in the class. This is not necessarily the field with
177  * index n; this is the nth field defined in the class directly, ignoring
178  * inheritance.
179  */
181 get_field(int n) const {
182  #ifndef NDEBUG //[
183  if (n < 0 || n >= (int)_fields.size()) {
184  std::cerr << *this << " "
185  << "n:" << n << " _fields.size():"
186  << (int)_fields.size() << std::endl;
187  // __asm { int 3 }
188  }
189  #endif //]
190  nassertr_always(n >= 0 && n < (int)_fields.size(), nullptr);
191  return _fields[n];
192 }
193 
194 /**
195  * Returns a pointer to the DCField that shares the indicated name. If the
196  * named field is not found in the current class, the parent classes will be
197  * searched, so the value returned may not actually be a field within this
198  * class. Returns NULL if there is no such field defined.
199  */
201 get_field_by_name(const string &name) const {
202  FieldsByName::const_iterator ni;
203  ni = _fields_by_name.find(name);
204  if (ni != _fields_by_name.end()) {
205  return (*ni).second;
206  }
207 
208  // We didn't have such a field, so check our parents.
209  Parents::const_iterator pi;
210  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
211  DCField *result = (*pi)->get_field_by_name(name);
212  if (result != nullptr) {
213  return result;
214  }
215  }
216 
217  // Nobody knew what this field is.
218  return nullptr;
219 }
220 
221 /**
222  * Returns a pointer to the DCField that has the indicated index number. If
223  * the numbered field is not found in the current class, the parent classes
224  * will be searched, so the value returned may not actually be a field within
225  * this class. Returns NULL if there is no such field defined.
226  */
228 get_field_by_index(int index_number) const {
229  FieldsByIndex::const_iterator ni;
230  ni = _fields_by_index.find(index_number);
231  if (ni != _fields_by_index.end()) {
232  return (*ni).second;
233  }
234 
235  // We didn't have such a field, so check our parents.
236  Parents::const_iterator pi;
237  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
238  DCField *result = (*pi)->get_field_by_index(index_number);
239  if (result != nullptr) {
240  // Cache this result for future lookups.
241  ((DCClass *)this)->_fields_by_index[index_number] = result;
242  return result;
243  }
244  }
245 
246  // Nobody knew what this field is.
247  return nullptr;
248 }
249 
250 /**
251  * Returns the total number of field fields defined in this class and all
252  * ancestor classes.
253  */
254 int DCClass::
256  if (dc_multiple_inheritance && dc_virtual_inheritance &&
257  _dc_file != nullptr) {
258  _dc_file->check_inherited_fields();
259  if (_inherited_fields.empty()) {
260  ((DCClass *)this)->rebuild_inherited_fields();
261  }
262 
263  // This assertion causes trouble when we are only parsing an incomplete DC
264  // file. nassertr(is_bogus_class() || !_inherited_fields.empty(), 0);
265  return (int)_inherited_fields.size();
266 
267  } else {
268  int num_fields = get_num_fields();
269 
270  Parents::const_iterator pi;
271  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
272  num_fields += (*pi)->get_num_inherited_fields();
273  }
274 
275  return num_fields;
276  }
277 }
278 
279 /**
280  * Returns the nth field field in the class and all of its ancestors.
281  *
282  * This *used* to be the same thing as get_field_by_index(), back when the
283  * fields were numbered sequentially within a class's inheritance hierarchy.
284  * Now that fields have a globally unique index number, this is no longer
285  * true.
286  */
288 get_inherited_field(int n) const {
289  if (dc_multiple_inheritance && dc_virtual_inheritance &&
290  _dc_file != nullptr) {
291  _dc_file->check_inherited_fields();
292  if (_inherited_fields.empty()) {
293  ((DCClass *)this)->rebuild_inherited_fields();
294  }
295  nassertr(n >= 0 && n < (int)_inherited_fields.size(), nullptr);
296  return _inherited_fields[n];
297 
298  } else {
299  Parents::const_iterator pi;
300  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
301  int psize = (*pi)->get_num_inherited_fields();
302  if (n < psize) {
303  return (*pi)->get_inherited_field(n);
304  }
305 
306  n -= psize;
307  }
308 
309  return get_field(n);
310  }
311 }
312 
313 /**
314  * Returns true if this class, or any class in the inheritance heirarchy for
315  * this class, is a "bogus" class--a forward reference to an as-yet-undefined
316  * class.
317  */
318 bool DCClass::
320  if (is_bogus_class()) {
321  return true;
322  }
323 
324  Parents::const_iterator pi;
325  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
326  if ((*pi)->inherits_from_bogus_class()) {
327  return true;
328  }
329  }
330 
331  return false;
332 }
333 
334 /**
335  * Write a string representation of this instance to <out>.
336  */
337 void DCClass::
338 output(ostream &out) const {
339  if (_is_struct) {
340  out << "struct";
341  } else {
342  out << "dclass";
343  }
344  if (!_name.empty()) {
345  out << " " << _name;
346  }
347 }
348 
349 #ifdef HAVE_PYTHON
350 /**
351  * Returns true if the DCClass object has an associated Python class
352  * definition, false otherwise.
353  */
354 bool DCClass::
355 has_class_def() const {
356  return (_class_def != nullptr);
357 }
358 #endif // HAVE_PYTHON
359 
360 #ifdef HAVE_PYTHON
361 /**
362  * Sets the class object associated with this DistributedClass. This object
363  * will be used to construct new instances of the class.
364  */
365 void DCClass::
366 set_class_def(PyObject *class_def) {
367  Py_XINCREF(class_def);
368  Py_XDECREF(_class_def);
369  _class_def = class_def;
370 }
371 #endif // HAVE_PYTHON
372 
373 #ifdef HAVE_PYTHON
374 /**
375  * Returns the class object that was previously associated with this
376  * DistributedClass. This will return a new reference to the object.
377  */
378 PyObject *DCClass::
379 get_class_def() const {
380  if (_class_def == nullptr) {
381  Py_INCREF(Py_None);
382  return Py_None;
383  }
384 
385  Py_INCREF(_class_def);
386  return _class_def;
387 }
388 #endif // HAVE_PYTHON
389 
390 #ifdef HAVE_PYTHON
391 /**
392  * Returns true if the DCClass object has an associated Python owner class
393  * definition, false otherwise.
394  */
395 bool DCClass::
396 has_owner_class_def() const {
397  return (_owner_class_def != nullptr);
398 }
399 #endif // HAVE_PYTHON
400 
401 #ifdef HAVE_PYTHON
402 /**
403  * Sets the owner class object associated with this DistributedClass. This
404  * object will be used to construct new owner instances of the class.
405  */
406 void DCClass::
407 set_owner_class_def(PyObject *owner_class_def) {
408  Py_XINCREF(owner_class_def);
409  Py_XDECREF(_owner_class_def);
410  _owner_class_def = owner_class_def;
411 }
412 #endif // HAVE_PYTHON
413 
414 #ifdef HAVE_PYTHON
415 /**
416  * Returns the owner class object that was previously associated with this
417  * DistributedClass. This will return a new reference to the object.
418  */
419 PyObject *DCClass::
420 get_owner_class_def() const {
421  if (_owner_class_def == nullptr) {
422  Py_INCREF(Py_None);
423  return Py_None;
424  }
425 
426  Py_INCREF(_owner_class_def);
427  return _owner_class_def;
428 }
429 #endif // HAVE_PYTHON
430 
431 #ifdef HAVE_PYTHON
432 /**
433  * Extracts the update message out of the packer and applies it to the
434  * indicated object by calling the appropriate method.
435  */
436 void DCClass::
437 receive_update(PyObject *distobj, DatagramIterator &di) const {
438 #ifdef WITHIN_PANDA
439  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
440 #endif
441  DCPacker packer;
442  const char *data = (const char *)di.get_datagram().get_data();
443  packer.set_unpack_data(data + di.get_current_index(),
444  di.get_remaining_size(), false);
445 
446  int field_id = packer.raw_unpack_uint16();
447  DCField *field = get_field_by_index(field_id);
448  if (field == nullptr) {
449  ostringstream strm;
450  strm
451  << "Received update for field " << field_id << ", not in class "
452  << get_name();
453  nassert_raise(strm.str());
454  return;
455  }
456 
457  packer.begin_unpack(field);
458  field->receive_update(packer, distobj);
459  packer.end_unpack();
460 
461  di.skip_bytes(packer.get_num_unpacked_bytes());
462 
463 }
464 #endif // HAVE_PYTHON
465 
466 #ifdef HAVE_PYTHON
467 /**
468  * Processes a big datagram that includes all of the "required" fields that
469  * are sent along with a normal "generate with required" message. This is all
470  * of the atomic fields that are marked "broadcast required".
471  */
472 void DCClass::
473 receive_update_broadcast_required(PyObject *distobj, DatagramIterator &di) const {
474 #ifdef WITHIN_PANDA
475  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
476 #endif
477  DCPacker packer;
478  const char *data = (const char *)di.get_datagram().get_data();
479  packer.set_unpack_data(data + di.get_current_index(),
480  di.get_remaining_size(), false);
481 
482  int num_fields = get_num_inherited_fields();
483  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
484  DCField *field = get_inherited_field(i);
485  if (field->as_molecular_field() == nullptr &&
486  field->is_required() && field->is_broadcast()) {
487  packer.begin_unpack(field);
488  field->receive_update(packer, distobj);
489  if (!packer.end_unpack()) {
490  break;
491  }
492  }
493  }
494 
495  di.skip_bytes(packer.get_num_unpacked_bytes());
496 }
497 #endif // HAVE_PYTHON
498 
499 #ifdef HAVE_PYTHON
500 /**
501  * Processes a big datagram that includes all of the "required" fields that
502  * are sent along with a normal "generate with required" message. This is all
503  * of the atomic fields that are marked "broadcast ownrecv". Should be used
504  * for 'owner-view' objects.
505  */
506 void DCClass::
507 receive_update_broadcast_required_owner(PyObject *distobj,
508  DatagramIterator &di) const {
509 #ifdef WITHIN_PANDA
510  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
511 #endif
512  DCPacker packer;
513  const char *data = (const char *)di.get_datagram().get_data();
514  packer.set_unpack_data(data + di.get_current_index(),
515  di.get_remaining_size(), false);
516 
517  int num_fields = get_num_inherited_fields();
518  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
519  DCField *field = get_inherited_field(i);
520  if (field->as_molecular_field() == nullptr &&
521  field->is_required() && (field->is_ownrecv() || field->is_broadcast())) {
522  packer.begin_unpack(field);
523  field->receive_update(packer, distobj);
524  if (!packer.end_unpack()) {
525  break;
526  }
527  }
528  }
529 
530  di.skip_bytes(packer.get_num_unpacked_bytes());
531 }
532 #endif // HAVE_PYTHON
533 
534 #ifdef HAVE_PYTHON
535 /**
536  * Processes a big datagram that includes all of the "required" fields that
537  * are sent when an avatar is created. This is all of the atomic fields that
538  * are marked "required", whether they are broadcast or not.
539  */
540 void DCClass::
541 receive_update_all_required(PyObject *distobj, DatagramIterator &di) const {
542 #ifdef WITHIN_PANDA
543  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
544 #endif
545  DCPacker packer;
546  const char *data = (const char *)di.get_datagram().get_data();
547  packer.set_unpack_data(data + di.get_current_index(),
548  di.get_remaining_size(), false);
549 
550  int num_fields = get_num_inherited_fields();
551  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
552  DCField *field = get_inherited_field(i);
553  if (field->as_molecular_field() == nullptr &&
554  field->is_required()) {
555  packer.begin_unpack(field);
556  field->receive_update(packer, distobj);
557  if (!packer.end_unpack()) {
558  break;
559  }
560  }
561  }
562 
563  di.skip_bytes(packer.get_num_unpacked_bytes());
564 }
565 #endif // HAVE_PYTHON
566 
567 #ifdef HAVE_PYTHON
568 /**
569  * Processes a datagram that lists some additional fields that are broadcast
570  * in one chunk.
571  */
572 void DCClass::
573 receive_update_other(PyObject *distobj, DatagramIterator &di) const {
574 #ifdef WITHIN_PANDA
575  PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
576 #endif
577  int num_fields = di.get_uint16();
578  for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
579  receive_update(distobj, di);
580  }
581 }
582 #endif // HAVE_PYTHON
583 
584 #ifdef HAVE_PYTHON
585 /**
586  * Processes an update for a named field from a packed value blob.
587  */
588 void DCClass::
589 direct_update(PyObject *distobj, const string &field_name,
590  const vector_uchar &value_blob) {
591  DCField *field = get_field_by_name(field_name);
592  nassertv_always(field != nullptr);
593 
594  DCPacker packer;
595  packer.set_unpack_data(value_blob);
596  packer.begin_unpack(field);
597  field->receive_update(packer, distobj);
598  packer.end_unpack();
599 }
600 #endif // HAVE_PYTHON
601 
602 #ifdef HAVE_PYTHON
603 /**
604  * Processes an update for a named field from a packed datagram.
605  */
606 void DCClass::
607 direct_update(PyObject *distobj, const string &field_name,
608  const Datagram &datagram) {
609  DCField *field = get_field_by_name(field_name);
610  nassertv_always(field != nullptr);
611 
612  DCPacker packer;
613  packer.set_unpack_data((const char *)datagram.get_data(), datagram.get_length(), false);
614  packer.begin_unpack(field);
615  field->receive_update(packer, distobj);
616  packer.end_unpack();
617 }
618 #endif // HAVE_PYTHON
619 
620 #ifdef HAVE_PYTHON
621 /**
622  * Looks up the current value of the indicated field by calling the
623  * appropriate get*() function, then packs that value into the datagram. This
624  * field is presumably either a required field or a specified optional field,
625  * and we are building up a datagram for the generate-with-required message.
626  *
627  * Returns true on success, false on failure.
628  */
629 bool DCClass::
630 pack_required_field(Datagram &datagram, PyObject *distobj,
631  const DCField *field) const {
632  DCPacker packer;
633  packer.begin_pack(field);
634  if (!pack_required_field(packer, distobj, field)) {
635  return false;
636  }
637  if (!packer.end_pack()) {
638  return false;
639  }
640 
641  datagram.append_data(packer.get_data(), packer.get_length());
642  return true;
643 }
644 #endif // HAVE_PYTHON
645 
646 #ifdef HAVE_PYTHON
647 /**
648  * Looks up the current value of the indicated field by calling the
649  * appropriate get*() function, then packs that value into the packer. This
650  * field is presumably either a required field or a specified optional field,
651  * and we are building up a datagram for the generate-with-required message.
652  *
653  * Returns true on success, false on failure.
654  */
655 bool DCClass::
656 pack_required_field(DCPacker &packer, PyObject *distobj,
657  const DCField *field) const {
658  const DCParameter *parameter = field->as_parameter();
659  if (parameter != nullptr) {
660  // This is the easy case: to pack a parameter, we just look on the class
661  // object for the data element.
662  string field_name = field->get_name();
663 
664  if (!PyObject_HasAttrString(distobj, (char *)field_name.c_str())) {
665  // If the attribute is not defined, but the field has a default value
666  // specified, quietly pack the default value.
667  if (field->has_default_value()) {
668  packer.pack_default_value();
669  return true;
670  }
671 
672  // If there is no default value specified, it's an error.
673  ostringstream strm;
674  strm << "Data element " << field_name
675  << ", required by dc file for dclass " << get_name()
676  << ", not defined on object";
677  nassert_raise(strm.str());
678  return false;
679  }
680  PyObject *result =
681  PyObject_GetAttrString(distobj, (char *)field_name.c_str());
682  nassertr(result != nullptr, false);
683 
684  // Now pack the value into the datagram.
685  bool pack_ok = parameter->pack_args(packer, result);
686  Py_DECREF(result);
687 
688  return pack_ok;
689  }
690 
691  if (field->as_molecular_field() != nullptr) {
692  ostringstream strm;
693  strm << "Cannot pack molecular field " << field->get_name()
694  << " for generate";
695  nassert_raise(strm.str());
696  return false;
697  }
698 
699  const DCAtomicField *atom = field->as_atomic_field();
700  nassertr(atom != nullptr, false);
701 
702  // We need to get the initial value of this field. There isn't a good,
703  // robust way to get this; presently, we just mangle the "setFoo()" name of
704  // the required field into "getFoo()" and call that.
705  string setter_name = atom->get_name();
706 
707  if (setter_name.empty()) {
708  ostringstream strm;
709  strm << "Required field is unnamed!";
710  nassert_raise(strm.str());
711  return false;
712  }
713 
714  if (atom->get_num_elements() == 0) {
715  // It sure doesn't make sense to have a required field with no parameters.
716  // What data, exactly, is required?
717  ostringstream strm;
718  strm << "Required field " << setter_name << " has no parameters!";
719  nassert_raise(strm.str());
720  return false;
721  }
722 
723  string getter_name = setter_name;
724  if (setter_name.substr(0, 3) == "set") {
725  // If the original method started with "set", we mangle this directly to
726  // "get".
727  getter_name[0] = 'g';
728 
729  } else {
730  // Otherwise, we add a "get" prefix, and capitalize the next letter.
731  getter_name = "get" + setter_name;
732  getter_name[3] = toupper(getter_name[3]);
733  }
734 
735  // Now we have to look up the getter on the distributed object and call it.
736  if (!PyObject_HasAttrString(distobj, (char *)getter_name.c_str())) {
737  // As above, if there's no getter but the field has a default value
738  // specified, quietly pack the default value.
739  if (field->has_default_value()) {
740  packer.pack_default_value();
741  return true;
742  }
743 
744  // Otherwise, with no default value it's an error.
745  ostringstream strm;
746  strm << "Distributed class " << get_name()
747  << " doesn't have getter named " << getter_name
748  << " to match required field " << setter_name;
749  nassert_raise(strm.str());
750  return false;
751  }
752  PyObject *func =
753  PyObject_GetAttrString(distobj, (char *)getter_name.c_str());
754  nassertr(func != nullptr, false);
755 
756  PyObject *empty_args = PyTuple_New(0);
757  PyObject *result = PyObject_CallObject(func, empty_args);
758  Py_DECREF(empty_args);
759  Py_DECREF(func);
760  if (result == nullptr) {
761  // We don't set this as an exception, since presumably the Python method
762  // itself has already triggered a Python exception.
763  std::cerr << "Error when calling " << getter_name << "\n";
764  return false;
765  }
766 
767  if (atom->get_num_elements() == 1) {
768  // In this case, we expect the getter to return one object, which we wrap
769  // up in a tuple.
770  PyObject *tuple = PyTuple_New(1);
771  PyTuple_SET_ITEM(tuple, 0, result);
772  result = tuple;
773 
774  } else {
775  // Otherwise, it had better already be a sequence or tuple of some sort.
776  if (!PySequence_Check(result)) {
777  ostringstream strm;
778  strm << "Since dclass " << get_name() << " method " << setter_name
779  << " is declared to have multiple parameters, Python function "
780  << getter_name << " must return a list or tuple.\n";
781  nassert_raise(strm.str());
782  return false;
783  }
784  }
785 
786  // Now pack the arguments into the datagram.
787  bool pack_ok = atom->pack_args(packer, result);
788  Py_DECREF(result);
789 
790  return pack_ok;
791 }
792 #endif // HAVE_PYTHON
793 
794 #ifdef HAVE_PYTHON
795 /**
796  * Generates a datagram containing the message necessary to send an update for
797  * the indicated distributed object from the client.
798  */
799 Datagram DCClass::
800 client_format_update(const string &field_name, DOID_TYPE do_id,
801  PyObject *args) const {
802  DCField *field = get_field_by_name(field_name);
803  if (field == nullptr) {
804  ostringstream strm;
805  strm << "No field named " << field_name << " in class " << get_name()
806  << "\n";
807  nassert_raise(strm.str());
808  return Datagram();
809  }
810 
811  return field->client_format_update(do_id, args);
812 }
813 #endif // HAVE_PYTHON
814 
815 #ifdef HAVE_PYTHON
816 /**
817  * Generates a datagram containing the message necessary to send an update for
818  * the indicated distributed object from the AI.
819  */
820 Datagram DCClass::
821 ai_format_update(const string &field_name, DOID_TYPE do_id,
822  CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, PyObject *args) const {
823  DCField *field = get_field_by_name(field_name);
824  if (field == nullptr) {
825  ostringstream strm;
826  strm << "No field named " << field_name << " in class " << get_name()
827  << "\n";
828  nassert_raise(strm.str());
829  return Datagram();
830  }
831 
832  return field->ai_format_update(do_id, to_id, from_id, args);
833 }
834 #endif // HAVE_PYTHON
835 
836 #ifdef HAVE_PYTHON
837 /**
838  * Generates a datagram containing the message necessary to send an update,
839  * using the indicated msg type for the indicated distributed object from the
840  * AI.
841  */
842 Datagram DCClass::
843 ai_format_update_msg_type(const string &field_name, DOID_TYPE do_id,
844  CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, int msg_type, PyObject *args) const {
845  DCField *field = get_field_by_name(field_name);
846  if (field == nullptr) {
847  ostringstream strm;
848  strm << "No field named " << field_name << " in class " << get_name()
849  << "\n";
850  nassert_raise(strm.str());
851  return Datagram();
852  }
853 
854  return field->ai_format_update_msg_type(do_id, to_id, from_id, msg_type, args);
855 }
856 #endif // HAVE_PYTHON
857 
858 #ifdef HAVE_PYTHON
859 /**
860  * Generates a datagram containing the message necessary to generate a new
861  * distributed object from the client. This requires querying the object for
862  * the initial value of its required fields.
863  *
864  * optional_fields is a list of fieldNames to generate in addition to the
865  * normal required fields.
866  *
867  * This method is only called by the CMU implementation.
868  */
869 Datagram DCClass::
870 client_format_generate_CMU(PyObject *distobj, DOID_TYPE do_id,
871  ZONEID_TYPE zone_id,
872  PyObject *optional_fields) const {
873  DCPacker packer;
874 
875  packer.raw_pack_uint16(CLIENT_OBJECT_GENERATE_CMU);
876 
877  packer.raw_pack_uint32(zone_id);
878  packer.raw_pack_uint16(_number);
879  packer.raw_pack_uint32(do_id);
880 
881  // Specify all of the required fields.
882  int num_fields = get_num_inherited_fields();
883  for (int i = 0; i < num_fields; ++i) {
884  DCField *field = get_inherited_field(i);
885  if (field->is_required() && field->as_molecular_field() == nullptr) {
886  packer.begin_pack(field);
887  if (!pack_required_field(packer, distobj, field)) {
888  return Datagram();
889  }
890  packer.end_pack();
891  }
892  }
893 
894  // Also specify the optional fields.
895  int num_optional_fields = 0;
896  if (PyObject_IsTrue(optional_fields)) {
897  num_optional_fields = PySequence_Size(optional_fields);
898  }
899  packer.raw_pack_uint16(num_optional_fields);
900 
901  for (int i = 0; i < num_optional_fields; i++) {
902  PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
903 #if PY_MAJOR_VERSION >= 3
904  string field_name = PyUnicode_AsUTF8(py_field_name);
905 #else
906  string field_name = PyString_AsString(py_field_name);
907 #endif
908  Py_XDECREF(py_field_name);
909 
910  DCField *field = get_field_by_name(field_name);
911  if (field == nullptr) {
912  ostringstream strm;
913  strm << "No field named " << field_name << " in class " << get_name()
914  << "\n";
915  nassert_raise(strm.str());
916  return Datagram();
917  }
918  packer.raw_pack_uint16(field->get_number());
919  packer.begin_pack(field);
920  if (!pack_required_field(packer, distobj, field)) {
921  return Datagram();
922  }
923  packer.end_pack();
924  }
925 
926  return Datagram(packer.get_data(), packer.get_length());
927 }
928 #endif // HAVE_PYTHON
929 
930 #ifdef HAVE_PYTHON
931 /**
932  * Generates a datagram containing the message necessary to generate a new
933  * distributed object from the AI. This requires querying the object for the
934  * initial value of its required fields.
935  *
936  * optional_fields is a list of fieldNames to generate in addition to the
937  * normal required fields.
938  */
939 Datagram DCClass::
940 ai_format_generate(PyObject *distobj, DOID_TYPE do_id,
941  DOID_TYPE parent_id, ZONEID_TYPE zone_id,
942  CHANNEL_TYPE district_channel_id, CHANNEL_TYPE from_channel_id,
943  PyObject *optional_fields) const {
944  DCPacker packer;
945 
946  packer.raw_pack_uint8(1);
947  packer.RAW_PACK_CHANNEL(district_channel_id);
948  packer.RAW_PACK_CHANNEL(from_channel_id);
949  // packer.raw_pack_uint8('A');
950 
951  bool has_optional_fields = (PyObject_IsTrue(optional_fields) != 0);
952 
953  if (has_optional_fields) {
954  packer.raw_pack_uint16(STATESERVER_CREATE_OBJECT_WITH_REQUIRED_OTHER);
955  } else {
956  packer.raw_pack_uint16(STATESERVER_CREATE_OBJECT_WITH_REQUIRED);
957  }
958 
959  packer.raw_pack_uint32(do_id);
960  // Parent is a bit overloaded; this parent is not about inheritance, this
961  // one is about the visibility container parent, i.e. the zone parent:
962  packer.raw_pack_uint32(parent_id);
963  packer.raw_pack_uint32(zone_id);
964  packer.raw_pack_uint16(_number);
965 
966  // Specify all of the required fields.
967  int num_fields = get_num_inherited_fields();
968  for (int i = 0; i < num_fields; ++i) {
969  DCField *field = get_inherited_field(i);
970  if (field->is_required() && field->as_molecular_field() == nullptr) {
971  packer.begin_pack(field);
972  if (!pack_required_field(packer, distobj, field)) {
973  return Datagram();
974  }
975  packer.end_pack();
976  }
977  }
978 
979  // Also specify the optional fields.
980  if (has_optional_fields) {
981  int num_optional_fields = PySequence_Size(optional_fields);
982  packer.raw_pack_uint16(num_optional_fields);
983 
984  for (int i = 0; i < num_optional_fields; ++i) {
985  PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
986 #if PY_MAJOR_VERSION >= 3
987  string field_name = PyUnicode_AsUTF8(py_field_name);
988 #else
989  string field_name = PyString_AsString(py_field_name);
990 #endif
991  Py_XDECREF(py_field_name);
992 
993  DCField *field = get_field_by_name(field_name);
994  if (field == nullptr) {
995  ostringstream strm;
996  strm << "No field named " << field_name << " in class " << get_name()
997  << "\n";
998  nassert_raise(strm.str());
999  return Datagram();
1000  }
1001 
1002  packer.raw_pack_uint16(field->get_number());
1003 
1004  packer.begin_pack(field);
1005  if (!pack_required_field(packer, distobj, field)) {
1006  return Datagram();
1007  }
1008  packer.end_pack();
1009  }
1010  }
1011 
1012  return Datagram(packer.get_data(), packer.get_length());
1013 }
1014 #endif // HAVE_PYTHON
1015 
1016 /**
1017  * Write a string representation of this instance to <out>.
1018  */
1019 void DCClass::
1020 output(ostream &out, bool brief) const {
1021  output_instance(out, brief, "", "", "");
1022 }
1023 
1024 /**
1025  * Generates a parseable description of the object to the indicated output
1026  * stream.
1027  */
1028 void DCClass::
1029 write(ostream &out, bool brief, int indent_level) const {
1030  indent(out, indent_level);
1031  if (_is_struct) {
1032  out << "struct";
1033  } else {
1034  out << "dclass";
1035  }
1036  if (!_name.empty()) {
1037  out << " " << _name;
1038  }
1039 
1040  if (!_parents.empty()) {
1041  Parents::const_iterator pi = _parents.begin();
1042  out << " : " << (*pi)->_name;
1043  ++pi;
1044  while (pi != _parents.end()) {
1045  out << ", " << (*pi)->_name;
1046  ++pi;
1047  }
1048  }
1049 
1050  out << " {";
1051  if (!brief && _number >= 0) {
1052  out << " // index " << _number;
1053  }
1054  out << "\n";
1055 
1056  if (_constructor != nullptr) {
1057  _constructor->write(out, brief, indent_level + 2);
1058  }
1059 
1060  Fields::const_iterator fi;
1061  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1062  if (!(*fi)->is_bogus_field()) {
1063  (*fi)->write(out, brief, indent_level + 2);
1064 
1065  /*
1066  if (true || (*fi)->has_default_value()) {
1067  indent(out, indent_level + 2) << "// = ";
1068  DCPacker packer;
1069  packer.set_unpack_data((*fi)->get_default_value());
1070  packer.begin_unpack(*fi);
1071  packer.unpack_and_format(out, false);
1072  if (!packer.end_unpack()) {
1073  out << "<error>";
1074  }
1075  out << "\n";
1076  }
1077  */
1078  }
1079  }
1080 
1081  indent(out, indent_level) << "};\n";
1082 }
1083 
1084 /**
1085  * Generates a parseable description of the object to the indicated output
1086  * stream.
1087  */
1088 void DCClass::
1089 output_instance(ostream &out, bool brief, const string &prename,
1090  const string &name, const string &postname) const {
1091  if (_is_struct) {
1092  out << "struct";
1093  } else {
1094  out << "dclass";
1095  }
1096  if (!_name.empty()) {
1097  out << " " << _name;
1098  }
1099 
1100  if (!_parents.empty()) {
1101  Parents::const_iterator pi = _parents.begin();
1102  out << " : " << (*pi)->_name;
1103  ++pi;
1104  while (pi != _parents.end()) {
1105  out << ", " << (*pi)->_name;
1106  ++pi;
1107  }
1108  }
1109 
1110  out << " {";
1111 
1112  if (_constructor != nullptr) {
1113  _constructor->output(out, brief);
1114  out << "; ";
1115  }
1116 
1117  Fields::const_iterator fi;
1118  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1119  if (!(*fi)->is_bogus_field()) {
1120  (*fi)->output(out, brief);
1121  out << "; ";
1122  }
1123  }
1124 
1125  out << "}";
1126  if (!prename.empty() || !name.empty() || !postname.empty()) {
1127  out << " " << prename << name << postname;
1128  }
1129 }
1130 
1131 /**
1132  * Accumulates the properties of this class into the hash.
1133  */
1134 void DCClass::
1135 generate_hash(HashGenerator &hashgen) const {
1136  hashgen.add_string(_name);
1137 
1138  if (is_struct()) {
1139  hashgen.add_int(1);
1140  }
1141 
1142  hashgen.add_int(_parents.size());
1143  Parents::const_iterator pi;
1144  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
1145  hashgen.add_int((*pi)->get_number());
1146  }
1147 
1148  if (_constructor != nullptr) {
1149  _constructor->generate_hash(hashgen);
1150  }
1151 
1152  hashgen.add_int(_fields.size());
1153  Fields::const_iterator fi;
1154  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1155  (*fi)->generate_hash(hashgen);
1156  }
1157 }
1158 
1159 /**
1160  * Empties the list of inherited fields for the class, so that it may be
1161  * rebuilt. This is normally only called by
1162  * DCFile::rebuild_inherited_fields().
1163  */
1164 void DCClass::
1166  _inherited_fields.clear();
1167 }
1168 
1169 /**
1170  * Recomputes the list of inherited fields for the class.
1171  */
1172 void DCClass::
1174  typedef pset<string> Names;
1175  Names names;
1176 
1177  _inherited_fields.clear();
1178 
1179  // First, all of the inherited fields from our parent are at the top of the
1180  // list.
1181  Parents::const_iterator pi;
1182  for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
1183  const DCClass *parent = (*pi);
1184  int num_inherited_fields = parent->get_num_inherited_fields();
1185  for (int i = 0; i < num_inherited_fields; ++i) {
1186  DCField *field = parent->get_inherited_field(i);
1187  if (field->get_name().empty()) {
1188  // Unnamed fields are always inherited. Except in the hack case.
1189  if (!dc_sort_inheritance_by_file) {
1190  _inherited_fields.push_back(field);
1191  }
1192 
1193  } else {
1194  bool inserted = names.insert(field->get_name()).second;
1195  if (inserted) {
1196  // The earlier parent shadows the later parent.
1197  _inherited_fields.push_back(field);
1198  }
1199  }
1200  }
1201  }
1202 
1203  // Now add the local fields at the end of the list. If any fields in this
1204  // list were already defined by a parent, we will shadow the parent
1205  // definition (that is, remove the parent's field from our list of inherited
1206  // fields).
1207  Fields::const_iterator fi;
1208  for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
1209  DCField *field = (*fi);
1210  if (field->get_name().empty()) {
1211  // Unnamed fields are always added.
1212  _inherited_fields.push_back(field);
1213 
1214  } else {
1215  bool inserted = names.insert(field->get_name()).second;
1216  if (!inserted) {
1217  // This local field shadows an inherited field. Remove the parent's
1218  // field from our list.
1219  shadow_inherited_field(field->get_name());
1220  }
1221 
1222  // Now add the local field.
1223  _inherited_fields.push_back(field);
1224  }
1225  }
1226 
1227  if (dc_sort_inheritance_by_file) {
1228  // Temporary hack.
1229  sort(_inherited_fields.begin(), _inherited_fields.end(), SortFieldsByIndex());
1230  }
1231 }
1232 
1233 /**
1234  * This is called only by rebuild_inherited_fields(). It removes the named
1235  * field from the list of _inherited_fields, presumably in preparation for
1236  * adding a new definition below.
1237  */
1238 void DCClass::
1239 shadow_inherited_field(const string &name) {
1240  Fields::iterator fi;
1241  for (fi = _inherited_fields.begin(); fi != _inherited_fields.end(); ++fi) {
1242  DCField *field = (*fi);
1243  if (field->get_name() == name) {
1244  _inherited_fields.erase(fi);
1245  return;
1246  }
1247  }
1248 
1249  // If we get here, the named field wasn't in the list. Huh.
1250  nassert_raise("named field not in list");
1251 }
1252 
1253 /**
1254  * Adds the newly-allocated field to the class. The class becomes the owner
1255  * of the pointer and will delete it when it destructs. Returns true if the
1256  * field is successfully added, or false if there was a name conflict or some
1257  * other problem.
1258  */
1259 bool DCClass::
1261  nassertr(field->get_class() == this || field->get_class() == nullptr, false);
1262  field->set_class(this);
1263  if (_dc_file != nullptr) {
1264  _dc_file->mark_inherited_fields_stale();
1265  }
1266 
1267  if (!field->get_name().empty()) {
1268  if (field->get_name() == _name) {
1269  // This field is a constructor.
1270  if (_constructor != nullptr) {
1271  // We already have a constructor.
1272  return false;
1273  }
1274  if (field->as_atomic_field() == nullptr) {
1275  // The constructor must be an atomic field.
1276  return false;
1277  }
1278  _constructor = field;
1279  _fields_by_name.insert
1280  (FieldsByName::value_type(field->get_name(), field));
1281  return true;
1282  }
1283 
1284  bool inserted = _fields_by_name.insert
1285  (FieldsByName::value_type(field->get_name(), field)).second;
1286 
1287  if (!inserted) {
1288  return false;
1289  }
1290  }
1291 
1292  if (_dc_file != nullptr &&
1293  ((dc_virtual_inheritance && dc_sort_inheritance_by_file) || !is_struct())) {
1294  if (dc_multiple_inheritance) {
1295  _dc_file->set_new_index_number(field);
1296  } else {
1298  }
1299 
1300  bool inserted = _fields_by_index.insert
1301  (FieldsByIndex::value_type(field->get_number(), field)).second;
1302 
1303  // It shouldn't be possible for that to fail.
1304  nassertr(inserted, false);
1305  }
1306 
1307  _fields.push_back(field);
1308  return true;
1309 }
1310 
1311 /**
1312  * Adds a new parent to the inheritance hierarchy of the class. This is
1313  * normally called only during parsing.
1314  */
1315 void DCClass::
1317  _parents.push_back(parent);
1318  _dc_file->mark_inherited_fields_stale();
1319 }
1320 
1321 /**
1322  * Assigns the unique number to this class. This is normally called only by
1323  * the DCFile interface as the class is added.
1324  */
1325 void DCClass::
1326 set_number(int number) {
1327  _number = number;
1328 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int get_number() const
Returns a unique index number associated with this field.
Definition: dcField.I:19
const std::string & get_name() const
Returns the name of this field, or empty string if the field is unnamed.
void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this class into the hash.
Definition: dcClass.cxx:1135
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:129
DCClass * get_class() const
Returns the DCClass pointer for the class that contains this field.
Definition: dcField.I:27
virtual void output(std::ostream &out) const
Write a string representation of this instance to <out>.
Definition: dcClass.cxx:338
void clear_inherited_fields()
Empties the list of inherited fields for the class, so that it may be rebuilt.
Definition: dcClass.cxx:1165
void add_int(int num)
Adds another integer to the hash so far.
DCClass * get_parent(int n) const
Returns the nth parent class this class inherits from.
Definition: dcClass.cxx:143
size_t get_num_unpacked_bytes() const
Returns the number of bytes that have been unpacked so far, or after unpack_end(),...
Definition: dcPacker.I:574
A single field of a Distributed Class, either atomic or molecular.
Definition: dcField.h:37
This is a convenience class to specialize ConfigVariable as a boolean type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const Datagram & get_datagram() const
Return the datagram of this iterator.
void add_string(const std::string &str)
Adds a string to the hash, by breaking it down into a sequence of integers.
unsigned int raw_unpack_uint16()
Unpacks the data from the buffer between unpacking sessions.
Definition: dcPacker.I:897
void raw_pack_uint8(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:740
void set_class(DCClass *dclass)
Assigns the class pointer to this field.
Definition: dcField.I:167
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void check_inherited_fields()
Rebuilds all of the inherited fields tables, if necessary.
Definition: dcFile.I:28
void set_number(int number)
Assigns the unique number to this field.
Definition: dcField.I:158
virtual DCAtomicField * as_atomic_field()
Returns the same field pointer converted to an atomic field pointer, if this is in fact an atomic fie...
Definition: dcField.cxx:112
bool is_broadcast() const
Returns true if the "broadcast" flag is set for this field, false otherwise.
Definition: dcField.I:77
Defines a particular DistributedClass as read from an input .dc file.
Definition: dcClass.h:44
bool is_struct() const
Returns true if the class has been identified with the "struct" keyword in the dc file,...
Definition: dcClass.I:44
void output(std::ostream &out) const
Write a string representation of this instance to <out>.
Definition: dcField.I:141
void set_new_index_number(DCField *field)
Sets the next sequential available index number on the indicated field.
Definition: dcFile.cxx:593
virtual void write(std::ostream &out, bool brief, int indent_level) const
Generates a parseable description of the object to the indicated output stream.
Definition: dcClass.cxx:1029
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
Definition: pStatTimer.h:30
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool inherits_from_bogus_class() const
Returns true if this class, or any class in the inheritance heirarchy for this class,...
Definition: dcClass.cxx:319
bool is_required() const
Returns true if the "required" flag is set for this field, false otherwise.
Definition: dcField.I:68
size_t get_length() const
Returns the current length of the buffer.
Definition: dcPacker.I:583
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
size_t get_remaining_size() const
Return the bytes left in the datagram.
A single atomic field of a Distributed Class, as read from a .dc file.
Definition: dcAtomicField.h:30
virtual DCMolecularField * as_molecular_field()
Returns the same field pointer converted to a molecular field pointer, if this is in fact a molecular...
Definition: dcField.cxx:130
virtual void generate_hash(HashGenerator &hashgen) const
Accumulates the properties of this field into the hash.
Definition: dcField.cxx:467
Represents the complete list of Distributed Class descriptions as read from a .dc file.
Definition: dcFile.h:32
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void raw_pack_uint32(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:758
DCField * get_field_by_index(int index_number) const
Returns a pointer to the DCField that has the indicated index number.
Definition: dcClass.cxx:228
DCField * get_field_by_name(const std::string &name) const
Returns a pointer to the DCField that shares the indicated name.
Definition: dcClass.cxx:201
void output_instance(std::ostream &out, bool brief, const std::string &prename, const std::string &name, const std::string &postname) const
Generates a parseable description of the object to the indicated output stream.
Definition: dcClass.cxx:1089
int get_num_elements() const
Returns the number of elements (parameters) of the atomic field.
DCField * get_inherited_field(int n) const
Returns the nth field field in the class and all of its ancestors.
Definition: dcClass.cxx:288
A lightweight class that represents a single element that may be timed and/or counted via stats.
Represents the type specification for a single parameter within a field specification.
Definition: dcParameter.h:35
void set_unpack_data(const vector_uchar &data)
Sets up the unpack_data pointer.
Definition: dcPacker.cxx:117
void pack_default_value()
Adds the default value for the current element into the stream.
Definition: dcPacker.cxx:552
size_t get_current_index() const
Returns the current position within the datagram of the next piece of data to extract.
void raw_pack_uint16(unsigned int value)
Packs the data into the buffer between packing sessions.
Definition: dcPacker.I:749
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
void skip_bytes(size_t size)
Skips over the indicated number of bytes in the datagram.
void add_parent(DCClass *parent)
Adds a new parent to the inheritance hierarchy of the class.
Definition: dcClass.cxx:1316
bool has_default_value() const
Returns true if a default value has been explicitly established for this field, false otherwise.
Definition: dcField.I:36
const char * get_data() const
Returns the beginning of the data buffer.
Definition: dcPacker.I:641
int get_num_parents() const
Returns the number of base classes this class inherits from.
Definition: dcClass.cxx:135
void write(std::ostream &out, int indent_level) const
Write a string representation of this instance to <out>.
Definition: dcField.I:149
This class generates an arbitrary hash number from a sequence of ints.
Definition: hashGenerator.h:24
bool is_ownrecv() const
Returns true if the "ownrecv" flag is set for this field, false otherwise.
Definition: dcField.I:125
DCField * get_constructor() const
Returns the constructor method for this class if it is defined, or NULL if the class uses the default...
Definition: dcClass.cxx:162
void mark_inherited_fields_stale()
Indicates that something has changed in one or more of the inheritance chains or the set of fields; t...
Definition: dcFile.I:40
int get_num_inherited_fields() const
Returns the total number of field fields defined in this class and all ancestor classes.
Definition: dcClass.cxx:255
void begin_pack(const DCPackerInterface *root)
Begins a packing session.
Definition: dcPacker.cxx:73
const std::string & get_name() const
Returns the name of this class.
Definition: dcClass.I:26
uint16_t get_uint16()
Extracts an unsigned 16-bit integer.
This class can be used for packing a series of numeric and string data into a binary stream,...
Definition: dcPacker.h:34
bool has_constructor() const
Returns true if this class has a constructor method, false if it just uses the default constructor.
Definition: dcClass.cxx:153
This is our own Panda specialization on the default STL set.
Definition: pset.h:49
A class to retrieve the individual data elements previously stored in a Datagram.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool add_field(DCField *field)
Adds the newly-allocated field to the class.
Definition: dcClass.cxx:1260
bool end_pack()
Finishes a packing session.
Definition: dcPacker.cxx:98
int get_num_fields() const
Returns the number of fields defined directly in this class, ignoring inheritance.
Definition: dcClass.cxx:171
void rebuild_inherited_fields()
Recomputes the list of inherited fields for the class.
Definition: dcClass.cxx:1173
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
bool is_bogus_class() const
Returns true if the class has been flagged as a bogus class.
Definition: dcClass.I:55
DCField * get_field(int n) const
Returns the nth field in the class.
Definition: dcClass.cxx:181
void begin_unpack(const DCPackerInterface *root)
Begins an unpacking session.
Definition: dcPacker.cxx:153
bool end_unpack()
Finishes the unpacking session.
Definition: dcPacker.cxx:179
size_t get_length() const
Returns the number of bytes in the datagram.
Definition: datagram.I:335
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
Definition: datagram.I:327
void set_number(int number)
Assigns the unique number to this class.
Definition: dcClass.cxx:1326
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.