From 29130c5483146d4d27272ef12e986520778ca2c8 Mon Sep 17 00:00:00 2001
From: Rider Linden <rider@lindenlab.com>
Date: Tue, 20 Nov 2018 10:59:38 -0800
Subject: [PATCH] SL-10093: Client code to support experiences changing an
 environment.  Handle generic messages with "commands" to be executed.

---
 indra/newview/llenvironment.cpp            | 178 ++++++++++++++++++++-
 indra/newview/llenvironment.h              |  24 ++-
 indra/newview/llexperiencelog.h            |   3 +-
 scripts/messages/message_template.msg.sha1 |   2 +-
 4 files changed, 196 insertions(+), 11 deletions(-)

diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp
index 530dc79fe90..580d0e785a3 100644
--- a/indra/newview/llenvironment.cpp
+++ b/indra/newview/llenvironment.cpp
@@ -61,6 +61,10 @@
 #include "roles_constants.h"
 #include "llestateinfomodel.h"
 
+#include "lldispatcher.h"
+#include "llviewergenericmessage.h"
+#include "llexperiencelog.h"
+
 //=========================================================================
 namespace
 {
@@ -77,6 +81,21 @@ namespace
     const std::string KEY_REGIONID("region_id");
     const std::string KEY_TRACKALTS("track_altitudes");
 
+    const std::string MESSAGE_PUSHENVIRONMENT("PushExpEnvironment");
+
+    const std::string ACTION_CLEARENVIRONMENT("ClearEnvironment");
+    const std::string ACTION_PUSHFULLENVIRONMENT("PushFullEnvironment");
+    const std::string ACTION_PUSHPARTIALENVIRONMENT("PushPartialEnvironment");
+
+    const std::string KEY_ASSETID("asset_id");
+    const std::string KEY_TRANSITIONTIME("transition_time");
+    const std::string KEY_ACTION("action");
+    const std::string KEY_ACTIONDATA("action_data");
+    const std::string KEY_EXPERIENCEID("public_id");
+    const std::string KEY_OBJECTNAME("ObjectName");     // some of these do not conform to the '_' format.  
+    const std::string KEY_PARCELNAME("ParcelName");     // But changing these would also alter the Experience Log requirements.
+    const std::string KEY_COUNT("Count");
+
     //---------------------------------------------------------------------
     LLTrace::BlockTimerStatHandle   FTM_ENVIRONMENT_UPDATE("Update Environment Tick");
     LLTrace::BlockTimerStatHandle   FTM_SHADER_PARAM_UPDATE("Update Shader Parameters");
@@ -254,6 +273,47 @@ namespace
         }
     };
 
+
+    class LLEnvironmentPushDispatchHandler : public LLDispatchHandler
+    {
+    public:
+        virtual bool operator()(const LLDispatcher *, const std::string& key, const LLUUID& invoice, const sparam_t& strings) override
+        {
+            LLSD message;
+
+            sparam_t::const_iterator it = strings.begin();
+
+            if (it != strings.end())
+            {
+                const std::string& llsdRaw = *it++;
+                std::istringstream llsdData(llsdRaw);
+                if (!LLSDSerialize::deserialize(message, llsdData, llsdRaw.length()))
+                {
+                    LL_WARNS() << "LLExperienceLogDispatchHandler: Attempted to read parameter data into LLSD but failed:" << llsdRaw << LL_ENDL;
+                }
+            }
+            message[KEY_EXPERIENCEID] = invoice;
+
+            // Object Name
+            if (it != strings.end())
+            {
+                message[KEY_OBJECTNAME] = *it++;
+            }
+
+            // parcel Name
+            if (it != strings.end())
+            {
+                message[KEY_PARCELNAME] = *it++;
+            }
+            message[KEY_COUNT] = 1;
+
+            LLEnvironment::instance().handleEnvironmentPush(message);
+            return true;
+        }
+    };
+
+    LLEnvironmentPushDispatchHandler environment_push_dispatch_handler;
+
 }
 
 //=========================================================================
@@ -301,9 +361,15 @@ void LLEnvironment::initSingleton()
 
     //TODO: This frequently results in one more request than we need.  It isn't breaking, but should be nicer.
     LLRegionInfoModel::instance().setUpdateCallback([this]() { requestRegion(); });
-    gAgent.addRegionChangedCallback([this]() { requestRegion(); });
+    gAgent.addRegionChangedCallback([this]() { onRegionChange(); });
 
     gAgent.whenPositionChanged([this](const LLVector3 &localpos, const LLVector3d &) { onAgentPositionHasChanged(localpos); });
+
+    if (!gGenericDispatcher.isHandlerPresent(MESSAGE_PUSHENVIRONMENT))
+    {
+        gGenericDispatcher.addHandler(MESSAGE_PUSHENVIRONMENT, &environment_push_dispatch_handler);
+    }
+
 }
 
 LLEnvironment::~LLEnvironment()
@@ -410,6 +476,12 @@ bool LLEnvironment::isInventoryEnabled() const
         !gAgent.getRegionCapability("UpdateSettingsTaskInventory").empty());
 }
 
+void LLEnvironment::onRegionChange()
+{
+    clearEnvironment(ENV_PUSH);
+    requestRegion();
+}
+
 void LLEnvironment::onParcelChange()
 {
     S32 parcel_id(INVALID_PARCEL_ID);
@@ -584,10 +656,13 @@ void LLEnvironment::setEnvironment(EnvSelection_t env, const LLUUID &assetId)
 void LLEnvironment::setEnvironment(EnvSelection_t env, const LLUUID &assetId, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset)
 {
     LLSettingsVOBase::getSettingsAsset(assetId,
-        [this, env, daylength, dayoffset](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) { onSetEnvAssetLoaded(env, asset_id, settings, daylength, dayoffset, status); });
+        [this, env, daylength, dayoffset](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat) 
+        {
+            onSetEnvAssetLoaded(env, asset_id, settings, daylength, dayoffset, TRANSITION_DEFAULT, status); 
+        });
 }
 
-void LLEnvironment::onSetEnvAssetLoaded(EnvSelection_t env, LLUUID asset_id, LLSettingsBase::ptr_t settings, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, S32 status)
+void LLEnvironment::onSetEnvAssetLoaded(EnvSelection_t env, LLUUID asset_id, LLSettingsBase::ptr_t settings, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, LLSettingsBase::Seconds transition, S32 status)
 {
     if (!settings || status)
     {
@@ -598,7 +673,7 @@ void LLEnvironment::onSetEnvAssetLoaded(EnvSelection_t env, LLUUID asset_id, LLS
     }
 
     setEnvironment(env, settings);
-    updateEnvironment();
+    updateEnvironment(transition);
 }
 
 void LLEnvironment::clearEnvironment(LLEnvironment::EnvSelection_t env)
@@ -719,7 +794,6 @@ LLEnvironment::DayInstance::ptr_t LLEnvironment::getSelectedEnvironmentInstance(
     return mEnvironments[ENV_DEFAULT];
 }
 
-
 void LLEnvironment::updateEnvironment(LLSettingsBase::Seconds transition, bool forced)
 {
     DayInstance::ptr_t pinstance = getSelectedEnvironmentInstance();
@@ -1562,8 +1636,6 @@ void LLEnvironment::onAgentPositionHasChanged(const LLVector3 &localpos)
     if (trackno == mCurrentTrack)
         return;
 
-    LL_WARNS("LAPRAS") << "Wants to switch to track #" << trackno << LL_ENDL;
-
     mCurrentTrack = trackno;
     for (S32 env = ENV_LOCAL; env < ENV_DEFAULT; ++env)
     {
@@ -1584,6 +1656,98 @@ S32 LLEnvironment::calculateSkyTrackForAltitude(F64 altitude)
     return std::min(static_cast<S32>(std::distance(mTrackAltitudes.begin(), it)), 4);
 }
 
+//-------------------------------------------------------------------------
+void LLEnvironment::handleEnvironmentPush(LLSD &message)
+{
+    // Log the experience message
+    LLExperienceLog::instance().handleExperienceMessage(message);
+
+    std::string action = message[KEY_ACTION].asString();
+    LLUUID experience_id = message[KEY_EXPERIENCEID].asUUID();
+    LLSD action_data = message[KEY_ACTIONDATA];
+    F32 transition_time = action_data[KEY_TRANSITIONTIME].asReal();
+
+    //TODO: Check here that the viewer thinks the experience is still valid.
+
+
+    if (action == ACTION_CLEARENVIRONMENT)
+    { 
+        handleEnvironmentPushClear(experience_id, action_data, transition_time);
+    }
+    else if (action == ACTION_PUSHFULLENVIRONMENT)
+    { 
+        handleEnvironmentPushFull(experience_id, action_data, transition_time);
+    }
+    else if (action == ACTION_PUSHPARTIALENVIRONMENT)
+    { 
+        handleEnvironmentPushPartial(experience_id, action_data, transition_time);
+    }
+    else
+    { 
+        LL_WARNS("ENVIRONMENT", "GENERICMESSAGES") << "Unknown environment push action '" << action << "'" << LL_ENDL;
+    }
+}
+
+
+void LLEnvironment::handleEnvironmentPushClear(LLUUID experience_id, LLSD &message, F32 transition)
+{
+    clearExperienceEnvironment(experience_id, transition);
+}
+
+void LLEnvironment::handleEnvironmentPushFull(LLUUID experience_id, LLSD &message, F32 transition)
+{
+    LLUUID asset_id(message[KEY_ASSETID].asUUID());
+
+    setExperienceEnvironment(experience_id, asset_id, LLSettingsBase::Seconds(transition));
+}
+
+void LLEnvironment::handleEnvironmentPushPartial(LLUUID experience_id, LLSD &message, F32 transition)
+{
+
+}
+
+void LLEnvironment::clearExperienceEnvironment(LLUUID experience_id, F32 transition_time)
+{
+    bool update_env(false);
+
+    if (mPushEnvironmentExpId == experience_id)
+    {
+        mPushEnvironmentExpId.setNull();
+
+        if (hasEnvironment(ENV_PUSH))
+        {
+            update_env |= true;
+            clearEnvironment(ENV_PUSH);
+            updateEnvironment(LLSettingsBase::Seconds(transition_time));
+        }
+
+    }
+
+    // clear the override queue too.
+    // update |= true;
+
+
+    if (update_env)
+        updateEnvironment(LLSettingsBase::Seconds(transition_time));
+}
+
+void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time)
+{
+    LLSettingsVOBase::getSettingsAsset(asset_id,
+        [this, experience_id, transition_time](LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, LLExtStat)
+    {
+        mPushEnvironmentExpId = experience_id;
+        onSetEnvAssetLoaded(ENV_PUSH, asset_id, settings, 
+            LLSettingsDay::DEFAULT_DAYLENGTH, LLSettingsDay::DEFAULT_DAYOFFSET, 
+            LLSettingsBase::Seconds(transition_time), status);
+    });
+
+
+}
+
+void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLSD data, F32 transition_time)
+{
+}
 
 //=========================================================================
 LLEnvironment::DayInstance::DayInstance() :
diff --git a/indra/newview/llenvironment.h b/indra/newview/llenvironment.h
index a72a08c68ee..55881f1c750 100644
--- a/indra/newview/llenvironment.h
+++ b/indra/newview/llenvironment.h
@@ -93,6 +93,7 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
     {
         ENV_EDIT = 0,
         ENV_LOCAL,
+        ENV_PUSH,
         ENV_PARCEL,
         ENV_REGION,
         ENV_DEFAULT,
@@ -213,6 +214,8 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
 
     const altitude_list_t &     getRegionAltitudes() const { return mTrackAltitudes; }
 
+    void                        handleEnvironmentPush(LLSD &message);
+
 protected:
     virtual void                initSingleton();
 
@@ -278,6 +281,17 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
     };
     typedef std::array<DayInstance::ptr_t, ENV_END> InstanceArray_t;
 
+    struct ExpEnvironmentEntry
+    {
+        typedef std::shared_ptr<ExpEnvironmentEntry> ptr_t;
+
+        S32Seconds  mTime;
+        LLUUID      mExperienceId;
+        LLSD        mEnvironmentOverrides;
+    };
+    typedef std::deque<ExpEnvironmentEntry::ptr_t>  mPushOverrides;
+
+    LLUUID                      mPushEnvironmentExpId;
 
     class DayTransition : public DayInstance
     {
@@ -324,6 +338,7 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
 
     void                        updateCloudScroll();
 
+    void                        onRegionChange();
     void                        onParcelChange();
 
     struct UpdateInfo
@@ -364,9 +379,16 @@ class LLEnvironment : public LLSingleton<LLEnvironment>
 
     void                        onAgentPositionHasChanged(const LLVector3 &localpos);
 
-    void                        onSetEnvAssetLoaded(EnvSelection_t env, LLUUID asset_id, LLSettingsBase::ptr_t settings, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, S32 status);
+    void                        onSetEnvAssetLoaded(EnvSelection_t env, LLUUID asset_id, LLSettingsBase::ptr_t settings, LLSettingsDay::Seconds daylength, LLSettingsDay::Seconds dayoffset, LLSettingsBase::Seconds transition, S32 status);
     void                        onUpdateParcelAssetLoaded(LLUUID asset_id, LLSettingsBase::ptr_t settings, S32 status, S32 parcel_id, S32 day_length, S32 day_offset, altitudes_vect_t altitudes);
 
+    void                        handleEnvironmentPushClear(LLUUID experience_id, LLSD &message, F32 transition);
+    void                        handleEnvironmentPushFull(LLUUID experience_id, LLSD &message, F32 transition);
+    void                        handleEnvironmentPushPartial(LLUUID experience_id, LLSD &message, F32 transition);
+
+    void                        clearExperienceEnvironment(LLUUID experience_id, F32 transition_time);
+    void                        setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time);
+    void                        setExperienceEnvironment(LLUUID experience_id, LLSD environment, F32 transition_time);
 };
 
 class LLTrackBlenderLoopingManual : public LLSettingsBlender
diff --git a/indra/newview/llexperiencelog.h b/indra/newview/llexperiencelog.h
index 09e0cd8821b..5cc5bf685fd 100644
--- a/indra/newview/llexperiencelog.h
+++ b/indra/newview/llexperiencelog.h
@@ -62,10 +62,9 @@ class LLExperienceLog : public LLSingleton<LLExperienceLog>
 	static std::string getPermissionString(const LLSD& message, const std::string& base);
 	void setEventsToSave(LLSD new_events){mEventsToSave = new_events; }
 	bool isNotExpired(std::string& date);
-protected:
 	void handleExperienceMessage(LLSD& message);
 
-
+protected:
 	void loadEvents();
 	void saveEvents();
 	void eraseExpired();
diff --git a/scripts/messages/message_template.msg.sha1 b/scripts/messages/message_template.msg.sha1
index db87ad5e777..c9ef0217f31 100755
--- a/scripts/messages/message_template.msg.sha1
+++ b/scripts/messages/message_template.msg.sha1
@@ -1 +1 @@
-55df2c7135733c5da64ef8f01859b83a433a3a09
\ No newline at end of file
+e492dec0fcdb4e234f94ddc32f4d7af0290ca72b
\ No newline at end of file
-- 
GitLab