489 lines
10 KiB
C++
489 lines
10 KiB
C++
/**
|
|
* @file llmultigesture.cpp
|
|
* @brief Gestures that are asset-based and can have multiple steps.
|
|
*
|
|
* $LicenseInfo:firstyear=2004&license=viewerlgpl$
|
|
* Second Life Viewer Source Code
|
|
* Copyright (C) 2010, Linden Research, Inc.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation;
|
|
* version 2.1 of the License only.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "linden_common.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include "stdio.h"
|
|
|
|
#include "llmultigesture.h"
|
|
|
|
#include "llerror.h"
|
|
#include "lldatapacker.h"
|
|
#include "llstl.h"
|
|
|
|
const S32 GESTURE_VERSION = 2;
|
|
|
|
//---------------------------------------------------------------------------
|
|
// LLMultiGesture
|
|
//---------------------------------------------------------------------------
|
|
LLMultiGesture::LLMultiGesture()
|
|
: mKey(),
|
|
mMask(),
|
|
mTrigger(),
|
|
mReplaceText(),
|
|
mSteps(),
|
|
mPlaying(FALSE),
|
|
mCurrentStep(0),
|
|
mDoneCallback(NULL),
|
|
mCallbackData(NULL)
|
|
{
|
|
reset();
|
|
}
|
|
|
|
LLMultiGesture::~LLMultiGesture()
|
|
{
|
|
std::for_each(mSteps.begin(), mSteps.end(), DeletePointer());
|
|
}
|
|
|
|
void LLMultiGesture::reset()
|
|
{
|
|
mPlaying = FALSE;
|
|
mCurrentStep = 0;
|
|
mWaitTimer.reset();
|
|
mWaitingTimer = FALSE;
|
|
mWaitingAnimations = FALSE;
|
|
mWaitingAtEnd = FALSE;
|
|
mRequestedAnimIDs.clear();
|
|
mPlayingAnimIDs.clear();
|
|
}
|
|
|
|
S32 LLMultiGesture::getMaxSerialSize() const
|
|
{
|
|
S32 max_size = 0;
|
|
|
|
// ascii format, being very conservative about possible
|
|
// label lengths.
|
|
max_size += 64; // version S32
|
|
max_size += 64; // key U8
|
|
max_size += 64; // mask U32
|
|
max_size += 256; // trigger string
|
|
max_size += 256; // replace string
|
|
|
|
max_size += 64; // step count S32
|
|
|
|
std::vector<LLGestureStep*>::const_iterator it;
|
|
for (it = mSteps.begin(); it != mSteps.end(); ++it)
|
|
{
|
|
LLGestureStep* step = *it;
|
|
max_size += 64; // type S32
|
|
max_size += step->getMaxSerialSize();
|
|
}
|
|
|
|
/* binary format
|
|
max_size += sizeof(S32); // version
|
|
max_size += sizeof(mKey);
|
|
max_size += sizeof(mMask);
|
|
max_size += mTrigger.length() + 1; // for null
|
|
|
|
max_size += sizeof(S32); // step count
|
|
|
|
std::vector<LLGestureStep*>::const_iterator it;
|
|
for (it = mSteps.begin(); it != mSteps.end(); ++it)
|
|
{
|
|
LLGestureStep* step = *it;
|
|
max_size += sizeof(S32); // type
|
|
max_size += step->getMaxSerialSize();
|
|
}
|
|
*/
|
|
|
|
return max_size;
|
|
}
|
|
|
|
BOOL LLMultiGesture::serialize(LLDataPacker& dp) const
|
|
{
|
|
dp.packS32(GESTURE_VERSION, "version");
|
|
dp.packU8(mKey, "key");
|
|
dp.packU32(mMask, "mask");
|
|
dp.packString(mTrigger, "trigger");
|
|
dp.packString(mReplaceText, "replace");
|
|
|
|
S32 count = (S32)mSteps.size();
|
|
dp.packS32(count, "step_count");
|
|
S32 i;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
LLGestureStep* step = mSteps[i];
|
|
|
|
dp.packS32(step->getType(), "step_type");
|
|
BOOL ok = step->serialize(dp);
|
|
if (!ok)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLMultiGesture::deserialize(LLDataPacker& dp)
|
|
{
|
|
S32 version;
|
|
dp.unpackS32(version, "version");
|
|
if (version != GESTURE_VERSION)
|
|
{
|
|
llwarns << "Bad LLMultiGesture version " << version
|
|
<< " should be " << GESTURE_VERSION
|
|
<< llendl;
|
|
return FALSE;
|
|
}
|
|
|
|
dp.unpackU8(mKey, "key");
|
|
dp.unpackU32(mMask, "mask");
|
|
|
|
|
|
dp.unpackString(mTrigger, "trigger");
|
|
|
|
dp.unpackString(mReplaceText, "replace");
|
|
|
|
S32 count;
|
|
dp.unpackS32(count, "step_count");
|
|
if (count < 0)
|
|
{
|
|
llwarns << "Bad LLMultiGesture step count " << count << llendl;
|
|
return FALSE;
|
|
}
|
|
|
|
S32 i;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
S32 type;
|
|
dp.unpackS32(type, "step_type");
|
|
|
|
EStepType step_type = (EStepType)type;
|
|
switch(step_type)
|
|
{
|
|
case STEP_ANIMATION:
|
|
{
|
|
LLGestureStepAnimation* step = new LLGestureStepAnimation();
|
|
BOOL ok = step->deserialize(dp);
|
|
if (!ok) return FALSE;
|
|
mSteps.push_back(step);
|
|
break;
|
|
}
|
|
case STEP_SOUND:
|
|
{
|
|
LLGestureStepSound* step = new LLGestureStepSound();
|
|
BOOL ok = step->deserialize(dp);
|
|
if (!ok) return FALSE;
|
|
mSteps.push_back(step);
|
|
break;
|
|
}
|
|
case STEP_CHAT:
|
|
{
|
|
LLGestureStepChat* step = new LLGestureStepChat();
|
|
BOOL ok = step->deserialize(dp);
|
|
if (!ok) return FALSE;
|
|
mSteps.push_back(step);
|
|
break;
|
|
}
|
|
case STEP_WAIT:
|
|
{
|
|
LLGestureStepWait* step = new LLGestureStepWait();
|
|
BOOL ok = step->deserialize(dp);
|
|
if (!ok) return FALSE;
|
|
mSteps.push_back(step);
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
llwarns << "Bad LLMultiGesture step type " << type << llendl;
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void LLMultiGesture::dump()
|
|
{
|
|
llinfos << "key " << S32(mKey) << " mask " << U32(mMask)
|
|
<< " trigger " << mTrigger
|
|
<< " replace " << mReplaceText
|
|
<< llendl;
|
|
U32 i;
|
|
for (i = 0; i < mSteps.size(); ++i)
|
|
{
|
|
LLGestureStep* step = mSteps[i];
|
|
step->dump();
|
|
}
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// LLGestureStepAnimation
|
|
//---------------------------------------------------------------------------
|
|
LLGestureStepAnimation::LLGestureStepAnimation()
|
|
: LLGestureStep(),
|
|
mAnimName("None"),
|
|
mAnimAssetID(),
|
|
mFlags(0x0)
|
|
{ }
|
|
|
|
LLGestureStepAnimation::~LLGestureStepAnimation()
|
|
{ }
|
|
|
|
S32 LLGestureStepAnimation::getMaxSerialSize() const
|
|
{
|
|
S32 max_size = 0;
|
|
|
|
// ascii
|
|
max_size += 256; // anim name
|
|
max_size += 64; // anim asset id
|
|
max_size += 64; // flags
|
|
|
|
/* binary
|
|
max_size += mAnimName.length() + 1;
|
|
max_size += sizeof(mAnimAssetID);
|
|
max_size += sizeof(mFlags);
|
|
*/
|
|
return max_size;
|
|
}
|
|
|
|
BOOL LLGestureStepAnimation::serialize(LLDataPacker& dp) const
|
|
{
|
|
dp.packString(mAnimName, "anim_name");
|
|
dp.packUUID(mAnimAssetID, "asset_id");
|
|
dp.packU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLGestureStepAnimation::deserialize(LLDataPacker& dp)
|
|
{
|
|
dp.unpackString(mAnimName, "anim_name");
|
|
|
|
// Apparently an earlier version of the gesture code added \r to the end
|
|
// of the animation names. Get rid of it. JC
|
|
if (!mAnimName.empty() && mAnimName[mAnimName.length() - 1] == '\r')
|
|
{
|
|
// chop the last character
|
|
mAnimName.resize(mAnimName.length() - 1);
|
|
}
|
|
|
|
dp.unpackUUID(mAnimAssetID, "asset_id");
|
|
dp.unpackU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
std::string LLGestureStepAnimation::getLabel() const
|
|
{
|
|
std::string label;
|
|
if (mFlags & ANIM_FLAG_STOP)
|
|
{
|
|
label = "Stop Animation: ";
|
|
}
|
|
else
|
|
{
|
|
label = "Start Animation: ";
|
|
}
|
|
label += mAnimName;
|
|
return label;
|
|
}
|
|
|
|
void LLGestureStepAnimation::dump()
|
|
{
|
|
llinfos << "step animation " << mAnimName
|
|
<< " id " << mAnimAssetID
|
|
<< " flags " << mFlags
|
|
<< llendl;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// LLGestureStepSound
|
|
//---------------------------------------------------------------------------
|
|
LLGestureStepSound::LLGestureStepSound()
|
|
: LLGestureStep(),
|
|
mSoundName("None"),
|
|
mSoundAssetID(),
|
|
mFlags(0x0)
|
|
{ }
|
|
|
|
LLGestureStepSound::~LLGestureStepSound()
|
|
{ }
|
|
|
|
S32 LLGestureStepSound::getMaxSerialSize() const
|
|
{
|
|
S32 max_size = 0;
|
|
max_size += 256; // sound name
|
|
max_size += 64; // sound asset id
|
|
max_size += 64; // flags
|
|
/* binary
|
|
max_size += mSoundName.length() + 1;
|
|
max_size += sizeof(mSoundAssetID);
|
|
max_size += sizeof(mFlags);
|
|
*/
|
|
return max_size;
|
|
}
|
|
|
|
BOOL LLGestureStepSound::serialize(LLDataPacker& dp) const
|
|
{
|
|
dp.packString(mSoundName, "sound_name");
|
|
dp.packUUID(mSoundAssetID, "asset_id");
|
|
dp.packU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLGestureStepSound::deserialize(LLDataPacker& dp)
|
|
{
|
|
dp.unpackString(mSoundName, "sound_name");
|
|
|
|
dp.unpackUUID(mSoundAssetID, "asset_id");
|
|
dp.unpackU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
std::string LLGestureStepSound::getLabel() const
|
|
{
|
|
std::string label("Sound: ");
|
|
label += mSoundName;
|
|
return label;
|
|
}
|
|
|
|
void LLGestureStepSound::dump()
|
|
{
|
|
llinfos << "step sound " << mSoundName
|
|
<< " id " << mSoundAssetID
|
|
<< " flags " << mFlags
|
|
<< llendl;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// LLGestureStepChat
|
|
//---------------------------------------------------------------------------
|
|
LLGestureStepChat::LLGestureStepChat()
|
|
: LLGestureStep(),
|
|
mChatText(),
|
|
mFlags(0x0)
|
|
{ }
|
|
|
|
LLGestureStepChat::~LLGestureStepChat()
|
|
{ }
|
|
|
|
S32 LLGestureStepChat::getMaxSerialSize() const
|
|
{
|
|
S32 max_size = 0;
|
|
max_size += 256; // chat text
|
|
max_size += 64; // flags
|
|
/* binary
|
|
max_size += mChatText.length() + 1;
|
|
max_size += sizeof(mFlags);
|
|
*/
|
|
return max_size;
|
|
}
|
|
|
|
BOOL LLGestureStepChat::serialize(LLDataPacker& dp) const
|
|
{
|
|
dp.packString(mChatText, "chat_text");
|
|
dp.packU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLGestureStepChat::deserialize(LLDataPacker& dp)
|
|
{
|
|
dp.unpackString(mChatText, "chat_text");
|
|
|
|
dp.unpackU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
std::string LLGestureStepChat::getLabel() const
|
|
{
|
|
std::string label("Chat: ");
|
|
label += mChatText;
|
|
return label;
|
|
}
|
|
|
|
void LLGestureStepChat::dump()
|
|
{
|
|
llinfos << "step chat " << mChatText
|
|
<< " flags " << mFlags
|
|
<< llendl;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
// LLGestureStepWait
|
|
//---------------------------------------------------------------------------
|
|
LLGestureStepWait::LLGestureStepWait()
|
|
: LLGestureStep(),
|
|
mWaitSeconds(0.f),
|
|
mFlags(0x0)
|
|
{ }
|
|
|
|
LLGestureStepWait::~LLGestureStepWait()
|
|
{ }
|
|
|
|
S32 LLGestureStepWait::getMaxSerialSize() const
|
|
{
|
|
S32 max_size = 0;
|
|
max_size += 64; // wait seconds
|
|
max_size += 64; // flags
|
|
/* binary
|
|
max_size += sizeof(mWaitSeconds);
|
|
max_size += sizeof(mFlags);
|
|
*/
|
|
return max_size;
|
|
}
|
|
|
|
BOOL LLGestureStepWait::serialize(LLDataPacker& dp) const
|
|
{
|
|
dp.packF32(mWaitSeconds, "wait_seconds");
|
|
dp.packU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL LLGestureStepWait::deserialize(LLDataPacker& dp)
|
|
{
|
|
dp.unpackF32(mWaitSeconds, "wait_seconds");
|
|
dp.unpackU32(mFlags, "flags");
|
|
return TRUE;
|
|
}
|
|
|
|
std::string LLGestureStepWait::getLabel() const
|
|
{
|
|
std::string label("--- Wait: ");
|
|
if (mFlags & WAIT_FLAG_TIME)
|
|
{
|
|
char buffer[64]; /* Flawfinder: ignore */
|
|
snprintf(buffer, sizeof(buffer), "%.1f seconds", (double)mWaitSeconds); /* Flawfinder: ignore */
|
|
label += buffer;
|
|
}
|
|
else if (mFlags & WAIT_FLAG_ALL_ANIM)
|
|
{
|
|
label += "until animations are done";
|
|
}
|
|
|
|
return label;
|
|
}
|
|
|
|
|
|
void LLGestureStepWait::dump()
|
|
{
|
|
llinfos << "step wait " << mWaitSeconds
|
|
<< " flags " << mFlags
|
|
<< llendl;
|
|
}
|