Files
libremetaverse/libsecondlife-cs/AssetSystem/AssetWearable.cs
Michael Cortez 0e82e60c7e * AssetWearable should use TryParse() and default value if failed...
* Provide a ghetto work around for what appears to be a bug in SL introduced during one of the last two grid updates.

git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@1022 52acb1d6-8a22-11de-b505-999d5b087335
2007-03-02 00:29:56 +00:00

541 lines
19 KiB
C#

/*
* Copyright (c) 2006, Second Life Reverse Engineering Team
* All rights reserved.
*
* - Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Neither the name of the Second Life Reverse Engineering Team nor the names
* of its contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Threading;
using System.Globalization;
using libsecondlife;
namespace libsecondlife.AssetSystem
{
/// <summary>
/// Asset for wearables such as Socks, Eyes, Gloves, Hair, Pants, Shape, Shirt, Shoes, Skin, Jacket, Skirt, Underpants
/// </summary>
public class AssetWearable : Asset
{
private string _Name = "";
public string Name
{
get { return _Name; }
set
{
_Name = value;
UpdateAssetData();
}
}
private string _Description = "";
public string Description
{
get { return _Description; }
set
{
_Description = value;
UpdateAssetData();
}
}
private AppearanceLayerType _AppearanceLayer = 0;
public AppearanceLayerType AppearanceLayer
{
get { return _AppearanceLayer; }
set
{
_AppearanceLayer = value;
UpdateAssetData();
}
}
private string _Sale_Type = "not";
public string Sale_Type
{
get { return _Sale_Type; }
set
{
_Sale_Type = value;
UpdateAssetData();
}
}
private uint _Sale_Price = 10;
public uint Sale_Price
{
get { return _Sale_Price; }
set
{
_Sale_Price = value;
UpdateAssetData();
}
}
private LLUUID _Creator_ID = new LLUUID();
public LLUUID Creator_ID
{
get { return _Creator_ID; }
set
{
_Creator_ID = value;
UpdateAssetData();
}
}
private LLUUID _Owner_ID = new LLUUID();
public LLUUID Owner_ID
{
get { return _Owner_ID; }
set
{
_Owner_ID = value;
UpdateAssetData();
}
}
private LLUUID _Last_Owner_ID = new LLUUID();
public LLUUID Last_Owner_ID
{
get { return _Last_Owner_ID; }
set
{
_Last_Owner_ID = value;
UpdateAssetData();
}
}
private LLUUID _Group_ID = new LLUUID();
public LLUUID Group_ID
{
get { return _Group_ID; }
set
{
_Group_ID = value;
UpdateAssetData();
}
}
private bool _Group_Owned = false;
public bool Group_Owned
{
get { return _Group_Owned; }
set
{
_Group_Owned = value;
UpdateAssetData();
}
}
private uint _Permission_Base_Mask = 0;
public uint Permission_Base_Mask
{
get { return _Permission_Base_Mask; }
set
{
_Permission_Base_Mask = value;
UpdateAssetData();
}
}
private uint _Permission_Owner_Mask = 0;
public uint Permission_Owner_Mask
{
get { return _Permission_Owner_Mask; }
set
{
_Permission_Owner_Mask = value;
UpdateAssetData();
}
}
private uint _Permission_Group_Mask = 0;
public uint Permission_Group_Mask
{
get { return _Permission_Group_Mask; }
set
{
_Permission_Group_Mask = value;
UpdateAssetData();
}
}
private uint _Permission_Everyone_Mask = 0;
public uint Permission_Everyone_Mask
{
get { return _Permission_Everyone_Mask; }
set
{
_Permission_Everyone_Mask = value;
UpdateAssetData();
}
}
private uint _Permission_Next_Owner_Mask = 0;
public uint Permission_Next_Owner_Mask
{
get { return _Permission_Next_Owner_Mask; }
set
{
_Permission_Next_Owner_Mask = value;
UpdateAssetData();
}
}
private Dictionary<int, float> _Parameters = new Dictionary<int, float>();
public Dictionary<int, float> Parameters
{
get { return _Parameters; }
set
{
_Parameters = value;
UpdateAssetData();
}
}
private Dictionary<uint, LLUUID> _Textures = new Dictionary<uint, LLUUID>();
public Dictionary<uint, LLUUID> Textures
{
get { return _Textures; }
set
{
_Textures = value;
UpdateAssetData();
}
}
private string[] _ForSaleNames = new string[]
{
"not",
"orig",
"copy",
"cntn"
};
private enum _ForSale
{
/// <summary>Not for sale</summary>
Not = 0,
/// <summary>The original is for sale</summary>
Original = 1,
/// <summary>Copies are for sale</summary>
Copy = 2,
/// <summary>The contents of the object are for sale</summary>
Contents = 3
}
private _ForSale _Sale = _ForSale.Not;
private int _SalePrice = 0;
public enum AppearanceLayerType : byte
{
/// <summary></summary>
Shape = 0,
/// <summary></summary>
Skin,
/// <summary></summary>
Hair,
/// <summary></summary>
Eyes,
/// <summary></summary>
Shirt,
/// <summary></summary>
Pants,
/// <summary></summary>
Shoes,
/// <summary></summary>
Socks,
/// <summary></summary>
Jacket,
/// <summary></summary>
Gloves,
/// <summary></summary>
Undershirt,
/// <summary></summary>
Underpants,
/// <summary></summary>
Skirt,
/// <summary></summary>
Invalid = 255
};
/// <summary>
/// </summary>
/// <param name="assetID"></param>
/// <param name="assetData"></param>
public AssetWearable(LLUUID assetID, sbyte assetType, byte[] assetData)
: base(assetID, assetType, false, assetData)
{
UpdateFromAssetData();
}
/// <summary>
/// Converts byte[] data from a data transfer into a bodypart class
/// </summary>
/// <returns></returns>
internal void UpdateFromAssetData()
{
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us");
if ( AssetData == null || AssetData.Length == 0)
{
return;
}
string wearableData = Helpers.FieldToUTF8String(this._AssetData);
int version = -1;
int n = -1;
try
{
n = wearableData.IndexOf('\n');
version = Int32.Parse(wearableData.Substring(19, n - 18));
wearableData = wearableData.Remove(0, n);
if (version != 22)
{
Console.WriteLine("** WARNING ** : Wearable asset has unrecognized version " + version);
return;
}
n = wearableData.IndexOf('\n');
Name = wearableData.Substring(0, n);
wearableData = wearableData.Remove(0, n);
n = wearableData.IndexOf('\n');
Description = wearableData.Substring(0, n);
wearableData = wearableData.Remove(0, n);
// Split in to an upper and lower half
string[] parts = wearableData.Split(new string[] { "parameters" }, StringSplitOptions.None);
parts[1] = "parameters" + parts[1];
// Parse the upper half
string[] lines = parts[0].Split('\n');
foreach (string thisline in lines)
{
string line = thisline.Trim();
string[] fields = line.Split('\t');
if (fields.Length == 2)
{
if (fields[0] == "creator_mask")
{
// Deprecated, apply this as the base mask
_Permission_Base_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
}
else if (fields[0] == "base_mask")
{
_Permission_Base_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
}
else if (fields[0] == "owner_mask")
{
_Permission_Owner_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
}
else if (fields[0] == "group_mask")
{
_Permission_Group_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
}
else if (fields[0] == "everyone_mask")
{
_Permission_Everyone_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
}
else if (fields[0] == "next_owner_mask")
{
_Permission_Next_Owner_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
}
else if (fields[0] == "creator_id")
{
_Creator_ID = new LLUUID(fields[1]);
}
else if (fields[0] == "owner_id")
{
_Owner_ID = new LLUUID(fields[1]);
}
else if (fields[0] == "last_owner_id")
{
_Last_Owner_ID = new LLUUID(fields[1]);
}
else if (fields[0] == "group_id")
{
_Group_ID = new LLUUID(fields[1]);
}
else if (fields[0] == "group_owned")
{
_Group_Owned = (Int32.Parse(fields[1]) != 0);
}
else if (fields[0] == "sale_type")
{
for (int i = 0; i < _ForSaleNames.Length; i++)
{
if (fields[1] == _ForSaleNames[i])
{
_Sale = (_ForSale)i;
break;
}
}
}
else if (fields[0] == "sale_price")
{
_SalePrice = Int32.Parse(fields[1]);
}
else if (fields[0] == "perm_mask")
{
Console.WriteLine("** WARNING ** : Wearable asset has deprecated perm_mask field, ignoring");
}
}
else if (line.StartsWith("type "))
{
AppearanceLayer = (AppearanceLayerType)Int32.Parse(line.Substring(5));
break;
}
}
// Break up the lower half in to parameters and textures
string[] lowerparts = parts[1].Split(new string[] { "textures" }, StringSplitOptions.None);
lowerparts[1] = "textures" + lowerparts[1];
// Parse the parameters
lines = lowerparts[0].Split('\n');
foreach (string line in lines)
{
string[] fields = line.Split(' ');
// Use exception handling to deal with all the lines we aren't interested in
try
{
int id = Int32.Parse(fields[0]);
float weight; Single.Parse(fields[1], System.Globalization.NumberStyles.Float);
if (Single.TryParse(fields[1], System.Globalization.NumberStyles.Float, new CultureInfo("en-us").NumberFormat, out weight) == false)
{
weight = 0.0f;
}
_Parameters[id] = weight;
}
catch (Exception)
{
}
}
// Parse the textures
lines = lowerparts[1].Split('\n');
foreach (string line in lines)
{
string[] fields = line.Split(' ');
// Use exception handling to deal with all the lines we aren't interested in
try
{
uint id = UInt32.Parse(fields[0]);
LLUUID texture = LLUUID.Parse(fields[1]);
_Textures[id] = texture;
}
catch (Exception)
{
}
}
return;
}
catch (Exception e)
{
Console.WriteLine("** WARNING **", "Failed to parse wearable asset: " + e.ToString());
}
return;
}
private void UpdateAssetData()
{
string data = "LLWearable version 22\n";
data += this._Name + "\n\n";
data += "\tpermissions 0\n\t{\n";
data += "\t\tbase_mask\t" + uintToHex(this._Permission_Base_Mask);
data += "\n\t\towner_mask\t" + uintToHex(this._Permission_Owner_Mask);
data += "\n\t\tgroup_mask\t" + uintToHex(this._Permission_Group_Mask);
data += "\n\t\teveryone_mask\t" + uintToHex(this._Permission_Everyone_Mask);
data += "\n\t\tnext_owner_mask\t" + uintToHex(this._Permission_Next_Owner_Mask);
data += "\n\t\tcreator_id\t" + this._Creator_ID.ToStringHyphenated();
data += "\n\t\towner_id\t" + this._Owner_ID.ToStringHyphenated();
data += "\n\t\tlast_owner_id\t" + this._Last_Owner_ID.ToStringHyphenated();
data += "\n\t\tgroup_id\t" + this._Group_ID.ToStringHyphenated();
data += "\n\t}";
data += "\n\tsale_info\t0";
data += "\n\t{";
data += "\n\t\tsale_type\t" + this._Sale_Type;
data += "\n\t\tsale_price\t" + this._Sale_Price;
data += "\n\t}";
data += "\ntype " + this._AppearanceLayer;
data += "\nparameters " + this._Parameters.Count;
foreach (KeyValuePair<int, float> param in this._Parameters)
{
string prm = string.Format("{0:f1}", param.Value);
if (prm == "-1.0" || prm == "1.0" || prm == "0.0")
{
switch (prm)
{
case "-1.0":
prm = "-1";
break;
case "0.0":
prm = "0";
break;
case "1.0":
prm = "1";
break;
}
}
data += "\n" + param.Key + " " + prm;
}
data += "\ntextures " + this._Textures.Count;
foreach (KeyValuePair<uint, LLUUID> texture in this._Textures)
{
data += "\n" + texture.Key + " " + texture.Value.ToStringHyphenated();
}
_AssetData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray());
}
private static string uintToHex(uint i)
{
return string.Format("{0:x8}", i);
}
public override void SetAssetData(byte[] data)
{
_AssetData = data;
if ( (_AssetData != null) && (_AssetData.Length > 0) )
{
UpdateFromAssetData();
}
}
}
}