From 4871f5ed8e6bd14b76d2dcc90ca83cafa426049a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Liru=20F=C3=A6rs?= Date: Tue, 10 Mar 2020 18:21:06 -0400 Subject: [PATCH] AO Refactor Should fix AO not turning on without opening floater first Cleans up code Reduces memory footprint, especially when not in use Removes unused functions and parameters Decouples AO from Floater class (AOSystem) Removes duplicate Idle state Formalizes singleton patterns of globals Centralizes override handling into override structs Fall back on simple english notecard explanation when missing config ini Fixes sitting override playing when sitting is disabled (and acting weird) Moves the bulk of override handling into override structs No longer state-based, now tracks using per-struct playing field --- indra/newview/floaterao.cpp | 1262 +++++++++++++------------------ indra/newview/floaterao.h | 235 +++--- indra/newview/llagent.cpp | 4 +- indra/newview/llagentcamera.cpp | 3 +- indra/newview/llappviewer.cpp | 3 + indra/newview/llstartup.cpp | 5 +- indra/newview/llvoavatar.cpp | 15 +- 7 files changed, 709 insertions(+), 818 deletions(-) diff --git a/indra/newview/floaterao.cpp b/indra/newview/floaterao.cpp index 2038aaa13..7b2618dd8 100644 --- a/indra/newview/floaterao.cpp +++ b/indra/newview/floaterao.cpp @@ -1,7 +1,7 @@ -/** +/** * @file llfloaterao.cpp * @brief clientside animation overrider - * by Skills Hak + * by Skills Hak & Liru Færs */ #include "llviewerprecompiledheaders.h" @@ -10,23 +10,23 @@ #include "llagent.h" #include "llagentcamera.h" -#include "llvoavatarself.h" #include "llanimationstates.h" -#include "lluictrlfactory.h" -#include "llstartup.h" -#include "llpreviewnotecard.h" -#include "llviewertexteditor.h" #include "llcombobox.h" #include "llfirstuse.h" - #include "llinventory.h" +#include "llinventorybridge.h" #include "llinventoryfunctions.h" #include "llinventorypanel.h" #include "llinventorymodelbackgroundfetch.h" -#include "roles_constants.h" +#include "llmemorystream.h" +#include "llnotecard.h" +#include "llpreviewnotecard.h" +#include "llstartup.h" +#include "lltexteditor.h" +#include "lluictrlfactory.h" +#include "llvoavatarself.h" #include "llviewerregion.h" - -#include "llinventorybridge.h" +#include "roles_constants.h" #include @@ -44,15 +44,12 @@ namespace bool is_underwater() { return enable_swim() && gAgentAvatarp && gAgentAvatarp->mBelowWater; } } -class AONotecardCallback : public LLInventoryCallback +class AONotecardCallback final : public LLInventoryCallback { public: - AONotecardCallback(std::string &filename) - { - mFileName = filename; - } + AONotecardCallback(const std::string& filename) : mFileName(filename) {} - void fire(const LLUUID &inv_item) + void fire(const LLUUID &inv_item) override { if (!mFileName.empty()) { @@ -77,8 +74,7 @@ public: while (!file.eof()) { getline(file, line); - line += '\n'; - text->insertText(line); + text->insertText(line + '\n'); } file.close(); @@ -92,16 +88,11 @@ private: std::string mFileName; }; -AOInvTimer* gAOInvTimer = nullptr; - // ------------------------------------------------------- -AOStandTimer* mAOStandTimer; - -AOStandTimer::AOStandTimer() : LLEventTimer( gSavedSettings.getF32("AOStandInterval") ) +AOStandTimer::AOStandTimer() : LLEventTimer(F32_MAX) { - tick(); } AOStandTimer::~AOStandTimer() { @@ -115,11 +106,10 @@ void AOStandTimer::reset() } BOOL AOStandTimer::tick() { - LLFloaterAO::stand_iterator++; // LL_INFOS() << "tick" << LL_ENDL; - LLFloaterAO::ChangeStand(); + if (auto ao = AOSystem::getIfExists()) + ao->cycleStand(); return false; -// return LLFloaterAO::ChangeStand(); //timer is always active now .. } // ------------------------------------------------------- @@ -130,80 +120,74 @@ AOInvTimer::AOInvTimer() : LLEventTimer( 1.0f ) AOInvTimer::~AOInvTimer() { } +bool AOInvTimer::needed() +{ + return LLStartUp::getStartupState() < STATE_INVENTORY_SEND // Haven't done inventory transfer yet + || !LLInventoryModelBackgroundFetch::instance().isEverythingFetched(); // Everything hasn't been fetched yet +} +void AOInvTimer::createIfNeeded() +{ + if (needed()) LLSingleton::getInstance(); + else AOSystem::getInstance(); +} BOOL AOInvTimer::tick() { - if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) + if (!gSavedSettings.getBOOL("AOEnabled")) return true; // If disabled on a tick, we don't care anymore + if (!needed()) { - if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { -// cmdline_printchat("Inventory fetched, loading AO."); - LLFloaterAO::getInstance(); // Initializes everything - return true; - } +// cmdline_printchat("Inventory fetched, loading AO."); + AOSystem::getInstance(); // Initializes everything + return true; } - return !gSavedSettings.getBOOL("AOEnabled"); + return false; +} + +class ObjectNameMatches final : public LLInventoryCollectFunctor +{ +public: + ObjectNameMatches(const std::string& name, const LLUUID& folder) : mName(name), mFolder(folder) {} + virtual ~ObjectNameMatches() {} + bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override + { + return item && item->getParentUUID() == mFolder && item->getName() == mName; + } +private: + const std::string& mName; + const LLUUID& mFolder; +}; + +static LLUUID invfolderid; +static LLUUID getAssetIDByName(const std::string& name) +{ + if (name.empty()) return LLUUID::null; + + LLViewerInventoryCategory::cat_array_t cats; + LLViewerInventoryItem::item_array_t items; + ObjectNameMatches matches(name, invfolderid); + gInventory.collectDescendentsIf(LLUUID::null, cats, items, false, matches, true); + + return items.empty() ? LLUUID(name) : items[0]->getAssetUUID(); +}; + +void AOSystem::start() +{ + llassert(!instanceExists() && !AOInvTimer::instanceExists()); // This should only be run once! + + auto control(gSavedSettings.getControl("AOEnabled")); + if (control->get()) AOInvTimer::createIfNeeded(); // Start the clock + + control->getSignal()->connect([](LLControlVariable*, const LLSD& enabled) { + if (enabled.asBoolean()) AOInvTimer::createIfNeeded(); // Start the clock + else deleteSingleton(); + }); } // STUFF ------------------------------------------------------- -AOState LLFloaterAO::mAnimationState = STATE_AGENT_IDLE; -int LLFloaterAO::stand_iterator = 0; - -LLUUID LLFloaterAO::invfolderid = LLUUID::null; -LLUUID LLFloaterAO::mCurrentStandId = LLUUID::null; - -LLComboBox* mcomboBox_stands; -LLComboBox* mcomboBox_walks; -LLComboBox* mcomboBox_runs; -LLComboBox* mcomboBox_jumps; -LLComboBox* mcomboBox_sits; -LLComboBox* mcomboBox_gsits; -LLComboBox* mcomboBox_crouchs; -LLComboBox* mcomboBox_cwalks; -LLComboBox* mcomboBox_falls; -LLComboBox* mcomboBox_hovers; -LLComboBox* mcomboBox_flys; -LLComboBox* mcomboBox_flyslows; -LLComboBox* mcomboBox_flyups; -LLComboBox* mcomboBox_flydowns; -LLComboBox* mcomboBox_lands; -LLComboBox* mcomboBox_typings; -LLComboBox* mcomboBox_floats; -LLComboBox* mcomboBox_swims; -LLComboBox* mcomboBox_swimups; -LLComboBox* mcomboBox_swimdowns; -LLComboBox* mcomboBox_standups; -LLComboBox* mcomboBox_prejumps; - -struct struct_overrides -{ - LLUUID orig_id; - LLUUID ao_id = LLUUID::null; - AOState state; -}; -std::vector mAOOverrides; - -struct struct_stands -{ - LLUUID ao_id; - std::string anim_name; -}; -std::vector mAOStands; - LLFloaterAO::LLFloaterAO(const LLSD&) : LLFloater("floater_ao") +, mCombos({}) { LLUICtrlFactory::getInstance()->buildFloater(this, "floater_ao.xml", nullptr, false); - init(); - gSavedSettings.getControl("AOEnabled")->getSignal()->connect(boost::bind(&LLFloaterAO::run)); - gSavedSettings.getControl("AOEnabled")->getSignal()->connect(std::bind([](const LLSD& enabled) - { - // Toggle typing AO the moment we toggle AO - const bool typing = gAgent.getRenderState() & AGENT_STATE_TYPING; - gAgent.sendAnimationRequest(GetAnimIDFromState(STATE_AGENT_TYPING), enabled && typing ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); - }, std::placeholders::_2)); - gSavedSettings.getControl("AOSitsEnabled")->getSignal()->connect(boost::bind(&LLFloaterAO::run)); - sSwimming = is_underwater(); - gSavedSettings.getControl("AOSwimEnabled")->getSignal()->connect(boost::bind(&LLFloaterAO::toggleSwim, boost::bind(is_underwater))); } void LLFloaterAO::onOpen() @@ -213,28 +197,6 @@ void LLFloaterAO::onOpen() LLFloaterAO::~LLFloaterAO() { - mcomboBox_stands = nullptr; - mcomboBox_walks = nullptr; - mcomboBox_runs = nullptr; - mcomboBox_jumps = nullptr; - mcomboBox_sits = nullptr; - mcomboBox_gsits = nullptr; - mcomboBox_crouchs = nullptr; - mcomboBox_cwalks = nullptr; - mcomboBox_falls = nullptr; - mcomboBox_hovers = nullptr; - mcomboBox_flys = nullptr; - mcomboBox_flyslows = nullptr; - mcomboBox_flyups = nullptr; - mcomboBox_flydowns = nullptr; - mcomboBox_lands = nullptr; - mcomboBox_typings = nullptr; - mcomboBox_floats = nullptr; - mcomboBox_swims = nullptr; - mcomboBox_swimups = nullptr; - mcomboBox_swimdowns = nullptr; - mcomboBox_standups = nullptr; - mcomboBox_prejumps = nullptr; // LL_INFOS() << "floater destroyed" << LL_ENDL; } @@ -242,335 +204,339 @@ BOOL LLFloaterAO::postBuild() { gSavedSettings.getControl("AOAdvanced")->getSignal()->connect(boost::bind(&LLFloaterAO::updateLayout, this, _2)); - getChild("reloadcard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickReloadCard)); - getChild("opencard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickOpenCard)); - getChild("newcard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickNewCard)); - getChild("prevstand")->setCommitCallback(boost::bind(&LLFloaterAO::onClickCycleStand, false)); - getChild("nextstand")->setCommitCallback(boost::bind(&LLFloaterAO::onClickCycleStand, true)); - getChild("standtime")->setCommitCallback(boost::bind(&LLFloaterAO::onSpinnerCommit)); + getChild("reloadcard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickReloadCard, this)); + getChild("opencard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickOpenCard, this)); + getChild("newcard")->setCommitCallback(boost::bind(&LLFloaterAO::onClickNewCard, this)); + getChild("prevstand")->setCommitCallback(boost::bind(&LLFloaterAO::onClickCycleStand, this, false)); + getChild("nextstand")->setCommitCallback(boost::bind(&LLFloaterAO::onClickCycleStand, this, true)); + getChild("standtime")->setCommitCallback(boost::bind(&LLFloaterAO::onSpinnerCommit, this)); - (mcomboBox_stands = getChild("stands"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_walks = getChild("walks"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_runs = getChild("runs"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_jumps = getChild("jumps"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_sits = getChild("sits"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_gsits = getChild("gsits"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_crouchs = getChild("crouchs"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_cwalks = getChild("cwalks"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_falls = getChild("falls"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_hovers = getChild("hovers"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_flys = getChild("flys"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_flyslows = getChild("flyslows"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_flyups = getChild("flyups"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_flydowns = getChild("flydowns"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_lands = getChild("lands"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_typings = getChild("typings"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_floats = getChild("floats"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_swims = getChild("swims"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_swimups = getChild("swimups"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_swimdowns = getChild("swimdowns"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit, _1)); - (mcomboBox_standups = getChild("standups"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); - (mcomboBox_prejumps = getChild("prejumps"))->setCommitCallback(boost::bind(&LLFloaterAO::onComboBoxCommit,_1)); + auto ao = AOSystem::getIfExists(); + const auto& cb = boost::bind(&LLFloaterAO::onComboBoxCommit, this, _1); + const auto& setup_combo = [&](const std::string& name, const AOState& state) { + if (auto combo = findChild(name)) + { + combo->setCommitCallback(cb); + LLControlVariablePtr setting = nullptr; + if (auto aop = ao ? ao->mAOOverrides[state] : nullptr) + setting = aop->setting; + else // AO is down or missing override struct(why?), try getting from UI + setting = combo->getControl(combo->getControlName()); + if (setting) combo->add(setting->get().asStringRef(), ADD_BOTTOM, true); + mCombos[state] = combo; + } + }; + setup_combo("stands", STATE_AGENT_IDLE); + setup_combo("walks", STATE_AGENT_WALK); + setup_combo("runs", STATE_AGENT_RUN); + setup_combo("prejumps", STATE_AGENT_PRE_JUMP); + setup_combo("jumps", STATE_AGENT_JUMP); + setup_combo("turnlefts", STATE_AGENT_TURNLEFT); + setup_combo("turnrights", STATE_AGENT_TURNRIGHT); + setup_combo("sits", STATE_AGENT_SIT); + setup_combo("gsits", STATE_AGENT_SIT_GROUND); + setup_combo("hovers", STATE_AGENT_HOVER); + setup_combo("flydowns", STATE_AGENT_HOVER_DOWN); + setup_combo("flyups", STATE_AGENT_HOVER_UP); + setup_combo("crouchs", STATE_AGENT_CROUCH); + setup_combo("cwalks", STATE_AGENT_CROUCHWALK); + setup_combo("falls", STATE_AGENT_FALLDOWN); + setup_combo("standups", STATE_AGENT_STANDUP); + setup_combo("lands", STATE_AGENT_LAND); + setup_combo("flys", STATE_AGENT_FLY); + setup_combo("flyslows", STATE_AGENT_FLYSLOW); + setup_combo("typings", STATE_AGENT_TYPE); + setup_combo("swimdowns", STATE_AGENT_SWIM_DOWN); + setup_combo("swimups", STATE_AGENT_SWIM_UP); + setup_combo("swims", STATE_AGENT_SWIM); + setup_combo("floats", STATE_AGENT_FLOAT); updateLayout(gSavedSettings.getBOOL("AOAdvanced")); + AOSystem::requestConfigNotecard(false); return true; } -void LLFloaterAO::onSpinnerCommit() -{ - if (mAOStandTimer) mAOStandTimer->reset(); -} - -void LLFloaterAO::onComboBoxCommit(LLUICtrl* ctrl) -{ - if (LLComboBox* box = (LLComboBox*)ctrl) - { - if (box->getName() == "stands") - { - stand_iterator = box->getCurrentIndex(); - cmdline_printchat(llformat("Changing stand to %s.",mAOStands[stand_iterator].anim_name.c_str())); - ChangeStand(); - } - else - { - AOState state = getStateFromCombo(box); - std::string stranim = box->getValue().asString(); -// LL_INFOS() << "state " << state << " - " << getAnimationState() << LL_ENDL; - gAgent.sendAnimationRequest(GetAnimIDFromState(state), ANIM_REQUEST_STOP); - bool start_cond = getAnimationState() == state && gSavedSettings.getBOOL("AOEnabled"); - switch (state) - { - case STATE_AGENT_SIT: - case STATE_AGENT_GROUNDSIT: - start_cond &= gAgentAvatarp && gAgentAvatarp->isSitting() && gSavedSettings.getBOOL("AOSitsEnabled"); - break; - default: break; - } - LLUUID anim = getAssetIDByName(stranim); - if (start_cond) gAgent.sendAnimationRequest(anim, ANIM_REQUEST_START); - gSavedPerAccountSettings.setString(ctrl->getControlName(), stranim); - for (auto& ao : mAOOverrides) - { - if (state == ao.state) - { - ao.ao_id = anim; - break; - } - } - } - } -} - void LLFloaterAO::updateLayout(bool advanced) { reshape(advanced ? 800 : 200, getRect().getHeight()); childSetVisible("tabcontainer", advanced); } -void LLFloaterAO::init() +void LLFloaterAO::onSpinnerCommit() const { - mAOStands.clear(); - mAOOverrides.clear(); - - struct_overrides overrideloader; - overrideloader.orig_id = ANIM_AGENT_WALK; overrideloader.state = STATE_AGENT_WALK; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_RUN; overrideloader.state = STATE_AGENT_RUN; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_PRE_JUMP; overrideloader.state = STATE_AGENT_PRE_JUMP; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_JUMP; overrideloader.state = STATE_AGENT_JUMP; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_TURNLEFT; overrideloader.state = STATE_AGENT_TURNLEFT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_TURNRIGHT; overrideloader.state = STATE_AGENT_TURNRIGHT; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_SIT; overrideloader.state = STATE_AGENT_SIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_FEMALE; overrideloader.state = STATE_AGENT_SIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_GENERIC; overrideloader.state = STATE_AGENT_SIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_GROUND; overrideloader.state = STATE_AGENT_GROUNDSIT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_SIT_GROUND_CONSTRAINED; overrideloader.state = STATE_AGENT_GROUNDSIT; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_HOVER; overrideloader.state = STATE_AGENT_HOVER; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_HOVER_DOWN; overrideloader.state = STATE_AGENT_HOVER_DOWN; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_HOVER_UP; overrideloader.state = STATE_AGENT_HOVER_UP; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_CROUCH; overrideloader.state = STATE_AGENT_CROUCH; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_CROUCHWALK; overrideloader.state = STATE_AGENT_CROUCHWALK; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_FALLDOWN; overrideloader.state = STATE_AGENT_FALLDOWN; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_STANDUP; overrideloader.state = STATE_AGENT_STANDUP; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_LAND; overrideloader.state = STATE_AGENT_LAND; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_TYPE; overrideloader.state = STATE_AGENT_TYPING; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_FLY; overrideloader.state = STATE_AGENT_FLY; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_FLYSLOW; overrideloader.state = STATE_AGENT_FLYSLOW; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_HOVER; overrideloader.state = STATE_AGENT_FLOAT; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_HOVER_DOWN; overrideloader.state = STATE_AGENT_SWIM_DOWN; mAOOverrides.push_back(overrideloader); - overrideloader.orig_id = ANIM_AGENT_HOVER_UP; overrideloader.state = STATE_AGENT_SWIM_UP; mAOOverrides.push_back(overrideloader); - - overrideloader.orig_id = ANIM_AGENT_FLY; overrideloader.state = STATE_AGENT_SWIM; mAOOverrides.push_back(overrideloader); - - bool success = true; - - if(LLStartUp::getStartupState() >= STATE_INVENTORY_SEND) - { - if(LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { - LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); - if (configncitem.notNull()) - { - success = false; - const LLInventoryItem* item = gInventory.getItem(configncitem); - if(item) - { - if (gAgent.allowOperation(PERM_COPY, item->getPermissions(),GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) - { - if(!item->getAssetUUID().isNull()) - { - LLUUID* new_uuid = new LLUUID(configncitem); - LLHost source_sim = LLHost::invalid; - invfolderid = item->getParentUUID(); - gAssetStorage->getInvItemAsset(source_sim, - gAgent.getID(), - gAgent.getSessionID(), - item->getPermissions().getOwner(), - LLUUID::null, - item->getUUID(), - item->getAssetUUID(), - item->getType(), - &onNotecardLoadComplete, - (void*)new_uuid, - true); - success = true; - } - } - } - } - } - } - - if (!success) - { - cmdline_printchat("Could not read the specified Config Notecard"); - } - -// mAnimationState = STATE_AGENT_IDLE; -// mCurrentStandId = LLUUID::null; -// setAnimationState(STATE_AGENT_IDLE); + if (auto ao = AOSystem::getIfExists()) + ao->mAOStandTimer.reset(); } - -void LLFloaterAO::run() +void LLFloaterAO::onComboBoxCommit(LLUICtrl* ctrl) const { - setAnimationState(STATE_AGENT_IDLE); // reset state - AOState state = getAnimationState(); // check if sitting or hovering - bool enabled = gSavedSettings.getBOOL("AOEnabled"); - if (state == STATE_AGENT_IDLE || state == STATE_AGENT_STAND) + if (LLComboBox* box = (LLComboBox*)ctrl) { - if (enabled) + std::string stranim = box->getValue().asString(); + if (auto ao = AOSystem::getIfExists()) { - if (mAOStandTimer) + if (box == mCombos[STATE_AGENT_IDLE]) { - mAOStandTimer->reset(); - ChangeStand(); + ao->stand_iterator = box->getCurrentIndex(); + llassert(ao->stand_iterator < ao->mAOStands.size()); + const auto& name = ao->mAOStands[ao->stand_iterator].anim_name; + llassert(name == box->getValue().asStringRef()); + cmdline_printchat("Changing stand to " + name + '.'); + ao->updateStand(); + ao->mAOStandTimer.reset(); } else { - mAOStandTimer = new AOStandTimer(); + AOState state = getStateFromCombo(box); + llassert(state != STATE_AGENT_END); + const LLUUID& anim = getAssetIDByName(stranim); + if (auto aop = ao->mAOOverrides[state]) + { +// LL_INFOS() << "state " << state << " - " << aop->playing() << LL_ENDL; + bool was_playing = aop->playing; + if (was_playing) aop->play(false); + aop->ao_id = anim; + if (was_playing) aop->play(); + } } } - else - { - stopMotion(getCurrentStandId(), true); //stop stand first then set state - setAnimationState(STATE_AGENT_IDLE); - } - } - else - { - bool sit = false; - switch (state) - { - case STATE_AGENT_SIT: - case STATE_AGENT_GROUNDSIT: - sit = true; - stopMotion(getCurrentStandId(), true); // Stop the current stand - break; - default: break; - } - gAgent.sendAnimationRequest(GetAnimIDFromState(state), (enabled && (!sit || gSavedSettings.getBOOL("AOSitsEnabled"))) ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); + gSavedPerAccountSettings.setString(ctrl->getControlName(), stranim); } } -void LLFloaterAO::typing(bool start) +void LLFloaterAO::onClickCycleStand(bool next) const +{ + auto ao = AOSystem::getIfExists(); + if (!ao) return; + auto stand = ao->cycleStand(next, false); + ao->mAOStandTimer.reset(); + if (stand < 0) return; + cmdline_printchat("Changed stand to " + ao->mAOStands[stand].anim_name + '.'); +} + +void LLFloaterAO::onClickReloadCard() const +{ + AOSystem::instance().initSingleton(); +} + +void LLFloaterAO::onClickOpenCard() const +{ + if (!AOInvTimer::needed()) + { + LLUUID config_nc_id = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); + if (config_nc_id.notNull()) + if (LLViewerInventoryItem* item = gInventory.getItem(config_nc_id)) + if (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) + if(!item->getAssetUUID().isNull()) + open_notecard(item, "Note: " + item->getName(), LLUUID::null, false); + } +} + +void LLFloaterAO::onClickNewCard() const +{ + // load the template file from app_settings/ao_template.ini then + // create a new properly-formatted notecard in the user's inventory + std::string ao_template = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "ao_template.ini"); + if (ao_template.empty()) + { + ao_template = "#Can't find ao_template.ini in app_settings!"; + LL_WARNS() << ao_template << LL_ENDL; + ao_template += "\n#ZHAO II Style Notecards are supported."; + } + + create_inventory_item(gAgentID, gAgentSessionID, + LLUUID::null, LLTransactionID::tnull, "New AO Notecard", + "Drop this notecard in your AO window to use", LLAssetType::AT_NOTECARD, + LLInventoryType::IT_NOTECARD, NOT_WEARABLE, PERM_ALL, new AONotecardCallback(ao_template)); +} + +AOState LLFloaterAO::getStateFromCombo(const LLComboBox* combo) const +{ + if (combo) + { + const auto& end = mCombos.end(); + const auto it = std::find(mCombos.begin(), end, combo); + if (it != end) return (AOState)std::distance(mCombos.begin(), it); + } + return STATE_AGENT_END; +} + +AOSystem::overrides::overrides(const char* setting_name) + : setting(setting_name ? gSavedPerAccountSettings.getControl("AODefault" + std::string(setting_name)) : nullptr) + , playing(false) +{ +} + +bool AOSystem::overrides::play_condition() const +{ + // Stop stand first then play + instance().stopCurrentStand(); + return false; +} + +void AOSystem::overrides::play(bool start) +{ + if (playing == start) return; +// LL_INFOS() << "st" << (start ? "art" : "op") << " override: " << aop->getOverride() << LL_ENDL; + // We can always stop, but starting is particular + if (start) + { + if (play_condition()) + return; + } + else if (playing && !isLowPriority()) // Stands were turned off if this isn't a low priority overrides + { + if (!isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying()) // check if sitting or hovering + instance().stand().play(); + } + playing = start; + gAgent.sendAnimationRequest(ao_id, start ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); +} + +bool AOSystem::override_stand::play_condition() const +{ + // Do not call base, stands do their own thing + // stands have lowest priority + return (!isAgentAvatarValid() || gAgentAvatarp->isSitting()) + && (gAgentCamera.cameraMouselook() && gSavedSettings.getBOOL("AONoStandsInMouselook")); +} + +bool AOSystem::override_sit::play_condition() const +{ + overrides::play_condition(); + return !gSavedSettings.getBOOL("AOSitsEnabled"); +} + +bool AOSystem::override_stand::overrideAnim(bool swimming, const LLUUID& anim) const +{ + return anim == ANIM_AGENT_STAND; +} + +static AOState getSitType() +{ + return gAgentAvatarp->getParent() ? STATE_AGENT_SIT : STATE_AGENT_SIT_GROUND; +} + +AOSystem::AOSystem() +: stand_iterator(0) +, mAOOverrides({}) +{ +// TODO: When we move to C++20 and when GCC and MSVC support it (at the time of writing, neither fully do), use __VA_OPT__ here instead. +#define ANY_OVERRIDE(which, state, ...) mAOOverrides[STATE_AGENT_##state] = new which(ANIM_AGENT_##state, ##__VA_ARGS__) +#define BASIC_OVERRIDE(state, ...) ANY_OVERRIDE(override_single, ##state, ##__VA_ARGS__) + mAOOverrides[STATE_AGENT_IDLE] = new override_stand(); + BASIC_OVERRIDE(WALK, "Walk"); + BASIC_OVERRIDE(RUN, "Run"); + BASIC_OVERRIDE(PRE_JUMP, "PreJump"); + BASIC_OVERRIDE(JUMP, "Jump"); + BASIC_OVERRIDE(TURNLEFT); + BASIC_OVERRIDE(TURNRIGHT); + +#define SIT_OVERRIDE(control, state, ...) mAOOverrides[STATE_AGENT_##state] = new override_sit(uuid_set_t{ANIM_AGENT_##state, __VA_ARGS__}, control) + SIT_OVERRIDE("Sit", SIT, ANIM_AGENT_SIT_FEMALE, ANIM_AGENT_SIT_GENERIC); + SIT_OVERRIDE("GroundSit", SIT_GROUND, ANIM_AGENT_SIT_GROUND_CONSTRAINED); +#undef SIT_OVERRIDE + + BASIC_OVERRIDE(HOVER, "Hover", false); + BASIC_OVERRIDE(HOVER_DOWN, "FlyDown", false); + BASIC_OVERRIDE(HOVER_UP, "FlyUp", false); + + BASIC_OVERRIDE(CROUCH, "Crouch"); + BASIC_OVERRIDE(CROUCHWALK, "CrouchWalk"); + BASIC_OVERRIDE(FALLDOWN, "Fall"); + BASIC_OVERRIDE(STANDUP, "StandUp"); + BASIC_OVERRIDE(LAND, "Land"); + + BASIC_OVERRIDE(FLY, "Fly", false); + BASIC_OVERRIDE(FLYSLOW, "FlySlow", false); + + ANY_OVERRIDE(override_low_priority, TYPE, "Typing"); + + mAOOverrides[STATE_AGENT_SWIM_DOWN] = new override_single(ANIM_AGENT_HOVER_DOWN, "SwimDown", true); + mAOOverrides[STATE_AGENT_SWIM_UP] = new override_single(ANIM_AGENT_HOVER_UP, "SwimUp", true); + mAOOverrides[STATE_AGENT_SWIM] = new override_single(ANIM_AGENT_FLY, "Swim", true); + mAOOverrides[STATE_AGENT_FLOAT] = new override_single(ANIM_AGENT_HOVER, "Float", true); +#undef BASIC_OVERRIDE +#undef ANY_OVERRIDE + + sSwimming = is_underwater(); + mConnections[0] = gSavedSettings.getControl("AOSitsEnabled")->getSignal()->connect([this](LLControlVariable*, const LLSD& val) { + if (!isAgentAvatarValid() || !gAgentAvatarp->isSitting()) return; + gAgent.sendAnimationRequest(mAOOverrides[getSitType()]->ao_id, val.asBoolean() ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); + }); + mConnections[1] = gSavedSettings.getControl("AOSwimEnabled")->getSignal()->connect(boost::bind(&AOSystem::toggleSwim, this, boost::bind(is_underwater))); +} + +AOSystem::~AOSystem() +{ + stopAllOverrides(); + for (auto& ao : mAOOverrides) + { + if (ao) + { + delete ao; + ao = nullptr; + } + } +} + +void AOSystem::requestConfigNotecard(bool reload) +{ + LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); + if (configncitem.notNull()) + { + bool success = false; + if (const LLInventoryItem* item = gInventory.getItem(configncitem)) + { + if (gAgent.allowOperation(PERM_COPY, item->getPermissions(), GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) + { + if (item->getAssetUUID().notNull()) + { + invfolderid = item->getParentUUID(); + gAssetStorage->getInvItemAsset(LLHost::invalid, + gAgentID, + gAgentSessionID, + item->getPermissions().getOwner(), + LLUUID::null, + item->getUUID(), + item->getAssetUUID(), + item->getType(), + [reload](LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, void* user_data, S32 status, LLExtStat ext_status) + { + parseNotecard(vfs, asset_uuid, type, status, reload); + }, + nullptr, + true); + success = true; + } + } + } + if (!success) cmdline_printchat("Could not read the specified Config Notecard"); + } +} + +void AOSystem::initSingleton() +{ + mAOStands.clear(); + requestConfigNotecard(); +} + +void AOSystem::typing(bool start) { uuid_vec_t anims; // If we're stopping, stop regardless, just in case the setting was toggled during (e.g.: keyboard shortcut) if (!start || gSavedSettings.getBOOL("PlayTypingAnim")) // Linden typing anims.push_back(ANIM_AGENT_TYPE); - if (gSavedSettings.getBOOL("AOEnabled")) // Typing override - anims.push_back(GetAnimIDFromState(STATE_AGENT_TYPING)); + if (const auto& ao = getIfExists()) // Typing override + anims.push_back(ao->mAOOverrides[STATE_AGENT_TYPE]->getOverride()); if (anims.empty()) return; gAgent.sendAnimationRequests(anims, start ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); } -AOState LLFloaterAO::flyToSwimState(const AOState& state) +AOState GetStateFromToken(const std::string& strtoken) { - switch (state) - { - case STATE_AGENT_HOVER: return STATE_AGENT_FLOAT; - case STATE_AGENT_FLY: return STATE_AGENT_SWIM; - case STATE_AGENT_HOVER_UP: return STATE_AGENT_SWIM_UP; - case STATE_AGENT_HOVER_DOWN: return STATE_AGENT_SWIM_DOWN; - default: return state; - } -} - -AOState LLFloaterAO::swimToFlyState(const AOState& state) -{ - switch (state) - { - case STATE_AGENT_FLOAT: return STATE_AGENT_HOVER; - case STATE_AGENT_SWIM: return STATE_AGENT_FLY; - case STATE_AGENT_SWIM_UP: return STATE_AGENT_HOVER_UP; - case STATE_AGENT_SWIM_DOWN: return STATE_AGENT_HOVER_DOWN; - default: return state; - } -} - -AOState LLFloaterAO::getAnimationState() -{ - if (gAgentAvatarp) - { - if (gAgentAvatarp->isSitting()) setAnimationState(STATE_AGENT_SIT); - else if (gAgent.getFlying()) setAnimationState(STATE_AGENT_HOVER); - } - return mAnimationState; -} - -void LLFloaterAO::setAnimationState(const AOState& state) -{ - mAnimationState = sSwimming ? flyToSwimState(state) : state; -} - -LLUUID LLFloaterAO::getCurrentStandId() -{ - return mCurrentStandId; -} - -void LLFloaterAO::setCurrentStandId(const LLUUID& id) -{ - mCurrentStandId = id; -} - -bool LLFloaterAO::swimCheck(const AOState& state) -{ - switch (state) - { - case STATE_AGENT_HOVER: - case STATE_AGENT_FLY: - case STATE_AGENT_HOVER_UP: - case STATE_AGENT_HOVER_DOWN: - return !sSwimming; - case STATE_AGENT_FLOAT: - case STATE_AGENT_SWIM: - case STATE_AGENT_SWIM_UP: - case STATE_AGENT_SWIM_DOWN: - return sSwimming; - default: return true; - } -} - -LLUUID LLFloaterAO::GetAnimID(const LLUUID& id) -{ - for (const auto& ao : mAOOverrides) - { - if (swimCheck(ao.state) && ao.orig_id == id) - { - return ao.ao_id; - } - } - return LLUUID::null; -} - -AOState LLFloaterAO::GetStateFromAnimID(const LLUUID& id) -{ - for (const auto& ao : mAOOverrides) - { - if (swimCheck(ao.state) && ao.orig_id == id) return ao.state; - } - return STATE_AGENT_IDLE; -} - -LLUUID LLFloaterAO::GetAnimIDFromState(const AOState& state) -{ - for (const auto& ao : mAOOverrides) - { - if (ao.state == state) return ao.ao_id; - } - return LLUUID::null; -} - -AOState LLFloaterAO::GetStateFromToken(std::string strtoken) -{ - if (strtoken == "[ Sitting On Ground ]") return STATE_AGENT_GROUNDSIT; + if (strtoken == "[ Sitting On Ground ]") return STATE_AGENT_SIT_GROUND; if (strtoken == "[ Sitting ]") return STATE_AGENT_SIT; if (strtoken == "[ Crouching ]") return STATE_AGENT_CROUCH; if (strtoken == "[ Crouch Walking ]") return STATE_AGENT_CROUCHWALK; @@ -588,297 +554,165 @@ AOState LLFloaterAO::GetStateFromToken(std::string strtoken) if (strtoken == "[ Turning Left ]") return STATE_AGENT_TURNLEFT; if (strtoken == "[ Walking ]") return STATE_AGENT_WALK; if (strtoken == "[ Landing ]") return STATE_AGENT_LAND; - if (strtoken == "[ Standing ]") return STATE_AGENT_STAND; + if (strtoken == "[ Standing ]") return STATE_AGENT_IDLE; if (strtoken == "[ Swimming Down ]") return STATE_AGENT_SWIM_DOWN; if (strtoken == "[ Swimming Up ]") return STATE_AGENT_SWIM_UP; if (strtoken == "[ Swimming Forward ]") return STATE_AGENT_SWIM; if (strtoken == "[ Floating ]") return STATE_AGENT_FLOAT; - if (strtoken == "[ Typing ]") return STATE_AGENT_TYPING; - return STATE_AGENT_IDLE; + if (strtoken == "[ Typing ]") return STATE_AGENT_TYPE; + return STATE_AGENT_END; } -void LLFloaterAO::onClickCycleStand(bool next) +void AOSystem::updateStand() { - if (mAOStands.empty()) return; - stand_iterator += (next ? 1 : -1); - if (stand_iterator < 0) stand_iterator = int( mAOStands.size()-stand_iterator); - if (stand_iterator > int( mAOStands.size()-1)) stand_iterator = 0; - cmdline_printchat(llformat("Changing stand to %s.",mAOStands[stand_iterator].anim_name.c_str())); - ChangeStand(); + auto& stand_ao = stand(); + bool is_standing = stand_ao.playing; + if (is_standing) stand_ao.play(false); // Stop stand first + stand_ao.update(mAOStands, stand_iterator); // Now update stand + if (is_standing && !mAOStands.empty()) // Play stand if needed + stand_ao.play(); } -void LLFloaterAO::ChangeStand() +int AOSystem::cycleStand(bool next, bool random) { - if (gSavedSettings.getBOOL("AOEnabled")) + if (mAOStands.empty()) return -1; + const int size = mAOStands.size(); + if (size > 1) { - if (gAgentAvatarp) - { - if (gSavedSettings.getBOOL("AONoStandsInMouselook") && gAgentCamera.cameraMouselook()) return; - - if (gAgentAvatarp->isSitting()) - { -// stopMotion(getCurrentStandId(), true); //stop stand first then set state -// if (getAnimationState() != STATE_AGENT_GROUNDSIT) setAnimationState(STATE_AGENT_SIT); -// setCurrentStandId(LLUUID::null); - return; - } - } - AOState state = getAnimationState(); - if (state == STATE_AGENT_IDLE || state == STATE_AGENT_STAND)// stands have lowest priority - { - if (mAOStands.empty()) return; - if (gSavedSettings.getBOOL("AOStandRandomize")) - { - stand_iterator = ll_rand(mAOStands.size()-1); - } - if (stand_iterator < 0) stand_iterator = int( mAOStands.size()-stand_iterator); - if (stand_iterator > int( mAOStands.size()-1)) stand_iterator = 0; - - int stand_iterator_previous = stand_iterator -1; - - if (stand_iterator_previous < 0) stand_iterator_previous = int( mAOStands.size()-1); - - if (mAOStands[stand_iterator].ao_id.notNull()) - { - stopMotion(getCurrentStandId(), true); //stop stand first then set state - startMotion(mAOStands[stand_iterator].ao_id, true); - - setAnimationState(STATE_AGENT_STAND); - setCurrentStandId(mAOStands[stand_iterator].ao_id); - if (mcomboBox_stands) mcomboBox_stands->selectNthItem(stand_iterator); -// LL_INFOS() << "changing stand to " << mAOStands[stand_iterator].anim_name << LL_ENDL; - } - } - } - else stopMotion(getCurrentStandId(), true); -} - -void LLFloaterAO::toggleSwim(bool underwater) -{ - static const LLCachedControl enabled(gSavedSettings, "AOEnabled", false); - - sSwimming = underwater && enable_swim(); - - // Don't send requests if we have the AO disabled. - if (enabled) - { - AOState state = getAnimationState(); - if (state != STATE_AGENT_IDLE && state != STATE_AGENT_STAND) // Don't bother if we're just standing or idle (Who pushed us?!) - { - // Stop all of the previous states - constexpr std::array swim_states = { STATE_AGENT_FLOAT, STATE_AGENT_SWIM, STATE_AGENT_SWIM_UP, STATE_AGENT_SWIM_DOWN }; - constexpr std::array fly_states = { STATE_AGENT_HOVER, STATE_AGENT_FLY, STATE_AGENT_HOVER_UP, STATE_AGENT_HOVER_DOWN }; - uuid_vec_t vec; - for (const auto& state : sSwimming ? fly_states : swim_states) - vec.push_back(GetAnimIDFromState(state)); - gAgent.sendAnimationRequests(vec, ANIM_REQUEST_STOP); - // Process new animations - gAgentAvatarp->processAnimationStateChanges(); - } - } -} - -void LLFloaterAO::doMotion(const LLUUID& id, bool start, bool stand) -{ - if (id.isNull()) return; - LLUUID anim = id; - if (stand) - { - if (start) - { - if (gAgentAvatarp && gAgentAvatarp->isSitting()) - return; - } - else setAnimationState(STATE_AGENT_IDLE); - } - else - { - anim = GetAnimID(id); - if (anim.isNull() || !gSavedSettings.getBOOL("AOEnabled")) return; - AOState state = GetStateFromAnimID(id); - if (start) - { - stopMotion(getCurrentStandId(), true); //stop stand first then set state - setAnimationState(state); -// LL_INFOS() << " state " << getAnimationState() << " start anim " << id << " overriding with " << anim << LL_ENDL; - if (state == STATE_AGENT_SIT && !gSavedSettings.getBOOL("AOSitsEnabled")) return; - } + if (random && gSavedSettings.getBOOL("AOStandRandomize")) + for (auto previous = stand_iterator; previous == stand_iterator; + stand_iterator = ll_rand(size)); else { -// LL_INFOS() << " state " << getAnimationState() << "/" << state << "(now 0) stop anim " << id << " overriding with " << anim << LL_ENDL; - if (getAnimationState() == state) setAnimationState(STATE_AGENT_IDLE); - ChangeStand(); // startMotion(getCurrentStandId(), true); + stand_iterator += next ? 1 : -1; + // Wrap around + if (stand_iterator == size) stand_iterator = 0; + else if (stand_iterator == -1) stand_iterator = size - 1; } + if (auto floater = LLFloaterAO::findInstance()) + if (auto combo = floater->getComboFromState(STATE_AGENT_IDLE)) + combo->selectNthItem(stand_iterator); +// LL_INFOS() << "changing stand to " << mAOStands[stand_iterator].anim_name << LL_ENDL; } - gAgent.sendAnimationRequest(anim, start ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); + updateStand(); + return stand_iterator; } -void LLFloaterAO::onClickReloadCard() +void AOSystem::toggleSwim(bool underwater) { - if (LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) - { - init(); - } -} + sSwimming = underwater && enable_swim(); -void LLFloaterAO::onClickOpenCard() -{ - if (LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) + if (isStanding()) return; // Don't bother if we're just standing (Who pushed us?!) + + typedef std::array flies_t; + // Stop all of the previous states +#define AOO(state) mAOOverrides[STATE_AGENT_##state] + const flies_t swims = { AOO(FLOAT), AOO(SWIM), AOO(SWIM_UP), AOO(SWIM_DOWN) }; + const flies_t flies = { AOO(HOVER), AOO(FLY), AOO(HOVER_UP), AOO(HOVER_DOWN) }; +#undef AOO + const auto& oldaos = sSwimming ? flies : swims; + const auto& newaos = sSwimming ? swims : flies; + + for (auto i = 0; i < oldaos.size(); ++i) { - LLUUID configncitem = (LLUUID)gSavedPerAccountSettings.getString("AOConfigNotecardID"); - if (configncitem.notNull()) + auto& old = *oldaos[i]; + if (old.playing) { - if (LLViewerInventoryItem* item = gInventory.getItem(configncitem)) - { - if (gAgent.allowOperation(PERM_COPY, item->getPermissions(),GP_OBJECT_MANIPULATE) || gAgent.isGodlike()) - { - if(!item->getAssetUUID().isNull()) - open_notecard(item, "Note: " + item->getName(), LLUUID::null, false); - } - } + old.play(false); + newaos[i]->play(); } } } -void LLFloaterAO::onClickNewCard() +void AOSystem::doMotion(const LLUUID& id, bool start) { - // load the template file from app_settings/ao_template.ini then - // create a new properly-formatted notecard in the user's inventory - std::string ao_template = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "ao_template.ini"); - if (!ao_template.empty()) + if (id.isNull() || !gAgentAvatarp) return; + + overrides* aop = nullptr; + AOState state = STATE_AGENT_IDLE; + for (U8 i = STATE_AGENT_IDLE; !aop && i < STATE_AGENT_END; ++i) { - LLPointer cb = new AONotecardCallback(ao_template); - create_inventory_item(gAgentID, gAgentSessionID, - LLUUID::null, LLTransactionID::tnull, "New AO Notecard", - "Drop this notecard in your AO window to use", LLAssetType::AT_NOTECARD, - LLInventoryType::IT_NOTECARD, NOT_WEARABLE, PERM_ALL, cb); - } - else - { - LL_WARNS() << "Can't find ao_template.ini in app_settings!" << LL_ENDL; - } -} - -struct AOAssetInfo -{ - std::string path, name; -}; - -AOState LLFloaterAO::getStateFromCombo(const LLComboBox* combo) -{ - if (combo == mcomboBox_stands) return STATE_AGENT_STAND; - if (combo == mcomboBox_walks) return STATE_AGENT_WALK; - if (combo == mcomboBox_runs) return STATE_AGENT_RUN; - if (combo == mcomboBox_jumps) return STATE_AGENT_JUMP; - if (combo == mcomboBox_sits) return STATE_AGENT_SIT; - if (combo == mcomboBox_gsits) return STATE_AGENT_GROUNDSIT; - if (combo == mcomboBox_crouchs) return STATE_AGENT_CROUCH; - if (combo == mcomboBox_cwalks) return STATE_AGENT_CROUCHWALK; - if (combo == mcomboBox_falls) return STATE_AGENT_FALLDOWN; - if (combo == mcomboBox_hovers) return STATE_AGENT_HOVER; - if (combo == mcomboBox_flys) return STATE_AGENT_FLY; - if (combo == mcomboBox_flyslows) return STATE_AGENT_FLYSLOW; - if (combo == mcomboBox_flyups) return STATE_AGENT_HOVER_UP; - if (combo == mcomboBox_flydowns) return STATE_AGENT_HOVER_DOWN; - if (combo == mcomboBox_lands) return STATE_AGENT_LAND; - if (combo == mcomboBox_typings) return STATE_AGENT_TYPING; - if (combo == mcomboBox_floats) return STATE_AGENT_FLOAT; - if (combo == mcomboBox_swims) return STATE_AGENT_SWIM; - if (combo == mcomboBox_swimups) return STATE_AGENT_SWIM_UP; - if (combo == mcomboBox_swimdowns) return STATE_AGENT_SWIM_DOWN; - if (combo == mcomboBox_standups) return STATE_AGENT_STANDUP; - if (combo == mcomboBox_prejumps) return STATE_AGENT_PRE_JUMP; - return STATE_AGENT_IDLE; -} - -LLComboBox* LLFloaterAO::getComboFromState(const AOState& state) -{ - switch (state) - { - case STATE_AGENT_STAND: return mcomboBox_stands; - case STATE_AGENT_WALK: return mcomboBox_walks; - case STATE_AGENT_RUN: return mcomboBox_runs; - case STATE_AGENT_JUMP: return mcomboBox_jumps; - case STATE_AGENT_SIT: return mcomboBox_sits; - case STATE_AGENT_GROUNDSIT: return mcomboBox_gsits; - case STATE_AGENT_CROUCH: return mcomboBox_crouchs; - case STATE_AGENT_CROUCHWALK: return mcomboBox_cwalks; - case STATE_AGENT_FALLDOWN: return mcomboBox_falls; - case STATE_AGENT_HOVER: return mcomboBox_hovers; - case STATE_AGENT_FLY: return mcomboBox_flys; - case STATE_AGENT_FLYSLOW: return mcomboBox_flyslows; - case STATE_AGENT_HOVER_UP: return mcomboBox_flyups; - case STATE_AGENT_HOVER_DOWN: return mcomboBox_flydowns; - case STATE_AGENT_LAND: return mcomboBox_lands; - case STATE_AGENT_TYPING: return mcomboBox_typings; - case STATE_AGENT_FLOAT: return mcomboBox_floats; - case STATE_AGENT_SWIM: return mcomboBox_swims; - case STATE_AGENT_SWIM_UP: return mcomboBox_swimups; - case STATE_AGENT_SWIM_DOWN: return mcomboBox_swimdowns; - case STATE_AGENT_STANDUP: return mcomboBox_standups; - case STATE_AGENT_PRE_JUMP: return mcomboBox_prejumps; - default: return nullptr; - } -} - -void LLFloaterAO::onNotecardLoadComplete(LLVFS *vfs,const LLUUID& asset_uuid,LLAssetType::EType type,void* user_data, S32 status, LLExtStat ext_status) -{ - if(status == LL_ERR_NOERR) - { - S32 size = vfs->getSize(asset_uuid, type); - U8* buffer = new U8[size]; - vfs->getData(asset_uuid, type, buffer, 0, size); - - if(type == LLAssetType::AT_NOTECARD) + auto& ao = mAOOverrides[i]; + if (ao && ao->overrideAnim(sSwimming, id)) { - LLViewerTextEditor* edit = new LLViewerTextEditor("",LLRect(0,0,0,0),S32_MAX,""); - if(edit->importBuffer((char*)buffer, (S32)size)) + aop = ao; + state = (AOState)i; + } + } + if (aop) + { +// LL_INFOS() << "st" << (start ? "art" : "op") << " anim " << id << " state " << state << LL_ENDL; + aop->play(start); + } +} + +void AOSystem::stopAllOverrides() const +{ + if (!isAgentAvatarValid()) return; + uuid_vec_t anims; + for (auto& ao : mAOOverrides) + { + if (ao->playing) + { + anims.push_back(ao->getOverride()); + ao->playing = false; + } + } + for (const auto& stand : mAOStands) + anims.push_back(stand.ao_id); + gAgent.sendAnimationRequests(anims, ANIM_REQUEST_STOP); +} + +void AOSystem::parseNotecard(LLVFS *vfs, const LLUUID& asset_uuid, LLAssetType::EType type, S32 status, bool reload) +{ + if (status == LL_ERR_NOERR) + { + if (type == LLAssetType::AT_NOTECARD) + { + AOSystem* self = getIfExists(); + S32 size = vfs->getSize(asset_uuid, LLAssetType::AT_NOTECARD); + U8* buffer = new U8[size]; + vfs->getData(asset_uuid, type, buffer, 0, size); + LLMemoryStream str(buffer, size); + LLNotecard nc; + if (nc.importStream(str)) { LL_INFOS() << "ao nc decode success" << LL_ENDL; - std::string card = edit->getText(); - edit->die(); - if (mcomboBox_stands) + if (self && reload) self->stopAllOverrides(); + + auto floater = LLFloaterAO::findInstance(); + if (floater) + for (auto& combo : floater->mCombos) { - mcomboBox_stands->clear(); - mcomboBox_stands->removeall(); + if (combo) + { + combo->clear(); + combo->removeall(); + } } - if (mcomboBox_walks) mcomboBox_walks->clear(); - if (mcomboBox_runs) mcomboBox_runs->clear(); - if (mcomboBox_jumps) mcomboBox_jumps->clear(); - if (mcomboBox_sits) mcomboBox_sits->clear(); - if (mcomboBox_gsits) mcomboBox_gsits->clear(); - if (mcomboBox_crouchs) mcomboBox_cwalks->clear(); - if (mcomboBox_cwalks) mcomboBox_cwalks->clear(); - if (mcomboBox_falls) mcomboBox_falls->clear(); - if (mcomboBox_hovers) mcomboBox_hovers->clear(); - if (mcomboBox_flys) mcomboBox_flys->clear(); - if (mcomboBox_flyslows) mcomboBox_flyslows->clear(); - if (mcomboBox_flyups) mcomboBox_flyups->clear(); - if (mcomboBox_flydowns) mcomboBox_flydowns->clear(); - if (mcomboBox_lands) mcomboBox_lands->clear(); - if (mcomboBox_typings) mcomboBox_typings->clear(); - if (mcomboBox_floats) mcomboBox_floats->clear(); - if (mcomboBox_swims) mcomboBox_swims->clear(); - if (mcomboBox_swimups) mcomboBox_swimups->clear(); - if (mcomboBox_swimdowns) mcomboBox_swimdowns->clear(); - if (mcomboBox_standups) mcomboBox_standups->clear(); - if (mcomboBox_prejumps) mcomboBox_prejumps->clear(); typedef boost::tokenizer > tokenizer; boost::char_separator sep("\n"); - tokenizer tokline(card, sep); + tokenizer tokline(nc.getText(), sep); for (const auto& strline : tokline) { // LL_INFOS() << "uncommented line: " << strline << LL_ENDL; - boost::regex type("^(\\s*)(\\[ )(.*)( \\])"); boost::smatch what; if (boost::regex_search(strline, what, type)) { - std::string strtoken(what[0]); + const std::string strtoken(what[0]); + const AOState state = GetStateFromToken(strtoken); + if (state == STATE_AGENT_END) + { + LL_WARNS() << "Invalid token: " << strtoken << LL_ENDL; + continue; + } // LL_INFOS() << "type: " << strtoken << LL_ENDL; + LLComboBox* combo = floater ? floater->getComboFromState(state) : nullptr; + auto aop = (reload && self) ? self->mAOOverrides[state] : nullptr; // LL_INFOS() << "anims in type: " << boost::regex_replace(strline, type, "") << LL_ENDL; boost::char_separator sep("|,"); @@ -886,90 +720,86 @@ void LLFloaterAO::onNotecardLoadComplete(LLVFS *vfs,const LLUUID& asset_uuid,LLA tokenizer tokanimnames(stranimnames, sep); for (const auto& stranim : tokanimnames) { - LLUUID animid(getAssetIDByName(stranim)); + if (stranim.empty()) continue; + const auto& animid(getAssetIDByName(stranim)); // LL_INFOS() << invfolderid.asString().c_str() << LL_ENDL; // LL_INFOS() << "anim: " << stranim.c_str() << " assetid: " << animid << LL_ENDL; - if (animid.isNull()) + if (animid.notNull()) { - cmdline_printchat(llformat("Warning: animation '%s' could not be found (Section: %s).",stranim.c_str(),strtoken.c_str())); - } - else - { - const AOState state = GetStateFromToken(strtoken); - switch (state) + if (aop) // If we're reloading { - case STATE_AGENT_STAND: - mAOStands.push_back({ animid, stranim }); - default: break; + if (state == STATE_AGENT_IDLE) + self->mAOStands.push_back({ animid, stranim }); + else + aop->ao_id = animid; } - if (LLComboBox* combo = getComboFromState(state)) - { - //LL_INFOS() << "1 anim: " << stranim.c_str() << " assetid: " << animid << LL_ENDL; - if (!combo->selectByValue(stranim)) //check if exist - combo->add(stranim, ADD_BOTTOM, true); - } - - for (auto& ao : mAOOverrides) - { - if (state == ao.state) - { - ao.ao_id = animid; - break; - } - } + if (combo && !combo->selectByValue(stranim)) // check if exists + combo->add(stranim, ADD_BOTTOM, true); } + else cmdline_printchat("Warning: animation '" + stranim + "' could not be found (Section: " + strtoken + ")."); } } } LL_INFOS() << "ao nc read sucess" << LL_ENDL; - for (auto& ao : mAOOverrides) + if (self) { - if (LLComboBox* combo = getComboFromState(ao.state)) + if (auto combo = floater ? floater->getComboFromState(STATE_AGENT_IDLE) : nullptr) + combo->selectNthItem(self->stand_iterator); + + for (U8 i = STATE_AGENT_IDLE+1; i < STATE_AGENT_END; ++i) { - std::string defaultanim = gSavedPerAccountSettings.getString(combo->getControlName()); - const LLUUID ao_id = getAssetIDByName(defaultanim); - if (ao_id != LLUUID::null) ao.ao_id = ao_id; - combo->selectByValue(defaultanim); + auto& aop = self->mAOOverrides[i]; + if (!aop) continue; + auto& ao = *aop; + const auto& setting = ao.setting; + if (!setting && ao.ao_id.isNull()) continue; + const auto& defaultanim = setting ? setting->get().asStringRef() : ao.ao_id.asString(); + if (defaultanim.empty()) continue; + const LLUUID& ao_id = getAssetIDByName(defaultanim); + if (reload && ao_id.notNull()) ao.ao_id = ao_id; + if (LLComboBox* combo = floater ? floater->getComboFromState(i) : nullptr) + if (!combo->selectByValue(defaultanim)) + combo->add(defaultanim, ADD_BOTTOM, true); + } + + if (reload && isAgentAvatarValid()) + { + // Fix the stand iter, container size may have changed + auto& iter = self->stand_iterator; + const auto& stands = self->mAOStands; + iter = llmin(iter, (int)stands.size()-1); + // Update the current stand + self->stand().update(stands, iter); + self->mAOStandTimer.reset(); + + const auto& anims = gAgentAvatarp->mPlayingAnimations; + bool playing = false; + for (auto& aop : self->mAOOverrides) + { + for (const auto& anim : anims) + { + if (aop && aop->overrideAnim(sSwimming, anim.first)) + { + if (!aop->isLowPriority()) playing = true; + aop->play(); + break; + } + } + } + + if (!playing) self->stand().play(); // Play stand if nothing was being played, this sometimes happens + + // Toggle typing AO the moment we toggle AO + typing(gAgent.getRenderState() & AGENT_STATE_TYPING); } } - run(); - } - else - { - LL_INFOS() << "ao nc decode error" << LL_ENDL; } + else LL_INFOS() << "ao nc decode error" << LL_ENDL; + delete[] buffer; } } - else - { - LL_INFOS() << "ao nc read error" << LL_ENDL; - } + else LL_INFOS() << "ao nc read error" << LL_ENDL; } - -class ObjectNameMatches : public LLInventoryCollectFunctor -{ -public: - ObjectNameMatches(std::string name) : sName(name) {} - virtual ~ObjectNameMatches() {} - virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) - { - return item && item->getParentUUID() == LLFloaterAO::invfolderid && item->getName() == sName; - } -private: - std::string sName; -}; - -const LLUUID& LLFloaterAO::getAssetIDByName(const std::string& name) -{ - if (name.empty() || !LLInventoryModelBackgroundFetch::instance().isEverythingFetched()) return LLUUID::null; - - LLViewerInventoryCategory::cat_array_t cats; - LLViewerInventoryItem::item_array_t items; - ObjectNameMatches matches(name); - gInventory.collectDescendentsIf(LLUUID::null,cats,items,false, matches); - - return items.empty() ? LLUUID::null : items[0]->getAssetUUID(); -}; diff --git a/indra/newview/floaterao.h b/indra/newview/floaterao.h index 2aaa789c9..e532db03b 100644 --- a/indra/newview/floaterao.h +++ b/indra/newview/floaterao.h @@ -2,54 +2,51 @@ #ifndef LL_LLFLOATERAO_H #define LL_LLFLOATERAO_H -#include "llfloater.h" -#include "llviewercontrol.h" #include "llagent.h" +#include "llcontrol.h" #include "lleventtimer.h" +#include "llfloater.h" -enum AOState +enum AOState : U8 { - STATE_AGENT_IDLE = 0, - STATE_AGENT_WALK = 1, - STATE_AGENT_RUN = 2, - STATE_AGENT_STAND = 3, + STATE_AGENT_IDLE , + STATE_AGENT_WALK, + STATE_AGENT_RUN, - STATE_AGENT_PRE_JUMP = 4, - STATE_AGENT_JUMP = 5, - STATE_AGENT_TURNLEFT = 6, - STATE_AGENT_TURNRIGHT = 7, + STATE_AGENT_PRE_JUMP, + STATE_AGENT_JUMP, + STATE_AGENT_TURNLEFT, + STATE_AGENT_TURNRIGHT, - STATE_AGENT_SIT = 8, - STATE_AGENT_GROUNDSIT = 9, + STATE_AGENT_SIT, + STATE_AGENT_SIT_GROUND, - STATE_AGENT_HOVER = 10, - STATE_AGENT_HOVER_DOWN = 11, - STATE_AGENT_HOVER_UP = 12, + STATE_AGENT_HOVER, + STATE_AGENT_HOVER_DOWN, + STATE_AGENT_HOVER_UP, - STATE_AGENT_CROUCH = 13, - STATE_AGENT_CROUCHWALK = 14, - STATE_AGENT_FALLDOWN = 15, - STATE_AGENT_STANDUP = 16, - STATE_AGENT_LAND = 17, + STATE_AGENT_CROUCH, + STATE_AGENT_CROUCHWALK, + STATE_AGENT_FALLDOWN, + STATE_AGENT_STANDUP, + STATE_AGENT_LAND, - STATE_AGENT_FLY = 18, - STATE_AGENT_FLYSLOW = 19, + STATE_AGENT_FLY, + STATE_AGENT_FLYSLOW, - STATE_AGENT_TYPING = 20, + STATE_AGENT_TYPE, - STATE_AGENT_SWIM_DOWN = 21, - STATE_AGENT_SWIM_UP = 22, - STATE_AGENT_SWIM = 23, - STATE_AGENT_FLOAT = 24, + STATE_AGENT_SWIM_DOWN, + STATE_AGENT_SWIM_UP, + STATE_AGENT_SWIM, + STATE_AGENT_FLOAT, STATE_AGENT_END }; - - - -class AOStandTimer : public LLEventTimer +class AOStandTimer final : public LLEventTimer { + friend class AOSystem; public: AOStandTimer(); ~AOStandTimer(); @@ -57,78 +54,146 @@ public: void reset(); }; -class AOInvTimer : public LLEventTimer +class AOInvTimer final : public LLEventTimer, public LLSingleton { -public: + friend class LLSingleton; + friend class AOSystem; AOInvTimer(); ~AOInvTimer(); + static void createIfNeeded(); +public: + static bool needed(); BOOL tick() override; }; -class LLFloaterAO : public LLFloater, public LLFloaterSingleton +class LLFloaterAO final : public LLFloater, public LLFloaterSingleton { + friend class AOSystem; public: - LLFloaterAO(const LLSD&); + LLFloaterAO(const LLSD&); BOOL postBuild() override; void onOpen() override; - virtual ~LLFloaterAO(); - - static void init(); - - static void run(); + virtual ~LLFloaterAO(); void updateLayout(bool advanced); - //static bool loadAnims(); + void onClickCycleStand(bool next) const; + void onClickReloadCard() const; + void onClickOpenCard() const; + void onClickNewCard() const; - static void typing(bool start); - static AOState flyToSwimState(const AOState& state); - static AOState swimToFlyState(const AOState& state); - static AOState getAnimationState(); - static void setAnimationState(const AOState& state); - - static LLUUID getCurrentStandId(); - static void setCurrentStandId(const LLUUID& id); - static int stand_iterator; - static void ChangeStand(); - static void toggleSwim(bool underwater); - - static void doMotion(const LLUUID& id, bool start, bool stand = false); - static void startMotion(const LLUUID& id, bool stand = false) { doMotion(id, true, stand); } - static void stopMotion(const LLUUID& id, bool stand = false) { doMotion(id, false, stand); } - - static bool swimCheck(const AOState& state); - static LLUUID GetAnimID(const LLUUID& id); - - static AOState GetStateFromAnimID(const LLUUID& id); - static LLUUID GetAnimIDFromState(const AOState& state); - static AOState GetStateFromToken(std::string strtoken); - - static void onClickCycleStand(bool next); - static void onClickReloadCard(); - static void onClickOpenCard(); - static void onClickNewCard(); - - static LLUUID invfolderid; - static const LLUUID& getAssetIDByName(const std::string& name); - private: - - static AOState mAnimationState; - static LLUUID mCurrentStandId; - - static void onSpinnerCommit(); - static void onComboBoxCommit(LLUICtrl* ctrl); + void onSpinnerCommit() const; + void onComboBoxCommit(LLUICtrl* ctrl) const; + std::array mCombos; protected: - static AOState getStateFromCombo(const class LLComboBox* combo); - static LLComboBox* getComboFromState(const AOState& state); - - static void onNotecardLoadComplete(LLVFS *vfs,const LLUUID& asset_uuid,LLAssetType::EType type,void* user_data, S32 status, LLExtStat ext_status); - + AOState getStateFromCombo(const class LLComboBox* combo) const; + LLComboBox* getComboFromState(const U8& state) const { return mCombos[state]; } }; -extern AOInvTimer* gAOInvTimer; +class AOSystem final : public LLSingleton +{ + friend class LLSingleton; + friend class AOInvTimer; + friend class LLFloaterAO; + AOSystem(); + ~AOSystem(); +public: + static void start(); // Runs the necessary actions to get the AOSystem ready, then initializes it. + void initSingleton() override; + + static void typing(bool start); + + int stand_iterator; + bool isStanding() const { return stand().playing; } + void updateStand(); + int cycleStand(bool next = true, bool random = true); + void toggleSwim(bool underwater); + + void doMotion(const LLUUID& id, bool start); + void startMotion(const LLUUID& id) { doMotion(id, true); } + void stopMotion(const LLUUID& id) { doMotion(id, false); } + void stopCurrentStand() const { stand().play(false); } + void stopAllOverrides() const; + +protected: + struct struct_stands + { + LLUUID ao_id; + std::string anim_name; + }; + typedef std::vector stands_vec; + stands_vec mAOStands; + + struct overrides + { + virtual bool overrideAnim(bool swimming, const LLUUID& anim) const = 0; + virtual const LLUUID& getOverride() const { return ao_id; } + virtual bool play_condition() const; // True if prevented from playing + virtual bool isLowPriority() const { return false; } + void play(bool start = true); + LLUUID ao_id; + LLPointer setting; + bool playing; + virtual ~overrides() {} + protected: + overrides(const char* setting_name); + }; + struct override_low_priority final : public overrides + { + override_low_priority(const LLUUID& id, const char* setting_name = nullptr) + : overrides(setting_name), orig_id(id) {} + bool overrideAnim(bool swimming, const LLUUID & anim) const override { return orig_id == anim; } + bool play_condition() const override { return false; } + bool isLowPriority() const override { return true; } + private: + const LLUUID orig_id; + }; + struct override_single final : public overrides + { + override_single(const LLUUID& id, const char* setting_name = nullptr, U8 swim = 2) + : overrides(setting_name), orig_id(id), swim(swim) {} + bool overrideAnim(bool swimming, const LLUUID& anim) const override { return (swim == 2 || !!swim == swimming) && orig_id == anim; } + private: + const LLUUID orig_id; + const U8 swim; // 2 = irrelevant, 0 = flying, 1 = swimming + }; + struct override_stand final : public overrides + { + override_stand() : overrides(nullptr) {} + bool overrideAnim(bool swimming, const LLUUID& anim) const override; + bool play_condition() const override; + bool isLowPriority() const override { return true; } + void update(const stands_vec& stands, const int& iter) + { + if (stands.empty()) ao_id.setNull(); + else ao_id = stands[iter].ao_id; + } + }; + struct override_sit final : public overrides + { + override_sit(const uuid_set_t& ids, const char* setting_name = nullptr) + : overrides(setting_name) + , orig_ids(ids) + {} + bool overrideAnim(bool swimming, const LLUUID& anim) const override { return orig_ids.find(anim) != orig_ids.end(); } + bool play_condition() const override; + private: + const uuid_set_t orig_ids; + }; + std::array mAOOverrides; + + override_stand& stand() const { return static_cast(*mAOOverrides[STATE_AGENT_IDLE]); } + +private: + std::array mConnections; + + AOStandTimer mAOStandTimer; + + static void requestConfigNotecard(bool reload = true); + static void parseNotecard(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, S32 status, bool reload); +}; #endif diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp index 28e5b8a5b..93924cfaa 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -2116,7 +2116,7 @@ void LLAgent::startTyping() } } - LLFloaterAO::typing(true); // Singu Note: Typing anims handled by AO/settings. + AOSystem::typing(true); // Singu Note: Typing anims handled by AO/settings. gChatBar-> sendChatFromViewer("", CHAT_TYPE_START, FALSE); } @@ -2129,7 +2129,7 @@ void LLAgent::stopTyping() if (mRenderState & AGENT_STATE_TYPING) { clearRenderState(AGENT_STATE_TYPING); - LLFloaterAO::typing(false); // Singu Note: Typing anims handled by AO/settings. + AOSystem::typing(false); // Singu Note: Typing anims handled by AO/settings. gChatBar-> sendChatFromViewer("", CHAT_TYPE_STOP, FALSE); } diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 727a59f4b..0b051809f 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -2265,7 +2265,8 @@ void LLAgentCamera::changeCameraToMouselook(BOOL animate) mMouselookTimer.reset(); gFocusMgr.setKeyboardFocus(NULL); - if (gSavedSettings.getBOOL("AONoStandsInMouselook")) LLFloaterAO::stopMotion(LLFloaterAO::getCurrentStandId(), true); + auto ao = AOSystem::getIfExists(); + if (ao && gSavedSettings.getBOOL("AONoStandsInMouselook")) ao->stopCurrentStand(); updateLastCamera(); mCameraMode = CAMERA_MODE_MOUSELOOK; diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 77382fd07..74645bde9 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -161,6 +161,7 @@ // in save_settings_to_globals() #include "llbutton.h" #include "llcombobox.h" +#include "floaterao.h" #include "floaterlocalassetbrowse.h" #include "llsurface.h" #include "llvotree.h" @@ -1659,6 +1660,8 @@ bool LLAppViewer::cleanup() LLCalc::cleanUp(); + AOSystem::deleteSingleton(); + LL_INFOS() << "Global stuff deleted" << LL_ENDL; // Note: this is where LLFeatureManager::getInstance()-> used to be deleted. diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 750de91bb..71b8e55e0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -2687,10 +2687,7 @@ bool idle_startup() } // Start the AO now that settings have loaded and login successful -- MC - if (!gAOInvTimer) - { - gAOInvTimer = new AOInvTimer(); - } + AOSystem::start(); gViewerWindow->showCursor(); gViewerWindow->getWindow()->resetBusyCount(); diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index bd43feff0..796bb6c93 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -4266,7 +4266,8 @@ void LLVOAvatar::idleUpdateBelowWater() BOOL old_below = mBelowWater; mBelowWater = avatar_height < water_height; if (old_below != mBelowWater) - LLFloaterAO::toggleSwim(mBelowWater); + if (auto ao = AOSystem::getIfExists()) + ao->toggleSwim(mBelowWater); } void LLVOAvatar::slamPosition() @@ -6301,7 +6302,7 @@ void LLVOAvatar::processAnimationStateChanges() } // clear all current animations - const bool AOEnabled(gSavedSettings.getBOOL("AOEnabled")); // + auto ao = isSelf() ? AOSystem::getIfExists() : nullptr; // AO is only for ME AnimIterator anim_it; for (anim_it = mPlayingAnimations.begin(); anim_it != mPlayingAnimations.end();) { @@ -6310,8 +6311,7 @@ void LLVOAvatar::processAnimationStateChanges() // playing, but not signaled, so stop if (found_anim == mSignaledAnimations.end()) { - if (AOEnabled && isSelf()) - LLFloaterAO::stopMotion(anim_it->first, FALSE); // if the AO replaced this anim serverside then stop it serverside + if (ao) ao->stopMotion(anim_it->first); // if the AO replaced this anim serverside then stop it serverside processSingleAnimationStateChange(anim_it->first, FALSE); // @@ -6337,10 +6337,7 @@ void LLVOAvatar::processAnimationStateChanges() // if (processSingleAnimationStateChange(anim_it->first, TRUE)) { - if (AOEnabled && isSelf()) // AO is only for ME - { - LLFloaterAO::startMotion(anim_it->first, false); // AO overrides the anim if needed - } + if (ao) ao->startMotion(anim_it->first); // AO overrides the anim if needed mPlayingAnimations[anim_it->first] = anim_it->second; ++anim_it; @@ -8040,8 +8037,6 @@ void LLVOAvatar::sitDown(BOOL bSitting) mIsSitting = bSitting; if (isSelf()) { - LLFloaterAO::ChangeStand(); - // [RLVa:KB] - Checked: 2010-08-29 (RLVa-1.2.1c) | Modified: RLVa-1.2.1c if (rlv_handler_t::isEnabled()) {