Split up floaterao.* into aosystem.* and aostate.h, also further refactor
This commit is contained in:
@@ -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
|
||||
|
||||
37
indra/newview/aostate.h
Normal file
37
indra/newview/aostate.h
Normal file
@@ -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
|
||||
};
|
||||
596
indra/newview/aosystem.cpp
Normal file
596
indra/newview/aosystem.cpp
Normal file
@@ -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 <boost/regex.hpp>
|
||||
|
||||
// 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<bool> 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<AOInvTimer>
|
||||
{
|
||||
friend class LLSingleton<AOInvTimer>;
|
||||
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<overrides*, 4> 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<boost::char_separator<char> > tokenizer;
|
||||
boost::char_separator<char> 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<char> 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;
|
||||
}
|
||||
101
indra/newview/aosystem.h
Normal file
101
indra/newview/aosystem.h
Normal file
@@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
|
||||
#include "aostate.h"
|
||||
#include "llcontrol.h"
|
||||
#include "lleventtimer.h"
|
||||
|
||||
class AOSystem final : public LLSingleton<AOSystem>
|
||||
{
|
||||
friend class LLSingleton<AOSystem>;
|
||||
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<struct_stands> 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<LLControlVariable> 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<overrides*, STATE_AGENT_END> mAOOverrides;
|
||||
|
||||
override_stand& stand() const { return static_cast<override_stand&>(*mAOOverrides[STATE_AGENT_IDLE]); }
|
||||
|
||||
private:
|
||||
std::array<boost::signals2::scoped_connection, 3> 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);
|
||||
};
|
||||
|
||||
@@ -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 <boost/regex.hpp>
|
||||
|
||||
// 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<bool> 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<overrides*, 4> 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<boost::char_separator<char> > tokenizer;
|
||||
boost::char_separator<char> 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<char> 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;
|
||||
}
|
||||
|
||||
@@ -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<AOInvTimer>
|
||||
{
|
||||
friend class LLSingleton<AOInvTimer>;
|
||||
friend class AOSystem;
|
||||
AOInvTimer();
|
||||
~AOInvTimer();
|
||||
static void createIfNeeded();
|
||||
public:
|
||||
static bool needed();
|
||||
BOOL tick() override;
|
||||
};
|
||||
|
||||
class LLFloaterAO final : public LLFloater, public LLFloaterSingleton<LLFloaterAO>
|
||||
{
|
||||
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<AOSystem>
|
||||
{
|
||||
friend class LLSingleton<AOSystem>;
|
||||
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<struct_stands> 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<LLControlVariable> 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<overrides*, STATE_AGENT_END> mAOOverrides;
|
||||
|
||||
override_stand& stand() const { return static_cast<override_stand&>(*mAOOverrides[STATE_AGENT_IDLE]); }
|
||||
|
||||
private:
|
||||
std::array<boost::signals2::scoped_connection, 3> 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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user