123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 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 "core/strings/stringUnit.h"
- #include "console/fieldBrushObject.h"
- #include "console/engineAPI.h"
- // Prefix added to dynamic-fields when they're used to store any copied static-fields when peristing.
- #define INTERNAL_FIELD_PREFIX "_fieldBrush_"
- // Size of return buffers used.
- const U32 bufferSizes = 1024 * 4;
- IMPLEMENT_CONOBJECT(FieldBrushObject);
- ConsoleDocClass( FieldBrushObject,
- "@brief For static-field copying/pasting, editor use only\n\n"
- "@internal"
- );
- FieldBrushObject::FieldBrushObject()
- {
- // Reset Description.
- mDescription = StringTable->EmptyString();
- mSortName = StringTable->EmptyString();
- }
- //-----------------------------------------------------------------------------
- // Persist Fields.
- //-----------------------------------------------------------------------------
- void FieldBrushObject::initPersistFields()
- {
- // Add Fields.
- addProtectedField("description", TypeCaseString, Offset(mDescription, FieldBrushObject), setDescription, defaultProtectedGetFn, "");
- addProtectedField("sortName", TypeString, Offset(mSortName, FieldBrushObject), setSortName, defaultProtectedGetFn, "");
- // Call Parent.
- Parent::initPersistFields();
- }
- //-----------------------------------------------------------------------------
- // Remove from Sim.
- //-----------------------------------------------------------------------------
- void FieldBrushObject::onRemove()
- {
- // Destroy any fields.
- destroyFields();
- // Call Parent.
- Parent::onRemove();
- }
- //-----------------------------------------------------------------------------
- // Destroy any fields.
- //-----------------------------------------------------------------------------
- void FieldBrushObject::destroyFields()
- {
- // Fetch Dynamic-Field Dictionary.
- SimFieldDictionary* pFieldDictionary = getFieldDictionary();
- // Any Field Dictionary?
- if ( pFieldDictionary == NULL )
- {
- // No, so we're done.
- return;
- }
- // Iterate fields.
- for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr )
- {
- // Fetch Field Entry.
- SimFieldDictionary::Entry* fieldEntry = *itr;
- // Internal Field?
- if ( dStrstr( fieldEntry->slotName, INTERNAL_FIELD_PREFIX ) == fieldEntry->slotName )
- {
- // Yes, so remove it.
- pFieldDictionary->setFieldValue( fieldEntry->slotName, "" );
- }
- }
- }
- //-----------------------------------------------------------------------------
- // Suppress Spaces.
- //-----------------------------------------------------------------------------
- static char replacebuf[1024];
- static char* suppressSpaces(const char* in_pname)
- {
- U32 i = 0;
- char chr;
- do
- {
- chr = in_pname[i];
- replacebuf[i++] = (chr != 32) ? chr : '_';
- } while(chr);
- return replacebuf;
- }
- //-----------------------------------------------------------------------------
- // Query Groups.
- //-----------------------------------------------------------------------------
- DefineEngineMethod(FieldBrushObject, queryGroups, const char*, (const char* simObjName), , "(simObject) Query available static-field groups for selected object./\n"
- "@param simObject Object to query static-field groups on.\n"
- "@return Space-seperated static-field group list.")
- {
- // Fetch selected object.
- SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
- // Valid object?
- if ( pSimObject == NULL )
- {
- // No, so warn.
- Con::warnf("FieldBrushObject::queryFieldGroups() - Invalid SimObject!");
- return NULL;
- }
- // Create Returnable Buffer.
- S32 maxBuffer = bufferSizes;
- char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
- char* pBuffer = pReturnBuffer;
- // Fetch Field List.
- const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
- // Iterate Fields.
- for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
- {
- // Fetch Field.
- const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
- // Start Group?
- if ( staticField.type == AbstractClassRep::StartGroupFieldType )
- {
- // Yes, so write-out group-name without spaces...
- char* pGroupNameNoSpaces = suppressSpaces(staticField.pGroupname);
- // Will the field fit?
- // NOTE:- We used "-1" to include the suffix space.
- if ( (maxBuffer - (S32)dStrlen(pGroupNameNoSpaces) - 1) >= 0 )
- {
- // Yes...
- // NOTE:- The group-name does not have the "_begingroup" suffix which should stay hidden.
- S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", pGroupNameNoSpaces );
- pBuffer += charsWritten;
- maxBuffer -= charsWritten;
- }
- else
- {
- // No, so warn.
- Con::warnf("FieldBrushObject::queryGroups() - Couldn't fit all groups into return string!");
- break;
- }
- }
- }
- // Strip final space.
- if ( pBuffer != pReturnBuffer )
- {
- *(pBuffer-1) = 0;
- }
- // Return Buffer.
- return pReturnBuffer;
- }
- //-----------------------------------------------------------------------------
- // Query Fields.
- //-----------------------------------------------------------------------------
- DefineEngineMethod(FieldBrushObject, queryFields, const char*, (const char* simObjName, const char* groupList), (""), "(simObject, [groupList]) Query available static-fields for selected object./\n"
- "@param simObject Object to query static-fields on.\n"
- "@param groupList groups to filter static-fields against.\n"
- "@return Space-seperated static-field list.")
- {
- // Fetch selected object.
- SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
- // Valid object?
- if ( pSimObject == NULL )
- {
- // No, so warn.
- Con::warnf("FieldBrushObject::queryFields() - Invalid SimObject!");
- return NULL;
- }
- // Create Returnable Buffer.
- S32 maxBuffer = bufferSizes;
- char* pReturnBuffer = Con::getReturnBuffer(bufferSizes);
- char* pBuffer = pReturnBuffer;
- // Fetch Field List.
- const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
- // Did we specify a groups list?
- if ( String::isEmpty(groupList) )
- {
- // No, so return all fields...
- // Iterate fields.
- for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
- {
- // Fetch Field.
- const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
- // Standard Field?
- if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
- staticField.type != AbstractClassRep::EndGroupFieldType &&
- staticField.type != AbstractClassRep::DeprecatedFieldType )
- {
- // Yes, so will the field fit?
- // NOTE:- We used "-1" to include the suffix space.
- if ( (maxBuffer - (S32)dStrlen(staticField.pFieldname) - 1) >= 0 )
- {
- // Yes, so write-out field-name.
- S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", staticField.pFieldname );
- pBuffer += charsWritten;
- maxBuffer -= charsWritten;
- }
- else
- {
- // No, so warn.
- Con::warnf("FieldBrushObject::queryFields() - Couldn't fit all fields into return string!");
- break;
- }
- }
- }
- // Strip final space.
- if ( pBuffer != pReturnBuffer )
- {
- *(pBuffer-1) = 0;
- }
- // Return field list.
- return pReturnBuffer;
- }
- // Yes, so filter by groups...
- // Group List.
- Vector<StringTableEntry> groups;
- // Yes, so fetch group list.
- // Yes, so calculate group Count.
- const U32 groupCount = StringUnit::getUnitCount( groupList, " \t\n" );
- char tempBuf[256];
- // Iterate groups...
- for ( U32 groupIndex = 0; groupIndex < groupCount; ++groupIndex )
- {
- // Copy string element.
- dStrcpy( tempBuf, StringUnit::getUnit( groupList, groupIndex, " \t\n" ), 256 );
- // Append internal name.
- dStrcat( tempBuf, "_begingroup", 256 );
- // Store Group.
- groups.push_back( StringTable->insert( tempBuf ) );
- }
- // Reset Valid Group.
- bool validGroup = false;
- // Iterate fields.
- for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
- {
- // Fetch Field.
- const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
- // Handle Group Type.
- switch( staticField.type )
- {
- // Start Group.
- case AbstractClassRep::StartGroupFieldType:
- {
- // Is this group valid?
- // Iterate groups...
- for ( U32 groupIndex = 0; groupIndex < groups.size(); ++groupIndex )
- {
- // Group selected?
- if ( groups[groupIndex] == staticField.pFieldname )
- {
- // Yes, so flag as valid.
- validGroup = true;
- break;
- }
- }
- } break;
- // End Group.
- case AbstractClassRep::EndGroupFieldType:
- {
- // Reset Valid Group.
- validGroup = false;
- } break;
- // Deprecated.
- case AbstractClassRep::DeprecatedFieldType:
- {
- } break;
- // Standard.
- default:
- {
- // Do we have a valid group?
- if ( validGroup )
- {
- // Yes, so will the field fit?
- // NOTE:- We used "-1" to include the suffix space.
- if ( (maxBuffer - (S32)dStrlen(staticField.pFieldname) - 1) >= 0 )
- {
- // Yes, so write-out field-name.
- S32 charsWritten = dSprintf( pBuffer, maxBuffer, "%s ", staticField.pFieldname );
- pBuffer += charsWritten;
- maxBuffer -= charsWritten;
- }
- else
- {
- // No, so warn.
- Con::warnf("FieldBrushObject::queryFields() - Couldn't fit all fields into return string!");
- // HACK: Easy way to finish iterating fields.
- fieldIndex = staticFields.size();
- break;
- }
- }
- } break;
- };
- }
- // Strip final space.
- if ( pBuffer != pReturnBuffer )
- {
- *(pBuffer-1) = 0;
- }
- // Return field list.
- return pReturnBuffer;
- }
- //-----------------------------------------------------------------------------
- // Copy Fields.
- //-----------------------------------------------------------------------------
- DefineEngineMethod(FieldBrushObject, copyFields, void, (const char* simObjName, const char* pFieldList), (""), "(simObject, [fieldList]) Copy selected static-fields for selected object./\n"
- "@param simObject Object to copy static-fields from.\n"
- "@param fieldList fields to filter static-fields against.\n"
- "@return No return value.")
- {
- // Fetch selected object.
- SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
- // Valid object?
- if ( pSimObject == NULL )
- {
- // No, so warn.
- Con::warnf("FieldBrushObject::copyFields() - Invalid SimObject!");
- return;
- }
- // Fetch field list.
-
- // Copy Fields.
- object->copyFields( pSimObject, pFieldList );
- }
- // Copy Fields.
- void FieldBrushObject::copyFields( SimObject* pSimObject, const char* fieldList )
- {
- // FieldBrushObject class?
- if ( String::compare(pSimObject->getClassName(), getClassName()) == 0 )
- {
- // Yes, so warn.
- Con::warnf("FieldBrushObject::copyFields() - Cannot copy FieldBrushObject objects!");
- return;
- }
- char tempBuf[bufferSizes];
- // Field List.
- Vector<StringTableEntry> fields;
- // Fetch valid field-list flag.
- bool validFieldList = ( fieldList != NULL );
- // Did we specify a fields list?
- if ( validFieldList )
- {
- // Yes, so calculate field Count.
- const U32 fieldCount = StringUnit::getUnitCount( fieldList, " \t\n" );
- // Iterate fields...
- for ( U32 fieldIndex = 0; fieldIndex < fieldCount; ++fieldIndex )
- {
- // Copy string element.
- dStrcpy( tempBuf, StringUnit::getUnit( fieldList, fieldIndex, " \t\n" ), bufferSizes );
- // Store field.
- fields.push_back( StringTable->insert( tempBuf ) );
- }
- }
- // Destroy Fields.
- destroyFields();
- // Fetch Field List.
- const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
- // Iterate fields.
- for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
- {
- // Fetch Field.
- const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
- // Standard Field?
- if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
- staticField.type != AbstractClassRep::EndGroupFieldType &&
- staticField.type != AbstractClassRep::DeprecatedFieldType )
- {
- // Set field-specified flag.
- bool fieldSpecified = !validFieldList;
- // Did we specify a fields list?
- if ( validFieldList )
- {
- // Yes, so is this field name selected?
- // Iterate fields...
- for ( U32 findFieldIDx = 0; findFieldIDx < fields.size(); ++findFieldIDx)
- {
- // Field selected?
- if ( staticField.pFieldname == fields[findFieldIDx] )
- {
- // Yes, so flag as such.
- fieldSpecified = true;
- break;
- }
- }
- }
- // Field specified?
- if ( fieldSpecified )
- {
- if ( staticField.elementCount <= 1 )
- {
- for( U32 fieldElement = 0; S32(fieldElement) < staticField.elementCount; ++fieldElement )
- {
- // Fetch Field Value.
- const char* fieldValue = (staticField.getDataFn)( pSimObject, Con::getData(staticField.type, (void *) (((const char *)pSimObject) + staticField.offset), fieldElement, staticField.table, staticField.flag) );
- // Field Value?
- if ( fieldValue )
- {
- // Yes.
- dSprintf( tempBuf, sizeof(tempBuf), INTERNAL_FIELD_PREFIX"%s", staticField.pFieldname );
- // Fetch Dynamic-Field Dictionary.
- SimFieldDictionary* pFieldDictionary = getFieldDictionary();
- // Set field value.
- if ( !pFieldDictionary )
- {
- setDataField( StringTable->insert( tempBuf ), NULL, fieldValue );
- }
- else
- {
- pFieldDictionary->setFieldValue( StringTable->insert( tempBuf ), fieldValue );
- }
- }
- }
- }
- }
- }
- }
- }
- //-----------------------------------------------------------------------------
- // Paste Fields.
- //-----------------------------------------------------------------------------
- DefineEngineMethod(FieldBrushObject, pasteFields, void, (const char* simObjName), , "(simObject) Paste copied static-fields to selected object./\n"
- "@param simObject Object to paste static-fields to.\n"
- "@return No return value.")
- {
- // Fetch selected object.
- SimObject* pSimObject = dynamic_cast<SimObject*>( Sim::findObject( simObjName ) );
- // Valid object?
- if ( pSimObject == NULL )
- {
- // No, so warn.
- Con::warnf("FieldBrushObject::pasteFields() - Invalid SimObject!");
- return;
- }
- // Paste Fields.
- object->pasteFields( pSimObject );
- }
- // Paste Fields.
- void FieldBrushObject::pasteFields( SimObject* pSimObject )
- {
- // FieldBrushObject class?
- if ( String::compare(pSimObject->getClassName(), getClassName()) == 0 )
- {
- // Yes, so warn.
- Con::warnf("FieldBrushObject::pasteFields() - Cannot paste FieldBrushObject objects!");
- return;
- }
- // Fetch Dynamic-Field Dictionary.
- SimFieldDictionary* pFieldDictionary = getFieldDictionary();
- // Any Field Dictionary?
- if ( pFieldDictionary == NULL )
- {
- // No, so we're done.
- return;
- }
- // Force modification of static-fields on target object!
- pSimObject->setModStaticFields( true );
- S32 prefixLength = dStrlen(INTERNAL_FIELD_PREFIX);
- // Iterate fields.
- for ( SimFieldDictionaryIterator itr(pFieldDictionary); *itr; ++itr )
- {
- // Fetch Field Entry.
- SimFieldDictionary::Entry* fieldEntry = *itr;
- // Internal Field?
- char* pInternalField = dStrstr( fieldEntry->slotName, INTERNAL_FIELD_PREFIX );
- if ( pInternalField == fieldEntry->slotName )
- {
- // Yes, so skip the prefix.
- pInternalField += prefixLength;
- // Is this a static-field on the target object?
- // NOTE:- We're doing this so we don't end-up creating a dynamic-field if it isn't present.
- // Fetch Field List.
- const AbstractClassRep::FieldList& staticFields = pSimObject->getFieldList();
- // Iterate fields.
- for( U32 fieldIndex = 0; fieldIndex < staticFields.size(); ++fieldIndex )
- {
- // Fetch Field.
- const AbstractClassRep::Field& staticField = staticFields[fieldIndex];
- // Standard Field?
- if ( staticField.type != AbstractClassRep::StartGroupFieldType &&
- staticField.type != AbstractClassRep::EndGroupFieldType &&
- staticField.type != AbstractClassRep::DeprecatedFieldType )
- {
- // Target field?
- if ( String::compare(staticField.pFieldname, pInternalField) == 0 )
- {
- // Yes, so set data.
- pSimObject->setDataField( staticField.pFieldname, NULL, fieldEntry->value );
- }
- }
- }
- }
- }
- }
|