Panda3D
 All Classes Functions Variables Enumerations
dcClass.cxx
00001 // Filename: dcClass.cxx
00002 // Created by:  drose (05Oct00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "dcClass.h"
00016 #include "dcFile.h"
00017 #include "dcAtomicField.h"
00018 #include "hashGenerator.h"
00019 #include "dcindent.h"
00020 #include "dcmsgtypes.h"
00021 
00022 #include "dcClassParameter.h"
00023 #include <algorithm>
00024 
00025 #ifdef WITHIN_PANDA
00026 #include "pStatTimer.h"
00027 
00028 #ifndef CPPPARSER
00029 PStatCollector DCClass::_update_pcollector("App:Show code:readerPollTask:Update");
00030 PStatCollector DCClass::_generate_pcollector("App:Show code:readerPollTask:Generate");
00031 #endif  // CPPPARSER
00032 
00033 ConfigVariableBool dc_multiple_inheritance
00034 ("dc-multiple-inheritance", true,
00035  PRC_DESC("Set this true to support multiple inheritance in the dc file.  "
00036           "If this is false, the old way, multiple inheritance is not "
00037           "supported, but field numbers will be numbered sequentially, "
00038           "which may be required to support old code that assumed this."));
00039 
00040 ConfigVariableBool dc_virtual_inheritance
00041 ("dc-virtual-inheritance", true,
00042  PRC_DESC("Set this true to support proper virtual inheritance in the "
00043           "dc file, so that diamond-of-death type constructs can be used.  "
00044           "This also enables shadowing (overloading) of inherited method "
00045           "names from a base class."));
00046 
00047 ConfigVariableBool dc_sort_inheritance_by_file
00048 ("dc-sort-inheritance-by-file", true,
00049  PRC_DESC("This is a temporary hack.  This should be true if you are using "
00050           "version 1.42 of the otp_server.exe binary, which sorted inherited "
00051           "fields based on the order of the classes within the DC file, "
00052           "rather than based on the order in which the references are made "
00053           "within the class."));
00054 
00055 
00056 #endif  // WITHIN_PANDA
00057 
00058 class SortFieldsByIndex {
00059 public:
00060   inline bool operator ()(const DCField *a, const DCField *b) const {
00061     return a->get_number() < b->get_number();
00062   }
00063 };
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: DCClass::Constructor
00067 //       Access: Public
00068 //  Description:
00069 ////////////////////////////////////////////////////////////////////
00070 DCClass::
00071 DCClass(DCFile *dc_file, const string &name, bool is_struct, bool bogus_class) : 
00072 #ifdef WITHIN_PANDA
00073   _class_update_pcollector(_update_pcollector, name),
00074   _class_generate_pcollector(_generate_pcollector, name),
00075 #endif
00076   _dc_file(dc_file),
00077   _name(name),
00078   _is_struct(is_struct),
00079   _bogus_class(bogus_class)
00080 {
00081   _number = -1;
00082   _constructor = NULL;
00083       
00084 #ifdef HAVE_PYTHON
00085   _class_def = NULL;
00086   _owner_class_def = NULL;
00087 #endif
00088 }
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: DCClass::Destructor
00092 //       Access: Public
00093 //  Description:
00094 ////////////////////////////////////////////////////////////////////
00095 DCClass::
00096 ~DCClass() {
00097   if (_constructor != (DCField *)NULL) {
00098     delete _constructor;
00099   }
00100 
00101   Fields::iterator fi;
00102   for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
00103     delete (*fi);
00104   }
00105 
00106 #ifdef HAVE_PYTHON
00107   Py_XDECREF(_class_def);
00108   Py_XDECREF(_owner_class_def);
00109 #endif
00110 }
00111 
00112 ////////////////////////////////////////////////////////////////////
00113 //     Function: DCClass::as_class
00114 //       Access: Published, Virtual
00115 //  Description: 
00116 ////////////////////////////////////////////////////////////////////
00117 DCClass *DCClass::
00118 as_class() {
00119   return this;
00120 }
00121 
00122 ////////////////////////////////////////////////////////////////////
00123 //     Function: DCClass::as_class
00124 //       Access: Published, Virtual
00125 //  Description: 
00126 ////////////////////////////////////////////////////////////////////
00127 const DCClass *DCClass::
00128 as_class() const {
00129   return this;
00130 }
00131 
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: DCClass::get_num_parents
00134 //       Access: Published
00135 //  Description: Returns the number of base classes this class
00136 //               inherits from.
00137 ////////////////////////////////////////////////////////////////////
00138 int DCClass::
00139 get_num_parents() const {
00140   return _parents.size();
00141 }
00142 
00143 ////////////////////////////////////////////////////////////////////
00144 //     Function: DCClass::get_parent
00145 //       Access: Published
00146 //  Description: Returns the nth parent class this class inherits
00147 //               from.
00148 ////////////////////////////////////////////////////////////////////
00149 DCClass *DCClass::
00150 get_parent(int n) const {
00151   nassertr(n >= 0 && n < (int)_parents.size(), NULL);
00152   return _parents[n];
00153 }
00154   
00155 ////////////////////////////////////////////////////////////////////
00156 //     Function: DCClass::has_constructor
00157 //       Access: Published
00158 //  Description: Returns true if this class has a constructor method,
00159 //               false if it just uses the default constructor.
00160 ////////////////////////////////////////////////////////////////////
00161 bool DCClass::
00162 has_constructor() const {
00163   return (_constructor != (DCField *)NULL);
00164 }
00165   
00166 ////////////////////////////////////////////////////////////////////
00167 //     Function: DCClass::get_constructor
00168 //       Access: Published
00169 //  Description: Returns the constructor method for this class if it
00170 //               is defined, or NULL if the class uses the default
00171 //               constructor.
00172 ////////////////////////////////////////////////////////////////////
00173 DCField *DCClass::
00174 get_constructor() const {
00175   return _constructor;
00176 }
00177 
00178 ////////////////////////////////////////////////////////////////////
00179 //     Function: DCClass::get_num_fields
00180 //       Access: Published
00181 //  Description: Returns the number of fields defined directly in this
00182 //               class, ignoring inheritance.
00183 ////////////////////////////////////////////////////////////////////
00184 int DCClass::
00185 get_num_fields() const {
00186   return _fields.size();
00187 }
00188 
00189 ////////////////////////////////////////////////////////////////////
00190 //     Function: DCClass::get_field
00191 //       Access: Published
00192 //  Description: Returns the nth field in the class.  This is not
00193 //               necessarily the field with index n; this is the nth
00194 //               field defined in the class directly, ignoring
00195 //               inheritance.
00196 ////////////////////////////////////////////////////////////////////
00197 DCField *DCClass::
00198 get_field(int n) const {
00199   #ifndef NDEBUG //[
00200   if (n < 0 || n >= (int)_fields.size()) {
00201     cerr << *this << " "
00202          << "n:" << n << " _fields.size():"
00203          << (int)_fields.size() << endl;
00204     // __asm { int 3 }
00205   }
00206   #endif //]
00207   nassertr_always(n >= 0 && n < (int)_fields.size(), NULL);
00208   return _fields[n];
00209 }
00210 
00211 ////////////////////////////////////////////////////////////////////
00212 //     Function: DCClass::get_field_by_name
00213 //       Access: Published
00214 //  Description: Returns a pointer to the DCField that shares the
00215 //               indicated name.  If the named field is not found in
00216 //               the current class, the parent classes will be
00217 //               searched, so the value returned may not actually be a
00218 //               field within this class.  Returns NULL if there is no
00219 //               such field defined.
00220 ////////////////////////////////////////////////////////////////////
00221 DCField *DCClass::
00222 get_field_by_name(const string &name) const {
00223   FieldsByName::const_iterator ni;
00224   ni = _fields_by_name.find(name);
00225   if (ni != _fields_by_name.end()) {
00226     return (*ni).second;
00227   }
00228 
00229   // We didn't have such a field, so check our parents.
00230   Parents::const_iterator pi;
00231   for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
00232     DCField *result = (*pi)->get_field_by_name(name);
00233     if (result != (DCField *)NULL) {
00234       return result;
00235     }
00236   }
00237 
00238   // Nobody knew what this field is.
00239   return (DCField *)NULL;
00240 }
00241 
00242 ////////////////////////////////////////////////////////////////////
00243 //     Function: DCClass::get_field_by_index
00244 //       Access: Published
00245 //  Description: Returns a pointer to the DCField that has the
00246 //               indicated index number.  If the numbered field is not
00247 //               found in the current class, the parent classes will
00248 //               be searched, so the value returned may not actually
00249 //               be a field within this class.  Returns NULL if there
00250 //               is no such field defined.
00251 ////////////////////////////////////////////////////////////////////
00252 DCField *DCClass::
00253 get_field_by_index(int index_number) const {
00254   FieldsByIndex::const_iterator ni;
00255   ni = _fields_by_index.find(index_number);
00256   if (ni != _fields_by_index.end()) {
00257     return (*ni).second;
00258   }
00259 
00260   // We didn't have such a field, so check our parents.
00261   Parents::const_iterator pi;
00262   for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
00263     DCField *result = (*pi)->get_field_by_index(index_number);
00264     if (result != (DCField *)NULL) {
00265       // Cache this result for future lookups.
00266       ((DCClass *)this)->_fields_by_index[index_number] = result;
00267       return result;
00268     }
00269   }
00270 
00271   // Nobody knew what this field is.
00272   return (DCField *)NULL;
00273 }
00274 
00275 ////////////////////////////////////////////////////////////////////
00276 //     Function: DCClass::get_num_inherited_fields
00277 //       Access: Published
00278 //  Description: Returns the total number of field fields defined in
00279 //               this class and all ancestor classes.
00280 ////////////////////////////////////////////////////////////////////
00281 int DCClass::
00282 get_num_inherited_fields() const {
00283   if (dc_multiple_inheritance && dc_virtual_inheritance && 
00284       _dc_file != (DCFile *)NULL) {
00285     _dc_file->check_inherited_fields();
00286     if (_inherited_fields.empty()) {
00287       ((DCClass *)this)->rebuild_inherited_fields();
00288     }
00289 
00290     // This assertion causes trouble when we are only parsing an
00291     // incomplete DC file.
00292     //nassertr(is_bogus_class() || !_inherited_fields.empty(), 0);
00293     return (int)_inherited_fields.size();
00294 
00295   } else {
00296     int num_fields = get_num_fields();
00297 
00298     Parents::const_iterator pi;
00299     for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
00300       num_fields += (*pi)->get_num_inherited_fields();
00301     }
00302     
00303     return num_fields;
00304   }
00305 }
00306 
00307 ////////////////////////////////////////////////////////////////////
00308 //     Function: DCClass::get_inherited_field
00309 //       Access: Published
00310 //  Description: Returns the nth field field in the class and all of
00311 //               its ancestors.  
00312 //
00313 //               This *used* to be the same thing as
00314 //               get_field_by_index(), back when the fields were
00315 //               numbered sequentially within a class's inheritance
00316 //               hierarchy.  Now that fields have a globally unique
00317 //               index number, this is no longer true.
00318 ////////////////////////////////////////////////////////////////////
00319 DCField *DCClass::
00320 get_inherited_field(int n) const {
00321   if (dc_multiple_inheritance && dc_virtual_inheritance && 
00322       _dc_file != (DCFile *)NULL) {
00323     _dc_file->check_inherited_fields();
00324     if (_inherited_fields.empty()) {
00325       ((DCClass *)this)->rebuild_inherited_fields();
00326     }
00327     nassertr(n >= 0 && n < (int)_inherited_fields.size(), NULL);
00328     return _inherited_fields[n];
00329 
00330   } else {
00331     Parents::const_iterator pi;
00332     for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
00333       int psize = (*pi)->get_num_inherited_fields();
00334       if (n < psize) {
00335         return (*pi)->get_inherited_field(n);
00336       }
00337       
00338       n -= psize;
00339     }
00340     
00341     return get_field(n);
00342   }
00343 }
00344 
00345 ////////////////////////////////////////////////////////////////////
00346 //     Function : DCClass::inherits_from_bogus_class
00347 //       Access : Published
00348 //  Description : Returns true if this class, or any class in the
00349 //                inheritance heirarchy for this class, is a "bogus"
00350 //                class--a forward reference to an as-yet-undefined
00351 //                class.
00352 ////////////////////////////////////////////////////////////////////
00353 bool DCClass::
00354 inherits_from_bogus_class() const {
00355   if (is_bogus_class()) {
00356     return true;
00357   }
00358 
00359   Parents::const_iterator pi;
00360   for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
00361     if ((*pi)->inherits_from_bogus_class()) {
00362       return true;
00363     }
00364   }
00365 
00366   return false;
00367 }
00368 
00369 ////////////////////////////////////////////////////////////////////
00370 //     Function : DCClass::output
00371 //       Access : Published, Virtual
00372 //  Description : Write a string representation of this instance to
00373 //                <out>.
00374 ////////////////////////////////////////////////////////////////////
00375 void DCClass::
00376 output(ostream &out) const {
00377   if (_is_struct) {
00378     out << "struct";
00379   } else {
00380     out << "dclass";
00381   }
00382   if (!_name.empty()) {
00383     out << " " << _name;
00384   }
00385 }
00386 
00387 #ifdef HAVE_PYTHON
00388 ////////////////////////////////////////////////////////////////////
00389 //     Function: DCClass::has_class_def
00390 //       Access: Published
00391 //  Description: Returns true if the DCClass object has an associated
00392 //               Python class definition, false otherwise.
00393 ////////////////////////////////////////////////////////////////////
00394 bool DCClass::
00395 has_class_def() const {
00396   return (_class_def != NULL);
00397 }
00398 #endif  // HAVE_PYTHON
00399 
00400 #ifdef HAVE_PYTHON
00401 ////////////////////////////////////////////////////////////////////
00402 //     Function: DCClass::set_class_def
00403 //       Access: Published
00404 //  Description: Sets the class object associated with this
00405 //               DistributedClass.  This object will be used to
00406 //               construct new instances of the class.
00407 ////////////////////////////////////////////////////////////////////
00408 void DCClass::
00409 set_class_def(PyObject *class_def) {
00410   Py_XINCREF(class_def);
00411   Py_XDECREF(_class_def);
00412   _class_def = class_def;
00413 }
00414 #endif  // HAVE_PYTHON
00415 
00416 #ifdef HAVE_PYTHON
00417 ////////////////////////////////////////////////////////////////////
00418 //     Function: DCClass::get_class_def
00419 //       Access: Published
00420 //  Description: Returns the class object that was previously
00421 //               associated with this DistributedClass.  This will
00422 //               return a new reference to the object.
00423 ////////////////////////////////////////////////////////////////////
00424 PyObject *DCClass::
00425 get_class_def() const {
00426   if (_class_def == NULL) {
00427     Py_INCREF(Py_None);
00428     return Py_None;
00429   }
00430 
00431   Py_INCREF(_class_def);
00432   return _class_def;
00433 }
00434 #endif  // HAVE_PYTHON
00435 
00436 #ifdef HAVE_PYTHON
00437 ////////////////////////////////////////////////////////////////////
00438 //     Function: DCClass::has_owner_class_def
00439 //       Access: Published
00440 //  Description: Returns true if the DCClass object has an associated
00441 //               Python owner class definition, false otherwise.
00442 ////////////////////////////////////////////////////////////////////
00443 bool DCClass::
00444 has_owner_class_def() const {
00445   return (_owner_class_def != NULL);
00446 }
00447 #endif  // HAVE_PYTHON
00448 
00449 #ifdef HAVE_PYTHON
00450 ////////////////////////////////////////////////////////////////////
00451 //     Function: DCClass::set_owner_class_def
00452 //       Access: Published
00453 //  Description: Sets the owner class object associated with this
00454 //               DistributedClass.  This object will be used to
00455 //               construct new owner instances of the class.
00456 ////////////////////////////////////////////////////////////////////
00457 void DCClass::
00458 set_owner_class_def(PyObject *owner_class_def) {
00459   Py_XINCREF(owner_class_def);
00460   Py_XDECREF(_owner_class_def);
00461   _owner_class_def = owner_class_def;
00462 }
00463 #endif  // HAVE_PYTHON
00464 
00465 #ifdef HAVE_PYTHON
00466 ////////////////////////////////////////////////////////////////////
00467 //     Function: DCClass::get_owner_class_def
00468 //       Access: Published
00469 //  Description: Returns the owner class object that was previously
00470 //               associated with this DistributedClass.  This will
00471 //               return a new reference to the object.
00472 ////////////////////////////////////////////////////////////////////
00473 PyObject *DCClass::
00474 get_owner_class_def() const {
00475   if (_owner_class_def == NULL) {
00476     Py_INCREF(Py_None);
00477     return Py_None;
00478   }
00479 
00480   Py_INCREF(_owner_class_def);
00481   return _owner_class_def;
00482 }
00483 #endif  // HAVE_PYTHON
00484 
00485 #ifdef HAVE_PYTHON
00486 ////////////////////////////////////////////////////////////////////
00487 //     Function: DCClass::receive_update
00488 //       Access: Published
00489 //  Description: Extracts the update message out of the packer and
00490 //               applies it to the indicated object by calling the
00491 //               appropriate method.
00492 ////////////////////////////////////////////////////////////////////
00493 void DCClass::
00494 receive_update(PyObject *distobj, DatagramIterator &di) const {
00495 #ifdef WITHIN_PANDA
00496   PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
00497 #endif
00498     DCPacker packer;
00499     const char *data = (const char *)di.get_datagram().get_data();
00500     packer.set_unpack_data(data + di.get_current_index(),
00501                            di.get_remaining_size(), false);
00502 
00503     int field_id = packer.raw_unpack_uint16();
00504     DCField *field = get_field_by_index(field_id);
00505     if (field == (DCField *)NULL) {
00506             ostringstream strm;
00507             strm
00508                 << "Received update for field " << field_id << ", not in class "
00509                 << get_name();
00510             nassert_raise(strm.str());
00511             return;
00512     }
00513 
00514     packer.begin_unpack(field);
00515     field->receive_update(packer, distobj);
00516     packer.end_unpack();
00517 
00518     di.skip_bytes(packer.get_num_unpacked_bytes());
00519 
00520 }
00521 #endif  // HAVE_PYTHON
00522 
00523 #ifdef HAVE_PYTHON
00524 ////////////////////////////////////////////////////////////////////
00525 //     Function: DCClass::receive_update_broadcast_required
00526 //       Access: Published
00527 //  Description: Processes a big datagram that includes all of the
00528 //               "required" fields that are sent along with a normal
00529 //               "generate with required" message.  This is all of the
00530 //               atomic fields that are marked "broadcast required".
00531 ////////////////////////////////////////////////////////////////////
00532 void DCClass::
00533 receive_update_broadcast_required(PyObject *distobj, DatagramIterator &di) const {
00534 #ifdef WITHIN_PANDA
00535   PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
00536 #endif
00537   DCPacker packer;
00538   const char *data = (const char *)di.get_datagram().get_data();
00539   packer.set_unpack_data(data + di.get_current_index(),
00540                          di.get_remaining_size(), false);
00541 
00542   int num_fields = get_num_inherited_fields();
00543   for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
00544     DCField *field = get_inherited_field(i);
00545     if (field->as_molecular_field() == (DCMolecularField *)NULL &&
00546         field->is_required() && field->is_broadcast()) {
00547       packer.begin_unpack(field);
00548       field->receive_update(packer, distobj);
00549       if (!packer.end_unpack()) {
00550         break;
00551       }
00552     }
00553   }
00554 
00555   di.skip_bytes(packer.get_num_unpacked_bytes());
00556 }
00557 #endif  // HAVE_PYTHON
00558 
00559 #ifdef HAVE_PYTHON
00560 ////////////////////////////////////////////////////////////////////
00561 //     Function: DCClass::receive_update_broadcast_required_owner
00562 //       Access: Published
00563 //  Description: Processes a big datagram that includes all of the
00564 //               "required" fields that are sent along with a normal
00565 //               "generate with required" message.  This is all of the
00566 //               atomic fields that are marked "broadcast ownrecv". Should
00567 //               be used for 'owner-view' objects.
00568 ////////////////////////////////////////////////////////////////////
00569 void DCClass::
00570 receive_update_broadcast_required_owner(PyObject *distobj,
00571                                         DatagramIterator &di) const {
00572 #ifdef WITHIN_PANDA
00573   PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
00574 #endif
00575   DCPacker packer;
00576   const char *data = (const char *)di.get_datagram().get_data();
00577   packer.set_unpack_data(data + di.get_current_index(),
00578                          di.get_remaining_size(), false);
00579 
00580   int num_fields = get_num_inherited_fields();
00581   for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
00582     DCField *field = get_inherited_field(i);
00583     if (field->as_molecular_field() == (DCMolecularField *)NULL &&
00584         field->is_required()) {
00585       packer.begin_unpack(field);
00586       if (field->is_ownrecv()) {
00587         field->receive_update(packer, distobj);
00588       } else {
00589         // It's not an ownrecv field; skip over it. It's difficult
00590         // to filter this on the server, ask Roger for the reason.
00591         packer.unpack_skip();
00592       }
00593       if (!packer.end_unpack()) {
00594         break;
00595       }
00596     }
00597   }
00598 
00599   di.skip_bytes(packer.get_num_unpacked_bytes());
00600 }
00601 #endif  // HAVE_PYTHON
00602 
00603 #ifdef HAVE_PYTHON
00604 ////////////////////////////////////////////////////////////////////
00605 //     Function: DCClass::receive_update_all_required
00606 //       Access: Published
00607 //  Description: Processes a big datagram that includes all of the
00608 //               "required" fields that are sent when an avatar is
00609 //               created.  This is all of the atomic fields that are
00610 //               marked "required", whether they are broadcast or not.
00611 ////////////////////////////////////////////////////////////////////
00612 void DCClass::
00613 receive_update_all_required(PyObject *distobj, DatagramIterator &di) const {
00614 #ifdef WITHIN_PANDA
00615   PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
00616 #endif
00617   DCPacker packer;
00618   const char *data = (const char *)di.get_datagram().get_data();
00619   packer.set_unpack_data(data + di.get_current_index(),
00620                          di.get_remaining_size(), false);
00621 
00622   int num_fields = get_num_inherited_fields();
00623   for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
00624     DCField *field = get_inherited_field(i);
00625     if (field->as_molecular_field() == (DCMolecularField *)NULL &&
00626         field->is_required()) {
00627       packer.begin_unpack(field);
00628       field->receive_update(packer, distobj);
00629       if (!packer.end_unpack()) {
00630         break;
00631       }
00632     }
00633   }
00634 
00635   di.skip_bytes(packer.get_num_unpacked_bytes());
00636 }
00637 #endif  // HAVE_PYTHON
00638 
00639 #ifdef HAVE_PYTHON
00640 ////////////////////////////////////////////////////////////////////
00641 //     Function: DCClass::receive_update_other
00642 //       Access: Published
00643 //  Description: Processes a datagram that lists some additional
00644 //               fields that are broadcast in one chunk.
00645 ////////////////////////////////////////////////////////////////////
00646 void DCClass::
00647 receive_update_other(PyObject *distobj, DatagramIterator &di) const {
00648 #ifdef WITHIN_PANDA
00649   PStatTimer timer(((DCClass *)this)->_class_update_pcollector);
00650 #endif
00651   int num_fields = di.get_uint16();
00652   for (int i = 0; i < num_fields && !PyErr_Occurred(); ++i) {
00653     receive_update(distobj, di);
00654   }
00655 }
00656 #endif  // HAVE_PYTHON
00657 
00658 #ifdef HAVE_PYTHON
00659 ////////////////////////////////////////////////////////////////////
00660 //     Function: DCClass::direct_update
00661 //       Access: Published
00662 //  Description: Processes an update for a named field from a packed
00663 //               value blob.
00664 ////////////////////////////////////////////////////////////////////
00665 void DCClass::
00666 direct_update(PyObject *distobj, const string &field_name, 
00667               const string &value_blob) {
00668   DCField *field = get_field_by_name(field_name);
00669   nassertv_always(field != NULL);
00670 
00671   DCPacker packer;
00672   packer.set_unpack_data(value_blob);
00673   packer.begin_unpack(field);
00674   field->receive_update(packer, distobj);
00675   packer.end_unpack();
00676 }
00677 #endif  // HAVE_PYTHON
00678 
00679 #ifdef HAVE_PYTHON
00680 ////////////////////////////////////////////////////////////////////
00681 //     Function: DCClass::direct_update
00682 //       Access: Published
00683 //  Description: Processes an update for a named field from a packed
00684 //               datagram.
00685 ////////////////////////////////////////////////////////////////////
00686 void DCClass::
00687 direct_update(PyObject *distobj, const string &field_name, 
00688               const Datagram &datagram) {
00689   direct_update(distobj, field_name, datagram.get_message());
00690 }
00691 #endif  // HAVE_PYTHON
00692 
00693 #ifdef HAVE_PYTHON
00694 ////////////////////////////////////////////////////////////////////
00695 //     Function: DCClass::pack_required_field
00696 //       Access: Published
00697 //  Description: Looks up the current value of the indicated field by
00698 //               calling the appropriate get*() function, then packs
00699 //               that value into the datagram.  This field is
00700 //               presumably either a required field or a specified
00701 //               optional field, and we are building up a datagram for
00702 //               the generate-with-required message.
00703 //
00704 //               Returns true on success, false on failure.
00705 ////////////////////////////////////////////////////////////////////
00706 bool DCClass::
00707 pack_required_field(Datagram &datagram, PyObject *distobj, 
00708                     const DCField *field) const {
00709   DCPacker packer;
00710   packer.begin_pack(field);
00711   if (!pack_required_field(packer, distobj, field)) {
00712     return false;
00713   }
00714   if (!packer.end_pack()) {
00715     return false;
00716   }
00717 
00718   datagram.append_data(packer.get_data(), packer.get_length());
00719   return true;
00720 }
00721 #endif  // HAVE_PYTHON
00722 
00723 #ifdef HAVE_PYTHON
00724 ////////////////////////////////////////////////////////////////////
00725 //     Function: DCClass::pack_required_field
00726 //       Access: Published
00727 //  Description: Looks up the current value of the indicated field by
00728 //               calling the appropriate get*() function, then packs
00729 //               that value into the packer.  This field is
00730 //               presumably either a required field or a specified
00731 //               optional field, and we are building up a datagram for
00732 //               the generate-with-required message.
00733 //
00734 //               Returns true on success, false on failure.
00735 ////////////////////////////////////////////////////////////////////
00736 bool DCClass::
00737 pack_required_field(DCPacker &packer, PyObject *distobj, 
00738                     const DCField *field) const {
00739   const DCParameter *parameter = field->as_parameter();
00740   if (parameter != (DCParameter *)NULL) {
00741     // This is the easy case: to pack a parameter, we just look on the
00742     // class object for the data element.
00743     string field_name = field->get_name();
00744 
00745     if (!PyObject_HasAttrString(distobj, (char *)field_name.c_str())) {
00746       // If the attribute is not defined, but the field has a default
00747       // value specified, quietly pack the default value.
00748       if (field->has_default_value()) {
00749         packer.pack_default_value();
00750         return true;
00751       }
00752 
00753       // If there is no default value specified, it's an error.
00754       ostringstream strm;
00755       strm << "Data element " << field_name
00756            << ", required by dc file for dclass " << get_name()
00757            << ", not defined on object";
00758       nassert_raise(strm.str());
00759       return false;
00760     }
00761     PyObject *result = 
00762       PyObject_GetAttrString(distobj, (char *)field_name.c_str());
00763     nassertr(result != (PyObject *)NULL, false);
00764 
00765     // Now pack the value into the datagram.
00766     bool pack_ok = parameter->pack_args(packer, result);
00767     Py_DECREF(result);
00768     
00769     return pack_ok;
00770   }
00771 
00772   if (field->as_molecular_field() != (DCMolecularField *)NULL) {
00773     ostringstream strm;
00774     strm << "Cannot pack molecular field " << field->get_name()
00775          << " for generate";
00776     nassert_raise(strm.str());
00777     return false;
00778   }
00779 
00780   const DCAtomicField *atom = field->as_atomic_field();
00781   nassertr(atom != (DCAtomicField *)NULL, false);
00782 
00783   // We need to get the initial value of this field.  There isn't a
00784   // good, robust way to get this; presently, we just mangle the
00785   // "setFoo()" name of the required field into "getFoo()" and call
00786   // that.
00787   string setter_name = atom->get_name();
00788 
00789   if (setter_name.empty()) {
00790     ostringstream strm;
00791     strm << "Required field is unnamed!";
00792     nassert_raise(strm.str());
00793     return false;
00794   }
00795 
00796   if (atom->get_num_elements() == 0) {
00797     // It sure doesn't make sense to have a required field with no
00798     // parameters.  What data, exactly, is required?
00799     ostringstream strm;
00800     strm << "Required field " << setter_name << " has no parameters!";
00801     nassert_raise(strm.str());
00802     return false;
00803   }
00804   
00805   string getter_name = setter_name;
00806   if (setter_name.substr(0, 3) == "set") {
00807     // If the original method started with "set", we mangle this
00808     // directly to "get".
00809     getter_name[0] = 'g';
00810 
00811   } else {
00812     // Otherwise, we add a "get" prefix, and capitalize the next
00813     // letter.
00814     getter_name = "get" + setter_name;
00815     getter_name[3] = toupper(getter_name[3]);
00816   }
00817   
00818   // Now we have to look up the getter on the distributed object
00819   // and call it.
00820   if (!PyObject_HasAttrString(distobj, (char *)getter_name.c_str())) {
00821     // As above, if there's no getter but the field has a default
00822     // value specified, quietly pack the default value.
00823     if (field->has_default_value()) {
00824       packer.pack_default_value();
00825       return true;
00826     }
00827 
00828     // Otherwise, with no default value it's an error.
00829     ostringstream strm;
00830     strm << "Distributed class " << get_name()
00831          << " doesn't have getter named " << getter_name
00832          << " to match required field " << setter_name;
00833     nassert_raise(strm.str());
00834     return false;
00835   }
00836   PyObject *func = 
00837     PyObject_GetAttrString(distobj, (char *)getter_name.c_str());
00838   nassertr(func != (PyObject *)NULL, false);
00839   
00840   PyObject *empty_args = PyTuple_New(0);
00841   PyObject *result = PyObject_CallObject(func, empty_args);
00842   Py_DECREF(empty_args);
00843   Py_DECREF(func);
00844   if (result == (PyObject *)NULL) {
00845     // We don't set this as an exception, since presumably the Python
00846     // method itself has already triggered a Python exception.
00847     cerr << "Error when calling " << getter_name << "\n";
00848     return false;
00849   }
00850   
00851   if (atom->get_num_elements() == 1) {
00852     // In this case, we expect the getter to return one object,
00853     // which we wrap up in a tuple.
00854     PyObject *tuple = PyTuple_New(1);
00855     PyTuple_SET_ITEM(tuple, 0, result);
00856     result = tuple;
00857 
00858   } else {
00859     // Otherwise, it had better already be a sequence or tuple of some
00860     // sort.
00861     if (!PySequence_Check(result)) {
00862       ostringstream strm;
00863       strm << "Since dclass " << get_name() << " method " << setter_name
00864            << " is declared to have multiple parameters, Python function " 
00865            << getter_name << " must return a list or tuple.\n";
00866       nassert_raise(strm.str());
00867       return false;
00868     }
00869   }
00870   
00871   // Now pack the arguments into the datagram.
00872   bool pack_ok = atom->pack_args(packer, result);
00873   Py_DECREF(result);
00874 
00875   return pack_ok;
00876 }
00877 #endif  // HAVE_PYTHON
00878 
00879 #ifdef HAVE_PYTHON
00880 ////////////////////////////////////////////////////////////////////
00881 //     Function: DCClass::client_format_update
00882 //       Access: Published
00883 //  Description: Generates a datagram containing the message necessary
00884 //               to send an update for the indicated distributed
00885 //               object from the client.
00886 ////////////////////////////////////////////////////////////////////
00887 Datagram DCClass::
00888 client_format_update(const string &field_name, DOID_TYPE do_id, 
00889                      PyObject *args) const {
00890   DCField *field = get_field_by_name(field_name);
00891   if (field == (DCField *)NULL) {
00892     ostringstream strm;
00893     strm << "No field named " << field_name << " in class " << get_name()
00894          << "\n";
00895     nassert_raise(strm.str());
00896     return Datagram();
00897   }
00898 
00899   return field->client_format_update(do_id, args);
00900 }
00901 #endif  // HAVE_PYTHON
00902 
00903 #ifdef HAVE_PYTHON
00904 ////////////////////////////////////////////////////////////////////
00905 //     Function: DCClass::ai_format_update
00906 //       Access: Published
00907 //  Description: Generates a datagram containing the message necessary
00908 //               to send an update for the indicated distributed
00909 //               object from the AI.
00910 ////////////////////////////////////////////////////////////////////
00911 Datagram DCClass::
00912 ai_format_update(const string &field_name, DOID_TYPE do_id, 
00913                  CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, PyObject *args) const {
00914   DCField *field = get_field_by_name(field_name);
00915   if (field == (DCField *)NULL) {
00916     ostringstream strm;
00917     strm << "No field named " << field_name << " in class " << get_name()
00918          << "\n";
00919     nassert_raise(strm.str());
00920     return Datagram();
00921   }
00922 
00923   return field->ai_format_update(do_id, to_id, from_id, args);
00924 }
00925 #endif  // HAVE_PYTHON
00926 
00927 #ifdef HAVE_PYTHON
00928 ////////////////////////////////////////////////////////////////////
00929 //     Function: DCClass::ai_format_update_msg_type
00930 //       Access: Published
00931 //  Description: Generates a datagram containing the message necessary
00932 //               to send an update, using the indicated msg type
00933 //               for the indicated distributed
00934 //               object from the AI.
00935 ////////////////////////////////////////////////////////////////////
00936 Datagram DCClass::
00937 ai_format_update_msg_type(const string &field_name, DOID_TYPE do_id, 
00938                  CHANNEL_TYPE to_id, CHANNEL_TYPE from_id, int msg_type, PyObject *args) const {
00939   DCField *field = get_field_by_name(field_name);
00940   if (field == (DCField *)NULL) {
00941     ostringstream strm;
00942     strm << "No field named " << field_name << " in class " << get_name()
00943          << "\n";
00944     nassert_raise(strm.str());
00945     return Datagram();
00946   }
00947 
00948   return field->ai_format_update_msg_type(do_id, to_id, from_id, msg_type, args);
00949 }
00950 #endif  // HAVE_PYTHON
00951 
00952 #ifdef HAVE_PYTHON
00953 ////////////////////////////////////////////////////////////////////
00954 //     Function: DCClass::client_format_generate_CMU
00955 //       Access: Published
00956 //  Description: Generates a datagram containing the message necessary
00957 //               to generate a new distributed object from the client.
00958 //               This requires querying the object for the initial
00959 //               value of its required fields.
00960 //
00961 //               optional_fields is a list of fieldNames to generate
00962 //               in addition to the normal required fields.
00963 //
00964 //               This method is only called by the CMU implementation.
00965 ////////////////////////////////////////////////////////////////////
00966 Datagram DCClass::
00967 client_format_generate_CMU(PyObject *distobj, DOID_TYPE do_id, 
00968                            ZONEID_TYPE zone_id,
00969                            PyObject *optional_fields) const {
00970   DCPacker packer;
00971 
00972   packer.raw_pack_uint16(CLIENT_OBJECT_GENERATE_CMU);
00973 
00974   packer.raw_pack_uint32(zone_id);
00975   packer.raw_pack_uint16(_number);
00976   packer.raw_pack_uint32(do_id);
00977 
00978   // Specify all of the required fields.
00979   int num_fields = get_num_inherited_fields();
00980   for (int i = 0; i < num_fields; ++i) {
00981     DCField *field = get_inherited_field(i);
00982     if (field->is_required() && field->as_molecular_field() == NULL) {
00983       packer.begin_pack(field);
00984       if (!pack_required_field(packer, distobj, field)) {
00985         return Datagram();
00986       }
00987       packer.end_pack();
00988     }
00989   }
00990 
00991   // Also specify the optional fields.
00992   int num_optional_fields = 0;
00993   if (PyObject_IsTrue(optional_fields)) {
00994     num_optional_fields = PySequence_Size(optional_fields);
00995   }
00996   packer.raw_pack_uint16(num_optional_fields);
00997 
00998   for (int i = 0; i < num_optional_fields; i++) {
00999     PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
01000     string field_name = PyString_AsString(py_field_name);
01001     Py_XDECREF(py_field_name);
01002     
01003     DCField *field = get_field_by_name(field_name);
01004     if (field == (DCField *)NULL) {
01005       ostringstream strm;
01006       strm << "No field named " << field_name << " in class " << get_name()
01007            << "\n";
01008       nassert_raise(strm.str());
01009       return Datagram();
01010     }
01011     packer.raw_pack_uint16(field->get_number());
01012     packer.begin_pack(field);
01013     if (!pack_required_field(packer, distobj, field)) {
01014       return Datagram();
01015     }
01016     packer.end_pack();
01017   }
01018 
01019   return Datagram(packer.get_data(), packer.get_length());
01020 }
01021 #endif  // HAVE_PYTHON
01022 
01023 #ifdef HAVE_PYTHON
01024 ////////////////////////////////////////////////////////////////////
01025 //     Function: DCClass::ai_format_generate
01026 //       Access: Published
01027 //  Description: Generates a datagram containing the message necessary
01028 //               to generate a new distributed object from the AI.
01029 //               This requires querying the object for the initial
01030 //               value of its required fields.
01031 //
01032 //               optional_fields is a list of fieldNames to generate
01033 //               in addition to the normal required fields.
01034 ////////////////////////////////////////////////////////////////////
01035 Datagram DCClass::
01036 ai_format_generate(PyObject *distobj, DOID_TYPE do_id, 
01037                    DOID_TYPE parent_id, ZONEID_TYPE zone_id,
01038                    CHANNEL_TYPE district_channel_id, CHANNEL_TYPE from_channel_id,
01039                    PyObject *optional_fields) const {
01040   DCPacker packer;
01041 
01042   packer.raw_pack_uint8(1);
01043   packer.RAW_PACK_CHANNEL(district_channel_id);
01044   packer.RAW_PACK_CHANNEL(from_channel_id);
01045     //packer.raw_pack_uint8('A');
01046 
01047   bool has_optional_fields = (PyObject_IsTrue(optional_fields) != 0);
01048 
01049   if (has_optional_fields) {
01050     packer.raw_pack_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED_OTHER);
01051   } else {
01052     packer.raw_pack_uint16(STATESERVER_OBJECT_GENERATE_WITH_REQUIRED);
01053   }
01054   
01055   // Parent is a bit overloaded; this parent is not about inheritance,
01056   // this one is about the visibility container parent, i.e. the zone
01057   // parent:
01058   if (parent_id) {
01059     packer.raw_pack_uint32(parent_id);
01060   }
01061   packer.raw_pack_uint32(zone_id);
01062   packer.raw_pack_uint16(_number);
01063   packer.raw_pack_uint32(do_id);
01064 
01065   // Specify all of the required fields.
01066   int num_fields = get_num_inherited_fields();
01067   for (int i = 0; i < num_fields; ++i) {
01068     DCField *field = get_inherited_field(i);
01069     if (field->is_required() && field->as_molecular_field() == NULL) {
01070       packer.begin_pack(field);
01071       if (!pack_required_field(packer, distobj, field)) {
01072         return Datagram();
01073       }
01074       packer.end_pack();
01075     }
01076   }
01077 
01078   // Also specify the optional fields.
01079   if (has_optional_fields) {
01080     int num_optional_fields = PySequence_Size(optional_fields);
01081     packer.raw_pack_uint16(num_optional_fields);
01082 
01083     for (int i = 0; i < num_optional_fields; ++i) {
01084       PyObject *py_field_name = PySequence_GetItem(optional_fields, i);
01085       string field_name = PyString_AsString(py_field_name);
01086       Py_XDECREF(py_field_name);
01087 
01088       DCField *field = get_field_by_name(field_name);
01089       if (field == (DCField *)NULL) {
01090         ostringstream strm;
01091         strm << "No field named " << field_name << " in class " << get_name()
01092              << "\n";
01093         nassert_raise(strm.str());
01094         return Datagram();
01095       }
01096 
01097       packer.raw_pack_uint16(field->get_number());
01098 
01099       packer.begin_pack(field);
01100       if (!pack_required_field(packer, distobj, field)) {
01101         return Datagram();
01102       }
01103       packer.end_pack();
01104     }
01105   }
01106 
01107   return Datagram(packer.get_data(), packer.get_length());
01108 }
01109 #endif  // HAVE_PYTHON
01110 #ifdef HAVE_PYTHON
01111 ////////////////////////////////////////////////////////////////////
01112 //     Function: DCClass::ai_database_generate_context
01113 //       Access: Published
01114 //  Description: Generates a datagram containing the message necessary
01115 //               to create a new database distributed object from the AI.
01116 //
01117 //               First Pass is to only incldue required values
01118 //               (with Defaults).                   
01119 ////////////////////////////////////////////////////////////////////
01120 Datagram DCClass::
01121 ai_database_generate_context(
01122     unsigned int context_id, DOID_TYPE parent_id, ZONEID_TYPE zone_id,
01123     CHANNEL_TYPE owner_channel,
01124     CHANNEL_TYPE database_server_id, CHANNEL_TYPE from_channel_id) const 
01125 {
01126   DCPacker packer;
01127   packer.raw_pack_uint8(1);
01128   packer.RAW_PACK_CHANNEL(database_server_id);
01129   packer.RAW_PACK_CHANNEL(from_channel_id);
01130   //packer.raw_pack_uint8('A');
01131   packer.raw_pack_uint16(STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT);
01132   packer.raw_pack_uint32(parent_id);  
01133   packer.raw_pack_uint32(zone_id);
01134   packer.RAW_PACK_CHANNEL(owner_channel);
01135   packer.raw_pack_uint16(_number); // DCD class ID
01136   packer.raw_pack_uint32(context_id);
01137 
01138   // Specify all of the required fields.
01139   int num_fields = get_num_inherited_fields();
01140   for (int i = 0; i < num_fields; ++i) {
01141     DCField *field = get_inherited_field(i);
01142     if (field->is_required() && field->as_molecular_field() == NULL) {
01143       packer.begin_pack(field);
01144       packer.pack_default_value();
01145       packer.end_pack();
01146     }
01147   }
01148 
01149   return Datagram(packer.get_data(), packer.get_length());
01150 }
01151 #endif  // HAVE_PYTHON
01152 
01153 #ifdef HAVE_PYTHON
01154 // TODO: remove this once Skyler has things working with the new server
01155 ////////////////////////////////////////////////////////////////////
01156 //     Function: DCClass::ai_database_generate_context_old
01157 //       Access: Published
01158 //  Description: Generates a datagram containing the message necessary
01159 //               to create a new database distributed object from the AI.
01160 //
01161 //               First Pass is to only incldue required values
01162 //               (with Defaults).                   
01163 ////////////////////////////////////////////////////////////////////
01164 Datagram DCClass::
01165 ai_database_generate_context_old(
01166     unsigned int context_id, DOID_TYPE parent_id, ZONEID_TYPE zone_id,
01167     CHANNEL_TYPE database_server_id, CHANNEL_TYPE from_channel_id) const 
01168 {
01169   DCPacker packer;
01170   packer.raw_pack_uint8(1);
01171   packer.RAW_PACK_CHANNEL(database_server_id);
01172   packer.RAW_PACK_CHANNEL(from_channel_id);
01173   //packer.raw_pack_uint8('A');
01174   packer.raw_pack_uint16(STATESERVER_OBJECT_CREATE_WITH_REQUIRED_CONTEXT);
01175   packer.raw_pack_uint32(parent_id);  
01176   packer.raw_pack_uint32(zone_id);
01177   packer.raw_pack_uint16(_number); // DCD class ID
01178   packer.raw_pack_uint32(context_id);
01179 
01180   // Specify all of the required fields.
01181   int num_fields = get_num_inherited_fields();
01182   for (int i = 0; i < num_fields; ++i) {
01183     DCField *field = get_inherited_field(i);
01184     if (field->is_required() && field->as_molecular_field() == NULL) {
01185       packer.begin_pack(field);
01186       packer.pack_default_value();
01187       packer.end_pack();
01188     }
01189   }
01190 
01191   return Datagram(packer.get_data(), packer.get_length());
01192 }
01193 #endif  // HAVE_PYTHON
01194 
01195 ////////////////////////////////////////////////////////////////////
01196 //     Function : DCClass::output
01197 //       Access : Public, Virtual
01198 //  Description : Write a string representation of this instance to
01199 //                <out>.
01200 ////////////////////////////////////////////////////////////////////
01201 void DCClass::
01202 output(ostream &out, bool brief) const {
01203   output_instance(out, brief, "", "", "");
01204 }
01205 
01206 ////////////////////////////////////////////////////////////////////
01207 //     Function: DCClass::write
01208 //       Access: Public, Virtual
01209 //  Description: Generates a parseable description of the object to
01210 //               the indicated output stream.
01211 ////////////////////////////////////////////////////////////////////
01212 void DCClass::
01213 write(ostream &out, bool brief, int indent_level) const {
01214   indent(out, indent_level);
01215   if (_is_struct) {
01216     out << "struct";
01217   } else {
01218     out << "dclass";
01219   }
01220   if (!_name.empty()) {
01221     out << " " << _name;
01222   }
01223 
01224   if (!_parents.empty()) {
01225     Parents::const_iterator pi = _parents.begin();
01226     out << " : " << (*pi)->_name;
01227     ++pi;
01228     while (pi != _parents.end()) {
01229       out << ", " << (*pi)->_name;
01230       ++pi;
01231     }
01232   }
01233 
01234   out << " {";
01235   if (!brief && _number >= 0) {
01236     out << "  // index " << _number;
01237   }
01238   out << "\n";
01239 
01240   if (_constructor != (DCField *)NULL) {
01241     _constructor->write(out, brief, indent_level + 2);
01242   }
01243 
01244   Fields::const_iterator fi;
01245   for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
01246     if (!(*fi)->is_bogus_field()) {
01247       (*fi)->write(out, brief, indent_level + 2);
01248 
01249       /*
01250       if (true || (*fi)->has_default_value()) {
01251         indent(out, indent_level + 2) << "// = ";
01252         DCPacker packer;
01253         packer.set_unpack_data((*fi)->get_default_value());
01254         packer.begin_unpack(*fi);
01255         packer.unpack_and_format(out, false);
01256         if (!packer.end_unpack()) {
01257           out << "<error>";
01258         }
01259         out << "\n";
01260       }
01261       */
01262     }
01263   }
01264 
01265   indent(out, indent_level) << "};\n";
01266 }
01267 
01268 ////////////////////////////////////////////////////////////////////
01269 //     Function: DCClass::output_instance
01270 //       Access: Public
01271 //  Description: Generates a parseable description of the object to
01272 //               the indicated output stream.
01273 ////////////////////////////////////////////////////////////////////
01274 void DCClass::
01275 output_instance(ostream &out, bool brief, const string &prename, 
01276                 const string &name, const string &postname) const {
01277   if (_is_struct) {
01278     out << "struct";
01279   } else {
01280     out << "dclass";
01281   }
01282   if (!_name.empty()) {
01283     out << " " << _name;
01284   }
01285 
01286   if (!_parents.empty()) {
01287     Parents::const_iterator pi = _parents.begin();
01288     out << " : " << (*pi)->_name;
01289     ++pi;
01290     while (pi != _parents.end()) {
01291       out << ", " << (*pi)->_name;
01292       ++pi;
01293     }
01294   }
01295 
01296   out << " {";
01297 
01298   if (_constructor != (DCField *)NULL) {
01299     _constructor->output(out, brief);
01300     out << "; ";
01301   }
01302 
01303   Fields::const_iterator fi;
01304   for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
01305     if (!(*fi)->is_bogus_field()) {
01306       (*fi)->output(out, brief);
01307       out << "; ";
01308     }
01309   }
01310 
01311   out << "}";
01312   if (!prename.empty() || !name.empty() || !postname.empty()) {
01313     out << " " << prename << name << postname;
01314   }
01315 }
01316 
01317 ////////////////////////////////////////////////////////////////////
01318 //     Function: DCClass::generate_hash
01319 //       Access: Public, Virtual
01320 //  Description: Accumulates the properties of this class into the
01321 //               hash.
01322 ////////////////////////////////////////////////////////////////////
01323 void DCClass::
01324 generate_hash(HashGenerator &hashgen) const {
01325   hashgen.add_string(_name);
01326 
01327   if (is_struct()) {
01328     hashgen.add_int(1);
01329   }
01330 
01331   hashgen.add_int(_parents.size());
01332   Parents::const_iterator pi;
01333   for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
01334     hashgen.add_int((*pi)->get_number());
01335   }
01336 
01337   if (_constructor != (DCField *)NULL) {
01338     _constructor->generate_hash(hashgen);
01339   }
01340 
01341   hashgen.add_int(_fields.size());
01342   Fields::const_iterator fi;
01343   for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
01344     (*fi)->generate_hash(hashgen);
01345   }
01346 }
01347 
01348 ////////////////////////////////////////////////////////////////////
01349 //     Function: DCClass::clear_inherited_fields
01350 //       Access: Public
01351 //  Description: Empties the list of inherited fields for the class,
01352 //               so that it may be rebuilt.  This is normally only
01353 //               called by DCFile::rebuild_inherited_fields().
01354 ////////////////////////////////////////////////////////////////////
01355 void DCClass::
01356 clear_inherited_fields() {
01357   _inherited_fields.clear();
01358 }
01359 
01360 ////////////////////////////////////////////////////////////////////
01361 //     Function: DCClass::rebuild_inherited_fields
01362 //       Access: Public
01363 //  Description: Recomputes the list of inherited fields for the class.
01364 ////////////////////////////////////////////////////////////////////
01365 void DCClass::
01366 rebuild_inherited_fields() {
01367   typedef pset<string> Names;
01368   Names names;
01369 
01370   _inherited_fields.clear();
01371   
01372   // First, all of the inherited fields from our parent are at the top
01373   // of the list.
01374   Parents::const_iterator pi;
01375   for (pi = _parents.begin(); pi != _parents.end(); ++pi) {
01376     const DCClass *parent = (*pi);
01377     int num_inherited_fields = parent->get_num_inherited_fields();
01378     for (int i = 0; i < num_inherited_fields; ++i) {
01379       DCField *field = parent->get_inherited_field(i);
01380       if (field->get_name().empty()) {
01381         // Unnamed fields are always inherited.  Except in the hack case.
01382         if (!dc_sort_inheritance_by_file) {
01383           _inherited_fields.push_back(field);
01384         }
01385 
01386       } else {
01387         bool inserted = names.insert(field->get_name()).second;
01388         if (inserted) {
01389           // The earlier parent shadows the later parent.
01390           _inherited_fields.push_back(field);
01391         }
01392       }
01393     }
01394   }
01395 
01396   // Now add the local fields at the end of the list.  If any fields
01397   // in this list were already defined by a parent, we will shadow the
01398   // parent definition (that is, remove the parent's field from our
01399   // list of inherited fields).
01400   Fields::const_iterator fi;
01401   for (fi = _fields.begin(); fi != _fields.end(); ++fi) {
01402     DCField *field = (*fi);
01403     if (field->get_name().empty()) {
01404       // Unnamed fields are always added. 
01405      _inherited_fields.push_back(field);
01406 
01407     } else {
01408       bool inserted = names.insert(field->get_name()).second;
01409       if (!inserted) {
01410         // This local field shadows an inherited field.  Remove the
01411         // parent's field from our list.
01412         shadow_inherited_field(field->get_name());
01413       }
01414 
01415       // Now add the local field.
01416       _inherited_fields.push_back(field);
01417     }
01418   }
01419 
01420   if (dc_sort_inheritance_by_file) {
01421     // Temporary hack.
01422     sort(_inherited_fields.begin(), _inherited_fields.end(), SortFieldsByIndex());
01423   }
01424 }
01425 
01426 ////////////////////////////////////////////////////////////////////
01427 //     Function: DCClass::shadow_inherited_field
01428 //       Access: Private
01429 //  Description: This is called only by rebuild_inherited_fields().
01430 //               It removes the named field from the list of
01431 //               _inherited_fields, presumably in preparation for
01432 //               adding a new definition below.
01433 ////////////////////////////////////////////////////////////////////
01434 void DCClass::
01435 shadow_inherited_field(const string &name) {
01436   Fields::iterator fi;
01437   for (fi = _inherited_fields.begin(); fi != _inherited_fields.end(); ++fi) {
01438     DCField *field = (*fi);
01439     if (field->get_name() == name) {
01440       _inherited_fields.erase(fi);
01441       return;
01442     }
01443   }
01444 
01445   // If we get here, the named field wasn't in the list.  Huh.
01446   nassertv(false);
01447 }
01448 
01449 ////////////////////////////////////////////////////////////////////
01450 //     Function: DCClass::add_field
01451 //       Access: Public
01452 //  Description: Adds the newly-allocated field to the class.  The
01453 //               class becomes the owner of the pointer and will
01454 //               delete it when it destructs.  Returns true if the
01455 //               field is successfully added, or false if there was a
01456 //               name conflict or some other problem.
01457 ////////////////////////////////////////////////////////////////////
01458 bool DCClass::
01459 add_field(DCField *field) {
01460   nassertr(field->get_class() == this || field->get_class() == NULL, false);
01461   field->set_class(this);
01462   if (_dc_file != (DCFile *)NULL) {
01463     _dc_file->mark_inherited_fields_stale();
01464   }
01465 
01466   if (!field->get_name().empty()) {
01467     if (field->get_name() == _name) {
01468       // This field is a constructor.
01469       if (_constructor != (DCField *)NULL) {
01470         // We already have a constructor.
01471         return false;
01472       }
01473       if (field->as_atomic_field() == (DCAtomicField *)NULL) {
01474         // The constructor must be an atomic field.
01475         return false;
01476       }
01477       _constructor = field;
01478       _fields_by_name.insert
01479         (FieldsByName::value_type(field->get_name(), field));
01480       return true;
01481     }
01482 
01483     bool inserted = _fields_by_name.insert
01484       (FieldsByName::value_type(field->get_name(), field)).second;
01485 
01486     if (!inserted) {
01487       return false;
01488     }
01489   }
01490 
01491   if (_dc_file != (DCFile *)NULL && 
01492       ((dc_virtual_inheritance && dc_sort_inheritance_by_file) || !is_struct())) {
01493     if (dc_multiple_inheritance) {
01494       _dc_file->set_new_index_number(field);
01495     } else {
01496       field->set_number(get_num_inherited_fields());
01497     }
01498 
01499     bool inserted = _fields_by_index.insert
01500       (FieldsByIndex::value_type(field->get_number(), field)).second;
01501 
01502     // It shouldn't be possible for that to fail.
01503     nassertr(inserted, false);
01504   }
01505 
01506   _fields.push_back(field);
01507   return true;
01508 }
01509 
01510 ////////////////////////////////////////////////////////////////////
01511 //     Function: DCClass::add_parent
01512 //       Access: Public
01513 //  Description: Adds a new parent to the inheritance hierarchy of the
01514 //               class.  This is normally called only during parsing.
01515 ////////////////////////////////////////////////////////////////////
01516 void DCClass::
01517 add_parent(DCClass *parent) {
01518   _parents.push_back(parent);
01519   _dc_file->mark_inherited_fields_stale();
01520 }
01521 
01522 ////////////////////////////////////////////////////////////////////
01523 //     Function: DCClass::set_number
01524 //       Access: Public
01525 //  Description: Assigns the unique number to this class.  This is
01526 //               normally called only by the DCFile interface as the
01527 //               class is added.
01528 ////////////////////////////////////////////////////////////////////
01529 void DCClass::
01530 set_number(int number) {
01531   _number = number;
01532 }
01533 
 All Classes Functions Variables Enumerations