Files
SingularityViewer/indra/newview/llfloaterteleport.cpp
2011-02-23 01:40:47 -06:00

329 lines
12 KiB
C++

/**
* @file llfloaterteleport.cpp
* @brief floater code for agentd teleports.
*
* $LicenseInfo:firstyear=2008&license=viewergpl$
*
* Copyright (c) 2008, Linden Research, Inc.
*
* Second Life Viewer Source Code
* The source code in this file ("Source Code") is provided by Linden Lab
* to you under the terms of the GNU General Public License, version 2.0
* ("GPL"), unless you have obtained a separate licensing agreement
* ("Other License"), formally executed by you and Linden Lab. Terms of
* the GPL can be found in doc/GPL-license.txt in this distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution, or
* online at http://secondlifegrid.net/programs/open_source/licensing/flossexception
*
* By copying, modifying or distributing this software, you acknowledge
* that you have read and understood your obligations described above,
* and agree to abide by those obligations.
*
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
* COMPLETENESS OR PERFORMANCE.
* $/LicenseInfo$
*/
//Teleport floater used for agent domain TP. URI text floater.
//Copyright International Business Machines Corporation 2008-9
//Contributed to Linden Research, Inc. under the Second Life Viewer Contribution
//Agreement and licensed as above.
#include "llviewerprecompiledheaders.h" // must be first include
#include "llfloaterteleport.h"
#include "llagent.h" //for hack in teleport start
#include "llchat.h"
#include "llcombobox.h"
#include "llfloaterchat.h"
#include "llsdserialize.h"
#include "llsdutil.h"
#include "llsdutil_math.h"
#include "lluictrlfactory.h" // builds floaters from XML
#include "llurlhistory.h"
#include "lluserauth.h" // for saving placeavatarresponder result
#include "llviewercontrol.h" // for gSavedSettings
#include "llviewerdisplay.h" // for gTeleportDisplay
#include "llviewermessage.h" // for send_agent_movement_complete attempt
#include "llviewerregion.h"
#include "llviewerwindow.h" // for hack in teleport start
#include "llvoavatar.h"
#include "llworld.h"
#include "pipeline.h" // for gPipeline
// OGPX HTTP responder for PlaceAvatar cap used for Teleport
// very similar to the responder in Login, but not as many fields are returned in the TP version
// OGPX TODO: should this be combined with the Login responder for rez_avatar/place?
// OGPX TODO: mResult should not get replaced in result(), instead
// should replace individual LLSD fields in mResult.
class LLPlaceAvatarTeleportResponder :
public LLHTTPClient::Responder
{
public:
LLPlaceAvatarTeleportResponder()
{
}
~LLPlaceAvatarTeleportResponder()
{
}
void error(U32 statusNum, const std::string& reason)
{
LL_INFOS("OGPX") << "LLPlaceAvatarTeleportResponder error in TP "
<< statusNum << " " << reason << LL_ENDL;
LLSD args;
args["REASON"] = reason;
LLNotifications::instance().add("CouldNotTeleportReason", args);
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
}
void result(const LLSD& content)
{
LLSD result;
result["agent_id"] = content["agent_id"]; // need this for send_complete_agent_movement
result["region_x"] = content["region_x"]; // need these for making the first region
result["region_y"] = content["region_y"];
result["login"] = "true"; // this gets checked in idle_startup()
result["session_id"] = content["session_id"];
result["secure_session_id"] = content["secure_session_id"];
result["circuit_code"] = content["circuit_code"];
result["sim_port"] = content["sim_port"];
result["sim_host"] = content["sim_host"];
result["look_at"] = content["look_at"];
// maintaining result seed_capability name for compatibility with legacy login
result["seed_capability"] = content["region_seed_capability"];
result["position"] = content["position"]; // save this for agentmovementcomplete type processing
// Even though we have the pretty print of the complete content returned, we still find it handy
// when scanning SecondLife.log to have these laid out in this way. So they are still here.
LL_DEBUGS("OGPX") << " Teleport placeAvatar responder " << LL_ENDL;
LL_DEBUGS("OGPX") << "agent_id: " << content["agent_id"] << LL_ENDL;
LL_DEBUGS("OGPX") << "region_x: " << content["region_x"] << LL_ENDL;
LL_DEBUGS("OGPX") << "session_id: " << content["session_id"] << LL_ENDL;
LL_DEBUGS("OGPX") << "sim_port: " << content["sim_port"] << LL_ENDL;
LL_DEBUGS("OGPX") << "sim_host: " << content["sim_host"] << LL_ENDL;
LL_DEBUGS("OGPX") << "look_at: " << content["look_at"] << LL_ENDL;
LL_DEBUGS("OGPX") << "position: " << content["position"] << LL_ENDL;
LL_DEBUGS("OGPX") << "seed_capability: " << content["region_seed_capability"] << LL_ENDL;
LL_INFOS("OGPX") << " All the LLSD PlaceAvatarTeleportResponder content: \n " << ll_pretty_print_sd(content) << LL_ENDL; // OGPX
// check "connect" to make sure place_avatar fully successful
if (!content["connect"].asBoolean())
{
// place_avatar failed somewhere
LL_INFOS("OGPX") << "TP failed, connect false in TP PlaceAvatarResponder " << LL_ENDL;
LLSD args;
args["REASON"] = "Place Avatar Failed";
//gViewerWindow->alertXml("CouldNotTeleportReason", args);
LLNotifications::instance().add("CouldNotTeleportReason",args);
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
return;
}
U64 region_handle;
region_handle = to_region_handle_global(content["region_x"].asInteger(), content["region_y"].asInteger());
LLHost sim_host;
U32 sim_port = strtoul(result["sim_port"].asString().c_str(), NULL, 10);
sim_host.setHostByName(result["sim_host"].asString().c_str());
sim_host.setPort(sim_port);
if (sim_host.isOk())
{
LLMessageSystem* msg = gMessageSystem;
gMessageSystem->enableCircuit(sim_host, TRUE);
msg->newMessageFast(_PREHASH_UseCircuitCode);
msg->nextBlockFast(_PREHASH_CircuitCode);
msg->addU32Fast(_PREHASH_Code, msg->getOurCircuitCode());
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
msg->sendReliable(sim_host);
}
else
{
LL_INFOS("OGPX") << "TP failed, could not resolve hostname for UDP messages." << LL_ENDL;
LLSD args;
args["REASON"] = "Failed to resolve host.";
//gViewerWindow->alertXml("CouldNotTeleportReason", args);
LLNotifications::instance().add("CouldNotTeleportReason", args);
gAgent.setTeleportState( LLAgent::TELEPORT_NONE );
return;
}
// Viewer trusts the simulator.
LLViewerRegion* regionp = LLWorld::getInstance()->addRegion(region_handle, sim_host);
regionp->setSeedCapability(content["seed_capability"].asString().c_str());
// process_agent_movement_complete needs the region to still be the old region gAgent.setRegion(regionp);
// placing these in result so they can be set properly in LLUserAuth result
// ...they are only passed in on login, and not on TP
result["session_id"] = gAgent.getSessionID();
result["agent_id"] = gAgent.getID();
result["circuit_code"].asString() = gMessageSystem->mOurCircuitCode; // this is what startup sets, is this proper to do?
// grab the skeleton and root.
result["inventory-skeleton"] = LLUserAuth::getInstance()->mResult["inventory-skeleton"];
result["inventory-root"] = LLUserAuth::getInstance()->mResult["inventory-root"];
LL_DEBUGS("OGPX") << "session_id: " << result["session_id"] << LL_ENDL;
// results need to be stored so process_agent_movement_complete() can pull them
LLUserAuth::getInstance()->mAuthResponse = LLUserAuth::E_OK;
// OGPX TODO: This just reeks of causing problems, because we are using
// ... mResult to store things that we get from other caps....So slamming a
// ... completely new result in on teleport is going to cause issues.
// ... It makes changing the things we save in mResult error prone.
// ... Question is, how should we really be storing the seemingly random things
// ... that we get back from (now) various different caps that used to all come back
// ... in the result of XMLRPC authenticate?
LLUserAuth::getInstance()->mResult = result;
// ... new sim not sending me much without sending it CompleteAgentMovement msg.
//gAgent.setTeleportState( LLAgent::TELEPORT_MOVING ); // process_agent_mv_complete looks for TELEPORT_MOVING
LLVector3 position = ll_vector3_from_sd(result["position"]);
gAgent.setHomePosRegion(region_handle, position); // taken from teleport_finish (not sure regular code path gets this)
send_complete_agent_movement(sim_host);
// Turn off progress msg (also need to do this in all the possible failure places)
// I think we leave this, as the scene is still changing during the
// processing of agentmovementcomeplete message. TELEPORT_NONE resets it anyway
// gViewerWindow->setShowProgress(FALSE);
}
};
// Statics
LLFloaterTeleport* LLFloaterTeleport::sInstance = NULL;
LLFloaterTeleport::LLFloaterTeleport()
: LLFloater("floater_teleport")
{
if(!sInstance)
{
LLUICtrlFactory::getInstance()->buildFloater(this, "floater_teleport.xml");
LLComboBox* regioncombo = getChild<LLComboBox>("teleport_edit");
regioncombo->setAllowTextEntry(TRUE, 256, FALSE); // URL bar needs to allow user text input
// iterate on uri list adding to combobox (couldn't figure out how to add them all in one call)
LLSD regionuri_history = LLURLHistory::getURLHistory("regionuri");
LLSD::array_iterator iter_history = regionuri_history.beginArray();
LLSD::array_iterator iter_end = regionuri_history.endArray();
for(; iter_history != iter_end; ++iter_history)
{
regioncombo->addSimpleElement((*iter_history).asString());
}
// select which is displayed if we have a current URL.
regioncombo->setSelectedByValue(LLSD(gSavedSettings.getString("CmdLineRegionURI")),TRUE);
// TODO : decide if 'enter' when selecting something from the combox box should *not* be sent
// to the floater (p.s. and figure out how to change it)
childSetAction("teleport_btn", onClickTeleport, this);
childSetAction("cancel_btn", onClickCancel, this);
setDefaultBtn("teleport_btn");
}
else
{
sInstance->show(NULL);
}
}
// static
void LLFloaterTeleport::show(void*)
{
if (!sInstance)
{
sInstance = new LLFloaterTeleport();
}
sInstance->open();
}
LLFloaterTeleport::~LLFloaterTeleport()
{
sInstance=NULL;
}
// static
void LLFloaterTeleport::onClickTeleport(void* userdata)
{
std::string placeAvatarCap = LLAppViewer::instance()->getPlaceAvatarCap();
LLSD args;
LLFloaterTeleport* self = (LLFloaterTeleport*)userdata;
std::string text = self->childGetText("teleport_edit");
if (text.find("://",0) == std::string::npos)
{
// if there is no uri, prepend it with http://
text = "http://"+text;
LL_DEBUGS("OGPX") << "Teleport URI was prepended, now " << text << LL_ENDL;
}
LL_DEBUGS("OGPX") << "onClickTeleport! from using place_avatar cap "<< placeAvatarCap << " contains "<< text << LL_ENDL;
LLStringUtil::trim(text); // trim extra spacing
gAgent.setTeleportSourceURL(gSavedSettings.getString("CmdLineRegionURI")); // grab src region name
gSavedSettings.setString("CmdLineRegionURI",text); // save the dst region
args["public_region_seed_capability"] = text;
args["position"] = ll_sd_from_vector3(LLVector3(128, 128, 50)); // default to middle of region above base terrain
LL_INFOS("OGPX") << " args to placeavatar cap " << placeAvatarCap << " on teleport: " << LLSDOStreamer<LLSDXMLFormatter>(args) << LL_ENDL;
LLHTTPClient::post(placeAvatarCap, args, new LLPlaceAvatarTeleportResponder());
gAgent.setTeleportMessage(
LLAgent::sTeleportProgressMessages["requesting"]);
gViewerWindow->setShowProgress(TRUE);
gAgent.teleportCore();
gAgent.setTeleportState( LLAgent::TELEPORT_PLACE_AVATAR ); // teleportcore() sets tp state to legacy path, so reset. ick!
gTeleportDisplayTimer.reset();
self->setVisible(FALSE);
if ( LLURLHistory::appendToURLCollection("regionuri",text))
{
// since URL history only populated on create of sInstance, add to combo list directly
LLComboBox* regioncombo = self->getChild<LLComboBox>("teleport_edit");
// BUG : this should add the new item to the combo box, but doesn't
regioncombo->addSimpleElement(text);
}
}
void LLFloaterTeleport::onClickCancel(void *userdata)
{
LLFloaterTeleport* self = (LLFloaterTeleport*)userdata;
LL_INFOS("OGPX") << "Teleport Cancel " << self->getName() << LL_ENDL;
self->setVisible(FALSE);
}