//----------------------------------------------------------------------------- // Copyright (c) 2013 GarageGames, LLC // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- #include "console/console.h" #include "sim/simBase.h" #include "io/bitStream.h" #include "io/fileStream.h" #include "io/resource/resourceManager.h" ////////////////////////////////////////////////////////////////////////// // SimObject Methods ////////////////////////////////////////////////////////////////////////// bool SimObject::writeObject(Stream *stream) { clearFieldFilters(); buildFilterList(); stream->writeString(getName() ? getName() : ""); // Static fields AbstractClassRep *rep = getClassRep(); AbstractClassRep::FieldList &fieldList = rep->mFieldList; AbstractClassRep::FieldList::iterator itr; U32 savePos = stream->getPosition(); U32 numFields = fieldList.size(); stream->write(numFields); for(itr = fieldList.begin();itr != fieldList.end();itr++) { if(itr->type >= AbstractClassRep::StartGroupFieldType || isFiltered(itr->pFieldname)) { numFields--; continue; } const char *field = getDataField(itr->pFieldname, NULL); if(field == NULL) field = ""; stream->writeString(itr->pFieldname); stream->writeString(field); } // Dynamic Fields if(mCanSaveFieldDictionary) { SimFieldDictionary * fieldDictionary = getFieldDictionary(); for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr) { SimFieldDictionary::Entry * entry = (*ditr); if(isFiltered(entry->slotName)) continue; stream->writeString(entry->slotName); stream->writeString(entry->value); numFields++; } } // Overwrite the number of fields with the correct value U32 savePos2 = stream->getPosition(); stream->setPosition(savePos); stream->write(numFields); stream->setPosition(savePos2); return true; } bool SimObject::readObject(Stream *stream) { const char *name = stream->readSTString(true); if(name && *name) assignName(name); U32 numFields; stream->read(&numFields); for(U32 i = 0;i < numFields;i++) { const char *fieldName = stream->readSTString(); const char *data = stream->readSTString(); setDataField(fieldName, NULL, data); } return true; } ////////////////////////////////////////////////////////////////////////// void SimObject::buildFilterList() { Con::executef(this, 1, "buildFilterList"); } ////////////////////////////////////////////////////////////////////////// void SimObject::addFieldFilter( const char *fieldName ) { StringTableEntry st = StringTable->insert(fieldName); for(S32 i = 0;i < mFieldFilter.size();i++) { if(mFieldFilter[i] == st) return; } mFieldFilter.push_back(st); } void SimObject::removeFieldFilter( const char *fieldName ) { StringTableEntry st = StringTable->insert(fieldName); for(S32 i = 0;i < mFieldFilter.size();i++) { if(mFieldFilter[i] == st) { mFieldFilter.erase(i); return; } } } void SimObject::clearFieldFilters() { mFieldFilter.clear(); } ////////////////////////////////////////////////////////////////////////// bool SimObject::isFiltered( const char *fieldName ) { StringTableEntry st = StringTable->insert(fieldName); for(S32 i = 0;i < mFieldFilter.size();i++) { if(mFieldFilter[i] == st) return true; } return false; } ////////////////////////////////////////////////////////////////////////// // SimSet Methods ////////////////////////////////////////////////////////////////////////// bool SimSet::writeObject( Stream *stream ) { if(! Parent::writeObject(stream)) return false; stream->write(size()); for(SimSet::iterator i = begin();i < end();++i) { if(! Sim::saveObject((*i), stream)) return false; } return true; } bool SimSet::readObject( Stream *stream ) { if(! Parent::readObject(stream)) return false; U32 numObj; stream->read(&numObj); for(U32 i = 0;i < numObj;i++) { SimObject *obj = Sim::loadObjectStream(stream); if(obj == NULL) return false; addObject(obj); } return true; } ////////////////////////////////////////////////////////////////////////// // Sim Functions ////////////////////////////////////////////////////////////////////////// namespace Sim { bool saveObject(SimObject *obj, const char *filename) { FileStream fs; if(ResourceManager->openFileForWrite(fs, filename, FileStream::Write)) { bool ret = saveObject(obj, &fs); fs.close(); return ret; } return false; } bool saveObject(SimObject *obj, Stream *stream) { stream->writeString(obj->getClassName()); return obj->writeObject(stream); } ////////////////////////////////////////////////////////////////////////// SimObject *loadObjectStream(const char *filename) { Stream * stream = ResourceManager->openStream(filename); if (stream) { SimObject *ret = loadObjectStream(stream); ResourceManager->closeStream(stream); return ret; } return NULL; } SimObject *loadObjectStream(Stream *stream) { const char *className = stream->readSTString(true); ConsoleObject *conObj = ConsoleObject::create(className); if(conObj == NULL) { Con::errorf("Sim::restoreObjectStream - Could not create object of class \"%s\"", className); return NULL; } SimObject *simObj = dynamic_cast(conObj); if(simObj == NULL) { Con::errorf("Sim::restoreObjectStream - Object of class \"%s\" is not a SimObject", className); delete simObj; return NULL; } if(simObj->readObject(stream)) { simObj->registerObject(); return simObj; } delete simObj; return NULL; } } // end namespace Sim ////////////////////////////////////////////////////////////////////////// // Console Methods ////////////////////////////////////////////////////////////////////////// ConsoleMethod(SimObject, addFieldFilter, void, 3, 3, "(fieldName) Adds the given field filter to the list of table entries.\n" "@param fieldName The name of the field filter to add.\n" "@return No return value") { object->addFieldFilter(argv[2]); } ConsoleMethod(SimObject, removeFieldFilter, void, 3, 3, "(fieldName) Removes the specified field filter from the table\n" "@param fieldName The name of the field filter to remove.\n" "@return No return value.") { object->removeFieldFilter(argv[2]); } ////////////////////////////////////////////////////////////////////////// // Console Functions ////////////////////////////////////////////////////////////////////////// ConsoleFunction(saveObject, bool, 3, 3, "(object, filename) Saves the given object to the given filename\n" "@param object The SimObject to save\n" "@param filename The name of the file in which to save the object\n" "@return Returns true on success and flase on failure") { SimObject *obj = dynamic_cast(Sim::findObject(argv[1])); if(obj == NULL) return false; return Sim::saveObject(obj, argv[2]); } ConsoleFunction(loadObject, S32, 2, 2, "(filename) Loads an object from the specified filename\n" "@param filename The name of the file to load the object from\n" "@return Returns the ID of the object on success, or 0 on failure.") { SimObject *obj = Sim::loadObjectStream(argv[1]); return obj ? obj->getId() : 0; }