Panda3D
|
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