/** * @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 #include "stdio.h" #include "llmultigesture.h" #include "llerror.h" #include "lldatapacker.h" #include "llstl.h" constexpr S32 GESTURE_VERSION = 2; //--------------------------------------------------------------------------- // LLMultiGesture //--------------------------------------------------------------------------- LLMultiGesture::LLMultiGesture() : mKey(), mMask(), mName(), mTrigger(), mReplaceText(), mSteps(), mPlaying(false), mLocal(false), mCurrentStep(0), mDoneCallback(nullptr) { reset(); } LLMultiGesture::~LLMultiGesture() { std::for_each(mSteps.begin(), mSteps.end(), DeletePointer()); } void LLMultiGesture::reset() { mPlaying = false; mLocal = 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 for (const auto& step : mSteps) { 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 for (const auto& step : mSteps) { 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"); for (const auto& step : mSteps) { dp.packS32(step->getType(), "step_type"); if (!step->serialize(dp)) { return false; } } return true; } bool LLMultiGesture::deserialize(LLDataPacker& dp) { S32 version; dp.unpackS32(version, "version"); if (version != GESTURE_VERSION) { LL_WARNS() << "Bad LLMultiGesture version " << version << " should be " << GESTURE_VERSION << LL_ENDL; 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) { LL_WARNS() << "Bad LLMultiGesture step count " << count << LL_ENDL; return false; } std::unique_ptr step; for (S32 i = 0; i < count; ++i) { S32 type; dp.unpackS32(type, "step_type"); switch((EStepType)type) { case STEP_ANIMATION: step.reset(new LLGestureStepAnimation); break; case STEP_SOUND: step.reset(new LLGestureStepSound); break; case STEP_CHAT: step.reset(new LLGestureStepChat); break; case STEP_WAIT: step.reset(new LLGestureStepWait); break; default: { LL_WARNS() << "Bad LLMultiGesture step type " << type << LL_ENDL; return false; } } if (!step->deserialize(dp)) return false; mSteps.push_back(step.release()); } return true; } void LLMultiGesture::dump() { LL_INFOS() << "key " << S32(mKey) << " mask " << U32(mMask) << " trigger " << mTrigger << " replace " << mReplaceText << LL_ENDL; for (const auto& step : mSteps) { 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.back() == '\r') { // chop the last character mAnimName.resize(mAnimName.length() - 1); } dp.unpackUUID(mAnimAssetID, "asset_id"); dp.unpackU32(mFlags, "flags"); return true; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepAnimation::getLabel() const { /* std::string label; if (mFlags & ANIM_FLAG_STOP) label = "Stop Animation: "; else label = "Start Animation: "; label += mAnimName;*/ return {mFlags & ANIM_FLAG_STOP ? "AnimFlagStop" : "AnimFlagStart", mAnimName}; } void LLGestureStepAnimation::dump() { LL_INFOS() << "step animation " << mAnimName << " id " << mAnimAssetID << " flags " << mFlags << LL_ENDL; } //--------------------------------------------------------------------------- // 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; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepSound::getLabel() const { // std::string label("Sound: "); // label += mSoundName; return {"Sound", mSoundName}; } void LLGestureStepSound::dump() { LL_INFOS() << "step sound " << mSoundName << " id " << mSoundAssetID << " flags " << mFlags << LL_ENDL; } //--------------------------------------------------------------------------- // 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; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepChat::getLabel() const { return {"Chat", mChatText}; } void LLGestureStepChat::dump() { LL_INFOS() << "step chat " << mChatText << " flags " << mFlags << LL_ENDL; } //--------------------------------------------------------------------------- // 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; } // *NOTE: result is translated in LLPreviewGesture::getLabel() std::vector LLGestureStepWait::getLabel() const { return {"Wait", mFlags & WAIT_FLAG_TIME ? llformat("%.1f seconds", mWaitSeconds) : mFlags & WAIT_FLAG_ALL_ANIM ? "until animations are done" : LLStringUtil::null}; } void LLGestureStepWait::dump() { LL_INFOS() << "step wait " << mWaitSeconds << " flags " << mFlags << LL_ENDL; }