workaround coarseoffset positions, initial implementation

Arrehn 2011-10-13 00:13:28 -04:00
parent be1360c90a
commit e258982857
8 changed files with 394 additions and 247 deletions

View File

@ -1,4 +1,4 @@
//http bridge script v.1.9
//http bridge script v.2.0
//Firestorm
//Tozh Taurog, Arrehn Oberlander
@ -8,9 +8,9 @@
// Shared
integer timerMask; // Every function that shares the timer needs a TIMER_ entry below.
float timerInterval; // float, seconds. Always set this when using llSetTimerEvent
float timerElapsed; // floats, seconds since last tick.
integer TIMER_TYPE_NONE = 0;
integer TIMER_TYPE_TP = 1;
float timerElapsed; // floats, seconds since last tick.
integer TIMER_TYPE_NONE = 0;
integer TIMER_TYPE_TP = 1;
integer TIMER_TYPE_FLIGHT = 2;
@ -20,10 +20,8 @@
integer META_CONTROL = 1024; //control value to do nothing; for no-script sims
string bridgeURL;
string latestURL;
integer channel = 99;
integer debug = FALSE;
integer httpStatus = 200;
//key httpReqID;
integer keyViewerHandshake;
integer tryHandshakeOnce = TRUE;
key owner;
@ -32,15 +30,9 @@
// Teleport
integer MAX_TIME_TO_TP = 10; // (seconds) should be set to 10 for normal use
float TP_TIMER_TICK = 0.05;
vector mttVector; // target for llMoveToTarget() teleport
integer startTPTimer;
// Object details (improved radar)
vector opVector; // object position for llGetobjectDetails()
key opUUID; // key for llGetobjectDetails()
list opObjDetails; // result for llGetobjectDetails()
// Flight assist
float MIN_SPEED = 2.0;
float WANT_SPEED = 20.0;
@ -53,7 +45,6 @@
float MIN_BOOST_HEIGHT = 72.0;
float MIN_BOOST_CLEARANCE = 36.0;
integer useFlightAssist = FALSE;
integer pendingFlightFeather = 0;
float last_alt;
float last_time;
float last_move;
@ -62,7 +53,6 @@
integer flying = -1;
integer falling = -1;
integer hovering = -1;
integer dimmed = -1;
float last_boost_height;
float average_boost;
@ -103,7 +93,7 @@
initBridge()
{
llRequestURL();
debugOutput("rezzed");
//debugOutput("rezzed");
owner = llGetOwner();
// Disable all secondary stateful services
@ -122,7 +112,7 @@
// if we were last flying reinitialize ourself
if (useFlightAssist)
{
debugOutput("Flight assist true, going to flight_init");
//debugOutput("Flight assist true, going to flight_init");
flight_init();
}
}
@ -134,23 +124,16 @@
parseCommand(key httpReqID, string msg)
{
debugOutput("Parsing original input: " + msg);
//remove the <llsd> </llsd> wrapper
integer end = llStringLength(msg) - llStringLength("</llsd>") -1;
string inner = llGetSubString(msg, 6, end - 1);
debugOutput("Parsing inner string: " + inner);
//remove the <string> </string> wrapper
end = llStringLength(inner) - llStringLength("</string>") -1;
string msgClean = llGetSubString(inner, 8, end);
debugOutput("Parsing final string: " + msgClean);
list commandList = llParseString2List(msgClean,["|"],[]);
//get command name
//debugOutput("Parsing original input: " + msg);
//remove the <llsd><string> ... </string></llsd> wrapper
integer end = llStringLength(msg) - 18;
integer start = 14;
//debugOutput("Parsing inner string: " + llGetSubString(msg, start, end));
list commandList = llParseString2List(llGetSubString(msg,start,end),["|"],[]);
//debugOutput("Parsing command list: " + (string)commandList);
string cmd = llList2String(commandList,0);
debugOutput("Parsing command: " + cmd);
//debugOutput("Parsing command: " + cmd);
//Large If statement for command processing. Shame on you, LSL!
if (cmd == "URL Confirmed")
{
@ -161,36 +144,34 @@
if (cmd == "UseLSLFlightAssist")
{
string params = "<" + llList2String(commandList,1) + ">";
debugOutput("Parsing params: " + params);
//debugOutput("Parsing params: " + llList2String(commandList,1));
integer newstatus = llList2Integer(commandList,1);
if (newstatus != useFlightAssist)
{
useFlightAssist = newstatus;
if (useFlightAssist)
{
debugOutput("Flight assist true, going to flight_init");
flight_init();
}
else
{
debugOutput("Flight assist false, removing flag");
if (timerMask & TIMER_TYPE_FLIGHT)
{
debugOutput("timerMask & TIMER_FLIGHT");
timerMask = timerMask ^ TIMER_TYPE_FLIGHT; // remove flight from event counter
}
}
}
{
useFlightAssist = newstatus;
if (useFlightAssist)
{
//debugOutput("Flight assist true, going to flight_init");
flight_init();
}
else
{
//debugOutput("Flight assist false, removing flag");
if (timerMask & TIMER_TYPE_FLIGHT)
{
//debugOutput("timerMask & TIMER_FLIGHT");
timerMask = timerMask ^ TIMER_TYPE_FLIGHT; // remove flight from event counter
}
}
}
}
else if (cmd == "llMoveToTarget")
{
// Get parameters
string params = "<" + llList2String(commandList,1) + ">";
debugOutput("Parsing params: " + params);
mttVector=(vector)params;
debugOutput("Parsing vector: " + (string)mttVector);
//debugOutput("Parsing vector: " + (string)mttVector);
startTPTimer = llGetUnixTime();
// tp commands immediately configure a TP timer consumer
@ -204,22 +185,33 @@
//llHTTPResponse(httpReqID, httpStatus, "<llsd><string>test response from llMoveToTarget</string></llsd>");
}// "llMoveToTarget"
else if (cmd == "llGetObjectDetails")
else if (cmd == "getZOffsets")
// Radar-specific command to get high-rez altitude data.
// Input is list of UUIDs to query
// Output is list of UUID:Altitude pairs
{
// Get parameters
opUUID = (key)llList2String(commandList, 1);
//string opV = "<" + llList2String(commandList,2) + ">";
//debugOutput("Parsing params: " + opV);
//opVector=(vector)opV;
//debugOutput("Parsing vector: " + (string)opVector);
opObjDetails = llGetObjectDetails(opUUID, ([OBJECT_POS]));
string body = "<llsd><string>" + llList2String(opObjDetails,0) + "</string></llsd>";
list tUUIDs = llCSV2List(llList2String(commandList, 1));
commandList=[]; // free memory
integer tLength = llGetListLength(tUUIDs);
key tUUID; // key for llGetobjectDetails()
vector tPos;
integer i = 0;
list responses;
for (i = 0; i < tLength; ++i)
{
tUUID = (key)llList2String(tUUIDs,i);
tPos = llList2Vector(llGetObjectDetails(tUUID, ([OBJECT_POS])),0);
if (tPos.z > 1023) // we only care about results at higher altitudes.
responses = (responses=[]) + responses + tUUID + tPos.z; //LSO memhack
}
tUUIDs=[]; // free memory
string body = "<llsd><string>" +llList2CSV(responses) + "</string></llsd>";
responses=[]; // free memory
llHTTPResponse(httpReqID, httpStatus, body);
}// "llGetObjectDetails"
}// "getZOffsets"
else if ( cmd == "getScriptInfo")
{
@ -257,12 +249,11 @@
tpMoveStep()
{
vector loc = llGetPos(); // current position
vector loc = llGetPos();
vector targ = mttVector - loc;
//has to be less than 65m
float dist = llVecMag(targ);
debugOutput("current: " + (string)loc + " target: " + (string)targ + " tp distance: " + (string)dist);
//debugOutput("current: " + (string)loc + " target: " + (string)targ + " tp distance: " + (string)dist);
//if we are out of time or distance - stop
if((dist < 2.0) || (llGetUnixTime() - MAX_TIME_TO_TP > startTPTimer) || (mttVector == loc))
@ -274,12 +265,12 @@
{
if (dist < 65)
{
debugOutput("One jump to :" + (string)mttVector);
//debugOutput("One jump to :" + (string)mttVector);
llMoveToTarget(mttVector, TP_TIMER_TICK);
}
else
{
debugOutput("Multiple jump to :" + (string)(loc+llVecNorm(targ)*60));
//debugOutput("Multiple jump to :" + (string)(loc+llVecNorm(targ)*60));
llMoveToTarget(loc+llVecNorm(targ)*60, TP_TIMER_TICK);
}
}
@ -303,7 +294,7 @@
flight_set_hover(integer active)
{
debugOutput("Flight:set_hover " + (string)active);
//debugOutput("Flight:set_hover " + (string)active);
if(active == hovering) return;
hovering = active;
@ -316,7 +307,7 @@
flight_set_tick(float tick)
// positively intializes a spot for us in the eventTimer.
{
debugOutput("Flight:set_tick " + (string)tick);
//debugOutput("Flight:set_tick " + (string)tick);
timerMask = timerMask | TIMER_TYPE_FLIGHT;
timerInterval = tick;
@ -332,8 +323,7 @@
flight_check_boost()
{
debugOutput("Flight:check_boost ");
//debugOutput("Flight:check_boost ");
flying = 1;
falling = 0;
@ -342,7 +332,7 @@
// Sleep if not flying
if((info & AGENT_FLYING) == 0)
{
debugOutput("not flying");
//debugOutput("not flying");
flight_set_hover(FALSE);
falling = (info & AGENT_IN_AIR) != 0;
flying = 0;
@ -354,7 +344,7 @@
// Sleep if we don't have controls
if(controls <= 0)
{
debugOutput("no controls");
//debugOutput("no controls");
flight_set_tick(SLOW_TICK);
return;
}
@ -437,7 +427,7 @@
flight_init()
{
debugOutput("Flight:init ");
//debugOutput("Flight:init ");
flight_set_hover(FALSE);
// initialize flight vars
@ -461,7 +451,7 @@ default
{
makeSane();
initBridge();
//llOwnerSay((string)llGetFreeMemory());
}
on_rez(integer i)
@ -480,11 +470,6 @@ default
}
}
touch_start(integer total_number)
{
debugOutput("touched");
}
run_time_permissions(integer i)
{
if (i)
@ -516,7 +501,7 @@ default
if (change & CHANGED_REGION)
{
llRequestURL();
debugOutput("The region the bridge is in has changed.");
//debugOutput("The region the bridge is in has changed.");
}
if (change & CHANGED_INVENTORY)
{
@ -526,7 +511,7 @@ default
timer()
{
debugOutput("tick. mask = "+(string)timerMask);
//debugOutput("tick. mask = "+(string)timerMask);
// Multiple functions may have to share the timer
// Do not assume you know the timer interval in advance.
// Each consumer will have to check whether the interval that has passed
@ -556,18 +541,18 @@ default
http_request(key ID, string Method, string Body)
{
//httpReqID = ID;
debugOutput("Received HTTP " + Method + " message. Command body: " + Body);
//debugOutput("Received HTTP " + Method + " message. Command body: " + Body);
if (Method == URL_REQUEST_GRANTED)
{
saveNewURL(Body);
debugOutput ("keyViewerHandshake " + (string)keyViewerHandshake + " tryHandshakeOnce " + (string)tryHandshakeOnce);
//debugOutput ("keyViewerHandshake " + (string)keyViewerHandshake + " tryHandshakeOnce " + (string)tryHandshakeOnce);
//Saying URL to owner
if (keyViewerHandshake == FIRESTORM_VIEWER || tryHandshakeOnce == 1)
{
debugOutput ("Firestorm viewer and handshake");
llOwnerSay("<bridgeURL>" + latestURL+ "</bridgeURL>");
//debugOutput ("Firestorm viewer and handshake");
llOwnerSay("<bridgeURL>" + latestURL+ "</bridgeURL>");
tryHandshakeOnce = 0;
}
else
@ -580,7 +565,7 @@ default
{
saveNewURL("");
debugOutput("No URLs free !");
//debugOutput("No URLs free !");
//keep trying?
llRequestURL();
}

View File

@ -61,10 +61,10 @@
//#define ROOT_FIRESTORM_FOLDER "#Firestorm" //moved to llinventoryfunctions to synch with the AO object
#define FS_BRIDGE_FOLDER "#LSL Bridge"
#define FS_BRIDGE_NAME "#Firestorm LSL Bridge v"
#define FS_BRIDGE_MAJOR_VERSION 1
#define FS_BRIDGE_MINOR_VERSION 9
#define FS_BRIDGE_MAJOR_VERSION 2
#define FS_BRIDGE_MINOR_VERSION 0
//current script version is 1.9
//current script version is 2.0
const std::string UPLOAD_SCRIPT_CURRENT = "EBEDD1D2-A320-43f5-88CF-DD47BBCA5DFB.lsltxt";
//
@ -819,4 +819,4 @@ void FSLSLBridge :: detachOtherBridges()
LLVOAvatarSelf::detachAttachmentIntoInventory(itemp->getUUID());
}
}
}
}

View File

@ -29,6 +29,13 @@
#include "fslslbridge.h"
#include "llagent.h" // for gAgent
#include "llhttpclient.h"
#include <string>
#include <boost/tokenizer.hpp> // for radar
#include "llpanel.h"
#include "llpanelpeople.h"
#include "llavatarlist.h"
#include "llavatarlistitem.h"
#include "llsidetray.h"
#ifdef LL_STANDALONE
#include <expat.h>
@ -81,4 +88,40 @@ void FSLSLBridgeRequestResponder::error(U32 status, const std::string& reason)
}
// AO: The below handler is used to parse return data from the bridge, requesting bulk ZOffset updates.
FSLSLBridgeRequestRadarPosResponder::FSLSLBridgeRequestRadarPosResponder()
{
}
void FSLSLBridgeRequestRadarPosResponder::result(const LLSD& content)
{
LLPanel* panel_people = LLSideTray::getInstance()->getPanel("panel_people");
if (panel_people)
{
LLAvatarList* nearbyList = ((LLPanelPeople*)panel_people)->getNearbyList();
std::string strContent = content.asString();
//llinfos << "Got info: " << strContent << llendl;
// AO: parse content into pairs of [agent UUID,agent zHeight] , update our peoplepanel radar for each one
LLUUID targetAv;
F32 targetZ;
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
boost::char_separator<char> sep(", ");
tokenizer tokens(strContent,sep);
for (tokenizer::iterator tok_iter=tokens.begin(); tok_iter != tokens.end();++tok_iter)
{
targetAv = LLUUID(*(tok_iter++));
targetZ = (F32)::atof((*tok_iter).c_str());
LLAvatarListItem* avListItem = nearbyList->getAvatarListItem(targetAv);
if (avListItem != NULL)
{
avListItem->setZOffset((F32)(targetZ));
//llinfos << targetAv << " ::: " << targetZ << llendl;
}
}
}
}

View File

@ -60,4 +60,19 @@ public:
virtual void error(U32 status, const std::string& reason);
};
//
// Responder used by radar for position lookups
//
class FSLSLBridgeRequestRadarPosResponder : public FSLSLBridgeRequestResponder
{
public:
FSLSLBridgeRequestRadarPosResponder();
//If we get back a normal response, handle it here
void result(const LLSD& content);
};
#endif // FS_LSLBRIDGEREQUEST_H

View File

@ -96,6 +96,8 @@ LLAvatarListItem::LLAvatarListItem(bool not_from_ui_factory/* = true*/)
mShowDisplayName(true),
mShowUsername(true),
mFirstSeen(time(NULL)),
mLastZOffsetTime(time(NULL)),
mZOffset(0),
mAvStatus(0),
mAvPosition(LLVector3d(0.0f,0.0f,0.0f)),
mShowFirstSeen(false),
@ -488,6 +490,26 @@ void LLAvatarListItem::setFirstSeen(time_t seentime)
mFirstSeen = seentime;
}
time_t LLAvatarListItem::getLastZOffsetTime()
{
return mLastZOffsetTime;
}
void LLAvatarListItem::setLastZOffsetTime(time_t oTime)
{
mLastZOffsetTime = oTime;
}
F32 LLAvatarListItem::getZOffset()
{
return mZOffset;
}
void LLAvatarListItem::setZOffset(F32 offset)
{
mZOffset = offset;
}
void LLAvatarListItem::setAvatarIconVisible(bool visible)
{
// Already done? Then do nothing.

View File

@ -113,6 +113,10 @@ public:
S32 getAvStatus();
void setFirstSeen(time_t seenTime);
time_t getFirstSeen();
void setLastZOffsetTime(time_t oTime);
time_t getLastZOffsetTime();
void setZOffset(F32 offset);
F32 getZOffset();
void showDisplayName(bool show);
void showFirstSeen(bool show);
void showStatusFlags(bool show);
@ -268,10 +272,12 @@ private:
LLUUID mAvatarId;
time_t mFirstSeen;
time_t mLastZOffsetTime;
F32 mZOffset;
S32 mAvStatus;
LLVector3d mAvPosition;
S32 mAvatarAge;
F32 mDistance;
F32 mDistance;
std::string mHighlihtSubstring; // substring to highlight
EOnlineStatus mOnlineStatus;

View File

@ -82,6 +82,8 @@
#include <boost/algorithm/string.hpp>
#include "llcontrol.h"
#include "lggcontactsets.h"
#include "fslslbridge.h"
#include "fslslbridgerequest.h"
using namespace std;
using namespace boost;
@ -546,9 +548,6 @@ LLPanelPeople::~LLPanelPeople()
delete mNearbyListUpdater;
delete mFriendListUpdater;
delete mRecentListUpdater;
lastRadarSweep.clear();
mRadarEnterAlerts.clear();
mRadarLeaveAlerts.clear();
if(LLVoiceClient::instanceExists())
{
@ -602,22 +601,18 @@ BOOL LLPanelPeople::postBuild()
LLPanel* nearby_tab = getChild<LLPanel>(NEARBY_TAB_NAME);
nearby_tab->getChildView("NearMeRange")->setVisible(gSavedSettings.getBOOL("LimitRadarByRange"));
// AO: radarlist takes over for nearbylist. It's a scroll list vs. avatarlist.
// AO: radarlist takes over for nearbylist for presentation.
mRadarList = nearby_tab->getChild<LLRadarListCtrl>("radar_list");
mRadarList->sortByColumn("range",TRUE); // sort by range
mRadarFrameCount = 0;
mRadarAlertRequest = false;
mRadarLastBulkOffsetRequestTime = 0;
// AO: mNearbyList is preserved as a data structure model for radar
mNearbyList = nearby_tab->getChild<LLAvatarList>("avatar_list");
mNearbyListUpdater->setActive(true); // AO: always keep radar active, for chat and channel integration
//nearby_tab->setVisibleCallback(boost::bind(&Updater::setActive, mNearbyListUpdater, _2));
// AO: Much of the below presentation options are now deprecated.
mNearbyList->setNoItemsCommentText(getString("no_one_near"));
mNearbyList->setNoItemsMsg(getString("no_one_near"));
mNearbyList->setNoFilteredItemsMsg(getString("no_one_filtered_near"));
mNearbyList->showUsername(false);
mNearbyList->showMiniProfileIcons(false);
mNearbyList->showPermissions(false);
// [RLVa:KB] - Checked: 2010-04-05 (RLVa-1.2.2a) | Added: RLVa-1.2.0d
mNearbyList->setRlvCheckShowNames(true);
// [/RLVa:KB]
@ -641,7 +636,6 @@ BOOL LLPanelPeople::postBuild()
mGroupList->setNoFilteredItemsMsg(getString("no_filtered_groups_msg"));
mRadarList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
mNearbyList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
mRecentList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
mAllFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
mOnlineFriendList->setContextMenu(&LLPanelPeopleMenus::gNearbyMenu);
@ -661,7 +655,6 @@ BOOL LLPanelPeople::postBuild()
mOnlineFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
mAllFriendList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
mNearbyList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onNearbyListDoubleClicked, this, _1));
mRecentList->setItemDoubleClickCallback(boost::bind(&LLPanelPeople::onAvatarListDoubleClicked, this, _1));
mRadarList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onRadarListDoubleClicked, this));
@ -673,7 +666,6 @@ BOOL LLPanelPeople::postBuild()
// Set openning IM as default on return action for avatar lists
mOnlineFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
mAllFriendList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
mNearbyList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
mRecentList->setReturnCallback(boost::bind(&LLPanelPeople::onImButtonClicked, this));
mGroupList->setDoubleClickCallback(boost::bind(&LLPanelPeople::onChatButtonClicked, this));
@ -881,24 +873,23 @@ void LLPanelPeople::updateNearbyList()
//AO : Warning, reworked heavily for Firestorm. Do not merge into here without understanding what it's doing.
if (!mNearbyList)
{
return;
}
//Configuration
F32 drawRadius = gSavedSettings.getF32("RenderFarClip");
BOOL limitRange = gSavedSettings.getBOOL("LimitRadarByRange");
static LLCachedControl<bool> sUseLSLBridge(gSavedSettings, "UseLSLBridge");
const LLVector3d& posSelf = gAgent.getPositionGlobal();
LLViewerRegion* reg = gAgent.getRegion();
LLUUID regionSelf;
if (reg)
regionSelf = reg->getRegionID();
bool alertScripts = mRadarAlertRequest; // assign this at the beginning of the call to resist race conditions
//const LLUUID regionSelf = gAgent.getRegion()->getRegionID();
bool alertScripts = mRadarAlertRequest; // save the current value, so it doesn't get changed out from under us by another thread
std::vector<LLPanel*> items;
LLWorld* world = LLWorld::getInstance();
time_t now = time(NULL);
//STEP 0: Clear data, saving pieces as needed.
//STEP 0: Clear model data, saving pieces as needed.
LLScrollListItem* lastRadarSelectedItem = mRadarList->getFirstSelected();
LLUUID selected_id;
S32 lastScroll = mRadarList->getScrollPos();
@ -909,8 +900,10 @@ void LLPanelPeople::updateNearbyList()
mRadarList->clearRows();
mRadarEnterAlerts.clear();
mRadarLeaveAlerts.clear();
mRadarOffsetRequests.clear();
//STEP 1:Detect Avatars & Positions in our defined range, dump them into avatarList
//STEP 1: Update our basic data model: detect Avatars & Positions in our defined range
std::vector<LLVector3d> positions;
std::vector<LLUUID> avatar_ids;
if (limitRange)
@ -921,28 +914,29 @@ void LLPanelPeople::updateNearbyList()
mNearbyList->setDirty(true,true); // AO: These optional arguements force updating even when we're not a visible window.
mNearbyList->getItems(items);
//STEP 2: Transform detected list data into more flexible multimap;
//STEP 2: Transform detected model list data into more flexible multimap data structure;
std::vector<LLVector3d>::const_iterator
pos_it = positions.begin(),
pos_end = positions.end();
std::vector<LLUUID>::const_iterator
item_it = avatar_ids.begin(),
item_end = avatar_ids.end();
for (;pos_it != pos_end && item_it != item_end; ++pos_it, ++item_it )
{
//2a. gather necessary model data
//
//2a. For each detected av, gather up all data we would want to display or use to drive alerts
//
LLUUID avId = static_cast<LLUUID>(*item_it);
LLVector3d avPos = static_cast<LLVector3d>(*pos_it);
LLAvatarListItem* av = mNearbyList->getAvatarListItem(avId);
F32 avRange = dist_vec(avPos, posSelf);
LLVector3d avPos = static_cast<LLVector3d>(*pos_it);
S32 seentime = 0;
LLUUID avRegion;
// Skip modelling this avatar if its basic data is either inaccessible, or it's a dummy placeholder
LLViewerRegion *reg = world->getRegionFromPosGlobal(avPos);
if ((!reg) || (!av)) // don't update this radar listing if data is inaccessible
continue;
// WS: If we have a dummy avatar. Then Don't display it in th
static LLUICachedControl<bool> showdummyav("FSShowDummyAVsinRadar");
if(!showdummyav){
LLVOAvatar* voav = (LLVOAvatar*)gObjectList.findObject(avId);
@ -957,11 +951,12 @@ void LLPanelPeople::updateNearbyList()
for (multimap<LLUUID,radarFields>::iterator it2 = dupeAvs.first; it2 != dupeAvs.second; ++it2)
{
if (it2->second.lastRegion == avRegion)
seentime = (S32)difftime(time(NULL),it2->second.firstSeen);
seentime = (S32)difftime(now,it2->second.firstSeen);
}
}
else
seentime = (S32)difftime(time(NULL),av->getFirstSeen());
seentime = (S32)difftime(now,av->getFirstSeen());
//av->setFirstSeen(now - (time_t)seentime); // maintain compatibility with underlying list, deprecated
S32 hours = (S32)(seentime / 3600);
S32 mins = (S32)((seentime - hours * 3600) / 60);
S32 secs = (S32)((seentime - hours * 3600 - mins * 60));
@ -972,32 +967,43 @@ void LLPanelPeople::updateNearbyList()
avFlagStr += "$";
std::string avAgeStr = av->getAvatarAge();
std::string avName = getRadarName(avId);
//llinfos << "Processing " << avName << " range: " << avRange << " key: " << avId << llendl;
//2b. ensure compatibility with avlist, should deprecate
av->setRange(avRange);
av->setPosition(avPos);
av->setFirstSeen(time(NULL) - (time_t)seentime);
av->setAvatarName(avName);
//2c Report all detected to scripts if we were asked for an update
if (alertScripts)
av->setAvatarName(avName); // maintain compatibility with underlying list, deprecated
U32 lastZOffsetTime = av->getLastZOffsetTime();
F32 avZOffset = av->getZOffset();
if (avPos[2] < 0.1) // if our official z position is 0.0, we need a correction.
{
mRadarEnterAlerts.push_back(avId);
}
// set correction if we have it
if (avZOffset > 0.1)
avPos[2] = avZOffset;
else
{
avPos[2] = 9999; // placeholder value, better than "0", until we get real data.
}
//schedule offset requests, if needed
if (sUseLSLBridge && (now > (mRadarLastBulkOffsetRequestTime + COARSE_OFFSET_INTERVAL)) && (now > lastZOffsetTime + COARSE_OFFSET_INTERVAL))
{
mRadarOffsetRequests.push_back(avId);
av->setLastZOffsetTime(now);
}
}
F32 avRange = dist_vec(avPos, posSelf);
av->setRange(avRange); // maintain compatibility with underlying list, deprecated
av->setPosition(avPos); // maintain compatibility with underlying list, deprecated
//2d. Report on net-new entries.
//
//2b. Process newly detected avatars
//
if (lastRadarSweep.count(avId) == 0)
{
// chat alerts
if (gSavedSettings.getBOOL("RadarReportChatRange") && (avRange <= CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered chat range (%3.2f m).",avRange)));
if (gSavedSettings.getBOOL("RadarReportDrawRange") && (avRange <= drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered draw distance (%3.2f m).",avRange)));
if (gSavedSettings.getBOOL("RadarReportSimRange") && (avRegion == regionSelf))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered the region (%3.2f m).",avRange)));
if (gSavedSettings.getBOOL("RadarEnterChannelAlert") && (!mRadarAlertRequest))
if (gSavedSettings.getBOOL("RadarEnterChannelAlert") || (alertScripts))
{
// Autodetect Phoenix chat UUID compatibility.
// If Leave channel alerts are not set, restrict reports to same-sim only.
@ -1010,9 +1016,84 @@ void LLPanelPeople::updateNearbyList()
mRadarEnterAlerts.push_back(avId);
}
}
//2e. Build out scrollist-style view
//
// 2c. Process previously detected avatars
//
else
{
radarFields rf; // will hold the newest version
// Check for range crossing alert threshholds, being careful to handle double-listings
if (lastRadarSweep.count(avId) == 1) // normal case, check from last position
{
rf = lastRadarSweep.find(avId)->second;
if (gSavedSettings.getBOOL("RadarReportChatRange"))
{
if ((avRange <= CHAT_NORMAL_RADIUS) && (rf.lastDistance > CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered chat range (%3.2f m).",avRange)));
else if ((avRange > CHAT_NORMAL_RADIUS) && (rf.lastDistance <= CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left chat range."));
}
if (gSavedSettings.getBOOL("RadarReportDrawRange"))
{
if ((avRange <= drawRadius) && (rf.lastDistance > drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered draw distance (%3.2f m).",avRange)));
else if ((avRange > drawRadius) && (rf.lastDistance <= drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left draw distance."));
}
if (gSavedSettings.getBOOL("RadarReportSimRange"))
{
if ((avRegion == regionSelf) && (avRegion != rf.lastRegion))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered the region (%3.2f m).",avRange)));
else if ((rf.lastRegion == regionSelf) && (avRegion != regionSelf))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left the region."));
}
}
else if (lastRadarSweep.count(avId) > 1) // handle duplicates, from sim crossing oddness
{
// iterate through all the duplicates found, searching for the newest.
rf.firstSeen=0;
pair<multimap<LLUUID,radarFields>::iterator,multimap<LLUUID,radarFields>::iterator> dupeAvs;
dupeAvs = lastRadarSweep.equal_range(avId);
for (multimap<LLUUID,radarFields>::iterator it2 = dupeAvs.first; it2 != dupeAvs.second; ++it2)
{
if (it2->second.firstSeen > rf.firstSeen)
rf = it2->second;
}
llinfos << "AO: Duplicates detected for " << avName <<" , most recent is " << rf.firstSeen << llendl;
if (gSavedSettings.getBOOL("RadarReportChatRange"))
{
if ((avRange <= CHAT_NORMAL_RADIUS) && (rf.lastDistance > CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered chat range (%3.2f m).",avRange)));
else if ((avRange > CHAT_NORMAL_RADIUS) && (rf.lastDistance <= CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left chat range."));
}
if (gSavedSettings.getBOOL("RadarReportDrawRange"))
{
if ((avRange <= drawRadius) && (rf.lastDistance > drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered draw distance (%3.2f m).",avRange)));
else if ((avRange > drawRadius) && (rf.lastDistance <= drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left draw distance."));
}
if (gSavedSettings.getBOOL("RadarReportSimRange"))
{
if ((avRegion == regionSelf) && (avRegion != rf.lastRegion))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered the region (%3.2f m).",avRange)));
else if ((rf.lastRegion == regionSelf) && (avRegion != regionSelf))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left the region."));
}
}
//If we were manually asked to update an external source for all existing avatars, add them to the queue.
if (alertScripts)
{
mRadarEnterAlerts.push_back(avId);
}
}
//
//2d. Build out scrollist-style presentation view for this avatar row
//
LLSD row;
row["value"] = avId;
row["columns"][0]["column"] = "name";
@ -1048,88 +1129,69 @@ void LLPanelPeople::updateNearbyList()
radarNameCell->setFontStyle(LLFontGL::BOLD);
else
radarNameCell->setFontStyle(LLFontGL::NORMAL);
if(LGGContactSets::getInstance()->hasFriendColorThatShouldShow(avId,FALSE,FALSE,TRUE))
{
radarNameCell->setColor(LGGContactSets::getInstance()->getFriendColor(avId));
}
//AO: Preserve selection
if (lastRadarSelectedItem)
{
if (avId == selected_id)
{
mRadarList->selectByID(avId);
updateButtons(); // TODO: only update on change, instead of every tick
}
//2f. Check for range crossing alert threshholds, being careful to handle double-listings
if (lastRadarSweep.count(avId) == 1) // normal case, check from last position
{
radarFields rf = lastRadarSweep.find(avId)->second;
if (gSavedSettings.getBOOL("RadarReportChatRange"))
{
if ((avRange <= CHAT_NORMAL_RADIUS) && (rf.lastDistance > CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered chat range (%3.2f m).",avRange)));
else if ((avRange > CHAT_NORMAL_RADIUS) && (rf.lastDistance <= CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left chat range."));
}
if (gSavedSettings.getBOOL("RadarReportDrawRange"))
{
if ((avRange <= drawRadius) && (rf.lastDistance > drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered draw distance (%3.2f m).",avRange)));
else if ((avRange > drawRadius) && (rf.lastDistance <= drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left draw distance."));
}
if (gSavedSettings.getBOOL("RadarReportSimRange"))
{
if ((avRegion == regionSelf) && (avRegion != rf.lastRegion))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered the region (%3.2f m).",avRange)));
else if ((rf.lastRegion == regionSelf) && (avRegion != regionSelf))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left the region."));
}
}
else if (lastRadarSweep.count(avId) > 1) // handle duplicates, from sim crossing oddness
{
// iterate through all the duplicates found, searching for the newest.
radarFields rf; // will hold the newest version
rf.firstSeen=0;
pair<multimap<LLUUID,radarFields>::iterator,multimap<LLUUID,radarFields>::iterator> dupeAvs;
dupeAvs = lastRadarSweep.equal_range(avId);
for (multimap<LLUUID,radarFields>::iterator it2 = dupeAvs.first; it2 != dupeAvs.second; ++it2)
{
if (it2->second.firstSeen > rf.firstSeen)
rf = it2->second;
}
llinfos << "AO: Duplicates detected for " << avName <<" , most recent is " << rf.firstSeen << llendl;
if (gSavedSettings.getBOOL("RadarReportChatRange"))
{
if ((avRange <= CHAT_NORMAL_RADIUS) && (rf.lastDistance > CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered chat range (%3.2f m).",avRange)));
else if ((avRange > CHAT_NORMAL_RADIUS) && (rf.lastDistance <= CHAT_NORMAL_RADIUS))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left chat range."));
}
if (gSavedSettings.getBOOL("RadarReportDrawRange"))
{
if ((avRange <= drawRadius) && (rf.lastDistance > drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered draw distance (%3.2f m).",avRange)));
else if ((avRange > drawRadius) && (rf.lastDistance <= drawRadius))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left draw distance."));
}
if (gSavedSettings.getBOOL("RadarReportSimRange"))
{
if ((avRegion == regionSelf) && (avRegion != rf.lastRegion))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, llformat(" entered the region (%3.2f m).",avRange)));
else if ((rf.lastRegion == regionSelf) && (avRegion != regionSelf))
LLAvatarNameCache::get(avId,boost::bind(&LLPanelPeople::radarAlertMsg, this, _1, _2, " left the region."));
}
}
}
//STEP 3.0
} // End STEP 2, all model/presentation row processing complete.
//Reset scroll position
mRadarList->setScrollPos(lastScroll);
//STEP 3: Handle any avatars that dropped off the detected list since last time.
//
//STEP 3 , process any bulk actions that require the whole model to be known first
//
//
//3a. dispatch requests for ZOffset updates, working around minimap's inaccurate height
//
if (mRadarOffsetRequests.size() > 0)
{
std::string prefix = "getZOffsets|";
std::string msg = "";
U32 updatesPerRequest=0;
while(mRadarOffsetRequests.size() > 0)
{
LLUUID avId = mRadarOffsetRequests.back();
mRadarOffsetRequests.pop_back();
msg = llformat("%s%s,",msg.c_str(),avId.asString().c_str());
if (++updatesPerRequest > MAX_OFFSET_REQUESTS)
{
msg = msg.substr(0,msg.size()-1);
FSLSLBridgeRequestResponder* responder = new FSLSLBridgeRequestRadarPosResponder();
FSLSLBridge::instance().viewerToLSL(prefix+msg,responder);
//llinfos << " OFFSET REQUEST SEGMENT"<< prefix << msg << llendl;
msg="";
updatesPerRequest = 0;
}
}
if (updatesPerRequest > 0)
{
msg = msg.substr(0,msg.size()-1);
FSLSLBridgeRequestResponder* responder = new FSLSLBridgeRequestRadarPosResponder();
FSLSLBridge::instance().viewerToLSL(prefix+msg,responder);
//llinfos << " OFFSET REQUEST FINAL " << prefix << msg << llendl;
}
// clear out the dispatch queue
mRadarOffsetRequests.clear();
mRadarLastBulkOffsetRequestTime = now;
}
//
//3b: process alerts for avatars that where here last frame, but gone this frame (ie, they left)
// as well as dispatch all earlier detected alerts for crossing range thresholds.
//
for (std::multimap <LLUUID, radarFields>::const_iterator i = lastRadarSweep.begin(); i != lastRadarSweep.end(); ++i)
{
LLUUID prevId = i->first;
@ -1147,31 +1209,6 @@ void LLPanelPeople::updateNearbyList()
mRadarLeaveAlerts.push_back(prevId);
}
}
//STEP 4: Update out local radar data cache, for faster tracking of changes
lastRadarSweep.clear();
for (std::vector<LLPanel*>::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
{
LLAvatarListItem* av = static_cast<LLAvatarListItem*>(*itItem);
radarFields rf;
rf.avName = av->getAvatarName();
rf.lastDistance = av->getRange();
rf.firstSeen = av->getFirstSeen();
rf.lastStatus = av->getAvStatus();
rf.lastGlobalPos = av->getPosition();
if (rf.lastGlobalPos != LLVector3d(0.0f,0.0f,0.0f))
{
LLViewerRegion* lastRegion = world->getRegionFromPosGlobal(rf.lastGlobalPos);
if (lastRegion)
rf.lastRegion = lastRegion->getRegionID();
}
else
rf.lastRegion = LLUUID(0);
lastRadarSweep.insert(pair<LLUUID,radarFields>(av->getAvatarId(),rf));
}
//STEP 5: Send out Chat alerts on events
if (mRadarEnterAlerts.size() > 0)
{
mRadarFrameCount++;
@ -1223,16 +1260,50 @@ void LLPanelPeople::updateNearbyList()
msgs->addString("ButtonLabel", msg.c_str());
gAgent.sendReliableMessage();
}
}
//STEP 6: Update GUI text of number of total users
mRadarList->setColumnLabel("name",llformat("NAME [%d]",lastRadarSweep.size()));
}
// reset any active alert requests
if (alertScripts)
mRadarAlertRequest = false;
//
//STEP 4: Cache our current model data, so we can compare it with the next fresh group of model data for fast change detection.
//
//minimap updates
lastRadarSweep.clear();
for (std::vector<LLPanel*>::const_iterator itItem = items.begin(); itItem != items.end(); ++itItem)
{
LLAvatarListItem* av = static_cast<LLAvatarListItem*>(*itItem);
radarFields rf;
rf.avName = av->getAvatarName();
rf.lastDistance = av->getRange();
rf.firstSeen = av->getFirstSeen();
rf.lastStatus = av->getAvStatus();
rf.ZOffset = av->getZOffset();
rf.lastGlobalPos = av->getPosition();
if ((rf.ZOffset > 0) && (rf.lastGlobalPos[2] < 1024)) // if our position may need an offset correction, see if we have one to apply
{
rf.lastGlobalPos[2] = rf.lastGlobalPos[2] + (1024 * rf.ZOffset);
}
//rf.lastZOffsetTime = av->getLastZOffsetTime();
if (rf.lastGlobalPos != LLVector3d(0.0f,0.0f,0.0f))
{
LLViewerRegion* lastRegion = world->getRegionFromPosGlobal(rf.lastGlobalPos);
if (lastRegion)
rf.lastRegion = lastRegion->getRegionID();
}
else
rf.lastRegion = LLUUID(0);
lastRadarSweep.insert(pair<LLUUID,radarFields>(av->getAvatarId(),rf));
}
//
//STEP 5: Final presentation updates
//
// update header w/number of avs detected in this sweep
mRadarList->setColumnLabel("name",llformat("NAME [%d]",lastRadarSweep.size()));
// update minimap with selected avatars
uuid_vec_t selected_uuids;
LLUUID sVal = mRadarList->getSelectedValue().asUUID();
if (sVal != LLUUID::null)

View File

@ -46,7 +46,8 @@ class LLMenuButton;
class LLMenuGL;
const U32 MAX_AVATARS_PER_ALERT = 7; // maximum number of UUIDs we can cram into a single channel radar alert message
const U32 COARSE_OFFSET_INTERVAL = 31; // seconds after which we query the bridge for a coarse location adjustment
const U32 COARSE_OFFSET_INTERVAL = 7; // seconds after which we query the bridge for a coarse location adjustment
const U32 MAX_OFFSET_REQUESTS = 60; // 2048 / UUID size, leaving overhead space
const U32 NAMEFORMAT_DISPLAYNAME = 0;
const U32 RADAR_CHAT_MIN_SPACING = 6; //minimum delay between radar chat messages
@ -179,7 +180,7 @@ private:
LLAvatarList* mRecentList;
LLGroupList* mGroupList;
LLRadarListCtrl* mRadarList;
LLNetMap* mMiniMap;
LLNetMap* mMiniMap;
LLHandle<LLView> mGroupPlusMenuHandle;
LLHandle<LLView> mNearbyViewSortMenuHandle;
@ -208,19 +209,23 @@ private:
{
std::string avName;
F32 lastDistance;
LLVector3d lastGlobalPos;
LLUUID lastRegion;
time_t firstSeen;
LLVector3d lastGlobalPos;
LLUUID lastRegion;
time_t firstSeen;
S32 lastStatus;
S32 coarseOffset;
U32 ZOffset;
time_t lastZOffsetTime;
};
std::multimap < LLUUID, radarFields > lastRadarSweep;
std::vector <LLUUID> mRadarEnterAlerts;
std::vector <LLUUID> mRadarLeaveAlerts;
std::vector <LLUUID> mRadarOffsetRequests;
S32 mRadarFrameCount;
bool mRadarAlertRequest;
F32 mRadarLastRequestTime;
U32 mRadarLastBulkOffsetRequestTime;
};
#endif //LL_LLPANELPEOPLE_H