Add AIXMLLindenGenepool - redo of archetype export/import using AIXML*.

In order to remove code duplication, and as prove of concept,
I redid the linden_genepool archetype export and import (from the Edit
Appearance Floater), using AIXML and AIAlert.

The import/export code did shrink significantly, and became a lot
simpler. Although a new file pair (aixmllindengenepool.{cpp,h}) is
added to define the (de)serialization of the linden_genepool XML format,
that code is now centralized in one place, and still a lot simpler.

As a bonus however, every possible error is now semi-automatically
reported to the user with all details that might help to overcome
the problem, like file names and system errors.
This commit is contained in:
Aleric Inglewood
2013-11-02 22:31:27 +01:00
parent d174b7fcf8
commit 2453c13e11
19 changed files with 605 additions and 429 deletions

View File

@@ -117,7 +117,8 @@ public:
/*virtual*/ void stopAnimating(BOOL upload_bake);
/*virtual*/ BOOL linkDrivenParams(visual_param_mapper mapper, BOOL only_cross_params);
/*virtual*/ void resetDrivenParams();
/*virtual*/ char const* getTypeString(void) const { return "param_driver"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion();
/*virtual*/ const LLVector4a& getAvgDistortion();

View File

@@ -173,6 +173,7 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex sex );
/*virtual*/ char const* getTypeString(void) const { return "param_morph"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion();

View File

@@ -109,7 +109,8 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ void apply( ESex sex );
/*virtual*/ char const* getTypeString(void) const { return "param_skeleton"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 0.1f; }
/*virtual*/ const LLVector4a& getAvgDistortion() { return mDefaultVec; }

View File

@@ -86,6 +86,7 @@ public:
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
/*virtual*/ char const* getTypeString(void) const { return "param_alpha"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 1.f; }
@@ -177,7 +178,7 @@ public:
/*virtual*/ void setWeight(F32 weight, BOOL upload_bake);
/*virtual*/ void setAnimationTarget(F32 target_value, BOOL upload_bake);
/*virtual*/ void animate(F32 delta, BOOL upload_bake);
/*virtual*/ char const* getTypeString(void) const { return "param_color"; }
// LLViewerVisualParam Virtual functions
/*virtual*/ F32 getTotalDistortion() { return 1.f; }

View File

@@ -143,6 +143,12 @@ BOOL LLViewerVisualParam::setInfo(LLViewerVisualParamInfo *info)
return TRUE;
}
//virtual
std::string LLViewerVisualParam::getDumpWearableTypeName(void) const
{
return LLWearableType::getTypeName(LLWearableType::EType(getInfo()->mWearableType));
}
/*
//=============================================================================
// These virtual functions should always be overridden,

View File

@@ -82,6 +82,7 @@ public:
// LLVisualParam Virtual functions
///*virtual*/ BOOL parseData(LLXmlTreeNode* node);
/*virtual*/ std::string getDumpWearableTypeName(void) const;
// New Virtual functions
virtual F32 getTotalDistortion() = 0;

View File

@@ -41,6 +41,7 @@ class LLVisualParam;
class LLTexGlobalColorInfo;
class LLTexGlobalColor;
class LLAvatarAppearance;
class AIArchetype;
// Abstract class.
class LLWearable

View File

@@ -162,6 +162,10 @@ public:
void setParamLocation(EParamLocation loc);
EParamLocation getParamLocation() const { return mParamLocation; }
// Singu extensions. Used for dumping the archtype.
virtual char const* getTypeString(void) const = 0;
virtual std::string getDumpWearableTypeName(void) const = 0;
protected:
F32 mCurWeight; // current weight
F32 mLastWeight; // last weight

View File

@@ -82,6 +82,7 @@ include_directories(
set(viewer_SOURCE_FILES
NACLantispam.cpp
aihttpview.cpp
aixmllindengenepool.cpp
aoremotectrl.cpp
ascentfloatercontactgroups.cpp
ascentkeyword.cpp
@@ -598,6 +599,7 @@ set(viewer_HEADER_FILES
NACLantispam.h
aihttpview.h
aixmllindengenepool.h
aoremotectrl.h
ascentfloatercontactgroups.h
ascentkeyword.h

View File

@@ -0,0 +1,205 @@
/**
* @file aixmllindengenepool.cpp
* @brief XML linden_genepool serialization support.
*
* Copyright (c) 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 01/11/2013
* Initial version, written by Aleric Inglewood @ SL
*/
// metaversion 1.0
// ===============
//
// Added as child of <linden_genepool>:
//
// <meta gridnick="secondlife" date="2013-07-16T16:49:00.40Z" />
//
// Optionally, as child of <archetype>, the following node may appear:
//
// <meta path="clothing/jackets" name="Purple jacket" description="A jacket with mainly the color purple" />
//
// Furthermore, metaversion 1.0 and higher allow the occurance of one or more <archetype> blocks.
// If this is used then it is strongly advised to use one <archetype> per wearable, so that
// the the <meta> node makes sense (it then refers to the wearable of that <archetype>).
//
// The reason for this clumsy way to link wearable to extra meta data is to stay
// compatible with the older format (no metaversion).
#include "sys.h"
#include "aixmllindengenepool.h"
#include "hippogridmanager.h"
#include "llvisualparam.h"
#include "llviewerwearable.h"
#include "llquantize.h"
extern void append_path_short(LLUUID const& id, std::string& path);
void AIXMLLindenGenepool::MetaData::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "meta", indentation);
tag.attribute("gridnick", mGridNick);
tag.attribute(DEFAULT_LLDATE_NAME, mDate);
}
AIXMLLindenGenepool::MetaData::MetaData(AIXMLElementParser const& parser)
{
parser.attribute("gridnick", mGridNick);
parser.attribute(DEFAULT_LLDATE_NAME, mDate);
}
AIXMLLindenGenepool::AIXMLLindenGenepool(LLFILE* fp) : AIXMLRootElement(fp, "linden_genepool")
{
attribute("version", "1.0");
attribute("metaversion", "1.0");
child(MetaData(gHippoGridManager->getConnectedGrid()->getGridNick(), LLDate::now()));
}
void AIVisualParamIDValuePair::toXML(std::ostream& os, int indentation) const
{
LLVisualParam const* visual_param = mVisualParam;
if (!visual_param && mWearable)
{
visual_param = mWearable->getVisualParam(mID);
}
if (visual_param)
{
AIXMLElement tag(os, "param", indentation);
tag.attribute("id", mID);
tag.attribute("name", visual_param->getName());
tag.attribute("value", mValue);
tag.attribute("u8", (U32)F32_to_U8(mValue, visual_param->getMinWeight(), visual_param->getMaxWeight()));
tag.attribute("type", visual_param->getTypeString());
tag.attribute("wearable", visual_param->getDumpWearableTypeName());
}
}
AIVisualParamIDValuePair::AIVisualParamIDValuePair(AIXMLElementParser const& parser)
{
// Only id and value are relevant. Ignore all other attributes.
parser.attribute("id", mID);
parser.attribute("value", mValue);
}
void AITextureIDUUIDPair::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "texture", indentation);
tag.attribute("te", mID);
tag.attribute(DEFAULT_LLUUID_NAME, mUUID);
}
AITextureIDUUIDPair::AITextureIDUUIDPair(AIXMLElementParser const& parser)
{
parser.attribute("te", mID);
parser.attribute(DEFAULT_LLUUID_NAME, mUUID);
}
void AIArchetype::MetaData::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "meta", indentation);
tag.attribute("path", mPath);
tag.attribute("name", mName);
tag.attribute("description", mDescription);
}
AIArchetype::MetaData::MetaData(AIXMLElementParser const& parser)
{
char const* missing = NULL;
if (!parser.attribute("path", mPath))
{
missing = "path";
}
if (!parser.attribute("name", mName))
{
missing = "name";
}
if (!parser.attribute("description", mDescription))
{
missing = "description";
}
if (missing)
{
THROW_ALERT("AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE", AIArgs("[ATTRIBUTE]", missing));
}
}
AIArchetype::MetaData::MetaData(LLViewerWearable const* wearable) : mName(wearable->getName()), mDescription(wearable->getDescription())
{
append_path_short(wearable->getItemID(), mPath);
}
AIArchetype::AIArchetype(void) : mType(LLWearableType::WT_NONE)
{
}
AIArchetype::AIArchetype(LLWearableType::EType type) : mType(type)
{
}
AIArchetype::AIArchetype(LLViewerWearable const* wearable) : mType(wearable->getType()), mMetaData(wearable)
{
}
void AIArchetype::toXML(std::ostream& os, int indentation) const
{
AIXMLElement tag(os, "archetype", indentation);
if (mType == LLWearableType::WT_NONE)
{
tag.attribute("name", "???");
}
else
{
tag.attribute("name", LLWearableType::getTypeName(mType));
}
if (!mMetaData.mPath.empty())
{
tag.child(mMetaData);
}
tag.child(mParams.begin(), mParams.end());
tag.child(mTextures.begin(), mTextures.end());
}
AIArchetype::AIArchetype(AIXMLElementParser const& parser)
{
std::string name;
mType = LLWearableType::WT_NONE;
if (!parser.attribute("name", name))
{
llwarns << "The <archetype> tag in file \"" << parser.filename() << "\" is missing the 'name' parameter." << llendl;
}
else if (name != "???")
{
mType = LLWearableType::typeNameToType(name);
}
if (parser.version() >= 1)
{
if (!parser.child("meta", mMetaData))
{
THROW_ALERT("AIArchetype_archetype_has_no_meta");
}
}
parser.push_back_children("param", mParams);
parser.push_back_children("texture", mTextures);
}

View File

@@ -0,0 +1,150 @@
/**
* @file aixmllindengenepool.h
* @brief XML linden_genepool serialization support.
*
* Copyright (c) 2013, Aleric Inglewood.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* There are special exceptions to the terms and conditions of the GPL as
* it is applied to this Source Code. View the full text of the exception
* in the file doc/FLOSS-exception.txt in this software distribution.
*
* CHANGELOG
* and additional copyright holders.
*
* 01/11/2013
* Initial version, written by Aleric Inglewood @ SL
*/
#ifndef AIXMLLINDENGENEPOOL_H
#define AIXMLLINDENGENEPOOL_H
#include "aixml.h"
#include "llwearabletype.h"
#include "llviewervisualparam.h"
#include <vector>
class LLViewerWearable;
class AIXMLLindenGenepool : public AIXMLRootElement
{
public:
struct MetaData
{
std::string mGridNick;
LLDate mDate;
MetaData(void) { }
MetaData(std::string const& grid_nick, LLDate const& date) : mGridNick(grid_nick), mDate(date) { }
void toXML(std::ostream& os, int indentation) const;
MetaData(AIXMLElementParser const& parser);
};
AIXMLLindenGenepool(LLFILE* fp);
};
class AIVisualParamIDValuePair
{
private:
// A wearable + ID define the LLVisualParam, but it also possible to specify the LLVisualParam directly.
LLVisualParam const* mVisualParam; // Specific LLVisualParam, given at construction, or ...
LLViewerWearable const* mWearable; // Underlaying wearable, if any.
U32 mID; // The visual parameter id.
F32 mValue; // The value of the visual parameter.
public:
AIVisualParamIDValuePair(LLVisualParam const* visual_param) :
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(visual_param->getWeight()) { }
AIVisualParamIDValuePair(LLVisualParam const* visual_param, F32 value) :
mVisualParam(visual_param), mWearable(NULL), mID(visual_param->getID()), mValue(value) { }
AIVisualParamIDValuePair(LLViewerWearable const* wearable, U32 id, F32 value) :
mVisualParam(NULL), mWearable(wearable), mID(id), mValue(value) { }
void toXML(std::ostream& os, int indentation) const;
AIVisualParamIDValuePair(AIXMLElementParser const& parser);
// Accessors.
U32 getID(void) const { return mID; }
F32 getValue(void) const { return mValue; }
};
class AITextureIDUUIDPair
{
private:
U32 mID;
LLUUID mUUID;
public:
AITextureIDUUIDPair(U32 id, LLUUID const& uuid) : mID(id), mUUID(uuid) { }
void toXML(std::ostream& os, int indentation) const;
AITextureIDUUIDPair(AIXMLElementParser const& parser);
// Accessors.
U32 getID(void) const { return mID; }
LLUUID const& getUUID(void) const { return mUUID; }
};
class AIArchetype
{
public:
struct MetaData
{
std::string mPath; // The wearable location in the inventory.
std::string mName; // The wearable name.
std::string mDescription; // The wearable description.
MetaData(void) { }
MetaData(LLViewerWearable const* wearable);
void toXML(std::ostream& os, int indentation) const;
MetaData(AIXMLElementParser const& parser);
};
typedef std::vector<AIVisualParamIDValuePair> params_type;
typedef std::vector<AITextureIDUUIDPair> textures_type;
private:
LLWearableType::EType mType; // The type of the wearable.
MetaData mMetaData;
params_type mParams;
textures_type mTextures;
public:
// Accessors.
LLWearableType::EType getType(void) const { return mType; }
MetaData const& getMetaData(void) const { return mMetaData; }
params_type const& getParams(void) const { return mParams; }
textures_type const& getTextures(void) const { return mTextures; }
public:
// An archtype without wearable has no (known) metadata. This is recognized because mPath will be empty.
// An archtype without type with get the attribute name="???".
AIArchetype(void); // <archetype name="???">
AIArchetype(LLWearableType::EType type); // <archetype name="shirt">
AIArchetype(LLViewerWearable const* wearable); // <archetype name="shirt"> <meta path="myclothes" name="blue shirt" description="Awesome blue shirt">
void add(AIVisualParamIDValuePair const& visual_param_id_value_pair) { mParams.push_back(visual_param_id_value_pair); }
void add(AITextureIDUUIDPair const& texture_id_uuid_pair) { mTextures.push_back(texture_id_uuid_pair); }
void toXML(std::ostream& os, int indentation) const;
AIArchetype(AIXMLElementParser const& parser);
};
#endif // AIXMLLINDENGENEPOOL_H

View File

@@ -53,8 +53,9 @@
#include "llvoavatarself.h"
#include "statemachine/aifilepicker.h"
#include "llxmltree.h"
#include "hippogridmanager.h"
#include "aixmllindengenepool.h"
#include "aifile.h"
using namespace LLAvatarAppearanceDefines;
@@ -330,215 +331,117 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker)
LLPanelEditWearable* panel_edit_wearable = getCurrentWearablePanel();
LLViewerWearable* edit_wearable = panel_edit_wearable->getWearable();
LLWearableType::EType panel_wearable_type = panel_edit_wearable->getType();
std::string label = utf8str_tolower(panel_edit_wearable->getLabel());
std::string const filename = filepicker->getFilename();
LLSD args(LLSD::emptyMap());
args["FILE"] = gDirUtilp->getBaseFileName(filename);
LLXmlTree xml;
BOOL success = xml.parseFile(filename, FALSE);
if (!success)
{
LLNotificationsUtil::add("AIXMLImportParseError", args);
return;
}
LLXmlTreeNode* root = xml.getRoot();
if (!root)
{
llwarns << "No root node found in wearable import file: " << filename << llendl;
LLNotificationsUtil::add("AIXMLImportParseError", args);
return;
}
//-------------------------------------------------------------------------
// <linden_genepool version="1.0" [metaversion="?"]> (root)
//-------------------------------------------------------------------------
if (!root->hasName("linden_genepool"))
{
llwarns << "Invalid wearable import file (missing linden_genepool header): " << filename << llendl;
LLNotificationsUtil::add("AIXMLImportRootTypeError", args);
return;
}
static LLStdStringHandle const version_string = LLXmlTree::addAttributeString("version");
std::string version;
if (!root->getFastAttributeString(version_string, version) || (version != "1.0"))
{
llwarns << "Invalid or incompatible linden_genepool version: " << version << " in file: " << filename << llendl;
args["TAG"] = "version";
args["VERSIONMAJOR"] = "1";
LLNotificationsUtil::add("AIXMLImportRootVersionError", args);
return;
}
static LLStdStringHandle const metaversion_string = LLXmlTree::addAttributeString("metaversion");
std::string metaversion;
U32 metaversion_major;
if (!root->getFastAttributeString(metaversion_string, metaversion))
{
llwarns << "Invalid linden_genepool metaversion: " << metaversion << " in file: " << filename << llendl;
metaversion_major = 0;
}
else if (!LLStringUtil::convertToU32(metaversion, metaversion_major) || metaversion_major > 1)
{
llwarns << "Invalid or incompatible linden_genepool metaversion: " << metaversion << " in file: " << filename << llendl;
args["TAG"] = "metaversion";
args["VERSIONMAJOR"] = "1";
LLNotificationsUtil::add("AIXMLImportRootVersionError", args);
return;
}
//-------------------------------------------------------------------------
// <meta gridnick="secondlife" date="2013-07-20T15:27:55.80Z">
//-------------------------------------------------------------------------
std::string gridnick;
LLDate date;
bool different_grid = false; // By default assume it was exported on the same grid as we're on now.
bool mixed_grids = false; // Set to true if two different grids (might) share UUIDs. Currently only "secondlife" and "secondlife_beta".
if (metaversion_major >= 1)
{
static LLStdStringHandle const gridnick_string = LLXmlTree::addAttributeString("gridnick");
static LLStdStringHandle const date_string = LLXmlTree::addAttributeString("date");
std::string date_s;
bool invalid = true;
LLXmlTreeNode* meta_node = root->getChildByName("meta");
if (!meta_node)
{
llwarns << "No meta (1) in wearable import file: " << filename << llendl;
}
else if (!meta_node->getFastAttributeString(gridnick_string, gridnick))
{
llwarns << "meta tag in file: " << filename << " is missing the 'gridnick' parameter." << llendl;
}
else if (!meta_node->getFastAttributeString(date_string, date_s) || !date.fromString(date_s))
{
llwarns << "meta tag in file: " << filename << " is missing or invalid 'date' parameter." << llendl;
}
else
{
invalid = false;
std::string current_gridnick = gHippoGridManager->getConnectedGrid()->getGridNick();
different_grid = gridnick != current_gridnick;
mixed_grids = (gridnick == "secondlife" && current_gridnick == "secondlife_beta") ||
(gridnick == "secondlife_beta" && current_gridnick == "secondlife");
}
if (invalid)
{
LLNotificationsUtil::add("AIXMLImportInvalidError", args);
return;
}
}
static LLStdStringHandle const name_string = LLXmlTree::addAttributeString("name");
//-------------------------------------------------------------------------
// <archetype name="???">
//-------------------------------------------------------------------------
LLXmlTreeNode* archetype_node = root->getChildByName("archetype");
if (!archetype_node)
{
llwarns << "No archetype in wearable import file: " << filename << llendl;
LLNotificationsUtil::add("AIXMLImportInvalidError", args);
return;
}
// Legacy that name="" exists. Using it as human (only) readable type label of contents. Don't use it for anything else because it might not be set.
std::string label = "???";
if (metaversion_major >= 1)
{
if (!archetype_node->getFastAttributeString(name_string, label))
{
llwarns << "archetype tag in file: " << filename << " is missing the 'name' parameter." << llendl;
}
}
//-------------------------------------------------------------------------
// <meta path="Clothing" name="New Shirt27" description="Some description"/>
//-------------------------------------------------------------------------
std::string path;
std::string wearable_name;
std::string wearable_description;
if (metaversion_major >= 1)
{
static LLStdStringHandle const path_string = LLXmlTree::addAttributeString("path");
static LLStdStringHandle const description_string = LLXmlTree::addAttributeString("description");
bool invalid = true;
LLXmlTreeNode* meta_node = archetype_node->getChildByName("meta");
if (!meta_node)
{
llwarns << "No meta (2) in wearable import file: " << filename << llendl;
}
else if (!meta_node->getFastAttributeString(path_string, path))
{
llwarns << "meta tag in file: " << filename << " is missing the 'path' parameter." << llendl;
}
else if (!meta_node->getFastAttributeString(name_string, wearable_name))
{
llwarns << "meta tag in file: " << filename << " is missing the 'name' parameter." << llendl;
}
else if (!meta_node->getFastAttributeString(description_string, wearable_description))
{
llwarns << "meta tag in file: " << filename << " is missing the 'description' parameter." << llendl;
}
else
{
invalid = false;
}
if (invalid)
{
LLNotificationsUtil::add("AIXMLImportInvalidError", args);
return;
}
}
// Parse the XML content.
static LLStdStringHandle const id_string = LLXmlTree::addAttributeString("id");
static LLStdStringHandle const value_string = LLXmlTree::addAttributeString("value");
static LLStdStringHandle const te_string = LLXmlTree::addAttributeString("te");
static LLStdStringHandle const uuid_string = LLXmlTree::addAttributeString("uuid");
bool found_param = false;
bool found_texture = false;
for(LLXmlTreeNode* child = archetype_node->getFirstChild(); child; child = archetype_node->getNextChild())
bool found_type = false;
bool different_grid = false; // By default assume it was exported on the same grid as we're on now.
bool mixed_grids = false; // Set to true if two different grids (might) share UUIDs. Currently only "secondlife" and "secondlife_beta".
std::string gridnick;
std::string wearable_types;
try
{
if (child->hasName("param"))
//-------------------------------------------------------------------------
// <linden_genepool version="1.0" [metaversion="?"]> (root)
//-------------------------------------------------------------------------
std::string metaversion;
U32 metaversion_major;
AIXMLParser linden_genepool(filename, "wearable import file", "linden_genepool", 1);
linden_genepool.attribute("version", "1.0");
linden_genepool.attribute("metaversion", metaversion);
if (!LLStringUtil::convertToU32(metaversion, metaversion_major) || metaversion_major > 1)
{
std::string id_s;
U32 id;
std::string value_s;
F32 value;
if (!child->getFastAttributeString(id_string, id_s) || !LLStringUtil::convertToU32(id_s, id) ||
!child->getFastAttributeString(value_string, value_s) || !LLStringUtil::convertToF32(value_s, value))
{
llwarns << "Possible syntax error or corruption for <param id=... value=... /> node in " << filename << llendl;
continue;
}
LLVisualParam* visual_param = edit_wearable->getVisualParam(id);
if (visual_param)
{
found_param = true;
visual_param->setWeight(value, FALSE);
}
llwarns << "Invalid or incompatible linden_genepool metaversion: " << metaversion << " in file: " << filename << llendl;
args["TAG"] = "metaversion";
args["VERSIONMAJOR"] = "1";
LLNotificationsUtil::add("AIXMLImportRootVersionError", args);
return;
}
else if (child->hasName("texture"))
//-------------------------------------------------------------------------
// <meta gridnick="secondlife" date="2013-07-20T15:27:55.80Z">
//-------------------------------------------------------------------------
AIXMLLindenGenepool::MetaData meta_data;
if (metaversion_major >= 1)
{
std::string te_s;
S32 te;
std::string uuid_s;
LLUUID uuid;
if (!child->getFastAttributeString(te_string, te_s) || !LLStringUtil::convertToS32(te_s, te) || te < 0 || te >= TEX_NUM_INDICES ||
!child->getFastAttributeString(uuid_string, uuid_s) || !uuid.set(uuid_s, TRUE))
linden_genepool.child("meta", meta_data);
std::string current_gridnick = gHippoGridManager->getConnectedGrid()->getGridNick();
gridnick = meta_data.mGridNick;
different_grid = gridnick != current_gridnick;
mixed_grids = (gridnick == "secondlife" && current_gridnick == "secondlife_beta") ||
(gridnick == "secondlife_beta" && current_gridnick == "secondlife");
}
std::vector<AIArchetype> archetypes;
linden_genepool.setVersion(metaversion_major);
linden_genepool.push_back_children("archetype", archetypes);
if (archetypes.empty())
{
THROW_ALERT("AIXMLImportNoArchetypeError", AIArgs("[FILE]", filename));
}
for (std::vector<AIArchetype>::iterator archetype = archetypes.begin(); archetype != archetypes.end(); ++archetype)
{
LLWearableType::EType type = archetype->getType();
if (type != LLWearableType::WT_NONE)
{
llwarns << "Possible syntax error or corruption for <texture te=... uuid=... /> node in " << filename << llendl;
continue;
}
ETextureIndex te_index = (ETextureIndex)te;
LLWearableType::EType te_wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(te_index);
if (te_wearable_type == edit_wearable->getType())
{
found_texture = true;
if (!different_grid || mixed_grids)
if (!wearable_types.empty())
{
panel_edit_wearable->setNewImageID(te_index, uuid);
wearable_types += "/";
}
wearable_types += LLWearableType::getTypeName(type);
if (panel_wearable_type == type)
{
found_type = true;
}
}
for (AIArchetype::params_type::const_iterator param = archetype->getParams().begin(); param != archetype->getParams().end(); ++param)
{
LLVisualParam* visual_param = edit_wearable->getVisualParam(param->getID());
if (visual_param)
{
found_param = true;
visual_param->setWeight(param->getValue(), FALSE);
}
}
for (AIArchetype::textures_type::const_iterator texture = archetype->getTextures().begin(); texture != archetype->getTextures().end(); ++texture)
{
U32 te = texture->getID();
if (te >= TEX_NUM_INDICES)
{
}
ETextureIndex te_index = (ETextureIndex)te;
LLWearableType::EType te_wearable_type = LLAvatarAppearanceDictionary::getTEWearableType(te_index);
if (te_wearable_type == edit_wearable->getType())
{
found_texture = true;
if (!different_grid || mixed_grids)
{
panel_edit_wearable->setNewImageID(te_index, texture->getUUID());
}
}
}
}
}
catch (AIAlert const& alert)
{
LLNotificationsUtil::add(AIAlert(AIAlertPrefix(), AIAlert::modal, "AIXMLImportError", AIArgs("[TYPE]", label), alert));
return;
}
if (found_param || found_texture)
{
edit_wearable->writeToAvatar(gAgentAvatarp);
@@ -558,10 +461,15 @@ void LLFloaterCustomize::onBtnImport_continued(AIFilePicker* filepicker)
}
}
}
else
else if (found_type)
{
args["TYPE"] = panel_edit_wearable->LLPanel::getLabel();
args["ARCHETYPENAME"] = label;
args["TYPE"] = label;
LLNotificationsUtil::add("AIXMLImportEmptyArchetype", args);
}
else if (!wearable_types.empty())
{
args["TYPE"] = label;
args["ARCHETYPENAME"] = wearable_types;
LLNotificationsUtil::add("AIXMLImportWearableTypeMismatch", args);
}
}
@@ -615,21 +523,29 @@ void LLFloaterCustomize::onBtnExport_continued(LLViewerWearable* edit_wearable,
}
std::string filename = filepicker->getFilename();
LLSD args(LLSD::emptyMap());
args["FILE"] = filename;
LLAPRFile outfile;
outfile.open(filename, LL_APR_WB);
if (!outfile.getFileHandle())
bool success = false;
try
{
llwarns << "Could not open \"" << filename << "\" for writing." << llendl;
LLNotificationsUtil::add("AIXMLExportWriteError", args);
return;
LLFILE* outfile = AIFile::fopen(filename, "wb");
AIXMLLindenGenepool linden_genepool(outfile);
linden_genepool.child(edit_wearable->getArchetype());
AIFile::close(outfile);
success = true;
}
catch (AIAlert const& alert)
{
LLNotificationsUtil::add(AIAlert(AIAlertPrefix(), AIAlert::modal, "AIXMLExportWriteError", AIArgs("[FILE]", filename), alert));
}
LLVOAvatar::dumpArchetypeXML_header(outfile, edit_wearable->getTypeName());
edit_wearable->archetypeExport(outfile);
LLVOAvatar::dumpArchetypeXML_footer(outfile);
if (success)
{
LLSD args(LLSD::emptyMap());
args["FILE"] = filename;
LLNotificationsUtil::add("AIXMLExportSuccess", args);
}
}
void LLFloaterCustomize::onBtnOk()

View File

@@ -40,6 +40,7 @@
#include "llviewerregion.h"
#include "llinventoryobserver.h"
#include "llinventoryfunctions.h"
#include "aixmllindengenepool.h"
using namespace LLAvatarAppearanceDefines;
@@ -134,32 +135,18 @@ LLWearable::EImportResult LLViewerWearable::importStream( std::istream& input_st
return result;
}
extern void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value);
void LLViewerWearable::archetypeExport(LLAPRFile& file) const
AIArchetype LLViewerWearable::getArchetype(void) const
{
apr_file_t* fp = file.getFileHandle();
std::string path;
append_path_short(mItemID, path);
apr_file_printf(fp, " <meta path=\"%s\" name=\"%s\" description=\"%s\"/>\n",
LLXMLNode::escapeXML(path).c_str(),
LLXMLNode::escapeXML(mName).c_str(),
LLXMLNode::escapeXML(mDescription).c_str());
AIArchetype archetype(this);
for (visual_param_index_map_t::const_iterator iter = mVisualParamIndexMap.begin(); iter != mVisualParamIndexMap.end(); ++iter)
{
LLVisualParam const* param = iter->second;
dump_visual_param(file, param, param->getWeight());
archetype.add(AIVisualParamIDValuePair(iter->second));
}
for (te_map_t::const_iterator iter = mTEMap.begin(); iter != mTEMap.end(); ++iter)
{
S32 te = iter->first;
LLUUID const& image_id = iter->second->getID();
apr_file_printf(fp, " <texture te=\"%i\" uuid=\"%s\"/>\n", te, image_id.asString().c_str());
archetype.add(AITextureIDUUIDPair(iter->first, iter->second->getID()));
}
apr_file_printf(fp, "\n");
return archetype;
}
// Avatar parameter and texture definitions can change over time.

View File

@@ -29,6 +29,7 @@
#include "llwearable.h"
#include "llavatarappearancedefines.h"
#include "aixmllindengenepool.h"
class LLVOAvatar;
class LLAPRFile;
@@ -67,8 +68,9 @@ public:
/*virtual*/ EImportResult importStream( std::istream& input_stream, LLAvatarAppearance* avatarp );
void archetypeExport(LLAPRFile& file) const;
// Singu extension.
AIArchetype getArchetype(void) const;
void setParamsToDefaults();
void setTexturesToDefaults();

View File

@@ -112,6 +112,8 @@
#include "llfloaterexploreanimations.h"
#include "aihttptimeoutpolicy.h"
#include "aixmllindengenepool.h"
#include "aifile.h"
#include "llavatarname.h"
@@ -7676,29 +7678,10 @@ bool LLVOAvatar::visualParamWeightsAreDefault()
void dump_visual_param(LLAPRFile& file, LLVisualParam const* viewer_param, F32 value)
{
std::string type_string = "unknown";
if (dynamic_cast<LLTexLayerParamAlpha const*>(viewer_param))
type_string = "param_alpha";
if (dynamic_cast<LLTexLayerParamColor const*>(viewer_param))
type_string = "param_color";
if (dynamic_cast<LLDriverParam const*>(viewer_param))
type_string = "param_driver";
if (dynamic_cast<LLPolyMorphTarget const*>(viewer_param))
type_string = "param_morph";
if (dynamic_cast<LLPolySkeletalDistortion const*>(viewer_param))
type_string = "param_skeleton";
S32 wtype = -1;
LLViewerVisualParam const* vparam = dynamic_cast<LLViewerVisualParam const*>(viewer_param);
if (vparam)
{
wtype = vparam->getWearableType();
}
S32 u8_value = F32_to_U8(value,viewer_param->getMinWeight(),viewer_param->getMaxWeight());
apr_file_printf(file.getFileHandle(), " <param id=\"%d\" name=\"%s\" value=\"%.3f\" u8=\"%d\" type=\"%s\" wearable=\"%s\"/>\n",
viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, type_string.c_str(),
LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()
// param_location_name(vparam->getParamLocation()).c_str()
);
viewer_param->getID(), viewer_param->getName().c_str(), value, u8_value, viewer_param->getTypeString(),
viewer_param->getDumpWearableTypeName().c_str());
}
void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
@@ -8356,127 +8339,83 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
dumpArchetypeXML_cont(fullpath, group_by_wearables);
}
// metaversion 1.0
// ===============
//
// Added as child of <linden_genepool>:
//
// <meta gridnick="secondlife" date="2013-07-16T16:49:00.40Z"/>
//
// Optionally, as child of <archetype>, the following node may appear:
//
// <meta path="clothing/jackets" name="Purple jacket" description="A jacket with mainly the color purple">
//
// Furthermore, metaversion 1.0 and higher allow the occurance of one or more <archetype> blocks.
// If this is used then it is strongly advised to use one <archetype> per wearable, so that
// the the <meta> node makes sense (it then refers to the wearable of that <archetype>).
//
// The reason for this clumsy way to link wearable to extra meta data is to stay
// compatible with the older format (no metaversion).
//
//static
void LLVOAvatar::dumpArchetypeXML_header(LLAPRFile& file, std::string const& archetype_name)
{
apr_file_t* fp = file.getFileHandle();
apr_file_printf(fp, "<?xml version=\"1.0\" encoding=\"US-ASCII\" standalone=\"yes\"?>\n");
apr_file_printf(fp, "<linden_genepool version=\"1.0\" metaversion=\"1.0\">\n");
apr_file_printf(fp, " <meta gridnick=\"%s\" date=\"%s\"/>\n",
LLXMLNode::escapeXML(gHippoGridManager->getConnectedGrid()->getGridNick()).c_str(),
LLDate::now().asString().c_str());
apr_file_printf(fp, " <archetype name=\"%s\">\n", archetype_name.c_str());
}
//static
void LLVOAvatar::dumpArchetypeXML_footer(LLAPRFile& file)
{
apr_file_t* fp = file.getFileHandle();
apr_file_printf(fp, " </archetype>\n");
apr_file_printf(fp, "</linden_genepool>\n");
}
void LLVOAvatar::dumpArchetypeXML_cont(std::string const& fullpath, bool group_by_wearables)
{
LLAPRFile outfile;
outfile.open(fullpath, LL_APR_WB );
apr_file_t* file = outfile.getFileHandle();
if (!file)
try
{
return;
AIFile outfile(fullpath, "wb");
AIXMLLindenGenepool linden_genepool(outfile);
if (group_by_wearables)
{
for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++)
{
AIArchetype archetype((LLWearableType::EType)type);
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
{
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
if( (viewer_param->getWearableType() == type) &&
(viewer_param->isTweakable() ) )
{
archetype.add(AIVisualParamIDValuePair(param));
}
}
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
{
if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)
{
// MULTIPLE_WEARABLES: extend to multiple wearables?
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
if( te_image )
{
archetype.add(AITextureIDUUIDPair(te, te_image->getID()));
}
}
}
linden_genepool.child(archetype);
}
}
else
{
// Just dump all params sequentially.
AIArchetype archetype; // Legacy: Type is set to WT_NONE and will result in <archetype name="???">.
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
{
archetype.add(AIVisualParamIDValuePair(param));
}
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
{
{
// MULTIPLE_WEARABLES: extend to multiple wearables?
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
if( te_image )
{
archetype.add(AITextureIDUUIDPair(te, te_image->getID()));
}
}
}
linden_genepool.child(archetype);
}
#if 0 // Wasn't used anyway.
bool ultra_verbose = false;
if (isSelf() && ultra_verbose)
{
// show the cloned params inside the wearables as well.
gAgentAvatarp->dumpWearableInfo(outfile);
}
#endif
}
else
catch(AIAlert const& alert)
{
llinfos << "xmlfile write handle obtained : " << fullpath << llendl;
LLNotificationsUtil::add(AIAlert(AIAlertPrefix(), AIAlert::modal, "AIXMLdumpArchetypeXMLError", AIArgs("[FILENAME]", fullpath), alert));
}
LLVOAvatar::dumpArchetypeXML_header(outfile);
if (group_by_wearables)
{
for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++)
{
const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
{
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
if( (viewer_param->getWearableType() == type) &&
(viewer_param->isTweakable() ) )
{
dump_visual_param(outfile, viewer_param, viewer_param->getWeight());
}
}
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
{
if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)
{
// MULTIPLE_WEARABLES: extend to multiple wearables?
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
if( te_image )
{
std::string uuid_str;
te_image->getID().toString( uuid_str );
apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
}
}
}
}
}
else
{
// Just dump all params sequentially.
for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
{
LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
dump_visual_param(outfile, viewer_param, viewer_param->getWeight());
}
for (U8 te = 0; te < TEX_NUM_INDICES; te++)
{
{
// MULTIPLE_WEARABLES: extend to multiple wearables?
LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
if( te_image )
{
std::string uuid_str;
te_image->getID().toString( uuid_str );
apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
}
}
}
}
LLVOAvatar::dumpArchetypeXML_footer(outfile);
bool ultra_verbose = false;
if (isSelf() && ultra_verbose)
{
// show the cloned params inside the wearables as well.
gAgentAvatarp->dumpWearableInfo(outfile);
}
// File will close when handle goes out of scope
}
void LLVOAvatar::setVisibilityRank(U32 rank)

View File

@@ -69,18 +69,8 @@
</form>
</template>
<notification name="AIXMLExportWriteError">Export Failure: could not open file "[FILE]" for writing.</notification>
<notification name="AIXMLImportGridMismatch">Import Warning: could not apply textures: [FILE] was exported on grid "[GRIDNAME]" while the currentgrid is "[CURGRID]".</notification>
<notification name="AIXMLImportParseError">Import Failure: could not read or parse wearable import file "[FILE]".</notification>
<notification name="AIXMLImportRootTypeError">Import Failure: the file "[FILE]" is not a linden_genepool XML file.</notification>
<notification name="AIXMLImportRootVersionError">Import Failure: the file "[FILE]" contains linden_genepool XML data with the wrong [TAG]. Version "[VERSIONMAJOR].0" or less is required.</notification>
<notification name="AIXMLImportInvalidError">Import Failure: the file "[FILE]" contains invalid data.</notification>
<notification name="AIXMLImportDifferentGrid">Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have NOT been applied!</notification>
<notification name="AIXMLImportMixedGrid">Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have been applied but might not exist here!</notification>

View File

@@ -149,30 +149,9 @@
<notification
icon="alertmodal.tga"
name="AIXMLExportWriteError"
name="AIXMLExportSuccess"
type="alertmodal">
Export Failure: could not open file &quot;[FILE]&quot; for writing.
</notification>
<notification
icon="alert.tga"
name="AIXMLImportGridMismatch"
type="alert">
Import Warning: could not apply textures: [FILE] was exported on grid &quot;[GRIDNAME]&quot; while the currentgrid is &quot;[CURGRID]&quot;.
</notification>
<notification
icon="alertmodal.tga"
name="AIXMLImportParseError"
type="alertmodal">
Import Failure: could not read or parse wearable import file &quot;[FILE]&quot;.
</notification>
<notification
icon="alertmodal.tga"
name="AIXMLImportRootTypeError"
type="alertmodal">
Import Failure: the file &quot;[FILE]&quot; is not a linden_genepool XML file.
Successfully exported wearable to &quot;[FILE]&quot;.
</notification>
<notification
@@ -182,13 +161,6 @@ Import Failure: the file &quot;[FILE]&quot; is not a linden_genepool XML file.
Import Failure: the file &quot;[FILE]&quot; contains linden_genepool XML data with the wrong [TAG]. Version &quot;[VERSIONMAJOR].0&quot; or less is required.
</notification>
<notification
icon="alertmodal.tga"
name="AIXMLImportInvalidError"
type="alertmodal">
Import Failure: the file &quot;[FILE]&quot; contains invalid data.
</notification>
<notification
icon="alertmodal.tga"
name="AIXMLImportDifferentGrid"
@@ -203,11 +175,19 @@ Import was successful but note that the wearable was exported on grid [EXPORTGRI
Import was successful but note that the wearable was exported on grid [EXPORTGRID] (and the current grid is [CURRENTGRID]). Texture UUIDs have been applied but might not exist here!
</notification>
<notification
icon="alert.tga"
name="AIXMLImportEmptyArchetype"
type="alert">
Import warning: the file &quot;[FILE]&quot; contains a wearable of the selected type ([TYPE]),
but contains no parameters or textures for that type. Nothing was imported.
</notification>
<notification
icon="alert.tga"
name="AIXMLImportWearableTypeMismatch"
type="alert">
Import Warning: the file &quot;[FILE]&quot; does not contain a wearable of type [TYPE].
Import warning: the file &quot;[FILE]&quot; does not contain a wearable of type [TYPE].
It contains an archetype of type [ARCHETYPENAME]. Please select the correct type before importing.
</notification>

View File

@@ -4400,4 +4400,13 @@ Try enclosing path to the editor with double quotes.
<string name="AIXMLElementParser_read_child_Invalid_uuid_in_FILEDESC_FILENAME">Invalid UUID in [FILEDESC] &quot;[FILENAME]&quot;.</string>
<string name="AIXMLElementParser_read_child_Invalid_date_DATE_in_FILEDESC_FILENAME">Invalid DATE ([DATE]) in [FILEDESC] &quot;[FILENAME]&quot;.</string>
<!-- AIArchetype exception alerts -->
<string name="AIArchetype_archetype_has_no_meta">archetype has no &lt;meta&gt; element.</string>
<string name="AIArchetype_MetaData_archetype_meta_has_no_ATTRIBUTE">archetype &lt;meta&gt; element has no &apos;[ATTRIBUTE]&apos; attribute.</string>
<string name="AIXMLdumpArchetypeXMLError">Failure dumping archetype to &quot;[FILENAME]&quot;:</string>
<string name="AIXMLExportWriteError">The export to file &quot;[FILE]&quot; failed:</string>
<string name="AIXMLImportError">Failed to import the [TYPE] wearable:</string>
<string name="AIXMLImportNoArchetypeError">No archetype found in wearable import file &quot;[FILE]&quot;.</string>
</strings>

View File

@@ -73,30 +73,10 @@
</form>
</template>
<notification name="AIXMLExportWriteError">
Fallo de Exportación: no se puede abrir el archivo &quot;[FILE]&quot; para escritura.
</notification>
<notification name="AIXMLImportGridMismatch">
Aviso de Importación: No se pueden aplicar las texturas: El [FILE] fue exportado en el grid &quot;[GRIDNAME]&quot; mientras que el grid actual es &quot;[CURGRID]&quot;.
</notification>
<notification name="AIXMLImportParseError">
Fallo de Importación: no se puede leer o analizar el archivo de vestimenta para importar &quot;[FILE]&quot;.
</notification>
<notification name="AIXMLImportRootTypeError">
Fallo de Importación: el archivo &quot;[FILE]&quot; no es un archivo linden_genepool XML.
</notification>
<notification name="AIXMLImportRootVersionError">
Fallo de Importación: el archivo &quot;[FILE]&quot; contiene datos linden_genepool XML con [TAG] erróneo. Se requiere Versión &quot;[VERSIONMAJOR].0&quot; o inferior.
</notification>
<notification name="AIXMLImportInvalidError">
Fallo de Importación: el archivo &quot;[FILE]&quot; contiene datos inválidos.
</notification>
<notification name="AIXMLImportDifferentGrid">
La importación se ha realizado con exito, pero ten presente que el objeto vestible fue exportado desde el grid [EXPORTGRID] (y el grid actual es [CURRENTGRID]). ¡No se aplicaron las UUIDs de las Texturas!
</notification>