/*
* 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 libsecondlife;
namespace libsecondlife.AssetSystem
{
///
/// Asset for wearables such as Socks, Eyes, Gloves, Hair, Pants, Shape, Shirt, Shoes, Skin, Jacket, Skirt, Underpants
///
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 _Parameters = new Dictionary();
public Dictionary Parameters
{
get { return _Parameters; }
set
{
_Parameters = value;
UpdateAssetData();
}
}
private Dictionary _Textures = new Dictionary();
public Dictionary Textures
{
get { return _Textures; }
set
{
_Textures = value;
UpdateAssetData();
}
}
private string[] _ForSaleNames = new string[]
{
"not",
"orig",
"copy",
"cntn"
};
private enum _ForSale
{
/// Not for sale
Not = 0,
/// The original is for sale
Original = 1,
/// Copies are for sale
Copy = 2,
/// The contents of the object are for sale
Contents = 3
}
private _ForSale _Sale = _ForSale.Not;
private int _SalePrice = 0;
public enum AppearanceLayerType : byte
{
///
Shape = 0,
///
Skin,
///
Hair,
///
Eyes,
///
Shirt,
///
Pants,
///
Shoes,
///
Socks,
///
Jacket,
///
Gloves,
///
Undershirt,
///
Underpants,
///
Skirt,
///
Invalid = 255
};
///
///
///
///
public AssetWearable(LLUUID assetID, sbyte assetType, byte[] assetData)
: base(assetID, assetType, false, assetData)
{
UpdateFromAssetData();
}
///
/// Converts byte[] data from a data transfer into a bodypart class
///
///
internal void UpdateFromAssetData()
{
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]);
_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 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 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();
}
}
}
}