/** * @file llfloaterscriptlimits.cpp * @author Gabriel Lee * @brief Implementation of the region info and controls floater and panels. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "llviewerprecompiledheaders.h" #include "llfloaterscriptlimits.h" // library includes #include "llavatarnamecache.h" #include "llsdutil.h" #include "llsdutil_math.h" #include "message.h" #include "llagent.h" #include "llfloateravatarpicker.h" #include "llfloaterland.h" #include "llfloaterreg.h" #include "llregionhandle.h" #include "llscrolllistctrl.h" #include "llscrolllistitem.h" #include "llparcel.h" #include "lltabcontainer.h" #include "lltracker.h" #include "lltrans.h" #include "llviewercontrol.h" #include "lluictrlfactory.h" #include "llviewerparcelmgr.h" #include "llviewerregion.h" #include "llviewerwindow.h" #include "llcorehttputil.h" ///---------------------------------------------------------------------------- /// LLFloaterScriptLimits ///---------------------------------------------------------------------------- // debug switches, won't work in release #ifndef LL_RELEASE_FOR_DOWNLOAD // dump responder replies to LL_INFOS() for debugging //#define DUMP_REPLIES_TO_LLINFOS #ifdef DUMP_REPLIES_TO_LLINFOS #include "llsdserialize.h" #include "llwindow.h" #endif // use fake LLSD responses to check the viewer side is working correctly // I'm syncing this with the server side efforts so hopfully we can keep // the to-ing and fro-ing between the two teams to a minimum //#define USE_FAKE_RESPONSES #ifdef USE_FAKE_RESPONSES const S32 FAKE_NUMBER_OF_URLS = 329; const S32 FAKE_AVAILABLE_URLS = 731; const S32 FAKE_AMOUNT_OF_MEMORY = 66741; const S32 FAKE_AVAILABLE_MEMORY = 895577; #endif #endif const S32 SIZE_OF_ONE_KB = 1024; LLFloaterScriptLimits::LLFloaterScriptLimits(const LLSD& seed) : LLFloater(seed) { } bool LLFloaterScriptLimits::postBuild() { mTab = getChild("scriptlimits_panels"); if(!mTab) { LL_WARNS() << "Error! couldn't get scriptlimits_panels, aborting Script Information setup" << LL_ENDL; return false; } // contruct the panel LLPanelScriptLimitsRegionMemory* panel_memory = new LLPanelScriptLimitsRegionMemory; mInfoPanels.push_back(panel_memory); panel_memory->buildFromFile( "panel_script_limits_region_memory.xml"); mTab->addTabPanel(panel_memory); mTab->selectTab(0); return true; } LLFloaterScriptLimits::~LLFloaterScriptLimits() { } // public void LLFloaterScriptLimits::refresh() { for(info_panels_t::iterator iter = mInfoPanels.begin(); iter != mInfoPanels.end(); ++iter) { (*iter)->refresh(); } } ///---------------------------------------------------------------------------- // Base class for panels ///---------------------------------------------------------------------------- LLPanelScriptLimitsInfo::LLPanelScriptLimitsInfo() : LLPanel() { } // virtual bool LLPanelScriptLimitsInfo::postBuild() { refresh(); return true; } // virtual void LLPanelScriptLimitsInfo::updateChild(LLUICtrl* child_ctr) { } ///---------------------------------------------------------------------------- // Memory Panel ///---------------------------------------------------------------------------- LLPanelScriptLimitsRegionMemory::~LLPanelScriptLimitsRegionMemory() { if(!mParcelId.isNull()) { LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); mParcelId.setNull(); } }; bool LLPanelScriptLimitsRegionMemory::getLandScriptResources() { if (!gAgent.getRegion()) return false; LLSD body; std::string url = gAgent.getRegion()->getCapability("LandResources"); if (!url.empty()) { LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro", boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro, this, url)); return true; } else { return false; } } void LLPanelScriptLimitsRegionMemory::getLandScriptResourcesCoro(std::string url) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptResourcesCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLSD postData; postData["parcel_id"] = mParcelId; LLSD result = httpAdapter->postAndSuspend(httpRequest, url, postData); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status) { LL_WARNS() << "Failed to get script resource info" << LL_ENDL; return; } // We could retrieve these sequentially inline from this coroutine. But // since the original code retrieved them in parallel I'll spawn two // coroutines to do the retrieval. // The summary service: if (result.has("ScriptResourceSummary")) { std::string urlResourceSummary = result["ScriptResourceSummary"].asString(); LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro", boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro, this, urlResourceSummary)); } if (result.has("ScriptResourceDetails")) { std::string urlResourceDetails = result["ScriptResourceDetails"].asString(); LLCoros::instance().launch("LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro", boost::bind(&LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro, this, urlResourceDetails)); } } void LLPanelScriptLimitsRegionMemory::getLandScriptSummaryCoro(std::string url) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptSummaryCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLSD result = httpAdapter->getAndSuspend(httpRequest, url); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status) { LL_WARNS() << "Unable to retrieve script summary." << LL_ENDL; return; } LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance("script_limits"); if (!instance) { LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; return; } LLTabContainer* tab = instance->getChild("scriptlimits_panels"); if (!tab) { LL_WARNS() << "Unable to access script limits tab" << LL_ENDL; return; } LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild("script_limits_region_memory_panel"); if (!panelMemory) { LL_WARNS() << "Unable to get memory panel." << LL_ENDL; return; } panelMemory->getChild("loading_text")->setValue(LLSD(std::string(""))); LLButton* btn = panelMemory->getChild("refresh_list_btn"); if (btn) { btn->setEnabled(true); } result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); panelMemory->setRegionSummary(result); } void LLPanelScriptLimitsRegionMemory::getLandScriptDetailsCoro(std::string url) { LLCore::HttpRequest::policy_t httpPolicy(LLCore::HttpRequest::DEFAULT_POLICY_ID); LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t httpAdapter(new LLCoreHttpUtil::HttpCoroutineAdapter("getLandScriptDetailsCoro", httpPolicy)); LLCore::HttpRequest::ptr_t httpRequest(new LLCore::HttpRequest); LLSD result = httpAdapter->getAndSuspend(httpRequest, url); LLSD httpResults = result[LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS]; LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults); if (!status) { LL_WARNS() << "Unable to retrieve script details." << LL_ENDL; return; } LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance("script_limits"); if (!instance) { LL_WARNS() << "Failed to get llfloaterscriptlimits instance" << LL_ENDL; return; } LLTabContainer* tab = instance->getChild("scriptlimits_panels"); if (!tab) { LL_WARNS() << "Unable to access script limits tab" << LL_ENDL; return; } LLPanelScriptLimitsRegionMemory* panelMemory = (LLPanelScriptLimitsRegionMemory*)tab->getChild("script_limits_region_memory_panel"); if (!panelMemory) { LL_WARNS() << "Unable to get memory panel." << LL_ENDL; return; } result.erase(LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS); panelMemory->setRegionDetails(result); } void LLPanelScriptLimitsRegionMemory::processParcelInfo(const LLParcelData& parcel_data) { if(!getLandScriptResources()) { std::string msg_error = LLTrans::getString("ScriptLimitsRequestError"); getChild("loading_text")->setValue(LLSD(msg_error)); } else { std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting"); getChild("loading_text")->setValue(LLSD(msg_waiting)); } } void LLPanelScriptLimitsRegionMemory::setParcelID(const LLUUID& parcel_id) { if (!parcel_id.isNull()) { if(!mParcelId.isNull()) { LLRemoteParcelInfoProcessor::getInstance()->removeObserver(mParcelId, this); mParcelId.setNull(); } mParcelId = parcel_id; LLRemoteParcelInfoProcessor::getInstance()->addObserver(parcel_id, this); LLRemoteParcelInfoProcessor::getInstance()->sendParcelInfoRequest(parcel_id); } else { std::string msg_error = LLTrans::getString("ScriptLimitsRequestError"); getChild("loading_text")->setValue(LLSD(msg_error)); } } // virtual void LLPanelScriptLimitsRegionMemory::setErrorStatus(S32 status, const std::string& reason) { LL_WARNS() << "Can't handle remote parcel request."<< " Http Status: "<< status << ". Reason : "<< reason<("scripts_list"); if(!list) { return; } std::string name = LLCacheName::buildUsername(full_name); std::vector::iterator id_itor; for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor) { LLSD element = *id_itor; if(element["owner_id"].asUUID() == id) { LLScrollListItem* item = list->getItem(element["id"].asUUID()); if(item) { item->getColumn(3)->setValue(LLSD(name)); element["columns"][3]["value"] = name; } } } } void LLPanelScriptLimitsRegionMemory::setRegionDetails(LLSD content) { LLScrollListCtrl *list = getChild("scripts_list"); if(!list) { LL_WARNS() << "Error getting the scripts_list control" << LL_ENDL; return; } auto number_parcels = content["parcels"].size(); LLStringUtil::format_map_t args_parcels; args_parcels["[PARCELS]"] = llformat ("%d", number_parcels); std::string msg_parcels = LLTrans::getString("ScriptLimitsParcelsOwned", args_parcels); getChild("parcels_listed")->setValue(LLSD(msg_parcels)); uuid_vec_t names_requested; // This makes the assumption that all objects will have the same set // of attributes, ie they will all have, or none will have locations // This is a pretty safe assumption as it's reliant on server version. bool has_locations = false; bool has_local_ids = false; for(size_t i = 0; i < number_parcels; i++) { std::string parcel_name = content["parcels"][i]["name"].asString(); auto number_objects = content["parcels"][i]["objects"].size(); S32 local_id = 0; if(content["parcels"][i].has("local_id")) { // if any locations are found flag that we can use them and turn on the highlight button has_local_ids = true; local_id = content["parcels"][i]["local_id"].asInteger(); } for(size_t j = 0; j < number_objects; j++) { S32 size = content["parcels"][i]["objects"][j]["resources"]["memory"].asInteger() / SIZE_OF_ONE_KB; S32 urls = content["parcels"][i]["objects"][j]["resources"]["urls"].asInteger(); std::string name_buf = content["parcels"][i]["objects"][j]["name"].asString(); LLUUID task_id = content["parcels"][i]["objects"][j]["id"].asUUID(); LLUUID owner_id = content["parcels"][i]["objects"][j]["owner_id"].asUUID(); // This field may not be sent by all server versions, but it's OK if // it uses the LLSD default of false bool is_group_owned = content["parcels"][i]["objects"][j]["is_group_owned"].asBoolean(); F32 location_x = 0.0f; F32 location_y = 0.0f; F32 location_z = 0.0f; if(content["parcels"][i]["objects"][j].has("location")) { // if any locations are found flag that we can use them and turn on the highlight button LLVector3 vec = ll_vector3_from_sd(content["parcels"][i]["objects"][j]["location"]); has_locations = true; location_x = vec.mV[0]; location_y = vec.mV[1]; location_z = vec.mV[2]; } std::string owner_buf; // in the future the server will give us owner names, so see if we're there yet: if(content["parcels"][i]["objects"][j].has("owner_name")) { owner_buf = content["parcels"][i]["objects"][j]["owner_name"].asString(); } // ...and if not use the slightly more painful method of disovery: else { bool name_is_cached; if (is_group_owned) { name_is_cached = gCacheName->getGroupName(owner_id, owner_buf); } else { LLAvatarName av_name; name_is_cached = LLAvatarNameCache::get(owner_id, &av_name); owner_buf = av_name.getUserName(); owner_buf = LLCacheName::buildUsername(owner_buf); } if(!name_is_cached) { if(std::find(names_requested.begin(), names_requested.end(), owner_id) == names_requested.end()) { names_requested.push_back(owner_id); if (is_group_owned) { gCacheName->getGroup(owner_id, boost::bind(&LLPanelScriptLimitsRegionMemory::onNameCache, this, _1, _2)); } else { LLAvatarNameCache::get(owner_id, boost::bind(&LLPanelScriptLimitsRegionMemory::onAvatarNameCache, this, _1, _2)); } } } } LLScrollListItem::Params item_params; item_params.value = task_id; LLScrollListCell::Params cell_params; cell_params.font = LLFontGL::getFontSansSerif(); // Start out right justifying numeric displays cell_params.font_halign = LLFontGL::RIGHT; cell_params.column = "size"; cell_params.value = size; item_params.columns.add(cell_params); cell_params.column = "urls"; cell_params.value = urls; item_params.columns.add(cell_params); cell_params.font_halign = LLFontGL::LEFT; // The rest of the columns are text to left justify them cell_params.column = "name"; cell_params.value = name_buf; item_params.columns.add(cell_params); cell_params.column = "owner"; cell_params.value = owner_buf; item_params.columns.add(cell_params); cell_params.column = "parcel"; cell_params.value = parcel_name; item_params.columns.add(cell_params); cell_params.column = "location"; cell_params.value = has_locations ? llformat("<%0.0f, %0.0f, %0.0f>", location_x, location_y, location_z) : ""; item_params.columns.add(cell_params); list->addRow(item_params); LLSD element; element["owner_id"] = owner_id; element["id"] = task_id; element["local_id"] = local_id; mObjectListItems.push_back(element); } } if (has_locations) { LLButton* btn = getChild("highlight_btn"); if(btn) { btn->setVisible(true); } } if (has_local_ids) { LLButton* btn = getChild("return_btn"); if(btn) { btn->setVisible(true); } } // save the structure to make object return easier mContent = content; } void LLPanelScriptLimitsRegionMemory::setRegionSummary(LLSD content) { if(content["summary"]["used"][0]["type"].asString() == std::string("memory")) { mParcelMemoryUsed = content["summary"]["used"][0]["amount"].asInteger() / SIZE_OF_ONE_KB; mParcelMemoryMax = content["summary"]["available"][0]["amount"].asInteger() / SIZE_OF_ONE_KB; mGotParcelMemoryUsed = true; } else if(content["summary"]["used"][1]["type"].asString() == std::string("memory")) { mParcelMemoryUsed = content["summary"]["used"][1]["amount"].asInteger() / SIZE_OF_ONE_KB; mParcelMemoryMax = content["summary"]["available"][1]["amount"].asInteger() / SIZE_OF_ONE_KB; mGotParcelMemoryUsed = true; } else { LL_WARNS() << "summary doesn't contain memory info" << LL_ENDL; return; } if(content["summary"]["used"][0]["type"].asString() == std::string("urls")) { mParcelURLsUsed = content["summary"]["used"][0]["amount"].asInteger(); mParcelURLsMax = content["summary"]["available"][0]["amount"].asInteger(); mGotParcelURLsUsed = true; } else if(content["summary"]["used"][1]["type"].asString() == std::string("urls")) { mParcelURLsUsed = content["summary"]["used"][1]["amount"].asInteger(); mParcelURLsMax = content["summary"]["available"][1]["amount"].asInteger(); mGotParcelURLsUsed = true; } else { LL_WARNS() << "summary doesn't contain urls info" << LL_ENDL; return; } if((mParcelMemoryUsed >= 0) && (mParcelMemoryMax >= 0)) { LLStringUtil::format_map_t args_parcel_memory; args_parcel_memory["[COUNT]"] = llformat ("%d", mParcelMemoryUsed); std::string translate_message = "ScriptLimitsMemoryUsedSimple"; if (0 < mParcelMemoryMax) { S32 parcel_memory_available = mParcelMemoryMax - mParcelMemoryUsed; args_parcel_memory["[MAX]"] = llformat ("%d", mParcelMemoryMax); args_parcel_memory["[AVAILABLE]"] = llformat ("%d", parcel_memory_available); translate_message = "ScriptLimitsMemoryUsed"; } std::string msg_parcel_memory = LLTrans::getString(translate_message, args_parcel_memory); getChild("memory_used")->setValue(LLSD(msg_parcel_memory)); } if((mParcelURLsUsed >= 0) && (mParcelURLsMax >= 0)) { S32 parcel_urls_available = mParcelURLsMax - mParcelURLsUsed; LLStringUtil::format_map_t args_parcel_urls; args_parcel_urls["[COUNT]"] = llformat ("%d", mParcelURLsUsed); args_parcel_urls["[MAX]"] = llformat ("%d", mParcelURLsMax); args_parcel_urls["[AVAILABLE]"] = llformat ("%d", parcel_urls_available); std::string msg_parcel_urls = LLTrans::getString("ScriptLimitsURLsUsed", args_parcel_urls); getChild("urls_used")->setValue(LLSD(msg_parcel_urls)); } } bool LLPanelScriptLimitsRegionMemory::postBuild() { childSetAction("refresh_list_btn", onClickRefresh, this); childSetAction("highlight_btn", onClickHighlight, this); childSetAction("return_btn", onClickReturn, this); std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestWaiting"); getChild("loading_text")->setValue(LLSD(msg_waiting)); LLScrollListCtrl *list = getChild("scripts_list"); if(!list) { return false; } list->setCommitCallback(boost::bind(&LLPanelScriptLimitsRegionMemory::checkButtonsEnabled, this)); checkButtonsEnabled(); //set all columns to resizable mode even if some columns will be empty for(S32 column = 0; column < list->getNumColumns(); column++) { LLScrollListColumn* columnp = list->getColumn(column); columnp->mHeader->setHasResizableElement(true); } return StartRequestChain(); } bool LLPanelScriptLimitsRegionMemory::StartRequestChain() { LLUUID region_id; LLFloaterLand* instance = LLFloaterReg::getTypedInstance("about_land"); if(!instance) { getChild("loading_text")->setValue(LLSD(std::string(""))); //might have to do parent post build here //if not logic below could use early outs return false; } LLParcel* parcel = instance->getCurrentSelectedParcel(); LLViewerRegion* region = LLViewerParcelMgr::getInstance()->getSelectionRegion(); if ((region) && (parcel)) { LLUUID current_region_id = gAgent.getRegion()->getRegionID(); LLVector3 parcel_center = parcel->getCenterpoint(); region_id = region->getRegionID(); if(region_id != current_region_id) { std::string msg_wrong_region = LLTrans::getString("ScriptLimitsRequestWrongRegion"); getChild("loading_text")->setValue(LLSD(msg_wrong_region)); return false; } LLVector3d pos_global = region->getCenterGlobal(); LLSD body; std::string url = region->getCapability("RemoteParcelRequest"); if (!url.empty()) { LLRemoteParcelInfoProcessor::getInstance()->requestRegionParcelInfo(url, region_id, parcel_center, pos_global, getObserverHandle()); } else { LL_WARNS() << "Can't get parcel info for script information request" << region_id << ". Region: " << region->getName() << " does not support RemoteParcelRequest" << LL_ENDL; std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestError"); getChild("loading_text")->setValue(LLSD(msg_waiting)); } } else { std::string msg_waiting = LLTrans::getString("ScriptLimitsRequestNoParcelSelected"); getChild("loading_text")->setValue(LLSD(msg_waiting)); } return LLPanelScriptLimitsInfo::postBuild(); } void LLPanelScriptLimitsRegionMemory::clearList() { LLCtrlListInterface *list = childGetListInterface("scripts_list"); if (list) { list->operateOnAll(LLCtrlListInterface::OP_DELETE); } mGotParcelMemoryUsed = false; mGotParcelMemoryMax = false; mGotParcelURLsUsed = false; mGotParcelURLsMax = false; LLStringUtil::format_map_t args_parcel_memory; std::string msg_empty_string(""); getChild("memory_used")->setValue(LLSD(msg_empty_string)); getChild("urls_used")->setValue(LLSD(msg_empty_string)); getChild("parcels_listed")->setValue(LLSD(msg_empty_string)); mObjectListItems.clear(); checkButtonsEnabled(); } void LLPanelScriptLimitsRegionMemory::checkButtonsEnabled() { LLScrollListCtrl* list = getChild("scripts_list"); getChild("highlight_btn")->setEnabled(list->getNumSelected() > 0); getChild("return_btn")->setEnabled(list->getNumSelected() > 0); } // static void LLPanelScriptLimitsRegionMemory::onClickRefresh(void* userdata) { LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance("script_limits"); if(instance) { LLTabContainer* tab = instance->getChild("scriptlimits_panels"); if(tab) { LLPanelScriptLimitsRegionMemory* panel_memory = (LLPanelScriptLimitsRegionMemory*)tab->getChild("script_limits_region_memory_panel"); if(panel_memory) { //To stop people from hammering the refesh button and accidentally dosing themselves - enough requests can crash the viewer! //turn the button off, then turn it on when we get a response LLButton* btn = panel_memory->getChild("refresh_list_btn"); if(btn) { btn->setEnabled(false); } panel_memory->clearList(); panel_memory->StartRequestChain(); } } return; } else { LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after refresh button clicked" << LL_ENDL; return; } } void LLPanelScriptLimitsRegionMemory::showBeacon() { LLScrollListCtrl* list = getChild("scripts_list"); if (!list) return; LLScrollListItem* first_selected = list->getFirstSelected(); if (!first_selected) return; std::string name = first_selected->getColumn(2)->getValue().asString(); std::string pos_string = first_selected->getColumn(5)->getValue().asString(); F32 x, y, z; S32 matched = sscanf(pos_string.c_str(), "<%g,%g,%g>", &x, &y, &z); if (matched != 3) return; LLVector3 pos_agent(x, y, z); LLVector3d pos_global = gAgent.getPosGlobalFromAgent(pos_agent); std::string tooltip(""); LLTracker::trackLocation(pos_global, name, tooltip, LLTracker::LOCATION_ITEM); } // static void LLPanelScriptLimitsRegionMemory::onClickHighlight(void* userdata) { LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance("script_limits"); if(instance) { LLTabContainer* tab = instance->getChild("scriptlimits_panels"); if(tab) { LLPanelScriptLimitsRegionMemory* panel = (LLPanelScriptLimitsRegionMemory*)tab->getChild("script_limits_region_memory_panel"); if(panel) { panel->showBeacon(); } } return; } else { LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << LL_ENDL; return; } } void LLPanelScriptLimitsRegionMemory::returnObjectsFromParcel(S32 local_id) { LLMessageSystem *msg = gMessageSystem; LLViewerRegion* region = gAgent.getRegion(); if (!region) return; LLCtrlListInterface *list = childGetListInterface("scripts_list"); if (!list || list->getItemCount() == 0) return; std::vector::iterator id_itor; bool start_message = true; for (id_itor = mObjectListItems.begin(); id_itor != mObjectListItems.end(); ++id_itor) { LLSD element = *id_itor; if (!list->isSelected(element["id"].asUUID())) { // Selected only continue; } if(element["local_id"].asInteger() != local_id) { // Not the parcel we are looking for continue; } if (start_message) { msg->newMessageFast(_PREHASH_ParcelReturnObjects); msg->nextBlockFast(_PREHASH_AgentData); msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID()); msg->addUUIDFast(_PREHASH_SessionID,gAgent.getSessionID()); msg->nextBlockFast(_PREHASH_ParcelData); msg->addS32Fast(_PREHASH_LocalID, element["local_id"].asInteger()); msg->addU32Fast(_PREHASH_ReturnType, RT_LIST); start_message = false; } msg->nextBlockFast(_PREHASH_TaskIDs); msg->addUUIDFast(_PREHASH_TaskID, element["id"].asUUID()); if (msg->isSendFullFast(_PREHASH_TaskIDs)) { msg->sendReliable(region->getHost()); start_message = true; } } if (!start_message) { msg->sendReliable(region->getHost()); } } void LLPanelScriptLimitsRegionMemory::returnObjects() { if(!mContent.has("parcels")) { return; } auto number_parcels = mContent["parcels"].size(); // a message per parcel containing all objects to be returned from that parcel for(size_t i = 0; i < number_parcels; i++) { S32 local_id = 0; if(mContent["parcels"][i].has("local_id")) { local_id = mContent["parcels"][i]["local_id"].asInteger(); returnObjectsFromParcel(local_id); } } onClickRefresh(NULL); } // static void LLPanelScriptLimitsRegionMemory::onClickReturn(void* userdata) { LLFloaterScriptLimits* instance = LLFloaterReg::getTypedInstance("script_limits"); if(instance) { LLTabContainer* tab = instance->getChild("scriptlimits_panels"); if(tab) { LLPanelScriptLimitsRegionMemory* panel = (LLPanelScriptLimitsRegionMemory*)tab->getChild("script_limits_region_memory_panel"); if(panel) { panel->returnObjects(); } } return; } else { LL_WARNS() << "could not find LLPanelScriptLimitsRegionMemory instance after highlight button clicked" << LL_ENDL; return; } }