Torque3D/Engine/source/console/simObjectMemento.cpp

158 lines
5.3 KiB
C++
Raw Normal View History

2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// 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 "platform/platform.h"
#include "console/simObjectMemento.h"
2023-04-23 08:39:54 +00:00
#include "script.h"
2012-09-19 15:15:01 +00:00
#include "console/simObject.h"
#include "console/simDatablock.h"
#include "core/stream/memStream.h"
SimObjectMemento::SimObjectMemento()
: mState( NULL ),
2017-01-12 04:34:46 +00:00
mIsDatablock( false )
2012-09-19 15:15:01 +00:00
{
}
SimObjectMemento::~SimObjectMemento()
{
dFree( mState );
}
void SimObjectMemento::save( SimObject *object )
{
// Cleanup any existing state data.
dFree( mState );
mObjectName = String::EmptyString;
2017-01-12 04:34:46 +00:00
// Use a stream to save the state.
2012-09-19 15:15:01 +00:00
MemStream stream( 256 );
U32 writeFlags = 0;
2017-01-12 04:34:46 +00:00
SimDataBlock* db = dynamic_cast<SimDataBlock*>(object);
if( !db )
stream.write( sizeof( "return " ) - 1, "return " );
else
2012-09-19 15:15:01 +00:00
{
2017-01-12 04:34:46 +00:00
mIsDatablock = true;
2012-09-19 15:15:01 +00:00
// Cull the datablock name from the output so that
// we can easily replace it in case the datablock's name
// is already taken when we call restore(). We can't use the same
// setup as with non-datablock classes as the return semantics
// are not the same.
writeFlags |= SimObject::NoName;
}
2017-01-12 04:34:46 +00:00
2012-09-19 15:15:01 +00:00
object->write( stream, 0, writeFlags );
stream.write( (UTF8)0 );
// Steal the data away from the stream.
mState = (UTF8*)stream.takeBuffer();
mObjectName = object->getName();
}
SimObject *SimObjectMemento::restore() const
{
// Make sure we have data to restore.
if ( !mState )
return NULL;
// TODO: We could potentially make this faster by
// caching the CodeBlock generated from the string
2017-01-12 04:34:46 +00:00
SimObject* object;
if( !mIsDatablock )
{
2012-09-19 15:15:01 +00:00
// Set the redefine behavior to automatically giving
// the new objects unique names. This will restore the
// old names if they are still available or give reasonable
// approximations if not.
const char* oldRedefineBehavior = Con::getVariable( "$Con::redefineBehavior" );
Con::setVariable( "$Con::redefineBehavior", "renameNew" );
// Read the object.
2023-04-23 08:39:54 +00:00
const UTF8* result = Con::evaluate( mState ).value;
2012-09-19 15:15:01 +00:00
// Restore the redefine behavior.
Con::setVariable( "$Con::redefineBehavior", oldRedefineBehavior );
2017-01-12 04:34:46 +00:00
if ( !result || !result[ 0 ] )
return NULL;
2012-09-19 15:15:01 +00:00
// Look up the object.
2017-01-12 04:34:46 +00:00
U32 objectId = dAtoi( result );
object = Sim::findObject( objectId );
}
else
{
2012-09-19 15:15:01 +00:00
String objectName = mObjectName;
// For datablocks, it's getting a little complicated. Datablock definitions cannot be used
// as expressions and thus we can't get to the datablock object we create by using the
// Con::evaluate() return value. Instead, we need to rely on the object name. However, if
// the name is already taken and needs to be changed, we need to manually do that. To complicate
// this further, we cannot rely on automatic renaming since then we don't know by what name
// the newly created object actually goes. So what we do is we alter the source text snapshot
// and substitute a name in case the old object name is actually taken now.
char* tempBuffer;
if( !Sim::findObject( objectName ) )
tempBuffer = mState;
else
{
String uniqueName = Sim::getUniqueName( objectName );
U32 uniqueNameLen = uniqueName.length();
char* pLeftParen = dStrchr( mState, '(' );
if( pLeftParen == NULL )
return NULL;
U32 numCharsToLeftParen = pLeftParen - mState;
dsize_t tempBufferLen = dStrlen(mState) + uniqueNameLen + 1;
tempBuffer = ( char* ) dMalloc( tempBufferLen );
2012-09-19 15:15:01 +00:00
dMemcpy( tempBuffer, mState, numCharsToLeftParen );
dMemcpy( &tempBuffer[ numCharsToLeftParen ], uniqueName, uniqueNameLen );
dStrcpy( &tempBuffer[ numCharsToLeftParen + uniqueNameLen ], &mState[ numCharsToLeftParen ], tempBufferLen - numCharsToLeftParen - uniqueNameLen );
2012-09-19 15:15:01 +00:00
}
2017-01-12 04:34:46 +00:00
Con::evaluate( tempBuffer );
2012-09-19 15:15:01 +00:00
if( tempBuffer != mState )
dFree( tempBuffer );
if( objectName == String::EmptyString )
2017-01-12 04:34:46 +00:00
return NULL;
2012-09-19 15:15:01 +00:00
2017-01-12 04:34:46 +00:00
object = Sim::findObject( objectName );
}
2012-09-19 15:15:01 +00:00
return object;
}