00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00067
00068
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
00092
00093
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
00114
00115
00116
00117 DCClass *DCClass::
00118 as_class() {
00119 return this;
00120 }
00121
00122
00123
00124
00125
00126
00127 const DCClass *DCClass::
00128 as_class() const {
00129 return this;
00130 }
00131
00132
00133
00134
00135
00136
00137
00138 int DCClass::
00139 get_num_parents() const {
00140 return _parents.size();
00141 }
00142
00143
00144
00145
00146
00147
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
00157
00158
00159
00160
00161 bool DCClass::
00162 has_constructor() const {
00163 return (_constructor != (DCField *)NULL);
00164 }
00165
00166
00167
00168
00169
00170
00171
00172
00173 DCField *DCClass::
00174 get_constructor() const {
00175 return _constructor;
00176 }
00177
00178
00179
00180
00181
00182
00183
00184 int DCClass::
00185 get_num_fields() const {
00186 return _fields.size();
00187 }
00188
00189
00190
00191
00192
00193
00194
00195
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
00205 }
00206 #endif //]
00207 nassertr_always(n >= 0 && n < (int)_fields.size(), NULL);
00208 return _fields[n];
00209 }
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
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
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
00239 return (DCField *)NULL;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
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
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
00266 ((DCClass *)this)->_fields_by_index[index_number] = result;
00267 return result;
00268 }
00269 }
00270
00271
00272 return (DCField *)NULL;
00273 }
00274
00275
00276
00277
00278
00279
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
00291
00292
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
00309
00310
00311
00312
00313
00314
00315
00316
00317
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
00347
00348
00349
00350
00351
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
00371
00372
00373
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
00390
00391
00392
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
00403
00404
00405
00406
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
00419
00420
00421
00422
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
00439
00440
00441
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
00452
00453
00454
00455
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
00468
00469
00470
00471
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
00488
00489
00490
00491
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
00526
00527
00528
00529
00530
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
00562
00563
00564
00565
00566
00567
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
00590
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
00606
00607
00608
00609
00610
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
00642
00643
00644
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
00661
00662
00663
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
00682
00683
00684
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
00696
00697
00698
00699
00700
00701
00702
00703
00704
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
00726
00727
00728
00729
00730
00731
00732
00733
00734
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
00742
00743 string field_name = field->get_name();
00744
00745 if (!PyObject_HasAttrString(distobj, (char *)field_name.c_str())) {
00746
00747
00748 if (field->has_default_value()) {
00749 packer.pack_default_value();
00750 return true;
00751 }
00752
00753
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
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
00784
00785
00786
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
00798
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
00808
00809 getter_name[0] = 'g';
00810
00811 } else {
00812
00813
00814 getter_name = "get" + setter_name;
00815 getter_name[3] = toupper(getter_name[3]);
00816 }
00817
00818
00819
00820 if (!PyObject_HasAttrString(distobj, (char *)getter_name.c_str())) {
00821
00822
00823 if (field->has_default_value()) {
00824 packer.pack_default_value();
00825 return true;
00826 }
00827
00828
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
00846
00847 cerr << "Error when calling " << getter_name << "\n";
00848 return false;
00849 }
00850
00851 if (atom->get_num_elements() == 1) {
00852
00853
00854 PyObject *tuple = PyTuple_New(1);
00855 PyTuple_SET_ITEM(tuple, 0, result);
00856 result = tuple;
00857
00858 } else {
00859
00860
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
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
00882
00883
00884
00885
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
00906
00907
00908
00909
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
00930
00931
00932
00933
00934
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
00955
00956
00957
00958
00959
00960
00961
00962
00963
00964
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
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
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
01026
01027
01028
01029
01030
01031
01032
01033
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
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
01056
01057
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
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
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
01113
01114
01115
01116
01117
01118
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
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);
01136 packer.raw_pack_uint32(context_id);
01137
01138
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
01155
01156
01157
01158
01159
01160
01161
01162
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
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);
01178 packer.raw_pack_uint32(context_id);
01179
01180
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
01197
01198
01199
01200
01201 void DCClass::
01202 output(ostream &out, bool brief) const {
01203 output_instance(out, brief, "", "", "");
01204 }
01205
01206
01207
01208
01209
01210
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
01251
01252
01253
01254
01255
01256
01257
01258
01259
01260
01261
01262 }
01263 }
01264
01265 indent(out, indent_level) << "};\n";
01266 }
01267
01268
01269
01270
01271
01272
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
01319
01320
01321
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
01350
01351
01352
01353
01354
01355 void DCClass::
01356 clear_inherited_fields() {
01357 _inherited_fields.clear();
01358 }
01359
01360
01361
01362
01363
01364
01365 void DCClass::
01366 rebuild_inherited_fields() {
01367 typedef pset<string> Names;
01368 Names names;
01369
01370 _inherited_fields.clear();
01371
01372
01373
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
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
01390 _inherited_fields.push_back(field);
01391 }
01392 }
01393 }
01394 }
01395
01396
01397
01398
01399
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
01405 _inherited_fields.push_back(field);
01406
01407 } else {
01408 bool inserted = names.insert(field->get_name()).second;
01409 if (!inserted) {
01410
01411
01412 shadow_inherited_field(field->get_name());
01413 }
01414
01415
01416 _inherited_fields.push_back(field);
01417 }
01418 }
01419
01420 if (dc_sort_inheritance_by_file) {
01421
01422 sort(_inherited_fields.begin(), _inherited_fields.end(), SortFieldsByIndex());
01423 }
01424 }
01425
01426
01427
01428
01429
01430
01431
01432
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
01446 nassertv(false);
01447 }
01448
01449
01450
01451
01452
01453
01454
01455
01456
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
01469 if (_constructor != (DCField *)NULL) {
01470
01471 return false;
01472 }
01473 if (field->as_atomic_field() == (DCAtomicField *)NULL) {
01474
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
01503 nassertr(inserted, false);
01504 }
01505
01506 _fields.push_back(field);
01507 return true;
01508 }
01509
01510
01511
01512
01513
01514
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
01524
01525
01526
01527
01528
01529 void DCClass::
01530 set_number(int number) {
01531 _number = number;
01532 }
01533