2068 lines
66 KiB
C++
2068 lines
66 KiB
C++
/**
|
|
* @file fsfloaterimport.cpp
|
|
* @brief Floater to import objects from a file.
|
|
*
|
|
* $LicenseInfo:firstyear=2013&license=viewerlgpl$
|
|
* Phoenix Firestorm Viewer Source Code
|
|
* Copyright (c) 2013 Techwolf Lupindo
|
|
*
|
|
* 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
|
|
*
|
|
* The Phoenix Firestorm Project, Inc., 1831 Oakwood Drive, Fairmont, Minnesota 56031-3225 USA
|
|
* http://www.firestormviewer.org
|
|
* $/LicenseInfo$
|
|
*/
|
|
|
|
#include "llviewerprecompiledheaders.h"
|
|
#include "fsfloaterimport.h"
|
|
|
|
#include "fscommon.h"
|
|
#include "llagent.h"
|
|
#include "llappviewer.h"
|
|
#include "llbuycurrencyhtml.h"
|
|
#include "llcallbacklist.h"
|
|
#include "llcheckboxctrl.h"
|
|
#include "lldatapacker.h"
|
|
#include "lldir.h"
|
|
#include "lleconomy.h"
|
|
#include "llfloaterperms.h"
|
|
#include "llinventorydefines.h"
|
|
#include "llinventoryfunctions.h"
|
|
#include "llmultigesture.h"
|
|
#include "llnotificationsutil.h"
|
|
#include "llparcel.h"
|
|
#include "llprimlinkinfo.h"
|
|
#include "llsdserialize.h"
|
|
#include "llsdutil_math.h"
|
|
#include "llsdutil.h"
|
|
#include "llstatusbar.h"
|
|
#include "lltooldraganddrop.h"
|
|
#include "lltrans.h"
|
|
#include "lltransactiontypes.h"
|
|
#include "llviewercontrol.h"
|
|
#include "llviewerinventory.h"
|
|
#include "llviewerobjectlist.h"
|
|
#include "llviewerparcelmgr.h"
|
|
#include "llviewerstats.h"
|
|
#include "llviewerregion.h"
|
|
#include "llvfile.h"
|
|
#include "llvfs.h"
|
|
#include "llvolumemessage.h"
|
|
#include "lltrace.h"
|
|
#include "fsexportperms.h"
|
|
#include <boost/algorithm/string_regex.hpp>
|
|
#include <boost/lexical_cast.hpp>
|
|
#include "llcoros.h"
|
|
#include "llcoproceduremanager.h"
|
|
#include "llsdutil.h"
|
|
|
|
struct FSResourceData
|
|
{
|
|
LLUUID uuid;
|
|
bool temporary;
|
|
LLAssetType::EType asset_type;
|
|
LLUUID inventory_item;
|
|
LLWearableType::EType wearable_type;
|
|
bool post_asset_upload;
|
|
LLUUID post_asset_upload_id;
|
|
FSFloaterImport *mFloater;
|
|
};
|
|
|
|
void resourceDeleter( LLResourceData *aData )
|
|
{
|
|
FSResourceData *data = (FSResourceData*)aData->mUserData;
|
|
delete data;
|
|
delete aData;
|
|
}
|
|
|
|
void uploadCoroutine( LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &a_httpAdapter, std::string aURL, LLSD aBody, LLAssetID aAssetId, LLAssetType::EType aAssetType, boost::shared_ptr< LLResourceData > aResourceData );
|
|
|
|
FSFloaterImport::FSFloaterImport(const LLSD& filename) :
|
|
LLFloater(filename),
|
|
mCreatingActive(false),
|
|
mLinkset(0),
|
|
mObject(0),
|
|
mPrim(0),
|
|
mImportState(IDLE),
|
|
mFileFullName(filename),
|
|
mObjectCreatedCallback(),
|
|
m_AssetsUploading( 0 )
|
|
{
|
|
mInstance = this;
|
|
|
|
mCommitCallbackRegistrar.add("Import.UploadAsset",boost::bind(&FSFloaterImport::onClickCheckBoxUploadAsset,this));
|
|
mCommitCallbackRegistrar.add("Import.TempAsset",boost::bind(&FSFloaterImport::onClickCheckBoxTempAsset,this));
|
|
|
|
gIdleCallbacks.addFunction(onIdle, this);
|
|
|
|
mSavedSettingShowNewInventory = gSavedSettings.getBOOL("ShowNewInventory");
|
|
}
|
|
|
|
FSFloaterImport::~FSFloaterImport()
|
|
{
|
|
if (!gIdleCallbacks.deleteFunction(onIdle, this))
|
|
{
|
|
LL_WARNS("import") << "FSFloaterImport::~FSFloaterImport() failed to delete idle callback" << LL_ENDL;
|
|
}
|
|
if (mObjectCreatedCallback.connected())
|
|
{
|
|
mObjectCreatedCallback.disconnect();
|
|
}
|
|
|
|
gSavedSettings.setBOOL("ShowNewInventory", mSavedSettingShowNewInventory);
|
|
}
|
|
|
|
BOOL FSFloaterImport::postBuild()
|
|
{
|
|
if (LLGlobalEconomy::getInstance()->getPriceUpload() == 0
|
|
|| gAgent.getRegion()->getCentralBakeVersion() > 0)
|
|
{
|
|
getChild<LLCheckBoxCtrl>("temp_asset")->setVisible(FALSE);
|
|
getChild<LLCheckBoxCtrl>("temp_asset")->set(FALSE);
|
|
}
|
|
getChild<LLButton>("import_btn")->setCommitCallback(boost::bind(&FSFloaterImport::onClickBtnImport, this));
|
|
loadFile();
|
|
populateBackupInfo();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// static
|
|
void FSFloaterImport::onIdle(void* user_data)
|
|
{
|
|
FSFloaterImport* self = (FSFloaterImport*)user_data;
|
|
self->onIdle();
|
|
}
|
|
|
|
void FSFloaterImport::onIdle()
|
|
{
|
|
if( getUploads() < 1 )
|
|
popNextAsset();
|
|
|
|
switch(mImportState)
|
|
{
|
|
case IDLE:
|
|
break;
|
|
case INVENTORY_TRANSFER:
|
|
{
|
|
if (mInventoryQueue.empty())
|
|
{
|
|
mImportState = IDLE;
|
|
mWaitTimer.stop();
|
|
|
|
if ((mObject + 1) >= mObjectSize)
|
|
{
|
|
if (mObjectSize > 1)
|
|
{
|
|
// should be allready selected
|
|
LL_DEBUGS("import") << "Linking " << mObjectSize << " objects. " << LLSelectMgr::getInstance()->getSelection()->getObjectCount() << " prims are selected" << LL_ENDL;
|
|
LLSelectMgr::getInstance()->sendLink();
|
|
mImportState = LINKING;
|
|
}
|
|
else
|
|
{
|
|
postLink();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mObject++;
|
|
createPrim();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (mWaitTimer.getElapsedTimeF32() < mThrottleTime)
|
|
{
|
|
return;
|
|
}
|
|
|
|
FSInventoryQueue item_queue = mInventoryQueue.back();
|
|
LL_DEBUGS("import") << "Dropping " << item_queue.item->getName() << " " << item_queue.item->getUUID() << " into " << item_queue.prim_name << " " << item_queue.object->getID() << LL_ENDL;
|
|
if (item_queue.item->getType() == LLAssetType::AT_LSL_TEXT)
|
|
{
|
|
LLToolDragAndDrop::dropScript(item_queue.object, item_queue.item, TRUE,
|
|
LLToolDragAndDrop::SOURCE_AGENT,
|
|
gAgentID);
|
|
}
|
|
else
|
|
{
|
|
LLToolDragAndDrop::dropInventory(item_queue.object, item_queue.item,
|
|
LLToolDragAndDrop::SOURCE_AGENT,
|
|
gAgentID);
|
|
}
|
|
mInventoryQueue.pop_back();
|
|
mWaitTimer.start();
|
|
}
|
|
break;
|
|
case LINKING:
|
|
if (LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() < 2)
|
|
{
|
|
mImportState = IDLE;
|
|
postLink();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::loadFile()
|
|
{
|
|
mFilePath = gDirUtilp->getDirName(mFilename);
|
|
mFilename = gDirUtilp->getBaseFileName(mFileFullName);
|
|
|
|
mManifest.clear();
|
|
mTextureQueue.clear();
|
|
mAnimQueue.clear();
|
|
mSoundQueue.clear();
|
|
mLinksetSize = 0;
|
|
mTexturesTotal = 0;
|
|
mAnimsTotal = 0;
|
|
mSoundsTotal = 0;
|
|
|
|
bool file_loaded = false;
|
|
llifstream filestream(mFileFullName.c_str(), std::ios_base::in | std::ios_base::binary);
|
|
if(filestream.is_open())
|
|
{
|
|
filestream.seekg(0, std::ios::end);
|
|
S32 file_size = (S32)filestream.tellg();
|
|
filestream.seekg(0, std::ios::beg);
|
|
if (unzip_llsd(mManifest, filestream, file_size))
|
|
{
|
|
file_loaded = true;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Failed to deserialize " << mFileFullName << LL_ENDL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Unable to open file: " << mFileFullName << LL_ENDL;
|
|
}
|
|
filestream.close();
|
|
|
|
if (file_loaded)
|
|
{
|
|
if (mManifest.has("format_version") && mManifest["format_version"].asInteger() <= OXP_FORMAT_VERSION)
|
|
{
|
|
LLSD& linksetsd = mManifest["linkset"];
|
|
U32 prims = 0;
|
|
for (LLSD::array_iterator linkset_iter = linksetsd.beginArray();
|
|
linkset_iter != linksetsd.endArray();
|
|
++linkset_iter)
|
|
{
|
|
LLSD& objectsd = mManifest["linkset"][mLinksetSize];
|
|
for (LLSD::array_iterator prim_iter = objectsd.beginArray();
|
|
prim_iter != objectsd.endArray();
|
|
++prim_iter)
|
|
{
|
|
processPrim(mManifest["prim"][(*prim_iter).asString()]);
|
|
prims++;
|
|
}
|
|
mLinksetSize++;
|
|
}
|
|
|
|
LLUIString stats = getString("file_status");
|
|
stats.setArg("[LINKSETS]", llformat("%u", mLinksetSize));
|
|
stats.setArg("[PRIMS]", llformat("%u", prims));
|
|
stats.setArg("[TEXTURES]", llformat("%u", mTexturesTotal));
|
|
stats.setArg("[SOUNDS]", llformat("%u", mSoundsTotal));
|
|
stats.setArg("[ANIMATIONS]", llformat("%u", mAnimsTotal));
|
|
stats.setArg("[ASSETS]", llformat("%u", mAssetsTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(stats.getString());
|
|
}
|
|
else
|
|
{
|
|
getChild<LLTextBox>("file_status_text")->setText(getString("file_version_error"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
getChild<LLTextBox>("file_status_text")->setText(getString("file_status_error"));
|
|
}
|
|
|
|
LL_DEBUGS("import") << "Linkset size is " << mLinksetSize << LL_ENDL;
|
|
if (mLinksetSize != 0)
|
|
{
|
|
getChild<LLButton>("import_btn")->setEnabled(TRUE);
|
|
getChild<LLCheckBoxCtrl>("do_not_attach")->setEnabled(TRUE);
|
|
getChild<LLCheckBoxCtrl>("region_position")->setEnabled(TRUE);
|
|
getChild<LLCheckBoxCtrl>("upload_asset")->setEnabled(TRUE);
|
|
}
|
|
else
|
|
{
|
|
getChild<LLButton>("import_btn")->setEnabled(FALSE);
|
|
getChild<LLCheckBoxCtrl>("do_not_attach")->setEnabled(FALSE);
|
|
getChild<LLCheckBoxCtrl>("region_position")->setEnabled(FALSE);
|
|
getChild<LLCheckBoxCtrl>("upload_asset")->setEnabled(FALSE);
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::populateBackupInfo()
|
|
{
|
|
childSetTextArg("filename_text", "[FILENAME]", mFilename);
|
|
childSetTextArg("client_text", "[VERSION]", mManifest["format_version"].asString());
|
|
childSetTextArg("client_text", "[CLIENT]", (mManifest.has("client") ? mManifest["client"].asString() : LLTrans::getString("Unknown")));
|
|
childSetTextArg("author_text", "[AUTHOR]", (mManifest.has("author") ? mManifest["author"].asString() : LLTrans::getString("Unknown")));
|
|
childSetTextArg("author_text", "[GRID]", (mManifest.has("grid") ? "@ " + mManifest["grid"].asString() : LLTrans::getString("Unknown")));
|
|
childSetTextArg("creation_date_text", "[DATE_STRING]", (mManifest.has("creation_date") ? mManifest["creation_date"].asString(): LLTrans::getString("Unknown")));
|
|
|
|
LLUIString title = getString("floater_title");
|
|
title.setArg("[FILENAME]", mFilename);
|
|
setTitle(title);
|
|
}
|
|
|
|
void FSFloaterImport::processPrim(LLSD& prim)
|
|
{
|
|
if (prim.has("texture"))
|
|
{
|
|
LLSD& textures = prim["texture"];
|
|
for (LLSD::array_iterator texture_iter = textures.beginArray();
|
|
texture_iter != textures.endArray();
|
|
++texture_iter)
|
|
{
|
|
addAsset((*texture_iter)["imageid"].asUUID(), LLAssetType::AT_TEXTURE);
|
|
}
|
|
}
|
|
|
|
if (prim.has("sculpt"))
|
|
{
|
|
addAsset(prim["sculpt"]["texture"].asUUID(), LLAssetType::AT_TEXTURE);
|
|
}
|
|
|
|
if (!prim.has("content"))
|
|
{
|
|
return;
|
|
}
|
|
|
|
LLSD& contentsd = prim["content"];
|
|
for (LLSD::array_iterator content_iter = contentsd.beginArray();
|
|
content_iter != contentsd.endArray();
|
|
++content_iter)
|
|
{
|
|
if (!mManifest["inventory"].has((*content_iter).asString()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
LLAssetType::EType asset_type = LLAssetType::lookup(mManifest["inventory"][(*content_iter).asString()]["type"].asString().c_str());
|
|
LLUUID asset_id = mManifest["inventory"][(*content_iter).asString()]["asset_id"].asUUID();
|
|
|
|
if (!mManifest["asset"].has(asset_id.asString()))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
addAsset(asset_id, asset_type);
|
|
std::vector<U8> buffer = mManifest["asset"][asset_id.asString()]["data"].asBinary();
|
|
|
|
switch(asset_type)
|
|
{
|
|
case LLAssetType::AT_CLOTHING:
|
|
case LLAssetType::AT_BODYPART:
|
|
{
|
|
std::string asset(buffer.begin(), buffer.end());
|
|
S32 position = asset.rfind("textures");
|
|
boost::regex pattern("[[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}");
|
|
boost::sregex_iterator m1(asset.begin() + position, asset.end(), pattern);
|
|
boost::sregex_iterator m2;
|
|
for( ; m1 != m2; ++m1)
|
|
{
|
|
LL_DEBUGS("export") << "Found wearable texture " << m1->str() << LL_ENDL;
|
|
if(LLUUID::validate(m1->str()))
|
|
{
|
|
addAsset(LLUUID(m1->str()), LLAssetType::AT_TEXTURE);
|
|
}
|
|
else
|
|
{
|
|
LL_DEBUGS("export") << "Invalied uuid: " << m1->str() << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_GESTURE:
|
|
{
|
|
buffer.push_back('\0');
|
|
LLMultiGesture* gesture = new LLMultiGesture();
|
|
LLDataPackerAsciiBuffer dp((char*)&buffer[0], (S32)buffer.size());
|
|
if (!gesture->deserialize(dp))
|
|
{
|
|
LL_WARNS("export") << "Unable to load gesture " << asset_id << LL_ENDL;
|
|
delete gesture;
|
|
gesture = NULL;
|
|
break;
|
|
}
|
|
|
|
S32 i;
|
|
S32 count = gesture->mSteps.size();
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
LLGestureStep* step = gesture->mSteps[i];
|
|
|
|
switch(step->getType())
|
|
{
|
|
case STEP_ANIMATION:
|
|
{
|
|
LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
|
|
addAsset(anim_step->mAnimAssetID, LLAssetType::AT_ANIMATION);
|
|
}
|
|
break;
|
|
case STEP_SOUND:
|
|
{
|
|
LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
|
|
addAsset(sound_step->mSoundAssetID, LLAssetType::AT_SOUND);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
delete gesture;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::addAsset(LLUUID asset_id, LLAssetType::EType asset_type)
|
|
{
|
|
if (!mManifest["asset"].has(asset_id.asString()))
|
|
{
|
|
LL_DEBUGS("import") << "Missing "<< asset_id.asString() << " asset data." << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
switch(asset_type)
|
|
{
|
|
case LLAssetType::AT_TEXTURE:
|
|
{
|
|
if (std::find(mTextureQueue.begin(), mTextureQueue.end(), asset_id) == mTextureQueue.end())
|
|
{
|
|
mTextureQueue.push_back(asset_id);
|
|
mTexturesTotal++;
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_SOUND:
|
|
{
|
|
if (std::find(mSoundQueue.begin(), mSoundQueue.end(), asset_id) == mSoundQueue.end())
|
|
{
|
|
mSoundQueue.push_back(asset_id);
|
|
mSoundsTotal++;
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_ANIMATION:
|
|
{
|
|
if (std::find(mAnimQueue.begin(), mAnimQueue.end(), asset_id) == mAnimQueue.end())
|
|
{
|
|
mAnimQueue.push_back(asset_id);
|
|
mAnimsTotal++;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
if (std::find(mAssetQueue.begin(), mAssetQueue.end(), asset_id) == mAssetQueue.end())
|
|
{
|
|
mAssetQueue.push_back(asset_id);
|
|
mAssetsTotal++;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::onClickBtnImport()
|
|
{
|
|
mPrimObjectMap.clear();
|
|
mLinkset = 0;
|
|
mObject = 0;
|
|
mPrim = 0;
|
|
mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
|
|
LLSelectMgr::getInstance()->deselectAll();
|
|
|
|
mStartPosition = gAgent.getPositionAgent();
|
|
LL_DEBUGS("import") << "gAgent position is " << mStartPosition << LL_ENDL;
|
|
LLVector3 offset;
|
|
offset.set(gSavedSettings.getVector3("FSImportBuildOffset"));
|
|
mStartPosition = mStartPosition + offset * gAgent.getQuat();
|
|
LL_DEBUGS("import") << "mStartPosition is " << mStartPosition << LL_ENDL;
|
|
|
|
// don't allow change during a long upload/import
|
|
getChild<LLButton>("import_btn")->setEnabled(FALSE);
|
|
getChild<LLCheckBoxCtrl>("do_not_attach")->setEnabled(FALSE);
|
|
getChild<LLCheckBoxCtrl>("region_position")->setEnabled(FALSE);
|
|
getChild<LLCheckBoxCtrl>("upload_asset")->setEnabled(FALSE);
|
|
getChild<LLCheckBoxCtrl>("temp_asset")->setEnabled(FALSE);
|
|
|
|
if (((mTexturesTotal + mSoundsTotal + mAnimsTotal + mAssetsTotal) != 0) && getChild<LLCheckBoxCtrl>("upload_asset")->get())
|
|
{
|
|
// do not pop up preview floaters when creating new inventory items.
|
|
gSavedSettings.setBOOL("ShowNewInventory", false);
|
|
|
|
if (!getChild<LLCheckBoxCtrl>("temp_asset")->get())
|
|
{
|
|
U32 expected_upload_cost = mTexturesTotal * (U32)LLGlobalEconomy::getInstance()->getPriceUpload();
|
|
if(!(can_afford_transaction(expected_upload_cost)))
|
|
{
|
|
LLStringUtil::format_map_t args;
|
|
args["AMOUNT"] = llformat("%d", expected_upload_cost);
|
|
LLBuyCurrencyHTML::openCurrencyFloater(LLTrans::getString("UploadingCosts", args), expected_upload_cost);
|
|
|
|
// re-enable the controls
|
|
getChild<LLButton>("import_btn")->setEnabled(TRUE);
|
|
getChild<LLCheckBoxCtrl>("do_not_attach")->setEnabled(TRUE);
|
|
getChild<LLCheckBoxCtrl>("region_position")->setEnabled(TRUE);
|
|
getChild<LLCheckBoxCtrl>("upload_asset")->setEnabled(TRUE);
|
|
getChild<LLCheckBoxCtrl>("temp_asset")->setEnabled(getChild<LLCheckBoxCtrl>("upload_asset")->get());
|
|
return;
|
|
}
|
|
}
|
|
if (!mTextureQueue.empty())
|
|
{
|
|
LLUIString status = getString("texture_uploading");
|
|
status.setArg("[TEXTURE]", llformat("%u", mTexturesTotal - (U32)mTextureQueue.size() + 1));
|
|
status.setArg("[TEXTURETOTAL]", llformat("%u", mTexturesTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mTextureQueue.front());
|
|
return;
|
|
}
|
|
if (!mSoundQueue.empty())
|
|
{
|
|
LLUIString status = getString("sound_uploading");
|
|
status.setArg("[SOUND]", llformat("%u", mSoundsTotal - (U32)mSoundQueue.size() + 1));
|
|
status.setArg("[SOUNDTOTAL]", llformat("%u", mSoundsTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mSoundQueue.front());
|
|
return;
|
|
}
|
|
if (!mAnimQueue.empty())
|
|
{
|
|
LLUIString status = getString("animation_uploading");
|
|
status.setArg("[ANIMATION]", llformat("%u", mAnimsTotal - (U32)mAnimQueue.size() + 1));
|
|
status.setArg("[ANIMATIONTOTAL]", llformat("%u", mAnimsTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mAnimQueue.front());
|
|
return;
|
|
}
|
|
if (!mAssetQueue.empty())
|
|
{
|
|
LLUIString status = getString("asset_uploading");
|
|
status.setArg("[ASSET]", llformat("%u", mAssetsTotal - (U32)mAssetQueue.size() + 1));
|
|
status.setArg("[ASSETTOTAL]", llformat("%u", mAssetsTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mAssetQueue.front());
|
|
return;
|
|
}
|
|
|
|
LL_WARNS("import") << "Nothing in queue, proceding to prim import." << LL_ENDL;
|
|
// restore setting to allow preview popups.
|
|
gSavedSettings.setBOOL("ShowNewInventory", mSavedSettingShowNewInventory);
|
|
importPrims();
|
|
}
|
|
else
|
|
{
|
|
importPrims();
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::onClickCheckBoxUploadAsset()
|
|
{
|
|
if (getChild<LLCheckBoxCtrl>("upload_asset")->get())
|
|
{
|
|
getChild<LLCheckBoxCtrl>("temp_asset")->setEnabled(TRUE);
|
|
LLUIString stats = getString("upload_cost");
|
|
stats.setArg("[COST]", llformat("%u", (mTexturesTotal + mSoundsTotal + mAnimsTotal) * (U32)LLGlobalEconomy::getInstance()->getPriceUpload()));
|
|
getChild<LLTextBox>("file_status_text")->setText(stats.getString());
|
|
}
|
|
else
|
|
{
|
|
getChild<LLCheckBoxCtrl>("temp_asset")->set(FALSE);
|
|
getChild<LLCheckBoxCtrl>("temp_asset")->setEnabled(FALSE);
|
|
std::string text;
|
|
getChild<LLTextBox>("file_status_text")->setText(text);
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::onClickCheckBoxTempAsset()
|
|
{
|
|
if (getChild<LLCheckBoxCtrl>("temp_asset")->get())
|
|
{
|
|
LLUIString stats = getString("upload_cost");
|
|
stats.setArg("[COST]", llformat("%u", 0));
|
|
getChild<LLTextBox>("file_status_text")->setText(stats.getString());
|
|
}
|
|
else
|
|
{
|
|
LLUIString stats = getString("upload_cost");
|
|
stats.setArg("[COST]", llformat("%u", (mTexturesTotal + mSoundsTotal + mAnimsTotal) * (U32)LLGlobalEconomy::getInstance()->getPriceUpload()));
|
|
getChild<LLTextBox>("file_status_text")->setText(stats.getString());
|
|
}
|
|
}
|
|
|
|
|
|
void FSFloaterImport::importPrims()
|
|
{
|
|
mObjectSize = 0;
|
|
LLSD& objectsd = mManifest["linkset"][mLinkset];
|
|
for (LLSD::array_iterator iter = objectsd.beginArray();
|
|
iter != objectsd.endArray();
|
|
++iter)
|
|
{
|
|
mObjectSize++;
|
|
}
|
|
LL_DEBUGS("import") << "Object size is " << mObjectSize << LL_ENDL;
|
|
if (mObjectSize > MAX_PRIMS_PER_OBJECT)
|
|
{
|
|
LL_WARNS("import") << "Object size is to large to link. " << mObjectSize << " is greater then max linking size of " << MAX_PRIMS_PER_OBJECT << LL_ENDL;
|
|
}
|
|
mRootPosition = mStartPosition;
|
|
LLUUID linkset_root_prim_uuid = mManifest["linkset"][0][0].asUUID();
|
|
LLSD& linkset_root_prim = mManifest["prim"][linkset_root_prim_uuid.asString()];
|
|
mLinksetPosition.setValue(linkset_root_prim["position"]);
|
|
mCreatingActive = true;
|
|
createPrim();
|
|
}
|
|
|
|
void FSFloaterImport::createPrim()
|
|
{
|
|
LLUIString status = getString("file_status_running");
|
|
status.setArg("[LINKSET]", llformat("%u", mLinkset + 1));
|
|
status.setArg("[LINKSETS]", llformat("%u", mLinksetSize));
|
|
status.setArg("[PRIM]", llformat("%u", mObject + 1));
|
|
status.setArg("[PRIMS]", llformat("%u", mObjectSize));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
|
|
LLUUID prim_uuid = mManifest["linkset"][mLinkset][mObject].asUUID();
|
|
LL_DEBUGS("import") << "Creating prim from " << prim_uuid.asString() << LL_ENDL;
|
|
LLSD& prim = mManifest["prim"][prim_uuid.asString()];
|
|
|
|
gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgentID);
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgentSessionID);
|
|
gMessageSystem->addUUIDFast(_PREHASH_GroupID, FSCommon::getGroupForRezzing());
|
|
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU8Fast(_PREHASH_Material, (U8)prim["material"].asInteger());
|
|
|
|
U32 flags = ll_U32_from_sd(prim["flags"]);
|
|
flags |= FLAGS_CREATE_SELECTED;
|
|
gMessageSystem->addU32Fast(_PREHASH_AddFlags, flags);
|
|
|
|
LLVolumeParams volume_params;
|
|
volume_params.getPathParams().fromLLSD(prim["volume"]["path"]);
|
|
volume_params.getProfileParams().fromLLSD(prim["volume"]["profile"]);
|
|
LLVolumeMessage::packVolumeParams(&volume_params, gMessageSystem);
|
|
|
|
gMessageSystem->addU8Fast(_PREHASH_PCode, LL_PCODE_VOLUME);
|
|
|
|
LLVector3 scale;
|
|
scale.setValue(prim["scale"]);
|
|
LL_DEBUGS("import") << "Creating prim scale of " << scale << LL_ENDL;
|
|
gMessageSystem->addVector3Fast(_PREHASH_Scale, scale );
|
|
|
|
LLQuaternion rotation = ll_quaternion_from_sd(prim["rotation"]);
|
|
if (mObject != 0)
|
|
{
|
|
rotation = rotation * mRootRotation;
|
|
}
|
|
else
|
|
{
|
|
mRootRotation = rotation;
|
|
}
|
|
gMessageSystem->addQuatFast(_PREHASH_Rotation, rotation);
|
|
|
|
LLVector3 position;
|
|
LLVector3 prim_position;
|
|
prim_position.setValue(prim["position"]);
|
|
if (mObject != 0)
|
|
{
|
|
position = (prim_position * mRootRotation) + mRootPosition;
|
|
}
|
|
else
|
|
{
|
|
position = mRootPosition;
|
|
}
|
|
|
|
if (mObjectCreatedCallback.connected())
|
|
{
|
|
mObjectCreatedCallback.disconnect();
|
|
}
|
|
mObjectCreatedCallback = gObjectList.setNewObjectCallback(boost::bind(&FSFloaterImport::processPrimCreated, this, _1));
|
|
|
|
LL_DEBUGS("import") << "Creating prim at position " << position << LL_ENDL;
|
|
gMessageSystem->addVector3Fast(_PREHASH_RayStart, position);
|
|
gMessageSystem->addVector3Fast(_PREHASH_RayEnd, position);
|
|
|
|
gMessageSystem->addU8Fast(_PREHASH_BypassRaycast, (U8)TRUE);
|
|
gMessageSystem->addU8Fast(_PREHASH_RayEndIsIntersection, (U8)FALSE);
|
|
gMessageSystem->addU8Fast(_PREHASH_State, (U8)0);
|
|
gMessageSystem->addUUIDFast(_PREHASH_RayTargetID, LLUUID::null);
|
|
gMessageSystem->sendReliable(gAgent.getRegion()->getHost());
|
|
LLTrace::add(LLStatViewer::OBJECT_CREATE,1);
|
|
}
|
|
|
|
bool FSFloaterImport::processPrimCreated(LLViewerObject* object)
|
|
{
|
|
if (!(mInstance && mCreatingActive))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
LLSelectMgr::getInstance()->selectObjectAndFamily(object, TRUE);
|
|
|
|
LLUUID prim_uuid = mManifest["linkset"][mLinkset][mObject].asUUID();
|
|
LLSD& prim = mManifest["prim"][prim_uuid.asString()];
|
|
LL_DEBUGS("import") << "Processing prim " << prim_uuid.asString() << " for object " << object->getID().asString() << LL_ENDL;
|
|
mPrimObjectMap[prim_uuid] = object->getID();
|
|
U32 object_local_id = object->getLocalID();
|
|
|
|
// due to raycasting prim placement errors, send prim position update that is more accurite.
|
|
LLVector3 position;
|
|
LLVector3 prim_position(prim["position"]);
|
|
if (mObject != 0)
|
|
{
|
|
position = (prim_position * mRootRotation) + mRootPosition;
|
|
}
|
|
else
|
|
{
|
|
position = mRootPosition;
|
|
}
|
|
LL_DEBUGS("import") << "Setting prim at position " << position << LL_ENDL;
|
|
setPrimPosition(UPD_POSITION, object, position);
|
|
|
|
#if (0) // reserved for possiable future bugfix should rot and scale not be accurite from prim creation.
|
|
|
|
LLQuaternion rotation = ll_quaternion_from_sd(prim["rotation"]);
|
|
if (mObject != 0)
|
|
{
|
|
rotation = rotation * mRootRotation;
|
|
}
|
|
|
|
LLVector3 scale(prim["scale"]);
|
|
LL_DEBUGS("import") << "Setting prim scale of " << scale << LL_ENDL;
|
|
|
|
setPrimPosition(UPD_POSITION|UPD_ROTATION|UPD_SCALE, object, position, rotation, scale);
|
|
#endif
|
|
|
|
S32 texture_count = (S32)object->getNumTEs();
|
|
for(S32 face = 0; face < texture_count; face++)
|
|
{
|
|
|
|
LLTextureEntry texture_entry;
|
|
if (texture_entry.fromLLSD(prim["texture"][face]))
|
|
{
|
|
LL_DEBUGS("import") << "Setting face " << face << " with texture " << prim["texture"][face]["imageid"].asUUID().asString() << LL_ENDL;
|
|
|
|
if (mAssetMap[texture_entry.getID()].notNull())
|
|
{
|
|
texture_entry.setID(mAssetMap[texture_entry.getID()]);
|
|
LL_DEBUGS("import") << "Replaced " << prim["texture"][face]["imageid"].asUUID().asString() << " with " << texture_entry.getID().asString() << LL_ENDL;
|
|
}
|
|
|
|
object->setTE((U8)face, texture_entry);
|
|
}
|
|
}
|
|
object->sendTEUpdate();
|
|
|
|
// [FS:CR] Materials
|
|
if(prim.has("materials"))
|
|
{
|
|
U8 te = 0;
|
|
LLSD materials = prim["materials"];
|
|
for (LLSD::array_iterator m_itr = materials.beginArray() ;
|
|
m_itr != materials.endArray() ;
|
|
++m_itr)
|
|
{
|
|
LL_DEBUGS("import") << "Setting materials" << LL_ENDL;
|
|
LLMaterial* mat = new LLMaterial();
|
|
mat->fromLLSD(*m_itr);
|
|
object->setTEMaterialParams(te, mat);
|
|
++te;
|
|
}
|
|
}
|
|
|
|
if (prim.has("sculpt"))
|
|
{
|
|
LL_DEBUGS("import") << "Found sculpt for " << prim_uuid.asString() << LL_ENDL;
|
|
LLSculptParams sculpt_params;
|
|
sculpt_params.fromLLSD(prim["sculpt"]);
|
|
LL_DEBUGS("import") << "Setting sculpt to " << prim["sculpt"]["texture"].asUUID().asString() << LL_ENDL;
|
|
|
|
if (mAssetMap[sculpt_params.getSculptTexture()].notNull())
|
|
{
|
|
sculpt_params.setSculptTexture(mAssetMap[sculpt_params.getSculptTexture()], sculpt_params.getSculptType());
|
|
LL_DEBUGS("import") << "Replaced " << prim["sculpt"]["texture"].asUUID().asString() << " with " << sculpt_params.getSculptTexture().asString() << LL_ENDL;
|
|
}
|
|
|
|
object->setParameterEntry(LLNetworkData::PARAMS_SCULPT, sculpt_params, true); // sets locally and fires off an update to the region.
|
|
}
|
|
|
|
if (prim.has("flexible"))
|
|
{
|
|
LL_DEBUGS("import") << "Found flexiable for " << prim_uuid.asString() << LL_ENDL;
|
|
LLFlexibleObjectData attributes;
|
|
attributes.fromLLSD(prim["flexible"]);
|
|
object->setParameterEntry(LLNetworkData::PARAMS_FLEXIBLE, attributes, true);
|
|
}
|
|
|
|
if (prim.has("light"))
|
|
{
|
|
LL_DEBUGS("import") << "Found light for " << prim_uuid.asString() << LL_ENDL;
|
|
LLLightParams light_param_block;
|
|
light_param_block.fromLLSD(prim["light"]);
|
|
object->setParameterEntry(LLNetworkData::PARAMS_LIGHT, light_param_block, true);
|
|
}
|
|
|
|
if (prim.has("light_texture"))
|
|
{
|
|
LL_DEBUGS("import") << "Found light_texture for " << prim_uuid.asString() << LL_ENDL;
|
|
LLLightImageParams new_light_image_param_block;
|
|
new_light_image_param_block.fromLLSD(prim["light_texture"]);
|
|
object->setParameterEntry(LLNetworkData::PARAMS_LIGHT_IMAGE, new_light_image_param_block, true);
|
|
}
|
|
|
|
if (prim.has("clickaction"))
|
|
{
|
|
LL_DEBUGS("import") << "Setting clickaction on " << prim_uuid.asString() << " to " << prim["clickaction"].asInteger() << LL_ENDL;
|
|
gMessageSystem->newMessageFast(_PREHASH_ObjectClickAction);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID() );
|
|
gMessageSystem->addU8("ClickAction", (U8)prim["clickaction"].asInteger());
|
|
gMessageSystem->sendReliable(object->getRegion()->getHost());
|
|
}
|
|
|
|
std::string prim_name;
|
|
if (prim.has("name"))
|
|
{
|
|
prim_name = prim["name"].asString();
|
|
LL_DEBUGS("import") << "Setting name on " << prim_uuid.asString() << " to " << prim_name << LL_ENDL;
|
|
gMessageSystem->newMessageFast(_PREHASH_ObjectName);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_LocalID, object_local_id);
|
|
gMessageSystem->addStringFast(_PREHASH_Name, prim_name);
|
|
gMessageSystem->sendReliable(object->getRegion()->getHost());
|
|
}
|
|
|
|
if (prim.has("description"))
|
|
{
|
|
LL_DEBUGS("import") << "Setting description on " << prim_uuid.asString() << " to " << prim["description"].asString() << LL_ENDL;
|
|
gMessageSystem->newMessageFast(_PREHASH_ObjectDescription);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_LocalID, object_local_id);
|
|
gMessageSystem->addStringFast(_PREHASH_Description, prim["description"].asString());
|
|
gMessageSystem->sendReliable(object->getRegion()->getHost());
|
|
}
|
|
|
|
if (prim.has("group_mask") || prim.has("everyone_mask") || prim.has("next_owner_mask"))
|
|
{
|
|
// can only set one permission bit at a time.
|
|
LL_DEBUGS("import") << "Setting permissions on " << prim_uuid.asString() << LL_ENDL;
|
|
gMessageSystem->newMessageFast(_PREHASH_ObjectPermissions);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
gMessageSystem->nextBlockFast(_PREHASH_HeaderData);
|
|
gMessageSystem->addBOOLFast(_PREHASH_Override, (BOOL)FALSE);
|
|
|
|
if (prim.has("group_mask"))
|
|
{
|
|
U32 group_mask = ll_U32_from_sd(prim["group_mask"]);
|
|
LL_DEBUGS("import") << "Setting group mask to " << group_mask << LL_ENDL;
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object_local_id);
|
|
gMessageSystem->addU8Fast(_PREHASH_Field, PERM_GROUP);
|
|
gMessageSystem->addBOOLFast(_PREHASH_Set, (BOOL)(group_mask & PERM_MODIFY) ? TRUE : FALSE);
|
|
gMessageSystem->addU32Fast(_PREHASH_Mask, PERM_MODIFY | PERM_MOVE | PERM_COPY);
|
|
}
|
|
if (prim.has("everyone_mask"))
|
|
{
|
|
U32 everyone_mask = ll_U32_from_sd(prim["everyone_mask"]);
|
|
LL_DEBUGS("import") << "Setting everyone mask to " << everyone_mask << LL_ENDL;
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object_local_id);
|
|
gMessageSystem->addU8Fast(_PREHASH_Field, PERM_EVERYONE);
|
|
gMessageSystem->addBOOLFast(_PREHASH_Set, (BOOL)(everyone_mask & PERM_MOVE) ? TRUE : FALSE);
|
|
gMessageSystem->addU32Fast(_PREHASH_Mask, PERM_MOVE);
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object_local_id);
|
|
gMessageSystem->addU8Fast(_PREHASH_Field, PERM_EVERYONE);
|
|
gMessageSystem->addBOOLFast(_PREHASH_Set, (BOOL)(everyone_mask & PERM_COPY) ? TRUE : FALSE);
|
|
gMessageSystem->addU32Fast(_PREHASH_Mask, PERM_COPY);
|
|
}
|
|
if (prim.has("next_owner_mask"))
|
|
{
|
|
U32 next_owner_mask = ll_U32_from_sd(prim["next_owner_mask"]);
|
|
LL_DEBUGS("import") << "Setting next owner mask to " << next_owner_mask << LL_ENDL;
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object_local_id);
|
|
gMessageSystem->addU8Fast(_PREHASH_Field, PERM_NEXT_OWNER);
|
|
gMessageSystem->addBOOLFast(_PREHASH_Set, (BOOL)(next_owner_mask & PERM_MODIFY) ? TRUE : FALSE);
|
|
gMessageSystem->addU32Fast(_PREHASH_Mask, PERM_MODIFY);
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object_local_id);
|
|
gMessageSystem->addU8Fast(_PREHASH_Field, PERM_NEXT_OWNER);
|
|
gMessageSystem->addBOOLFast(_PREHASH_Set, (BOOL)(next_owner_mask & PERM_COPY) ? TRUE : FALSE);
|
|
gMessageSystem->addU32Fast(_PREHASH_Mask, PERM_COPY);
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object_local_id);
|
|
gMessageSystem->addU8Fast(_PREHASH_Field, PERM_NEXT_OWNER);
|
|
gMessageSystem->addBOOLFast(_PREHASH_Set, (BOOL)(next_owner_mask & PERM_TRANSFER) ? TRUE : FALSE);
|
|
gMessageSystem->addU32Fast(_PREHASH_Mask, PERM_TRANSFER);
|
|
}
|
|
|
|
gMessageSystem->sendReliable(object->getRegion()->getHost());
|
|
|
|
}
|
|
|
|
if (prim.has("sale_info"))
|
|
{
|
|
LLSaleInfo sale_info;
|
|
BOOL has_perm_mask;
|
|
U32 perm_mask;
|
|
sale_info.fromLLSD(prim["sale_info"], has_perm_mask, perm_mask);
|
|
if (sale_info.isForSale())
|
|
{
|
|
LL_DEBUGS("import") << "Setting sale info on " << prim_uuid.asString() << LL_ENDL;
|
|
gMessageSystem->newMessageFast(_PREHASH_ObjectSaleInfo);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_LocalID, object->getLocalID());
|
|
sale_info.packMessage(gMessageSystem);
|
|
gMessageSystem->sendReliable(object->getRegion()->getHost());
|
|
}
|
|
}
|
|
|
|
if (prim.has("ExtraPhysics"))
|
|
{
|
|
LLSD sim_features;
|
|
object->getRegion()->getSimulatorFeatures(sim_features);
|
|
if (sim_features.has("PhysicsShapeTypes"))
|
|
{
|
|
LL_DEBUGS("import") << "Setting physics on " << prim_uuid.asString() << LL_ENDL;
|
|
LLSD& extra_physics = prim["ExtraPhysics"];
|
|
|
|
U8 type = (U8)extra_physics["PhysicsShapeType"].asInteger();
|
|
F32 density = (F32)extra_physics["Density"].asReal();
|
|
F32 friction = (F32)extra_physics["Friction"].asReal();
|
|
F32 restitution = (F32)extra_physics["Restitution"].asReal();
|
|
F32 gravity = (F32)extra_physics["GravityMultiplier"].asReal();
|
|
|
|
object->setPhysicsShapeType(type);
|
|
object->setPhysicsGravity(gravity);
|
|
object->setPhysicsFriction(friction);
|
|
object->setPhysicsDensity(density);
|
|
object->setPhysicsRestitution(restitution);
|
|
object->updateFlags(TRUE);
|
|
}
|
|
}
|
|
|
|
mInventoryQueue.clear();
|
|
if (prim.has("content"))
|
|
{
|
|
LLSD& contentsd = prim["content"];
|
|
for (LLSD::array_iterator content_iter = contentsd.beginArray();
|
|
content_iter != contentsd.endArray();
|
|
++content_iter)
|
|
{
|
|
if (!mManifest["inventory"].has((*content_iter).asString()))
|
|
{
|
|
LL_WARNS("import") << "Inventory content " << (*content_iter) << " was not found in import file." << LL_ENDL;
|
|
continue;
|
|
}
|
|
|
|
LLSD& item_sd = mManifest["inventory"][(*content_iter).asString()];
|
|
LLUUID asset_id = item_sd["asset_id"].asUUID();
|
|
|
|
if (asset_id.isNull())
|
|
{
|
|
LL_WARNS("import") << "Item " << item_sd["desc"].asString() << " " << (*content_iter) << " had NULL asset ID." << LL_ENDL;
|
|
continue;
|
|
}
|
|
|
|
if (mAssetMap[asset_id].isNull())
|
|
{
|
|
// asset was not uploaded, search inventory using asset_id
|
|
searchInventory(asset_id, object, prim_name);
|
|
continue;
|
|
}
|
|
|
|
LLUUID new_asset_id = mAssetMap[asset_id];
|
|
if (mAssetItemMap[new_asset_id].isNull())
|
|
{
|
|
// no item was created for asset, search inventory using new_asset_id
|
|
searchInventory(new_asset_id, object, prim_name);
|
|
continue;
|
|
}
|
|
|
|
LLUUID item_id = mAssetItemMap[new_asset_id];
|
|
LLViewerInventoryItem* item = gInventory.getItem(item_id);
|
|
if (!item)
|
|
{
|
|
// else item was not found, search inventory using new_asset id
|
|
searchInventory(new_asset_id, object, prim_name);
|
|
continue;
|
|
}
|
|
|
|
FSInventoryQueue item_queue;
|
|
item_queue.item = item;
|
|
item_queue.object = object;
|
|
item_queue.prim_name = prim_name;
|
|
mInventoryQueue.push_back(item_queue);
|
|
}
|
|
}
|
|
|
|
if (mInventoryQueue.size() < 20)
|
|
{
|
|
mThrottleTime = 0.25f;
|
|
}
|
|
else
|
|
{
|
|
mThrottleTime = 0.5f;
|
|
}
|
|
|
|
mImportState = INVENTORY_TRANSFER;
|
|
mWaitTimer.start();
|
|
|
|
return true;
|
|
}
|
|
|
|
void FSFloaterImport::searchInventory(LLUUID asset_id, LLViewerObject* object, std::string prim_name)
|
|
{
|
|
LLViewerInventoryCategory::cat_array_t cats;
|
|
LLViewerInventoryItem::item_array_t items;
|
|
LLAssetIDMatches asset_id_matches(asset_id);
|
|
gInventory.collectDescendentsIf(LLUUID::null,
|
|
cats,
|
|
items,
|
|
LLInventoryModel::INCLUDE_TRASH,
|
|
asset_id_matches);
|
|
|
|
if (items.size())
|
|
{
|
|
LLViewerInventoryItem* item = items.at(0);
|
|
|
|
FSInventoryQueue item_queue;
|
|
item_queue.item = item;
|
|
item_queue.object = object;
|
|
item_queue.prim_name = prim_name;
|
|
mInventoryQueue.push_back(item_queue);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Asset " << asset_id << " was not found in inventory. Asset not added to object." << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::postLink()
|
|
{
|
|
if (!mCreatingActive)
|
|
{
|
|
LL_WARNS("import") << "Post link called without being active." << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
LLUUID root_prim_uuid = mManifest["linkset"][mLinkset][0].asUUID();
|
|
LLSD& root_prim = mManifest["prim"][root_prim_uuid.asString()];
|
|
if (root_prim.has("attachment_point") && !getChild<LLCheckBoxCtrl>("do_not_attach")->get())
|
|
{
|
|
LL_DEBUGS("import") << "Attaching to " << root_prim["attachment_point"].asInteger() << LL_ENDL;
|
|
LLSelectMgr::getInstance()->sendAttach((U8)root_prim["attachment_point"].asInteger(), false);
|
|
|
|
LLViewerObject* root_object = gObjectList.findObject(mPrimObjectMap[root_prim_uuid]);
|
|
|
|
setPrimPosition(UPD_POSITION|UPD_LINKED_SETS, root_object, LLVector3(root_prim["position"]));
|
|
}
|
|
|
|
if (getChild<LLCheckBoxCtrl>("region_position")->get())
|
|
{
|
|
if (root_prim.has("attachment_point"))
|
|
{
|
|
LL_DEBUGS("import") << "Object is an attachment, can not retore to region position." << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
LLViewerObject* root_object = gObjectList.findObject(mPrimObjectMap[root_prim_uuid]);
|
|
|
|
setPrimPosition(UPD_POSITION|UPD_LINKED_SETS, root_object, LLVector3(root_prim["position"]));
|
|
}
|
|
}
|
|
|
|
LLSelectMgr::getInstance()->deselectAll();
|
|
|
|
if ((mLinkset + 1) >= mLinksetSize)
|
|
{
|
|
// all done
|
|
mCreatingActive = false;
|
|
LL_DEBUGS("import") << "Finished with " << mLinkset << " linksets and " << mObject << " prims in last linkset" << LL_ENDL;
|
|
mObjectSelection = NULL;
|
|
getChild<LLTextBox>("file_status_text")->setText(getString("file_status_done"));
|
|
}
|
|
else
|
|
{
|
|
mObject = 0;
|
|
mLinkset++;
|
|
|
|
mObjectSize = 0;
|
|
LLSD& objectsd = mManifest["linkset"][mLinkset];
|
|
for (
|
|
LLSD::array_iterator iter = objectsd.beginArray();
|
|
iter != objectsd.endArray();
|
|
++iter)
|
|
{
|
|
mObjectSize++;
|
|
}
|
|
LL_DEBUGS("import") << "Next linkset Object size is " << mObjectSize << LL_ENDL;
|
|
|
|
LLUUID root_prim_uuid = mManifest["linkset"][mLinkset][0].asUUID();
|
|
LLSD& root_prim = mManifest["prim"][root_prim_uuid.asString()];
|
|
LLVector3 root_prim_location(root_prim["position"]);
|
|
mRootPosition = mStartPosition + (root_prim_location - mLinksetPosition);
|
|
createPrim();
|
|
}
|
|
}
|
|
|
|
void FSFloaterImport::setPrimPosition(U8 type, LLViewerObject* object, LLVector3 position, LLQuaternion rotation, LLVector3 scale)
|
|
{
|
|
gMessageSystem->newMessage(_PREHASH_MultipleObjectUpdate);
|
|
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
|
|
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
|
|
gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
|
|
gMessageSystem->addU8Fast(_PREHASH_Type, type);
|
|
U8 data[256];
|
|
S32 offset = 0;
|
|
|
|
if (type & UPD_POSITION)
|
|
{
|
|
htonmemcpy(&data[offset], &(position.mV), MVT_LLVector3, 12);
|
|
offset += 12;
|
|
}
|
|
if (type & UPD_ROTATION)
|
|
{
|
|
LLVector3 vec = rotation.packToVector3();
|
|
htonmemcpy(&data[offset], &(vec.mV), MVT_LLQuaternion, 12);
|
|
offset += 12;
|
|
}
|
|
if (type & UPD_SCALE)
|
|
{
|
|
htonmemcpy(&data[offset], &(scale.mV), MVT_LLVector3, 12);
|
|
offset += 12;
|
|
}
|
|
gMessageSystem->addBinaryDataFast(_PREHASH_Data, data, offset);
|
|
gMessageSystem->sendReliable(object->getRegion()->getHost());
|
|
}
|
|
|
|
void FSFloaterImport::uploadAsset(LLUUID asset_id, LLUUID inventory_item)
|
|
{
|
|
bool temporary = false;
|
|
std::vector<U8> asset_data = mManifest["asset"][asset_id.asString()]["data"].asBinary();
|
|
std::string name = mManifest["asset"][asset_id.asString()]["name"].asString();
|
|
std::string description = mManifest["asset"][asset_id.asString()]["description"].asString();
|
|
LLAssetType::EType asset_type = LLAssetType::lookup(mManifest["asset"][asset_id.asString()]["type"].asString().c_str());
|
|
std::string url;
|
|
LLSD body = LLSD::emptyMap();
|
|
LLFolderType::EType folder_type = LLFolderType::assetTypeToFolderType(asset_type);
|
|
LLUUID folder_id = gInventory.findCategoryUUIDForType(folder_type);
|
|
LLInventoryType::EType inventory_type = LLInventoryType::defaultForAssetType(asset_type);
|
|
bool new_file_agent_inventory = false;
|
|
LLWearableType::EType wearable_type = NOT_WEARABLE;
|
|
std::string perms_prefix = "";
|
|
|
|
if (name.empty())
|
|
{
|
|
name = llformat("Uploaded %s %s", LLAssetType::lookupHumanReadable(asset_type), asset_id.asString().c_str());
|
|
}
|
|
|
|
switch(asset_type)
|
|
{
|
|
case LLAssetType::AT_TEXTURE:
|
|
{
|
|
perms_prefix = "Uploads";
|
|
temporary = getChild<LLCheckBoxCtrl>("temp_asset")->get();
|
|
if (temporary)
|
|
{
|
|
url = gAgent.getRegionCapability("UploadBakedTexture");
|
|
}
|
|
else
|
|
{
|
|
url = gAgent.getRegionCapability("NewFileAgentInventory");
|
|
new_file_agent_inventory = true;
|
|
}
|
|
LLTrace::add(LLStatViewer::UPLOAD_TEXTURE,1);
|
|
}
|
|
break;
|
|
case LLAssetType::AT_SOUND:
|
|
{
|
|
perms_prefix = "Uploads";
|
|
temporary = getChild<LLCheckBoxCtrl>("temp_asset")->get();
|
|
if (temporary)
|
|
{
|
|
// skip upload due to no temp support for sound
|
|
pushNextAsset(LLUUID::null, asset_id, asset_type);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
url = gAgent.getRegionCapability("NewFileAgentInventory");
|
|
new_file_agent_inventory = true;
|
|
LLTrace::add(LLStatViewer::UPLOAD_SOUND,1);
|
|
}
|
|
|
|
}
|
|
break;
|
|
case LLAssetType::AT_CLOTHING:
|
|
case LLAssetType::AT_BODYPART:
|
|
{
|
|
perms_prefix = "Wearables";
|
|
std::string asset(asset_data.begin(), asset_data.end());
|
|
|
|
S32 position = asset.rfind("type");
|
|
S32 end = asset.find("\n", position);
|
|
wearable_type = (LLWearableType::EType)boost::lexical_cast<S32>(asset.substr(position + 5, (end - (position + 5))));
|
|
|
|
if (getChild<LLCheckBoxCtrl>("temp_asset")->get())
|
|
{
|
|
// wearables don't support using temp textures.
|
|
break;
|
|
}
|
|
|
|
position = asset.rfind("textures");
|
|
boost::regex pattern("[[:xdigit:]]{8}(-[[:xdigit:]]{4}){3}-[[:xdigit:]]{12}");
|
|
boost::sregex_iterator m1(asset.begin() + position, asset.end(), pattern);
|
|
boost::sregex_iterator m2;
|
|
bool replace = false;
|
|
for( ; m1 != m2; ++m1)
|
|
{
|
|
LL_DEBUGS("export") << "Found wearable texture " << m1->str() << LL_ENDL;
|
|
if(LLUUID::validate(m1->str()))
|
|
{
|
|
LLUUID texture_id = LLUUID(m1->str());
|
|
if (mAssetMap[texture_id].notNull())
|
|
{
|
|
asset.replace(m1->position(), m1->length(), mAssetMap[texture_id].asString());
|
|
replace = true;
|
|
LL_DEBUGS("export") << "Replaced wearable texture " << m1->str() << " with " << mAssetMap[texture_id].asString() << LL_ENDL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LL_DEBUGS("export") << "Invalied uuid: " << m1->str() << LL_ENDL;
|
|
}
|
|
}
|
|
if (replace)
|
|
{
|
|
std::copy(asset.begin(), asset.end(), asset_data.begin());
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_NOTECARD:
|
|
{
|
|
perms_prefix = "Notecards";
|
|
if (inventory_item.isNull())
|
|
{
|
|
// create inventory item first
|
|
FSResourceData* ci_data = new FSResourceData;
|
|
ci_data->uuid = asset_id;
|
|
ci_data->mFloater = this;
|
|
ci_data->asset_type = asset_type;
|
|
ci_data->post_asset_upload = false;
|
|
LLPointer<LLInventoryCallback> cb = new FSCreateItemCallback(ci_data);
|
|
create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
|
|
folder_id, LLTransactionID::tnull, name, description, asset_type, inventory_type,
|
|
NOT_WEARABLE, PERM_ALL, cb);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
url = gAgent.getRegionCapability("UpdateNotecardAgentInventory");
|
|
body["item_id"] = inventory_item;
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_LSL_TEXT:
|
|
{
|
|
perms_prefix = "Scripts";
|
|
if (inventory_item.isNull())
|
|
{
|
|
// create inventory item first
|
|
FSResourceData* ci_data = new FSResourceData;
|
|
ci_data->uuid = asset_id;
|
|
ci_data->mFloater = this;
|
|
ci_data->asset_type = asset_type;
|
|
ci_data->post_asset_upload = false;
|
|
LLPointer<LLInventoryCallback> cb = new FSCreateItemCallback(ci_data);
|
|
create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
|
|
folder_id, LLTransactionID::tnull, name, description, asset_type, inventory_type,
|
|
NOT_WEARABLE, PERM_MOVE | PERM_TRANSFER, cb);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
url = gAgent.getRegionCapability("UpdateScriptAgent");
|
|
body["item_id"] = inventory_item;
|
|
if (gSavedSettings.getBOOL("FSSaveInventoryScriptsAsMono"))
|
|
{
|
|
body["target"] = "mono";
|
|
}
|
|
else
|
|
{
|
|
body["target"] = "lsl2";
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_ANIMATION:
|
|
{
|
|
perms_prefix = "Uploads";
|
|
temporary = getChild<LLCheckBoxCtrl>("temp_asset")->get();
|
|
if (temporary)
|
|
{
|
|
// no temp support, skip
|
|
pushNextAsset(LLUUID::null, asset_id, asset_type);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
url = gAgent.getRegionCapability("NewFileAgentInventory");
|
|
new_file_agent_inventory = true;
|
|
LLTrace::add(LLStatViewer::ANIMATION_UPLOADS,1);
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_GESTURE:
|
|
{
|
|
perms_prefix = "Gestures";
|
|
if (inventory_item.isNull())
|
|
{
|
|
// create inventory item first
|
|
FSResourceData* ci_data = new FSResourceData;
|
|
ci_data->uuid = asset_id;
|
|
ci_data->mFloater = this;
|
|
ci_data->asset_type = asset_type;
|
|
ci_data->post_asset_upload = false;
|
|
LLPointer<LLInventoryCallback> cb = new FSCreateItemCallback(ci_data);
|
|
create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
|
|
folder_id, LLTransactionID::tnull, name, description, asset_type, inventory_type,
|
|
NOT_WEARABLE, PERM_ALL, cb);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
url = gAgent.getRegionCapability("UpdateGestureAgentInventory");
|
|
body["item_id"] = inventory_item;
|
|
asset_data.push_back('\0');
|
|
LLMultiGesture* gesture = new LLMultiGesture();
|
|
LLDataPackerAsciiBuffer dp((char*)&asset_data[0], (S32)asset_data.size());
|
|
if (!gesture->deserialize(dp))
|
|
{
|
|
LL_WARNS("export") << "Unable to load gesture " << asset_id << LL_ENDL;
|
|
delete gesture;
|
|
break;
|
|
}
|
|
|
|
S32 i;
|
|
S32 count = gesture->mSteps.size();
|
|
bool replace = false;
|
|
for (i = 0; i < count; ++i)
|
|
{
|
|
LLGestureStep* step = gesture->mSteps[i];
|
|
|
|
switch(step->getType())
|
|
{
|
|
case STEP_ANIMATION:
|
|
{
|
|
LLGestureStepAnimation* anim_step = (LLGestureStepAnimation*)step;
|
|
if (mAssetMap[anim_step->mAnimAssetID].notNull())
|
|
{
|
|
LL_DEBUGS("export") << "Replaced animation " << anim_step->mAnimAssetID.asString() << " with " << mAssetMap[anim_step->mAnimAssetID].asString() << LL_ENDL;
|
|
anim_step->mAnimAssetID = mAssetMap[anim_step->mAnimAssetID];
|
|
replace = true;
|
|
}
|
|
}
|
|
break;
|
|
case STEP_SOUND:
|
|
{
|
|
LLGestureStepSound* sound_step = (LLGestureStepSound*)step;
|
|
if (mAssetMap[sound_step->mSoundAssetID].notNull())
|
|
{
|
|
LL_DEBUGS("export") << "Replaced sound " << sound_step->mSoundAssetID.asString() << " with " << mAssetMap[sound_step->mSoundAssetID].asString() << LL_ENDL;
|
|
sound_step->mSoundAssetID = mAssetMap[sound_step->mSoundAssetID];
|
|
replace = true;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
if (replace)
|
|
{
|
|
S32 max_size = gesture->getMaxSerialSize();
|
|
char* buffer = new char[max_size];
|
|
LLDataPackerAsciiBuffer dp(buffer, max_size);
|
|
if (!gesture->serialize(dp))
|
|
{
|
|
LL_WARNS("export") << "Unable to serialize gesture " << asset_id << LL_ENDL;
|
|
delete[] buffer;
|
|
delete gesture;
|
|
break;
|
|
}
|
|
S32 size = dp.getCurrentSize();
|
|
asset_data.assign(buffer, buffer + size);
|
|
delete[] buffer;
|
|
}
|
|
delete gesture;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
url = gAgent.getRegionCapability("NewFileAgentInventory");
|
|
new_file_agent_inventory = true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
LLTransactionID tid;
|
|
tid.generate();
|
|
LLAssetID new_asset_id = tid.makeAssetID(gAgent.getSecureSessionID());
|
|
|
|
LLVFile::writeFile((U8*)&asset_data[0], (S32)asset_data.size(), gVFS, new_asset_id, asset_type);
|
|
|
|
LLResourceData* data( new LLResourceData );
|
|
data->mAssetInfo.mTransactionID = tid;
|
|
data->mAssetInfo.mUuid = new_asset_id;
|
|
data->mAssetInfo.mType = asset_type;
|
|
data->mAssetInfo.mCreatorID = gAgentID;
|
|
data->mInventoryType = inventory_type;
|
|
data->mNextOwnerPerm = LLFloaterPerms::getNextOwnerPerms(perms_prefix);
|
|
data->mExpectedUploadCost = LLGlobalEconomy::getInstance()->getPriceUpload();
|
|
FSResourceData* fs_data = new FSResourceData;
|
|
fs_data->uuid = asset_id;
|
|
fs_data->mFloater = this;
|
|
fs_data->temporary = temporary;
|
|
fs_data->inventory_item = inventory_item;
|
|
fs_data->wearable_type = wearable_type;
|
|
fs_data->asset_type = asset_type;
|
|
data->mUserData = fs_data;
|
|
data->mAssetInfo.setName(name);
|
|
data->mAssetInfo.setDescription(description);
|
|
data->mPreferredLocation = folder_type;
|
|
|
|
if(!url.empty())
|
|
{
|
|
if (new_file_agent_inventory)
|
|
{
|
|
body["folder_id"] = folder_id;
|
|
body["asset_type"] = LLAssetType::lookup(asset_type);
|
|
body["inventory_type"] = LLInventoryType::lookup(inventory_type);
|
|
body["name"] = name;
|
|
body["description"] = description;
|
|
body["next_owner_mask"] = LLSD::Integer(LLFloaterPerms::getNextOwnerPerms(perms_prefix));
|
|
body["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms(perms_prefix));
|
|
body["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms(perms_prefix));
|
|
}
|
|
|
|
|
|
boost::shared_ptr< LLResourceData> pData( data, resourceDeleter );
|
|
|
|
LLCoprocedureManager::instance().enqueueCoprocedure( "FSImporter", "Upload asset", boost::bind( uploadCoroutine, _1, url, body, new_asset_id, asset_type, pData ) );
|
|
|
|
LL_DEBUGS("import") << "Asset upload via capability of " << new_asset_id.asString() << " to " << url << " of " << asset_id.asString() << LL_ENDL;
|
|
}
|
|
else
|
|
{
|
|
gAssetStorage->storeAssetData(tid,asset_type,FSFloaterImport::onAssetUploadComplete, data, temporary, temporary, temporary);
|
|
LL_DEBUGS("import") << "Asset upload via AssetStorage of " << new_asset_id.asString() << " of " << asset_id.asString() << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
// static
|
|
void FSFloaterImport::onAssetUploadComplete(const LLUUID& uuid, void* userdata, S32 result, LLExtStat ext_status)
|
|
{
|
|
LLResourceData* data = (LLResourceData*)userdata;
|
|
if (!data)
|
|
{
|
|
LL_WARNS("import") << "Got Asset upload complete without data info" << LL_ENDL;
|
|
return;
|
|
}
|
|
|
|
FSResourceData* fs_data = (FSResourceData*)data->mUserData;
|
|
if (!fs_data)
|
|
{
|
|
LL_WARNS("import") << "Missing FSResourceData, can not continue." << LL_ENDL;
|
|
return;
|
|
}
|
|
FSFloaterImport* self = fs_data->mFloater;
|
|
LLUUID asset_id = uuid;
|
|
|
|
if (result >= 0)
|
|
{
|
|
const LLUUID folder_id = gInventory.findCategoryUUIDForType(data->mPreferredLocation);
|
|
|
|
if (fs_data->inventory_item.isNull())
|
|
{
|
|
if (fs_data->temporary)
|
|
{
|
|
LLUUID item_id;
|
|
item_id.generate();
|
|
LLPermissions perm;
|
|
perm.init(gAgentID, gAgentID, gAgentID, gAgentID);
|
|
perm.setMaskBase(PERM_ALL);
|
|
perm.setMaskOwner(PERM_ALL);
|
|
perm.setMaskEveryone(PERM_ALL);
|
|
perm.setMaskGroup(PERM_ALL);
|
|
LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(item_id, folder_id, perm,
|
|
data->mAssetInfo.mTransactionID.makeAssetID(gAgent.getSecureSessionID()),
|
|
data->mAssetInfo.mType, data->mInventoryType, data->mAssetInfo.getName(),
|
|
"Temporary asset", LLSaleInfo::DEFAULT, LLInventoryItemFlags::II_FLAGS_NONE,
|
|
time_corrected());
|
|
gInventory.updateItem(item);
|
|
gInventory.notifyObservers();
|
|
}
|
|
else
|
|
{
|
|
if (LLAssetType::AT_SOUND == data->mAssetInfo.mType ||
|
|
LLAssetType::AT_TEXTURE == data->mAssetInfo.mType ||
|
|
LLAssetType::AT_ANIMATION == data->mAssetInfo.mType)
|
|
{
|
|
// Charge the user for the upload.
|
|
S32 expected_upload_cost = data->mExpectedUploadCost;
|
|
LLViewerRegion* region = gAgent.getRegion();
|
|
if(region)
|
|
{
|
|
// Charge user for upload
|
|
gStatusBar->debitBalance(expected_upload_cost);
|
|
|
|
LLMessageSystem* msg = gMessageSystem;
|
|
msg->newMessageFast(_PREHASH_MoneyTransferRequest);
|
|
msg->nextBlockFast(_PREHASH_AgentData);
|
|
msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
|
|
msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
|
|
msg->nextBlockFast(_PREHASH_MoneyData);
|
|
msg->addUUIDFast(_PREHASH_SourceID, gAgent.getID());
|
|
msg->addUUIDFast(_PREHASH_DestID, LLUUID::null);
|
|
msg->addU8("Flags", 0);
|
|
// we tell the sim how much we were expecting to pay so it
|
|
// can respond to any discrepancy
|
|
msg->addS32Fast(_PREHASH_Amount, expected_upload_cost);
|
|
msg->addU8Fast(_PREHASH_AggregatePermNextOwner, (U8)LLAggregatePermissions::AP_EMPTY);
|
|
msg->addU8Fast(_PREHASH_AggregatePermInventory, (U8)LLAggregatePermissions::AP_EMPTY);
|
|
msg->addS32Fast(_PREHASH_TransactionType, TRANS_UPLOAD_CHARGE);
|
|
msg->addStringFast(_PREHASH_Description, NULL);
|
|
msg->sendReliable(region->getHost());
|
|
}
|
|
}
|
|
|
|
// Actually add the upload to inventory
|
|
LL_DEBUGS("import") << "Adding " << asset_id << " to inventory." << LL_ENDL;
|
|
|
|
if(folder_id.notNull())
|
|
{
|
|
U32 next_owner_perms = data->mNextOwnerPerm;
|
|
if(PERM_NONE == next_owner_perms)
|
|
{
|
|
next_owner_perms = PERM_MOVE | PERM_TRANSFER;
|
|
}
|
|
fs_data->post_asset_upload = true;
|
|
fs_data->post_asset_upload_id = asset_id;
|
|
LLPointer<LLInventoryCallback> cb = new FSCreateItemCallback(fs_data);
|
|
create_inventory_item(gAgent.getID(), gAgent.getSessionID(),
|
|
folder_id, data->mAssetInfo.mTransactionID, data->mAssetInfo.getName(),
|
|
data->mAssetInfo.getDescription(), data->mAssetInfo.mType,
|
|
data->mInventoryType, fs_data->wearable_type, next_owner_perms,
|
|
cb);
|
|
// delete data; // can this be done without deleting fs_data that still is in use?
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Can't find a folder to put asset in" << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Saving into user inventory
|
|
LLViewerInventoryItem* item;
|
|
item = (LLViewerInventoryItem*)gInventory.getItem(fs_data->inventory_item);
|
|
if(item)
|
|
{
|
|
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem(item);
|
|
new_item->setDescription(data->mAssetInfo.getDescription());
|
|
new_item->setTransactionID(data->mAssetInfo.mTransactionID);
|
|
new_item->setAssetUUID(asset_id);
|
|
new_item->updateServer(FALSE);
|
|
gInventory.updateItem(new_item);
|
|
gInventory.notifyObservers();
|
|
LL_DEBUGS("import") << "Asset " << asset_id << " saved into " << "inventory item " << item->getName() << LL_ENDL;
|
|
self->mAssetItemMap[asset_id] = fs_data->inventory_item;
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Inventory item for asset " << asset_id << " is no longer in agent inventory. Skipping to next asset upload." << LL_ENDL;
|
|
asset_id = LLUUID::null;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLSD args;
|
|
args["FILE"] = LLInventoryType::lookupHumanReadable(data->mInventoryType);
|
|
args["REASON"] = std::string(LLAssetStorage::getErrorString(result));
|
|
LLNotificationsUtil::add("CannotUploadReason", args);
|
|
}
|
|
|
|
if (self)
|
|
{
|
|
self->pushNextAsset(asset_id, fs_data->uuid, data->mAssetInfo.mType);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Unable to upload next asset due to missing self." << LL_ENDL;
|
|
}
|
|
|
|
delete fs_data;
|
|
delete data;
|
|
}
|
|
|
|
void FSFloaterImport::pushNextAsset( LLUUID new_uuid, LLUUID asset_id, LLAssetType::EType asset_type )
|
|
{
|
|
NextAsset oAsset;
|
|
oAsset.new_uuid = new_uuid;
|
|
oAsset.asset_id = asset_id;
|
|
oAsset.asset_type = asset_type;
|
|
m_NextAssets.push_back( oAsset );
|
|
}
|
|
|
|
void FSFloaterImport::popNextAsset()
|
|
{
|
|
if( m_NextAssets.empty() )
|
|
return;
|
|
|
|
NextAsset oAsset = m_NextAssets.front();
|
|
m_NextAssets.pop_front();
|
|
|
|
LLUUID new_uuid = oAsset.new_uuid;
|
|
LLUUID asset_id = oAsset.asset_id;
|
|
LLAssetType::EType asset_type = oAsset.asset_type;
|
|
|
|
if (gDisconnected)
|
|
{
|
|
// on logout, all assest uploads callbacks are fired.
|
|
// this fixes a crash on logout if there are still pending uploads.
|
|
// Crash is due to ~distructor is called for *this before the callbacks are fired.
|
|
return;
|
|
}
|
|
|
|
switch(asset_type)
|
|
{
|
|
case LLAssetType::AT_TEXTURE:
|
|
{
|
|
uuid_vec_t::iterator iter = std::find(mTextureQueue.begin(), mTextureQueue.end(), asset_id);
|
|
if ( iter != mTextureQueue.end())
|
|
{
|
|
if (new_uuid.notNull())
|
|
{
|
|
mAssetMap[asset_id] = new_uuid;
|
|
}
|
|
mTextureQueue.erase(iter);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Error with texture upload, got callback without texture in mTextureQueue." << LL_ENDL;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_SOUND:
|
|
{
|
|
uuid_vec_t::iterator iter = std::find(mSoundQueue.begin(), mSoundQueue.end(), asset_id);
|
|
if ( iter != mSoundQueue.end())
|
|
{
|
|
if (new_uuid.notNull())
|
|
{
|
|
mAssetMap[asset_id] = new_uuid;
|
|
}
|
|
mSoundQueue.erase(iter);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Error with sound upload, got callback without sound in mSoundQueue." << LL_ENDL;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
case LLAssetType::AT_ANIMATION:
|
|
{
|
|
uuid_vec_t::iterator iter = std::find(mAnimQueue.begin(), mAnimQueue.end(), asset_id);
|
|
if ( iter != mAnimQueue.end())
|
|
{
|
|
if (new_uuid.notNull())
|
|
{
|
|
mAssetMap[asset_id] = new_uuid;
|
|
}
|
|
mAnimQueue.erase(iter);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Error with animation upload, got callback without animation in mAnimQueue." << LL_ENDL;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
{
|
|
uuid_vec_t::iterator iter = std::find(mAssetQueue.begin(), mAssetQueue.end(), asset_id);
|
|
if ( iter != mAssetQueue.end())
|
|
{
|
|
if (new_uuid.notNull())
|
|
{
|
|
mAssetMap[asset_id] = new_uuid;
|
|
}
|
|
mAssetQueue.erase(iter);
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Error with asset upload, got callback without asset in mAssetQueue." << LL_ENDL;
|
|
return;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!mTextureQueue.empty())
|
|
{
|
|
LLUIString status = getString("texture_uploading");
|
|
status.setArg("[TEXTURE]", llformat("%u", mTexturesTotal - (U32)mTextureQueue.size() + 1));
|
|
status.setArg("[TEXTURETOTAL]", llformat("%u", mTexturesTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mTextureQueue.front());
|
|
return;
|
|
}
|
|
if (!mSoundQueue.empty())
|
|
{
|
|
LLUIString status = getString("sound_uploading");
|
|
status.setArg("[SOUND]", llformat("%u", mSoundsTotal - (U32)mSoundQueue.size() + 1));
|
|
status.setArg("[SOUNDTOTAL]", llformat("%u", mSoundsTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mSoundQueue.front());
|
|
return;
|
|
}
|
|
if (!mAnimQueue.empty())
|
|
{
|
|
LLUIString status = getString("animation_uploading");
|
|
status.setArg("[ANIMATION]", llformat("%u", mAnimsTotal - (U32)mAnimQueue.size() + 1));
|
|
status.setArg("[ANIMATIONTOTAL]", llformat("%u", mAnimsTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mAnimQueue.front());
|
|
return;
|
|
}
|
|
if (!mAssetQueue.empty())
|
|
{
|
|
LLUIString status = getString("asset_uploading");
|
|
status.setArg("[ASSET]", llformat("%u", mAssetsTotal - (U32)mAssetQueue.size() + 1));
|
|
status.setArg("[ASSETTOTAL]", llformat("%u", mAssetsTotal));
|
|
getChild<LLTextBox>("file_status_text")->setText(status.getString());
|
|
uploadAsset(mAssetQueue.front());
|
|
return;
|
|
}
|
|
|
|
LL_DEBUGS("import") << "Nothing left in upload queue, proceding to prim import." << LL_ENDL;
|
|
// restore setting to allow preview popups.
|
|
gSavedSettings.setBOOL("ShowNewInventory", mSavedSettingShowNewInventory);
|
|
importPrims();
|
|
}
|
|
|
|
FSCreateItemCallback::FSCreateItemCallback(FSResourceData* data) :
|
|
mData(data)
|
|
{
|
|
}
|
|
|
|
void FSCreateItemCallback::fire(const LLUUID& inv_item)
|
|
{
|
|
FSFloaterImport* self = mData->mFloater;
|
|
|
|
if (inv_item.isNull())
|
|
{
|
|
LL_WARNS( "import" ) << "Item creation for asset failed, skipping " << mData->uuid.asString() << LL_ENDL;
|
|
if (self)
|
|
{
|
|
self->pushNextAsset( LLUUID::null, mData->uuid, mData->asset_type );
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS("import") << "Unable to upload next asset due to missing self." << LL_ENDL;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if( mData->post_asset_upload )
|
|
{
|
|
self->mAssetItemMap[ mData->post_asset_upload_id ] = inv_item;
|
|
self->pushNextAsset( mData->post_asset_upload_id, mData->uuid, mData->asset_type );
|
|
}
|
|
else
|
|
{
|
|
self->uploadAsset( mData->uuid, inv_item );
|
|
}
|
|
}
|
|
|
|
class UploadFlag
|
|
{
|
|
FSFloaterImport *mFloater;
|
|
public:
|
|
UploadFlag( FSFloaterImport *aFloater )
|
|
: mFloater( aFloater )
|
|
{
|
|
if( mFloater )
|
|
mFloater->startUpload();
|
|
}
|
|
|
|
~UploadFlag()
|
|
{
|
|
if( mFloater )
|
|
mFloater->uploadDone();
|
|
}
|
|
};
|
|
|
|
void uploadCoroutine( LLCoreHttpUtil::HttpCoroutineAdapter::ptr_t &a_httpAdapter, std::string aURL, LLSD aBody, LLAssetID aAssetId, LLAssetType::EType aAssetType, boost::shared_ptr< LLResourceData > aResourceData )
|
|
{
|
|
FSResourceData* fs_data = (FSResourceData*)aResourceData->mUserData;
|
|
FSFloaterImport* self = fs_data->mFloater;
|
|
UploadFlag uploadDone( self );
|
|
|
|
LLCore::HttpRequest::ptr_t pRequest( new LLCore::HttpRequest() );
|
|
LLSD postResult = a_httpAdapter->postAndSuspend( pRequest, aURL, aBody );
|
|
|
|
LLSD httpResults = postResult[ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ];
|
|
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD(httpResults);
|
|
|
|
if( !status )
|
|
{
|
|
LL_WARNS( "import" ) << "Error " << status.toULong() << " reason: " << status.toString() << LL_ENDL;
|
|
LL_WARNS( "import" ) << "Skipping " << fs_data->uuid.asString() << " due to upload error." << LL_ENDL;
|
|
if( self )
|
|
{
|
|
self->pushNextAsset( LLUUID::null, fs_data->uuid, aResourceData->mAssetInfo.mType );
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS( "import" ) << "Unable to upload next asset due to missing self." << LL_ENDL;
|
|
}
|
|
}
|
|
|
|
std::string uploader = postResult[ "uploader" ].asString();
|
|
|
|
if( uploader.empty() )
|
|
{
|
|
LL_WARNS( "import" ) << "No upload url provided. Nothing uploaded." << LL_ENDL;
|
|
self->pushNextAsset( LLUUID::null, fs_data->uuid, aResourceData->mAssetInfo.mType );
|
|
return;
|
|
}
|
|
|
|
if (!gVFS->getExists(aAssetId, aAssetType))
|
|
{
|
|
LL_WARNS() << "Asset doesn't exist in VFS anymore. Nothing uploaded." << LL_ENDL;
|
|
self->pushNextAsset( LLUUID::null, fs_data->uuid, aResourceData->mAssetInfo.mType );
|
|
return;
|
|
}
|
|
|
|
LLSD postContentResult;
|
|
{
|
|
pRequest.reset( new LLCore::HttpRequest() );
|
|
|
|
postContentResult = a_httpAdapter->postFileAndSuspend( pRequest, uploader, aAssetId, aAssetType );
|
|
LLSD httpResults = postContentResult[ LLCoreHttpUtil::HttpCoroutineAdapter::HTTP_RESULTS ];
|
|
LLCore::HttpStatus status = LLCoreHttpUtil::HttpCoroutineAdapter::getStatusFromLLSD( httpResults );
|
|
|
|
std::string ulstate = postContentResult[ "state" ].asString();
|
|
|
|
|
|
if( (!status) || (ulstate != "complete") )
|
|
{
|
|
self->pushNextAsset( LLUUID::null, fs_data->uuid, aResourceData->mAssetInfo.mType );
|
|
LL_WARNS( "import" ) << "Asset upload failed." << ll_pretty_print_sd( postContentResult) << LL_ENDL;
|
|
return;
|
|
}
|
|
}
|
|
|
|
LLUUID item_id = aBody[ "item_id" ];
|
|
std::string responseResult = postContentResult[ "state" ];
|
|
LLUUID new_id = postContentResult[ "new_asset" ];
|
|
|
|
LL_DEBUGS( "import" ) << "result: " << responseResult << " new_id: " << new_id << LL_ENDL;
|
|
|
|
// rename the file in the VFS to the actual asset id
|
|
gVFS->renameFile(aAssetId, aAssetType, new_id, aAssetType);
|
|
|
|
if( item_id.isNull() )
|
|
{
|
|
if( fs_data->temporary )
|
|
{
|
|
if( responseResult == "complete" )
|
|
{
|
|
LLUUID folder_id( gInventory.findCategoryUUIDForType( aResourceData->mPreferredLocation ) );
|
|
|
|
LLUUID temp_item_id;
|
|
temp_item_id.generate();
|
|
LLPermissions perm;
|
|
perm.init( gAgentID, gAgentID, gAgentID, gAgentID );
|
|
perm.setMaskBase( PERM_ALL );
|
|
perm.setMaskOwner( PERM_ALL );
|
|
perm.setMaskEveryone( PERM_ALL );
|
|
perm.setMaskGroup( PERM_ALL );
|
|
|
|
LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem( temp_item_id, folder_id, perm, new_id, aResourceData->mAssetInfo.mType, aResourceData->mInventoryType, aResourceData->mAssetInfo.getName(),
|
|
"Temporary asset", LLSaleInfo::DEFAULT, LLInventoryItemFlags::II_FLAGS_NONE, time_corrected() );
|
|
gInventory.updateItem( item );
|
|
gInventory.notifyObservers();
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS( "import" ) << "Unable to add texture, got bad result." << LL_ENDL;
|
|
new_id = LLUUID::null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLAssetType::EType asset_type = LLAssetType::lookup( aBody[ "asset_type" ].asString() );
|
|
LLInventoryType::EType inventory_type = LLInventoryType::lookup( aBody[ "inventory_type" ].asString() );
|
|
S32 upload_price = LLGlobalEconomy::getInstance()->getPriceUpload();
|
|
|
|
const std::string inventory_type_string = aBody[ "asset_type" ].asString();
|
|
const LLUUID& item_folder_id = aBody[ "folder_id" ].asUUID();
|
|
const std::string& item_name = aBody[ "name" ];
|
|
const std::string& item_description = aBody[ "description" ];
|
|
|
|
if( upload_price > 0 )
|
|
{
|
|
// this upload costed us L$, update our balance
|
|
// and display something saying that it cost L$
|
|
LLStatusBar::sendMoneyBalanceRequest();
|
|
|
|
// <FS:CR> FIRE-10628 - Option to supress upload cost notification
|
|
if( gSavedSettings.getBOOL( "FSShowUploadPaymentToast" ) )
|
|
{
|
|
LLSD args;
|
|
args[ "AMOUNT" ] = llformat( "%d", upload_price );
|
|
LLNotificationsUtil::add( "UploadPayment", args );
|
|
}
|
|
// </FS:CR>
|
|
}
|
|
|
|
if( item_folder_id.notNull() )
|
|
{
|
|
U32 everyone_perms = PERM_NONE;
|
|
U32 group_perms = PERM_NONE;
|
|
U32 next_owner_perms = PERM_ALL;
|
|
if( postContentResult.has( "new_next_owner_mask" ) )
|
|
{
|
|
// The server provided creation perms so use them.
|
|
// Do not assume we got the perms we asked for in
|
|
// since the server may not have granted them all.
|
|
everyone_perms = postContentResult[ "new_everyone_mask" ].asInteger();
|
|
group_perms = postContentResult[ "new_group_mask" ].asInteger();
|
|
next_owner_perms = postContentResult[ "new_next_owner_mask" ].asInteger();
|
|
}
|
|
else
|
|
{
|
|
// The server doesn't provide creation perms
|
|
// so use old assumption-based perms.
|
|
if( inventory_type_string != "snapshot" )
|
|
{
|
|
next_owner_perms = PERM_MOVE | PERM_TRANSFER;
|
|
}
|
|
}
|
|
|
|
LLPermissions new_perms;
|
|
new_perms.init( gAgent.getID(), gAgent.getID(), LLUUID::null, LLUUID::null );
|
|
|
|
new_perms.initMasks( PERM_ALL, PERM_ALL, everyone_perms, group_perms, next_owner_perms );
|
|
|
|
U32 inventory_item_flags = 0;
|
|
if( postContentResult.has( "inventory_flags" ) )
|
|
{
|
|
inventory_item_flags = (U32)postContentResult[ "inventory_flags" ].asInteger();
|
|
if( inventory_item_flags != 0 )
|
|
{
|
|
LL_INFOS() << "inventory_item_flags " << inventory_item_flags << LL_ENDL;
|
|
}
|
|
}
|
|
S32 creation_date_now = time_corrected();
|
|
|
|
LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem( postContentResult[ "new_inventory_item" ].asUUID(), item_folder_id, new_perms, postContentResult[ "new_asset" ].asUUID(),
|
|
asset_type, inventory_type, item_name, item_description, LLSaleInfo::DEFAULT, inventory_item_flags, creation_date_now );
|
|
|
|
gInventory.updateItem( item );
|
|
gInventory.notifyObservers();
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS( "import" ) << "Can't find a folder to put the texture in" << LL_ENDL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
LLViewerInventoryItem* item = (LLViewerInventoryItem*)gInventory.getItem( item_id );
|
|
if( !item )
|
|
{
|
|
LL_WARNS( "import" ) << "Inventory item for " << aAssetId << " is no longer in agent inventory. Skipping to next asset upload." << LL_ENDL;
|
|
new_id = LLUUID::null;
|
|
}
|
|
else
|
|
{
|
|
// Update viewer inventory item
|
|
LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem( item );
|
|
new_item->setAssetUUID( postContentResult[ "new_asset" ].asUUID() );
|
|
gInventory.updateItem( new_item );
|
|
gInventory.notifyObservers();
|
|
|
|
LL_DEBUGS( "import" ) << "Asset " << postContentResult[ "new_asset" ].asString() << " saved into " << "inventory item " << item->getName() << LL_ENDL;
|
|
self->mAssetItemMap[ postContentResult[ "new_asset" ].asUUID() ] = item_id;
|
|
}
|
|
}
|
|
|
|
if( self )
|
|
{
|
|
self->pushNextAsset( new_id, fs_data->uuid, aResourceData->mAssetInfo.mType );
|
|
}
|
|
else
|
|
{
|
|
LL_WARNS( "import" ) << "Unable to upload next asset due to missing self." << LL_ENDL;
|
|
}
|
|
}
|