diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index 550d2d11d..d0ed1d211 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -92,6 +92,7 @@ set(viewer_SOURCE_FILES aixmllindengenepool.cpp alfloaterregiontracker.cpp aoremotectrl.cpp + aosystem.cpp ascentfloatercontactgroups.cpp ascentkeyword.cpp ascentprefschat.cpp @@ -636,6 +637,8 @@ set(viewer_HEADER_FILES aixmllindengenepool.h alfloaterregiontracker.h aoremotectrl.h + aostate.h + aosystem.h ascentfloatercontactgroups.h ascentkeyword.h ascentprefschat.h diff --git a/indra/newview/aostate.h b/indra/newview/aostate.h new file mode 100644 index 000000000..8f8fbc635 --- /dev/null +++ b/indra/newview/aostate.h @@ -0,0 +1,37 @@ +#pragma once + +enum AOState : U8 +{ + STATE_AGENT_IDLE, + STATE_AGENT_WALK, + STATE_AGENT_RUN, + + STATE_AGENT_PRE_JUMP, + STATE_AGENT_JUMP, + STATE_AGENT_TURNLEFT, + STATE_AGENT_TURNRIGHT, + + STATE_AGENT_SIT, + STATE_AGENT_SIT_GROUND, + + STATE_AGENT_HOVER, + STATE_AGENT_HOVER_DOWN, + STATE_AGENT_HOVER_UP, + + STATE_AGENT_CROUCH, + STATE_AGENT_CROUCHWALK, + STATE_AGENT_FALLDOWN, + STATE_AGENT_STANDUP, + STATE_AGENT_LAND, + + STATE_AGENT_FLY, + STATE_AGENT_FLYSLOW, + + STATE_AGENT_TYPE, + + STATE_AGENT_SWIM_DOWN, + STATE_AGENT_SWIM_UP, + STATE_AGENT_SWIM, + STATE_AGENT_FLOAT, + STATE_AGENT_END +}; diff --git a/indra/newview/aosystem.cpp b/indra/newview/aosystem.cpp new file mode 100644 index 000000000..18e12445b --- /dev/null +++ b/indra/newview/aosystem.cpp @@ -0,0 +1,596 @@ +/** + * @file aosystem.cpp + * @brief clientside animation overrider + * by Skills Hak & Liru Færs + */ + +#include "llviewerprecompiledheaders.h" + +#include "aosystem.h" + +#include "floaterao.h" +#include "llagent.h" +#include "llagentcamera.h" +#include "llanimationstates.h" +#include "llinventoryfunctions.h" +#include "llinventorypanel.h" +#include "llinventorymodelbackgroundfetch.h" +#include "llmemorystream.h" +#include "llnotecard.h" +#include "llstartup.h" +#include "llvoavatarself.h" +#include "llviewerregion.h" +#include "roles_constants.h" + +#include + +// Uncomment and use instead if we ever add the chatbar as a command line - MC +void cmdline_printchat(const std::string& message); + +namespace +{ + bool sSwimming = false; + bool enable_swim() + { + static const LLCachedControl swim(gSavedSettings, "AOSwimEnabled", false); + return swim; + } + bool is_underwater() { return enable_swim() && gAgentAvatarp && gAgentAvatarp->mBelowWater; } +} + +// ------------------------------------------------------- +void AOSystem::AOStandTimer::reset() +{ + mPeriod = gSavedSettings.getF32("AOStandInterval"); + mEventTimer.reset(); +// LL_INFOS() << "reset" << LL_ENDL; +} + +// ------------------------------------------------------- +class AOInvTimer final : public LLEventTimer, public LLSingleton +{ + friend class LLSingleton; + friend class AOSystem; + AOInvTimer() : LLEventTimer(1.0f) {} + ~AOInvTimer() {} + static void createIfNeeded() + { + if (needed()) LLSingleton::getInstance(); + else AOSystem::getInstance(); + } +public: + static bool needed() + { + return LLStartUp::getStartupState() < STATE_INVENTORY_SEND // Haven't done inventory transfer yet + || !LLInventoryModelBackgroundFetch::instance().isEverythingFetched(); // Everything hasn't been fetched yet + } + BOOL tick() override + { + if (!gSavedSettings.getBOOL("AOEnabled")) return true; // If disabled on a tick, we don't care anymore + if (!needed()) + { +// cmdline_printchat("Inventory fetched, loading AO."); + AOSystem::getInstance(); // Initializes everything + return true; + } + 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; +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 ------------------------------------------------------- + +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); +} + +struct override_low_priority final : public AOSystem::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 AOSystem::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_sit final : public AOSystem::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 + { + overrides::play_condition(); + return !gSavedSettings.getBOOL("AOSitsEnabled"); + } +private: + const uuid_set_t orig_ids; +}; + +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_stand::overrideAnim(bool swimming, const LLUUID& anim) const +{ + return anim == ANIM_AGENT_STAND; +} + +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 + + auto swim_forced = gSavedSettings.getControl("AOSwimForced"); + sSwimming = swim_forced->get().asBoolean() || is_underwater(); + mConnections[0] = gSavedSettings.getControl("AOSitsEnabled")->getSignal()->connect([this](LLControlVariable*, const LLSD& val) { + if (!isAgentAvatarValid() || !gAgentAvatarp->isSitting()) return; + gAgent.sendAnimationRequest(mAOOverrides[gAgentAvatarp->getParent() ? STATE_AGENT_SIT : STATE_AGENT_SIT_GROUND]->ao_id, val.asBoolean() ? ANIM_REQUEST_START : ANIM_REQUEST_STOP); + }); + const auto& swim_cb = [=](LLControlVariable*, const LLSD&){ toggleSwim(swim_forced->get().asBoolean() || is_underwater()); }; + auto swim_enabled = gSavedSettings.getControl("AOSwimEnabled"); + mConnections[1] = swim_enabled->getSignal()->connect(swim_cb); + mConnections[2] = swim_forced->getSignal()->connect([swim_cb, swim_enabled](LLControlVariable*, const LLSD& val) { + if (val.asBoolean()) // Automatically enable Swim AO. + swim_enabled->set(true); + swim_cb(nullptr, LLSD()); + }); +} + +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 (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 GetStateFromToken(const std::string& strtoken) +{ + 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; + if (strtoken == "[ Standing Up ]") return STATE_AGENT_STANDUP; + if (strtoken == "[ Falling ]") return STATE_AGENT_FALLDOWN; + if (strtoken == "[ Flying Down ]") return STATE_AGENT_HOVER_DOWN; + if (strtoken == "[ Flying Up ]") return STATE_AGENT_HOVER_UP; + if (strtoken == "[ Flying Slow ]") return STATE_AGENT_FLYSLOW; + if (strtoken == "[ Flying ]") return STATE_AGENT_FLY; + if (strtoken == "[ Hovering ]") return STATE_AGENT_HOVER; + if (strtoken == "[ Jumping ]") return STATE_AGENT_JUMP; + if (strtoken == "[ Pre Jumping ]") return STATE_AGENT_PRE_JUMP; + if (strtoken == "[ Running ]") return STATE_AGENT_RUN; + if (strtoken == "[ Turning Right ]") return STATE_AGENT_TURNRIGHT; + 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_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_TYPE; + return STATE_AGENT_END; +} + +void AOSystem::updateStand() +{ + 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(); +} + +int AOSystem::cycleStand(bool next, bool random) +{ + if (mAOStands.empty()) return -1; + const int size = mAOStands.size(); + if (size > 1) + { + if (random && gSavedSettings.getBOOL("AOStandRandomize")) + for (auto previous = stand_iterator; previous == stand_iterator; + stand_iterator = ll_rand(size)); + else + { + 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; + } + updateStand(); + return stand_iterator; +} + +void AOSystem::toggleSwim(bool underwater) +{ + sSwimming = underwater && enable_swim(); + + 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) + { + auto& old = *oldaos[i]; + if (old.playing) + { + old.play(false); + newaos[i]->play(); + } + } +} + +void AOSystem::doMotion(const LLUUID& id, bool start) +{ + 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) + { + auto& ao = mAOOverrides[i]; + if (ao && ao->overrideAnim(sSwimming, id)) + { + 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; + + if (self && reload) self->stopAllOverrides(); + + auto floater = LLFloaterAO::findInstance(); + if (floater) + for (auto& combo : floater->mCombos) + { + if (combo) + { + combo->clear(); + combo->removeall(); + } + } + + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("\n"); + 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)) + { + 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("|,"); + std::string stranimnames(boost::regex_replace(strline, type, "")); + tokenizer tokanimnames(stranimnames, sep); + for (const auto& stranim : tokanimnames) + { + 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.notNull()) + { + if (aop) // If we're reloading + { + if (state == STATE_AGENT_IDLE) + self->mAOStands.push_back({ animid, stranim }); + else + aop->ao_id = animid; + } + + 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; + + if (self) + { + 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) + { + 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); + } + } + } + else LL_INFOS() << "ao nc decode error" << LL_ENDL; + delete[] buffer; + } + } + else LL_INFOS() << "ao nc read error" << LL_ENDL; +} diff --git a/indra/newview/aosystem.h b/indra/newview/aosystem.h new file mode 100644 index 000000000..8dbfc6c78 --- /dev/null +++ b/indra/newview/aosystem.h @@ -0,0 +1,101 @@ +#pragma once + +#include "aostate.h" +#include "llcontrol.h" +#include "lleventtimer.h" + +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); + }; + friend struct override_low_priority; + friend struct override_single; + friend struct override_sit; + 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; + } + }; + std::array mAOOverrides; + + override_stand& stand() const { return static_cast(*mAOOverrides[STATE_AGENT_IDLE]); } + +private: + std::array mConnections; + + + class AOStandTimer final : public LLEventTimer + { + friend class AOSystem; + public: + AOStandTimer() : LLEventTimer(F32_MAX) {} + ~AOStandTimer() + { +// LL_INFOS() << "dead" << LL_ENDL; + } + BOOL tick() override + { +// LL_INFOS() << "tick" << LL_ENDL; + if (auto ao = AOSystem::getIfExists()) + ao->cycleStand(); + return false; + } + void reset(); + }; + AOStandTimer mAOStandTimer; + + static void requestConfigNotecard(bool reload = true); + static void parseNotecard(LLVFS* vfs, const LLUUID& asset_uuid, LLAssetType::EType type, S32 status, bool reload); +}; + diff --git a/indra/newview/floaterao.cpp b/indra/newview/floaterao.cpp index 7df3387fb..973c4e233 100644 --- a/indra/newview/floaterao.cpp +++ b/indra/newview/floaterao.cpp @@ -1,49 +1,27 @@ /** * @file llfloaterao.cpp - * @brief clientside animation overrider + * @brief clientside animation overrider floater * by Skills Hak & Liru Færs */ #include "llviewerprecompiledheaders.h" #include "floaterao.h" +#include "aosystem.h" #include "llagent.h" -#include "llagentcamera.h" -#include "llanimationstates.h" #include "llcombobox.h" #include "llfirstuse.h" -#include "llinventory.h" -#include "llinventorybridge.h" -#include "llinventoryfunctions.h" #include "llinventorypanel.h" -#include "llinventorymodelbackgroundfetch.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 "roles_constants.h" -#include - // Uncomment and use instead if we ever add the chatbar as a command line - MC void cmdline_printchat(const std::string& message); -namespace -{ - bool sSwimming = false; - bool enable_swim() - { - static const LLCachedControl swim(gSavedSettings, "AOSwimEnabled", false); - return swim; - } - bool is_underwater() { return enable_swim() && gAgentAvatarp && gAgentAvatarp->mBelowWater; } -} - class AONotecardCallback final : public LLInventoryCallback { public: @@ -53,7 +31,7 @@ public: { if (!mFileName.empty()) { - LLPreviewNotecard* nc = (LLPreviewNotecard*)LLPreview::show(inv_item); + auto nc = (LLPreviewNotecard*)LLPreview::show(inv_item); if (!nc) { auto item = gInventory.getItem(inv_item); @@ -89,101 +67,6 @@ private: }; -// ------------------------------------------------------- - -AOStandTimer::AOStandTimer() : LLEventTimer(F32_MAX) -{ -} -AOStandTimer::~AOStandTimer() -{ -// LL_INFOS() << "dead" << LL_ENDL; -} -void AOStandTimer::reset() -{ - mPeriod = gSavedSettings.getF32("AOStandInterval"); - mEventTimer.reset(); -// LL_INFOS() << "reset" << LL_ENDL; -} -BOOL AOStandTimer::tick() -{ -// LL_INFOS() << "tick" << LL_ENDL; - if (auto ao = AOSystem::getIfExists()) - ao->cycleStand(); - return false; -} - -// ------------------------------------------------------- - -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 (!gSavedSettings.getBOOL("AOEnabled")) return true; // If disabled on a tick, we don't care anymore - if (!needed()) - { -// cmdline_printchat("Inventory fetched, loading AO."); - AOSystem::getInstance(); // Initializes everything - return true; - } - 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 ------------------------------------------------------- - LLFloaterAO::LLFloaterAO(const LLSD&) : LLFloater("floater_ao") , mCombos({}) { @@ -288,15 +171,17 @@ void LLFloaterAO::onComboBoxCommit(LLUICtrl* ctrl) const } else { - AOState state = getStateFromCombo(box); - llassert(state != STATE_AGENT_END); - const LLUUID& anim = getAssetIDByName(stranim); + auto end = mCombos.end(); + auto it = std::find(mCombos.begin(), end, box); + llassert(it != end); + const auto state = std::distance(mCombos.begin(), it); if (auto aop = ao->mAOOverrides[state]) { + LLUUID getAssetIDByName(const std::string & name); // LL_INFOS() << "state " << state << " - " << aop->playing() << LL_ENDL; bool was_playing = aop->playing; if (was_playing) aop->play(false); - aop->ao_id = anim; + aop->ao_id = getAssetIDByName(stranim); if (was_playing) aop->play(); } } @@ -322,15 +207,12 @@ void LLFloaterAO::onClickReloadCard() const 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); - } + auto 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 @@ -350,464 +232,3 @@ void LLFloaterAO::onClickNewCard() const "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 - - auto swim_forced = gSavedSettings.getControl("AOSwimForced"); - sSwimming = swim_forced->get().asBoolean() || 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); - }); - const auto& swim_cb = [=](LLControlVariable*, const LLSD&){ toggleSwim(swim_forced->get().asBoolean() || is_underwater()); }; - auto swim_enabled = gSavedSettings.getControl("AOSwimEnabled"); - mConnections[1] = swim_enabled->getSignal()->connect(swim_cb); - mConnections[2] = swim_forced->getSignal()->connect([swim_cb, swim_enabled](LLControlVariable*, const LLSD& val) { - if (val.asBoolean()) // Automatically enable Swim AO. - swim_enabled->set(true); - swim_cb(nullptr, LLSD()); - }); -} - -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 (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 GetStateFromToken(const std::string& strtoken) -{ - 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; - if (strtoken == "[ Standing Up ]") return STATE_AGENT_STANDUP; - if (strtoken == "[ Falling ]") return STATE_AGENT_FALLDOWN; - if (strtoken == "[ Flying Down ]") return STATE_AGENT_HOVER_DOWN; - if (strtoken == "[ Flying Up ]") return STATE_AGENT_HOVER_UP; - if (strtoken == "[ Flying Slow ]") return STATE_AGENT_FLYSLOW; - if (strtoken == "[ Flying ]") return STATE_AGENT_FLY; - if (strtoken == "[ Hovering ]") return STATE_AGENT_HOVER; - if (strtoken == "[ Jumping ]") return STATE_AGENT_JUMP; - if (strtoken == "[ Pre Jumping ]") return STATE_AGENT_PRE_JUMP; - if (strtoken == "[ Running ]") return STATE_AGENT_RUN; - if (strtoken == "[ Turning Right ]") return STATE_AGENT_TURNRIGHT; - 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_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_TYPE; - return STATE_AGENT_END; -} - -void AOSystem::updateStand() -{ - 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(); -} - -int AOSystem::cycleStand(bool next, bool random) -{ - if (mAOStands.empty()) return -1; - const int size = mAOStands.size(); - if (size > 1) - { - if (random && gSavedSettings.getBOOL("AOStandRandomize")) - for (auto previous = stand_iterator; previous == stand_iterator; - stand_iterator = ll_rand(size)); - else - { - 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; - } - updateStand(); - return stand_iterator; -} - -void AOSystem::toggleSwim(bool underwater) -{ - sSwimming = underwater && enable_swim(); - - 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) - { - auto& old = *oldaos[i]; - if (old.playing) - { - old.play(false); - newaos[i]->play(); - } - } -} - -void AOSystem::doMotion(const LLUUID& id, bool start) -{ - 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) - { - auto& ao = mAOOverrides[i]; - if (ao && ao->overrideAnim(sSwimming, id)) - { - 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; - - if (self && reload) self->stopAllOverrides(); - - auto floater = LLFloaterAO::findInstance(); - if (floater) - for (auto& combo : floater->mCombos) - { - if (combo) - { - combo->clear(); - combo->removeall(); - } - } - - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("\n"); - 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)) - { - 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("|,"); - std::string stranimnames(boost::regex_replace(strline, type, "")); - tokenizer tokanimnames(stranimnames, sep); - for (const auto& stranim : tokanimnames) - { - 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.notNull()) - { - if (aop) // If we're reloading - { - if (state == STATE_AGENT_IDLE) - self->mAOStands.push_back({ animid, stranim }); - else - aop->ao_id = animid; - } - - 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; - - if (self) - { - 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) - { - 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); - } - } - } - else LL_INFOS() << "ao nc decode error" << LL_ENDL; - delete[] buffer; - } - } - else LL_INFOS() << "ao nc read error" << LL_ENDL; -} diff --git a/indra/newview/floaterao.h b/indra/newview/floaterao.h index e532db03b..187493e34 100644 --- a/indra/newview/floaterao.h +++ b/indra/newview/floaterao.h @@ -1,71 +1,8 @@ +#pragma once -#ifndef LL_LLFLOATERAO_H -#define LL_LLFLOATERAO_H - -#include "llagent.h" -#include "llcontrol.h" -#include "lleventtimer.h" +#include "aostate.h" #include "llfloater.h" - -enum AOState : U8 -{ - STATE_AGENT_IDLE , - STATE_AGENT_WALK, - STATE_AGENT_RUN, - - STATE_AGENT_PRE_JUMP, - STATE_AGENT_JUMP, - STATE_AGENT_TURNLEFT, - STATE_AGENT_TURNRIGHT, - - STATE_AGENT_SIT, - STATE_AGENT_SIT_GROUND, - - STATE_AGENT_HOVER, - STATE_AGENT_HOVER_DOWN, - STATE_AGENT_HOVER_UP, - - STATE_AGENT_CROUCH, - STATE_AGENT_CROUCHWALK, - STATE_AGENT_FALLDOWN, - STATE_AGENT_STANDUP, - STATE_AGENT_LAND, - - STATE_AGENT_FLY, - STATE_AGENT_FLYSLOW, - - STATE_AGENT_TYPE, - - STATE_AGENT_SWIM_DOWN, - STATE_AGENT_SWIM_UP, - STATE_AGENT_SWIM, - STATE_AGENT_FLOAT, - STATE_AGENT_END -}; - -class AOStandTimer final : public LLEventTimer -{ - friend class AOSystem; -public: - AOStandTimer(); - ~AOStandTimer(); - BOOL tick() override; - void reset(); -}; - -class AOInvTimer final : public LLEventTimer, public LLSingleton -{ - friend class LLSingleton; - friend class AOSystem; - AOInvTimer(); - ~AOInvTimer(); - static void createIfNeeded(); -public: - static bool needed(); - BOOL tick() override; -}; - class LLFloaterAO final : public LLFloater, public LLFloaterSingleton { friend class AOSystem; @@ -89,111 +26,5 @@ private: protected: - AOState getStateFromCombo(const class LLComboBox* combo) const; LLComboBox* getComboFromState(const U8& state) const { return mCombos[state]; } }; - -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 93924cfaa..171205a2c 100644 --- a/indra/newview/llagent.cpp +++ b/indra/newview/llagent.cpp @@ -106,7 +106,7 @@ #include "lluictrlfactory.h" //For LLUICtrlFactory::getLayeredXMLNode -#include "floaterao.h" // for Typing override +#include "aosystem.h" // for Typing override #include "hippolimits.h" // for getMaxAgentGroups // [RLVa:KB] - Checked: 2011-11-04 (RLVa-1.4.4a) #include "rlvactions.h" diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp index 0b051809f..c08751eda 100644 --- a/indra/newview/llagentcamera.cpp +++ b/indra/newview/llagentcamera.cpp @@ -29,6 +29,7 @@ #include "pipeline.h" +#include "aosystem.h" //For AOSystem #include "llagent.h" #include "llanimationstates.h" #include "llfloatercamera.h" @@ -49,7 +50,6 @@ #include "llwindow.h" #include "llworld.h" #include "llfloatertools.h" //For gFloaterTools -#include "floaterao.h" //For LLFloaterAO #include "llfloatercustomize.h" //For gFloaterCustomize // [RLVa:KB] - Checked: 2010-05-10 (RLVa-1.2.0g) #include "rlvhandler.h" diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 74645bde9..6a4f3fcce 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -159,9 +159,9 @@ // Included so that constants/settings might be initialized // in save_settings_to_globals() +#include "aosystem.h" #include "llbutton.h" #include "llcombobox.h" -#include "floaterao.h" #include "floaterlocalassetbrowse.h" #include "llsurface.h" #include "llvotree.h" diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp index 71b8e55e0..6df4e95d0 100644 --- a/indra/newview/llstartup.cpp +++ b/indra/newview/llstartup.cpp @@ -52,9 +52,9 @@ #include "llaudioengine_openal.h" #endif +#include "aosystem.h" #include "hippogridmanager.h" #include "hippolimits.h" -#include "floaterao.h" #include "statemachine/aifilepicker.h" #include "lfsimfeaturehandler.h" diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index fee9676a7..6d945b613 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -109,8 +109,8 @@ #include "llvoicevisualizer.h" // Ventrella #include "llsdserialize.h" //For the client definitions +#include "aosystem.h" #include "llcachename.h" -#include "floaterao.h" #include "llsdutil.h" #include "llskinningutil.h"