phoenix-firestorm/indra/newview/fsfloaterimport.cpp

1963 lines
62 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 "llagent.h"
#include "llagentcamera.h"
#include "llappviewer.h"
#include "llbuycurrencyhtml.h"
#include "llcallbacklist.h"
#include "llcheckboxctrl.h"
#include "lldatapacker.h"
#include "lldir.h"
#include "lleconomy.h"
#include "llfilepicker.h"
#include "llfloaterperms.h"
#include "llfloaterreg.h"
#include "llinventorydefines.h"
#include "llinventoryfunctions.h"
#include "lllineeditor.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 "material_codes.h"
#include <boost/algorithm/string_regex.hpp>
#include <boost/lexical_cast.hpp>
FSFloaterImport::FSFloaterImport(const LLSD& key) :
LLFloater(key),
mCreatingActive(false),
mLinkset(0),
mObject(0),
mPrim(0),
mImportState(IDLE),
mFileReady(false)
{
mInstance = this;
mCommitCallbackRegistrar.add("Import.PickFile",boost::bind(&FSFloaterImport::onClickBtnPickFile,this));
mCommitCallbackRegistrar.add("Import.ImportLinkset",boost::bind(&FSFloaterImport::onClickBtnImport,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;
}
gSavedSettings.setBOOL("ShowNewInventory", mSavedSettingShowNewInventory);
}
// static
void FSFloaterImport::onIdle(void* user_data)
{
FSFloaterImport* self = (FSFloaterImport*)user_data;
self->onIdle();
}
void FSFloaterImport::onIdle()
{
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::onClickBtnPickFile()
{
// pick a file
LLFilePicker& file_picker = LLFilePicker::instance();
if(!file_picker.getOpenFile(LLFilePicker::FFLOAD_IMPORT))
{
// User canceled or we failed to acquire file.
return;
}
mFileFullName = file_picker.getFirstFile();
mFilePath = gDirUtilp->getDirName(mFileName);
mFileName= gDirUtilp->getBaseFileName(mFileFullName);
getChild<LLLineEditor>("filename")->setValue(LLSD(mFileName));
mFile.clear();
mTextureQueue.clear();
mAnimQueue.clear();
mSoundQueue.clear();
mFileReady = false;
mLinksetSize = 0;
mTexturesTotal = 0;
mAnimsTotal = 0;
mSoundsTotal = 0;
llifstream filestream(mFileFullName, 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(mFile, filestream, file_size))
{
mFileReady = 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 (mFileReady)
{
if (mFile.has("format_version") && mFile["format_version"].asInteger() == 1)
{
LLSD& linksetsd = mFile["linkset"];
U32 prims = 0;
for (LLSD::array_iterator linkset_iter = linksetsd.beginArray();
linkset_iter != linksetsd.endArray();
++linkset_iter)
{
LLSD& objectsd = mFile["linkset"][mLinksetSize];
for (LLSD::array_iterator prim_iter = objectsd.beginArray();
prim_iter != objectsd.endArray();
++prim_iter)
{
processPrim(mFile["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_file")->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_file")->setEnabled(FALSE);
getChild<LLCheckBoxCtrl>("do_not_attach")->setEnabled(FALSE);
getChild<LLCheckBoxCtrl>("region_position")->setEnabled(FALSE);
getChild<LLCheckBoxCtrl>("upload_asset")->setEnabled(FALSE);
}
}
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 (!mFile["inventory"].has((*content_iter).asString()))
{
continue;
}
LLAssetType::EType asset_type = LLAssetType::lookup(mFile["inventory"][(*content_iter).asString()]["type"].asString().c_str());
LLUUID asset_id = mFile["inventory"][(*content_iter).asString()]["asset_id"].asUUID();
if (!mFile["asset"].has(asset_id.asString()))
{
continue;
}
addAsset(asset_id, asset_type);
std::vector<U8> buffer = mFile["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;
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 (!mFile["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(5.0f, 0.0f, 2.0f); // TODO: add debug settings for this and maybe expose in the UI.
mStartPosition = mStartPosition + offset * gAgent.getQuat();
LL_DEBUGS("import") << "mStartPosition is " << mStartPosition << LL_ENDL;
// don't allow change during a long upload/import
getChild<LLButton>("pick_file")->setEnabled(FALSE);
getChild<LLButton>("import_file")->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::Singleton::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>("pick_file")->setEnabled(TRUE);
getChild<LLButton>("import_file")->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::Singleton::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::Singleton::getInstance()->getPriceUpload()));
getChild<LLTextBox>("file_status_text")->setText(stats.getString());
}
}
void FSFloaterImport::importPrims()
{
mObjectSize = 0;
LLSD& objectsd = mFile["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 = mFile["linkset"][0][0].asUUID();
LLSD& linkset_root_prim = mFile["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 = mFile["linkset"][mLinkset][mObject].asUUID();
LL_DEBUGS("import") << "Creating prim from " << prim_uuid.asString() << LL_ENDL;
LLSD& prim = mFile["prim"][prim_uuid.asString()];
gMessageSystem->newMessageFast(_PREHASH_ObjectAdd);
gMessageSystem->nextBlockFast(_PREHASH_AgentData);
gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
LLUUID group_id = gAgent.getGroupID();
LLParcel *parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
if (gSavedSettings.getBOOL("RezUnderLandGroup"))
{
if (gAgent.isInGroup(parcel->getGroupID()))
{
group_id = parcel->getGroupID();
}
else if (gAgent.isInGroup(parcel->getOwnerID()))
{
group_id = parcel->getOwnerID();
}
}
gMessageSystem->addUUIDFast(_PREHASH_GroupID, group_id);
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;
}
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());
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_CREATE_COUNT);
}
bool FSFloaterImport::processPrimCreated(LLViewerObject* object)
{
if (!(mInstance && mCreatingActive))
{
return false;
}
LLSelectMgr::getInstance()->selectObjectAndFamily(object, TRUE);
LLUUID prim_uuid = mFile["linkset"][mLinkset][mObject].asUUID();
LLSD& prim = mFile["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();
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()]);
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 regine.
}
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 (!mFile["inventory"].has((*content_iter).asString()))
{
LL_WARNS("import") << "Inventory content " << (*content_iter) << " was not found in import file." << LL_ENDL;
continue;
}
LLSD& item_sd = mFile["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.count())
{
LLViewerInventoryItem* item = items.get(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 = mFile["linkset"][mLinkset][0].asUUID();
LLSD& root_prim = mFile["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"));
// re-enable the controls, but force to pick file due to need to re-create the upload queues.
getChild<LLButton>("pick_file")->setEnabled(TRUE);
}
else
{
mObject = 0;
mLinkset++;
mObjectSize = 0;
LLSD& objectsd = mFile["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 = mFile["linkset"][mLinkset][0].asUUID();
LLSD& root_prim = mFile["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 tempary = false;
std::vector<U8> asset_data = mFile["asset"][asset_id.asString()]["data"].asBinary();
std::string name = mFile["asset"][asset_id.asString()]["name"].asString();
std::string description = mFile["asset"][asset_id.asString()]["description"].asString();
LLAssetType::EType asset_type = LLAssetType::lookup(mFile["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;
if (name.empty())
{
name = llformat("Uploaded %s %s", LLAssetType::lookupHumanReadable(asset_type), asset_id.asString().c_str());
}
switch(asset_type)
{
case LLAssetType::AT_TEXTURE:
{
tempary = getChild<LLCheckBoxCtrl>("temp_asset")->get();
if (tempary)
{
url = gAgent.getRegion()->getCapability("UploadBakedTexture");
}
else
{
url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
new_file_agent_inventory = true;
}
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_TEXTURE_COUNT);
}
break;
case LLAssetType::AT_SOUND:
{
tempary = getChild<LLCheckBoxCtrl>("temp_asset")->get();
if (tempary)
{
// skip upload due to no temp support for sound
nextAsset(LLUUID::null, asset_id, asset_type);
return;
}
else
{
url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
new_file_agent_inventory = true;
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_SOUND_COUNT);
}
}
break;
case LLAssetType::AT_CLOTHING:
case LLAssetType::AT_BODYPART:
{
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:
{
if (inventory_item.isNull())
{
// create inventory item first
FSResourceData* ci_data = new FSResourceData;
ci_data->uuid = asset_id;
ci_data->user_data = 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.getRegion()->getCapability("UpdateNotecardAgentInventory");
body["item_id"] = inventory_item;
}
}
break;
case LLAssetType::AT_LSL_TEXT:
{
if (inventory_item.isNull())
{
// create inventory item first
FSResourceData* ci_data = new FSResourceData;
ci_data->uuid = asset_id;
ci_data->user_data = 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.getRegion()->getCapability("UpdateScriptAgent");
body["item_id"] = inventory_item;
if (gSavedSettings.getBOOL("FSSaveInventoryScriptsAsMono"))
{
body["target"] = "mono";
}
else
{
body["target"] = "lsl2";
}
}
}
break;
case LLAssetType::AT_ANIMATION:
{
tempary = getChild<LLCheckBoxCtrl>("temp_asset")->get();
if (tempary)
{
// no temp support, skip
nextAsset(LLUUID::null, asset_id, asset_type);
return;
}
else
{
url = gAgent.getRegion()->getCapability("NewFileAgentInventory");
new_file_agent_inventory = true;
LLViewerStats::getInstance()->incStat(LLViewerStats::ST_UPLOAD_ANIM_COUNT);
}
}
break;
case LLAssetType::AT_GESTURE:
{
if (inventory_item.isNull())
{
// create inventory item first
FSResourceData* ci_data = new FSResourceData;
ci_data->uuid = asset_id;
ci_data->user_data = 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.getRegion()->getCapability("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.getRegion()->getCapability("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();
data->mExpectedUploadCost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
FSResourceData* fs_data = new FSResourceData;
fs_data->uuid = asset_id;
fs_data->user_data = this;
fs_data->tempary = tempary;
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());
body["group_mask"] = LLSD::Integer(LLFloaterPerms::getGroupPerms());
body["everyone_mask"] = LLSD::Integer(LLFloaterPerms::getEveryonePerms());
}
LLHTTPClient::post(url, body, new FSAssetResponder(body, new_asset_id, asset_type, data));
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,
tempary,
tempary,
tempary);
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 = (FSFloaterImport*)fs_data->user_data;
LLUUID asset_id = uuid;
if (result >= 0)
{
const LLUUID folder_id = gInventory.findCategoryUUIDForType(data->mPreferredLocation);
if (fs_data->inventory_item.isNull())
{
if (fs_data->tempary)
{
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->nextAsset(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::nextAsset(LLUUID new_uuid, LLUUID asset_id, LLAssetType::EType 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)
{
FSResourceData* data = (FSResourceData*)mData;
FSFloaterImport* self = (FSFloaterImport*)data->user_data;
if (inv_item.isNull())
{
LL_WARNS("import") << "Item creation for asset failed, skipping " << data->uuid.asString() << LL_ENDL;
if (self)
{
self->nextAsset(LLUUID::null, data->uuid, data->asset_type);
}
else
{
LL_WARNS("import") << "Unable to upload next asset due to missing self." << LL_ENDL;
}
return;
}
if (data->post_asset_upload)
{
self->mAssetItemMap[data->post_asset_upload_id] = inv_item;
self->nextAsset(data->post_asset_upload_id, data->uuid, data->asset_type);
}
else
{
self->uploadAsset(data->uuid, inv_item);
}
}
FSAssetResponder::FSAssetResponder(const LLSD& post_data,
const LLUUID& vfile_id,
LLAssetType::EType asset_type,
LLResourceData* data) :
LLAssetUploadResponder(post_data, vfile_id, asset_type),
mData(data)
{
}
FSAssetResponder::~FSAssetResponder()
{
}
void FSAssetResponder::uploadComplete(const LLSD& content)
{
LLUUID item_id = mPostData["item_id"];
std::string result = content["state"];
LLUUID new_id = content["new_asset"];
LL_DEBUGS("import") << "result: " << result << " new_id: " << new_id << LL_ENDL;
LLResourceData* data = (LLResourceData*)mData;
FSResourceData* fs_data = (FSResourceData*)data->mUserData;
FSFloaterImport* self = (FSFloaterImport*)fs_data->user_data;
if (item_id.isNull())
{
if (fs_data->tempary)
{
if (result == "complete")
{
LLUUID folder_id(gInventory.findCategoryUUIDForType(data->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,
data->mAssetInfo.mType, data->mInventoryType, data->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(mPostData["asset_type"].asString());
LLInventoryType::EType inventory_type = LLInventoryType::lookup(mPostData["inventory_type"].asString());
S32 upload_price = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
const std::string inventory_type_string = mPostData["asset_type"].asString();
const LLUUID& item_folder_id = mPostData["folder_id"].asUUID();
const std::string& item_name = mPostData["name"];
const std::string& item_description = mPostData["description"];
if ( upload_price > 0 )
{
// this upload costed us L$, update our balance
// and display something saying that it cost L$
LLStatusBar::sendMoneyBalanceRequest();
LLSD args;
args["AMOUNT"] = llformat("%d", upload_price);
LLNotificationsUtil::add("UploadPayment", args);
}
if( item_folder_id.notNull() )
{
U32 everyone_perms = PERM_NONE;
U32 group_perms = PERM_NONE;
U32 next_owner_perms = PERM_ALL;
if( content.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 = content["new_everyone_mask"].asInteger();
group_perms = content["new_group_mask"].asInteger();
next_owner_perms = content["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 (content.has("inventory_flags"))
{
inventory_item_flags = (U32) content["inventory_flags"].asInteger();
if (inventory_item_flags != 0)
{
llinfos << "inventory_item_flags " << inventory_item_flags << llendl;
}
}
S32 creation_date_now = time_corrected();
LLPointer<LLViewerInventoryItem> item = new LLViewerInventoryItem(content["new_inventory_item"].asUUID(),
item_folder_id,
new_perms,
content["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 " << mVFileID << " 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(content["new_asset"].asUUID());
gInventory.updateItem(new_item);
gInventory.notifyObservers();
LL_DEBUGS("import") << "Asset " << content["new_asset"].asString() << " saved into " << "inventory item " << item->getName() << LL_ENDL;
self->mAssetItemMap[content["new_asset"].asUUID()] = item_id;
}
}
if (self)
{
self->nextAsset(new_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 FSAssetResponder::error(U32 statusNum, const std::string& reason)
{
LL_WARNS("import") << "Error " << statusNum << " reason: " << reason << LL_ENDL;
LLResourceData* data = (LLResourceData*)mData;
FSResourceData* fs_data = (FSResourceData*)data->mUserData;
FSFloaterImport* self = (FSFloaterImport*)fs_data->user_data;
LL_WARNS("import") << "Skipping " << fs_data->uuid.asString() << " due to upload error." << LL_ENDL;
if (self)
{
self->nextAsset(LLUUID::null, 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;
}