diff --git a/OpenMetaverse.GUI/MiniMap.cs b/OpenMetaverse.GUI/MiniMap.cs
index 003a86f4..3cecd843 100644
--- a/OpenMetaverse.GUI/MiniMap.cs
+++ b/OpenMetaverse.GUI/MiniMap.cs
@@ -24,11 +24,12 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
-using OpenMetaverse.Imaging;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
+using OpenMetaverse.Imaging;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.GUI
{
diff --git a/OpenMetaverse/AppearanceManager.cs b/OpenMetaverse/AppearanceManager.cs
index 9da5a725..434a72ac 100644
--- a/OpenMetaverse/AppearanceManager.cs
+++ b/OpenMetaverse/AppearanceManager.cs
@@ -32,6 +32,7 @@ using System.IO;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.Imaging;
+using OpenMetaverse.Assets;
namespace OpenMetaverse
{
diff --git a/OpenMetaverse/AssetManager.cs b/OpenMetaverse/AssetManager.cs
index 931fc710..7a97e9cd 100644
--- a/OpenMetaverse/AssetManager.cs
+++ b/OpenMetaverse/AssetManager.cs
@@ -30,6 +30,7 @@ using System.Threading;
using System.IO;
using OpenMetaverse;
using OpenMetaverse.Packets;
+using OpenMetaverse.Assets;
namespace OpenMetaverse
{
diff --git a/OpenMetaverse/AssetTypes.cs b/OpenMetaverse/AssetTypes.cs
deleted file mode 100644
index e3d727d5..00000000
--- a/OpenMetaverse/AssetTypes.cs
+++ /dev/null
@@ -1,784 +0,0 @@
-/*
- * Copyright (c) 2007-2008, openmetaverse.org
- * 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 openmetaverse.org 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.Text;
-using System.Collections.Generic;
-using OpenMetaverse.Imaging;
-
-namespace OpenMetaverse
-{
- ///
- ///
- ///
- [Flags]
- public enum WearableType : byte
- {
- /// A shape
- Shape = 0,
- ///
- Skin,
- ///
- Hair,
- ///
- Eyes,
- ///
- Shirt,
- ///
- Pants,
- ///
- Shoes,
- ///
- Socks,
- ///
- Jacket,
- ///
- Gloves,
- ///
- Undershirt,
- ///
- Underpants,
- ///
- Skirt,
- ///
- Invalid = 255
- };
-
- ///
- /// Base class for all Asset types
- ///
- public abstract class Asset
- {
- /// A byte array containing the raw asset data
- public byte[] AssetData;
- /// True if the asset it only stored on the server temporarily
- public bool Temporary;
- /// A unique ID
- private UUID _AssetID;
- /// The assets unique ID
- public UUID AssetID
- {
- get { return _AssetID; }
- internal set { _AssetID = value; }
- }
-
- ///
- /// The "type" of asset, Notecard, Animation, etc
- ///
- public abstract AssetType AssetType
- {
- get;
- }
-
- ///
- /// Construct a new Asset object
- ///
- public Asset() { }
-
- ///
- /// Construct a new Asset object
- ///
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public Asset(UUID assetID, byte[] assetData)
- {
- _AssetID = assetID;
- AssetData = assetData;
- }
-
- ///
- /// Regenerates the AssetData byte array from the properties
- /// of the derived class.
- ///
- public abstract void Encode();
-
- ///
- /// Decodes the AssetData, placing it in appropriate properties of the derived
- /// class.
- ///
- /// True if the asset decoding succeeded, otherwise false
- public abstract bool Decode();
- }
-
- ///
- /// Represents an Animation
- ///
- public class AssetAnimation : Asset
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Animation; } }
-
- /// Default Constructor
- public AssetAnimation() { }
-
- ///
- /// Construct an Asset object of type Animation
- ///
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetAnimation(UUID assetID, byte[] assetData)
- : base(assetID, assetData)
- {
- AssetData = assetData;
- }
-
- public override void Encode() { }
- public override bool Decode() { return true; }
- }
-
- ///
- /// Represents a string of characters encoded with specific formatting properties
- ///
- public class AssetNotecard : Asset
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Notecard; } }
-
- /// A text string containing the raw contents of the notecard
- public string Text = null;
-
- /// Construct an Asset of type Notecard
- public AssetNotecard() { }
-
- ///
- /// Construct an Asset object of type Notecard
- ///
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetNotecard(UUID assetID, byte[] assetData) : base(assetID, assetData)
- {
- Decode();
- }
-
- ///
- /// Construct an Asset object of type Notecard
- ///
- /// A text string containing the raw contents of the notecard
- public AssetNotecard(string text)
- {
- Text = text;
- Encode();
- }
-
- ///
- /// Encode the raw contents of a string with the specific Linden Text properties
- ///
- public override void Encode()
- {
- string temp = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length ";
- temp += Text.Length + "\n";
- temp += Text;
- temp += "}";
- AssetData = Utils.StringToBytes(temp);
- }
-
- ///
- /// Decode the raw asset data including the Linden Text properties
- ///
- /// true if the AssetData was successfully decoded to a string
- public override bool Decode()
- {
- Text = Utils.BytesToString(AssetData);
- return true;
- }
- }
-
- ///
- /// Represents a Landmark with RegionID and Position vector
- ///
- public class AssetLandmark : Asset
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Landmark; } }
-
- /// UUID of the Landmark target region
- public UUID RegionID = UUID.Zero;
- /// Local position of the target
- public Vector3 Position = Vector3.Zero;
-
- /// Construct an Asset of type Landmark
- public AssetLandmark() { }
-
- ///
- /// Construct an Asset object of type Landmark
- ///
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetLandmark(UUID assetID, byte[] assetData)
- : base(assetID, assetData)
- {
- Decode();
- }
-
- ///
- /// Constuct an asset of type Landmark
- ///
- /// UUID of the target region
- /// Local position of landmark
- public AssetLandmark(UUID regionID, Vector3 pos)
- {
- RegionID = regionID;
- Position = pos;
- Encode();
- }
-
- ///
- /// Encode the raw contents of a string with the specific Landmark format
- ///
- public override void Encode()
- {
- string temp = "Landmark version 2\n";
- temp += "region_id " + RegionID + "\n";
- temp += String.Format("local_pos {0:0.00} {1:0.00} {2:0.00}\n", Position.X, Position.Y, Position.Z);
- AssetData = Utils.StringToBytes(temp);
- }
-
- ///
- /// Decode the raw asset data, populating the RegionID and Position
- ///
- /// true if the AssetData was successfully decoded to a UUID and Vector
- public override bool Decode()
- {
- String text = Utils.BytesToString(AssetData);
- if(text.ToLower().Contains("landmark version 2"))
- {
- RegionID = new UUID(text.Substring(text.IndexOf("region_id") + 10, 36));
- String vecDelim = " ";
- String[] vecStrings = text.Substring(text.IndexOf("local_pos") + 10).Split(vecDelim.ToCharArray());
- if(vecStrings.Length == 3)
- {
- Position = new Vector3(float.Parse(vecStrings[0]), float.Parse(vecStrings[1]), float.Parse(vecStrings[2]));
- return true;
- }
- }
- return false;
- }
- }
-
- ///
- /// Represents an LSL Text object containing a string of UTF encoded characters
- ///
- public class AssetScriptText : Asset
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.LSLText; } }
-
- /// A string of characters represting the script contents
- public string Source;
-
- /// Initializes a new AssetScriptText object
- public AssetScriptText() { }
-
- ///
- /// Initializes a new AssetScriptText object with parameters
- ///
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetScriptText(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
-
- ///
- /// Initializes a new AssetScriptText object with parameters
- ///
- /// A string containing the scripts contents
- public AssetScriptText(string source)
- {
- Source = source;
- }
-
- ///
- /// Encode a string containing the scripts contents into byte encoded AssetData
- ///
- public override void Encode()
- {
- AssetData = Utils.StringToBytes(Source);
- }
-
- ///
- /// Decode a byte array containing the scripts contents into a string
- ///
- /// true if decoding is successful
- public override bool Decode()
- {
- Source = Utils.BytesToString(AssetData);
- return true;
- }
- }
-
- ///
- /// Represents an AssetScriptBinary object containing the
- /// LSO compiled bytecode of an LSL script
- ///
- public class AssetScriptBinary : Asset
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.LSLBytecode; } }
-
- /// Initializes a new instance of an AssetScriptBinary object
- public AssetScriptBinary() { }
-
- /// Initializes a new instance of an AssetScriptBinary object with parameters
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetScriptBinary(UUID assetID, byte[] assetData)
- : base(assetID, assetData)
- {
- AssetData = assetData;
- }
-
- ///
- /// TODO: Encodes a scripts contents into a LSO Bytecode file
- ///
- public override void Encode() { }
-
- ///
- /// TODO: Decode LSO Bytecode into a string
- ///
- /// true
- public override bool Decode() { return true; }
- }
-
- ///
- /// Represents a Sound Asset
- ///
- public class AssetSound : Asset
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Sound; } }
-
- /// Initializes a new instance of an AssetSound object
- public AssetSound() { }
-
- /// Initializes a new instance of an AssetSound object with parameters
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetSound(UUID assetID, byte[] assetData)
- : base(assetID, assetData)
- {
- AssetData = assetData;
- }
-
- ///
- /// TODO: Encodes a sound file
- ///
- public override void Encode() { }
-
- ///
- /// TODO: Decode a sound file
- ///
- /// true
- public override bool Decode() { return true; }
- }
-
- ///
- /// Represents a texture
- ///
- public class AssetTexture : Asset
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Texture; } }
-
- /// A object containing image data
- public ManagedImage Image;
-
- ///
- public OpenJPEG.J2KLayerInfo[] LayerInfo;
-
- ///
- public int Components;
-
- /// Initializes a new instance of an AssetTexture object
- public AssetTexture() { }
-
- ///
- /// Initializes a new instance of an AssetTexture object
- ///
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetTexture(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
-
- ///
- /// Initializes a new instance of an AssetTexture object
- ///
- /// A object containing texture data
- public AssetTexture(ManagedImage image)
- {
- Image = image;
- Components = 0;
- if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
- Components += 3;
- if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
- ++Components;
- if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
- ++Components;
- if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
- ++Components;
- }
-
- ///
- /// Populates the byte array with a JPEG2000
- /// encoded image created from the data in
- ///
- public override void Encode()
- {
- AssetData = OpenJPEG.Encode(Image);
- }
-
- ///
- /// Decodes the JPEG2000 data in AssetData to the
- /// object
- ///
- /// True if the decoding was successful, otherwise false
- public override bool Decode()
- {
- Components = 0;
-
- if (OpenJPEG.DecodeToImage(AssetData, out Image))
- {
- if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
- Components += 3;
- if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
- ++Components;
- if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
- ++Components;
- if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
- ++Components;
-
- return true;
- }
- else
- {
- return false;
- }
- }
-
- ///
- /// Decodes the begin and end byte positions for each quality layer in
- /// the image
- ///
- ///
- public bool DecodeLayerBoundaries()
- {
- return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo, out Components);
- }
- }
-
- ///
- /// Represents a primitive asset
- ///
- public class AssetPrim : Asset
- {
-
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Object; } }
-
- /// Initializes a new instance of an AssetPrim object
- public AssetPrim() { }
-
-
- ///
- /// TODO:
- ///
- public override void Encode() { }
-
- ///
- /// TODO:
- ///
- /// true
- public override bool Decode() { return true; }
- }
-
- ///
- /// Represents a Wearable Asset, Clothing, Hair, Skin, Etc
- ///
- public abstract class AssetWearable : Asset
- {
- /// A string containing the name of the asset
- public string Name = String.Empty;
- /// A string containing a short description of the asset
- public string Description = String.Empty;
- /// The Assets WearableType
- public WearableType WearableType = WearableType.Shape;
- /// The For-Sale status of the object
- public SaleType ForSale;
- /// An Integer representing the purchase price of the asset
- public int SalePrice;
- /// The of the assets creator
- public UUID Creator;
- /// The of the assets current owner
- public UUID Owner;
- /// The of the assets prior owner
- public UUID LastOwner;
- /// The of the Group this asset is set to
- public UUID Group;
- /// True if the asset is owned by a
- public bool GroupOwned;
- /// The Permissions mask of the asset
- public Permissions Permissions;
- /// A Dictionary containing Key/Value pairs of the objects parameters
- public Dictionary Params = new Dictionary();
- /// A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures
- public Dictionary Textures = new Dictionary();
-
- /// Initializes a new instance of an AssetWearable object
- public AssetWearable() { }
-
- /// Initializes a new instance of an AssetWearable object with parameters
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetWearable(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
-
- /// Initializes a new instance of an AssetWearable object with parameters
- /// A string containing the asset parameters
- public AssetWearable(string source)
- {
- AssetData = Utils.StringToBytes(source);
- }
-
- ///
- /// Decode an assets byte encoded data to a string
- ///
- /// true if the asset data was decoded successfully
- public override bool Decode()
- {
- int version = -1;
- Permissions = new Permissions();
- string data = Utils.BytesToString(AssetData);
-
- data = data.Replace("\r", String.Empty);
- string[] lines = data.Split('\n');
- for (int stri = 0; stri < lines.Length; stri++)
- {
- if (stri == 0)
- {
- string versionstring = lines[stri];
- version = Int32.Parse(versionstring.Split(' ')[2]);
- if (version != 22 && version != 18)
- return false;
- }
- else if (stri == 1)
- {
- Name = lines[stri];
- }
- else if (stri == 2)
- {
- Description = lines[stri];
- }
- else
- {
- string line = lines[stri].Trim();
- string[] fields = line.Split('\t');
-
- if (fields.Length == 1)
- {
- fields = line.Split(' ');
- if (fields[0] == "parameters")
- {
- int count = Int32.Parse(fields[1]) + stri;
- for (; stri < count; )
- {
- stri++;
- line = lines[stri].Trim();
- fields = line.Split(' ');
-
- int id = Int32.Parse(fields[0]);
- if (fields[1] == ",")
- fields[1] = "0";
- else
- fields[1] = fields[1].Replace(',', '.');
-
- float weight = float.Parse(fields[1], System.Globalization.NumberStyles.Float,
- Utils.EnUsCulture.NumberFormat);
-
- Params[id] = weight;
- }
- }
- else if (fields[0] == "textures")
- {
- int count = Int32.Parse(fields[1]) + stri;
- for (; stri < count; )
- {
- stri++;
- line = lines[stri].Trim();
- fields = line.Split(' ');
-
- AppearanceManager.TextureIndex id = (AppearanceManager.TextureIndex)Int32.Parse(fields[0]);
- UUID texture = new UUID(fields[1]);
-
- Textures[id] = texture;
- }
- }
- else if (fields[0] == "type")
- {
- WearableType = (WearableType)Int32.Parse(fields[1]);
- }
-
- }
- else if (fields.Length == 2)
- {
- switch (fields[0])
- {
- case "creator_mask":
- // Deprecated, apply this as the base mask
- Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
- break;
- case "base_mask":
- Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
- break;
- case "owner_mask":
- Permissions.OwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
- break;
- case "group_mask":
- Permissions.GroupMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
- break;
- case "everyone_mask":
- Permissions.EveryoneMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
- break;
- case "next_owner_mask":
- Permissions.NextOwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
- break;
- case "creator_id":
- Creator = new UUID(fields[1]);
- break;
- case "owner_id":
- Owner = new UUID(fields[1]);
- break;
- case "last_owner_id":
- LastOwner = new UUID(fields[1]);
- break;
- case "group_id":
- Group = new UUID(fields[1]);
- break;
- case "group_owned":
- GroupOwned = (Int32.Parse(fields[1]) != 0);
- break;
- case "sale_type":
- ForSale = Utils.StringToSaleType(fields[1]);
- break;
- case "sale_price":
- SalePrice = Int32.Parse(fields[1]);
- break;
- case "sale_info":
- // Container for sale_type and sale_price, ignore
- break;
- default:
- return false;
- }
- }
- }
- }
-
- return true;
- }
-
- ///
- /// Encode the assets string represantion into a format consumable by the asset server
- ///
- public override void Encode()
- {
- const string NL = "\n";
-
- StringBuilder data = new StringBuilder("LLWearable version 22\n");
- data.Append(Name); data.Append(NL); data.Append(NL);
- data.Append("\tpermissions 0\n\t{\n");
- data.Append("\t\tbase_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.BaseMask)); data.Append(NL);
- data.Append("\t\towner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.OwnerMask)); data.Append(NL);
- data.Append("\t\tgroup_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.GroupMask)); data.Append(NL);
- data.Append("\t\teveryone_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.EveryoneMask)); data.Append(NL);
- data.Append("\t\tnext_owner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.NextOwnerMask)); data.Append(NL);
- data.Append("\t\tcreator_id\t"); data.Append(Creator.ToString()); data.Append(NL);
- data.Append("\t\towner_id\t"); data.Append(Owner.ToString()); data.Append(NL);
- data.Append("\t\tlast_owner_id\t"); data.Append(LastOwner.ToString()); data.Append(NL);
- data.Append("\t\tgroup_id\t"); data.Append(Group.ToString()); data.Append(NL);
- if (GroupOwned) data.Append("\t\tgroup_owned\t1\n");
- data.Append("\t}\n");
- data.Append("\tsale_info\t0\n");
- data.Append("\t{\n");
- data.Append("\t\tsale_type\t"); data.Append(Utils.SaleTypeToString(ForSale)); data.Append(NL);
- data.Append("\t\tsale_price\t"); data.Append(SalePrice); data.Append(NL);
- data.Append("\t}\n");
- data.Append("type "); data.Append((int)WearableType); data.Append(NL);
-
- data.Append("parameters "); data.Append(Params.Count); data.Append(NL);
- foreach (KeyValuePair param in Params)
- {
- data.Append(param.Key); data.Append(" "); data.Append(Helpers.FloatToTerseString(param.Value)); data.Append(NL);
- }
-
- data.Append("textures "); data.Append(Textures.Count); data.Append(NL);
- foreach (KeyValuePair texture in Textures)
- {
- data.Append((byte)texture.Key); data.Append(" "); data.Append(texture.Value.ToString()); data.Append(NL);
- }
-
- AssetData = Utils.StringToBytes(data.ToString());
- }
- }
-
-
- ///
- /// Represents an that can be worn on an avatar
- /// such as a Shirt, Pants, etc.
- ///
- public class AssetClothing : AssetWearable
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Clothing; } }
-
- /// Initializes a new instance of an AssetScriptBinary object
- public AssetClothing() { }
-
- /// Initializes a new instance of an AssetScriptBinary object with parameters
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetClothing(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
-
- /// Initializes a new instance of an AssetScriptBinary object with parameters
- /// A string containing the Clothings data
- public AssetClothing(string source) : base(source) { }
- }
-
- ///
- /// Represents an that represents an avatars body ie: Hair, Etc.
- ///
- public class AssetBodypart : AssetWearable
- {
- /// Override the base classes AssetType
- public override AssetType AssetType { get { return AssetType.Bodypart; } }
-
- /// Initializes a new instance of an AssetBodyPart object
- public AssetBodypart() { }
-
- /// Initializes a new instance of an AssetBodyPart object with parameters
- /// A unique specific to this asset
- /// A byte array containing the raw asset data
- public AssetBodypart(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
-
-
- /// Initializes a new instance of an AssetBodyPart object with parameters
- /// A string representing the values of the Bodypart
- public AssetBodypart(string source) : base(source) { }
- }
-}
diff --git a/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs b/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs
new file mode 100644
index 00000000..b3ce3da8
--- /dev/null
+++ b/OpenMetaverse/Assets/Archiving/ArchiveConstants.cs
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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.Collections.Generic;
+using OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Constants for the archiving module
+ ///
+ public class ArchiveConstants
+ {
+ ///
+ /// The location of the archive control file
+ ///
+ public static readonly string CONTROL_FILE_PATH = "archive.xml";
+
+ ///
+ /// Path for the assets held in an archive
+ ///
+ public static readonly string ASSETS_PATH = "assets/";
+
+ ///
+ /// Path for the prims file
+ ///
+ public static readonly string OBJECTS_PATH = "objects/";
+
+ ///
+ /// Path for terrains. Technically these may be assets, but I think it's quite nice to split them out.
+ ///
+ public static readonly string TERRAINS_PATH = "terrains/";
+
+ ///
+ /// Path for region settings.
+ ///
+ public static readonly string SETTINGS_PATH = "settings/";
+
+ ///
+ /// The character the separates the uuid from extension information in an archived asset filename
+ ///
+ public static readonly string ASSET_EXTENSION_SEPARATOR = "_";
+
+ ///
+ /// Extensions used for asset types in the archive
+ ///
+ public static readonly IDictionary ASSET_TYPE_TO_EXTENSION = new Dictionary();
+ public static readonly IDictionary EXTENSION_TO_ASSET_TYPE = new Dictionary();
+
+ static ArchiveConstants()
+ {
+ ASSET_TYPE_TO_EXTENSION[AssetType.Animation] = ASSET_EXTENSION_SEPARATOR + "animation.bvh";
+ ASSET_TYPE_TO_EXTENSION[AssetType.Bodypart] = ASSET_EXTENSION_SEPARATOR + "bodypart.txt";
+ ASSET_TYPE_TO_EXTENSION[AssetType.CallingCard] = ASSET_EXTENSION_SEPARATOR + "callingcard.txt";
+ ASSET_TYPE_TO_EXTENSION[AssetType.Clothing] = ASSET_EXTENSION_SEPARATOR + "clothing.txt";
+ ASSET_TYPE_TO_EXTENSION[AssetType.Folder] = ASSET_EXTENSION_SEPARATOR + "folder.txt"; // Not sure if we'll ever see this
+ ASSET_TYPE_TO_EXTENSION[AssetType.Gesture] = ASSET_EXTENSION_SEPARATOR + "gesture.txt";
+ ASSET_TYPE_TO_EXTENSION[AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg";
+ ASSET_TYPE_TO_EXTENSION[AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga";
+ ASSET_TYPE_TO_EXTENSION[AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt";
+ ASSET_TYPE_TO_EXTENSION[AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this
+ ASSET_TYPE_TO_EXTENSION[AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso";
+ ASSET_TYPE_TO_EXTENSION[AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl";
+ ASSET_TYPE_TO_EXTENSION[AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt";
+ ASSET_TYPE_TO_EXTENSION[AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml";
+ ASSET_TYPE_TO_EXTENSION[AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this
+ ASSET_TYPE_TO_EXTENSION[AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this
+ ASSET_TYPE_TO_EXTENSION[AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this
+ ASSET_TYPE_TO_EXTENSION[AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg";
+ ASSET_TYPE_TO_EXTENSION[AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav";
+ ASSET_TYPE_TO_EXTENSION[AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2";
+ ASSET_TYPE_TO_EXTENSION[AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga";
+ ASSET_TYPE_TO_EXTENSION[AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this
+
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = AssetType.Animation;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = AssetType.Bodypart;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "callingcard.txt"] = AssetType.CallingCard;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "clothing.txt"] = AssetType.Clothing;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "folder.txt"] = AssetType.Folder;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "gesture.txt"] = AssetType.Gesture;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = AssetType.ImageJPEG;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = AssetType.ImageTGA;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = AssetType.Landmark;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = AssetType.LostAndFoundFolder;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = AssetType.LSLBytecode;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = AssetType.LSLText;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = AssetType.Notecard;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = AssetType.Object;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = AssetType.RootFolder;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = AssetType.Simstate;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = AssetType.SnapshotFolder;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = AssetType.Sound;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = AssetType.SoundWAV;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = AssetType.Texture;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = AssetType.TextureTGA;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = AssetType.TrashFolder;
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs b/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs
new file mode 100644
index 00000000..d94af687
--- /dev/null
+++ b/OpenMetaverse/Assets/Archiving/AssetsArchiver.cs
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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.IO;
+using System.Reflection;
+using System.Xml;
+using OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Archives assets
+ ///
+ public class AssetsArchiver
+ {
+ ///
+ /// Post a message to the log every x assets as a progress bar
+ ///
+ //static int LOG_ASSET_LOAD_NOTIFICATION_INTERVAL = 50;
+
+ ///
+ /// Archive assets
+ ///
+ protected IDictionary m_assets;
+
+ public AssetsArchiver(IDictionary assets)
+ {
+ m_assets = assets;
+ }
+
+ ///
+ /// Archive the assets given to this archiver to the given archive.
+ ///
+ ///
+ public void Archive(TarArchiveWriter archive)
+ {
+ //WriteMetadata(archive);
+ WriteData(archive);
+ }
+
+ ///
+ /// Write an assets metadata file to the given archive
+ ///
+ ///
+ protected void WriteMetadata(TarArchiveWriter archive)
+ {
+ StringWriter sw = new StringWriter();
+ XmlTextWriter xtw = new XmlTextWriter(sw);
+
+ xtw.Formatting = Formatting.Indented;
+ xtw.WriteStartDocument();
+
+ xtw.WriteStartElement("assets");
+
+ foreach (UUID uuid in m_assets.Keys)
+ {
+ Asset asset = m_assets[uuid];
+
+ if (asset != null)
+ {
+ xtw.WriteStartElement("asset");
+
+ string extension = string.Empty;
+
+ if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.AssetType))
+ {
+ extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.AssetType];
+ }
+
+ xtw.WriteElementString("filename", uuid.ToString() + extension);
+
+ xtw.WriteElementString("name", uuid.ToString());
+ xtw.WriteElementString("description", String.Empty);
+ xtw.WriteElementString("asset-type", asset.AssetType.ToString());
+
+ xtw.WriteEndElement();
+ }
+ }
+
+ xtw.WriteEndElement();
+
+ xtw.WriteEndDocument();
+
+ archive.WriteFile("assets.xml", sw.ToString());
+ }
+
+ ///
+ /// Write asset data files to the given archive
+ ///
+ ///
+ protected void WriteData(TarArchiveWriter archive)
+ {
+ // It appears that gtar, at least, doesn't need the intermediate directory entries in the tar
+ //archive.AddDir("assets");
+
+ int assetsAdded = 0;
+
+ foreach (UUID uuid in m_assets.Keys)
+ {
+ Asset asset = m_assets[uuid];
+
+ string extension = string.Empty;
+
+ if (ArchiveConstants.ASSET_TYPE_TO_EXTENSION.ContainsKey(asset.AssetType))
+ {
+ extension = ArchiveConstants.ASSET_TYPE_TO_EXTENSION[asset.AssetType];
+ }
+ else
+ {
+ Logger.Log(String.Format(
+ "Unrecognized asset type {0} with uuid {1}. This asset will be saved but not reloaded",
+ asset.AssetType, asset.AssetID), Helpers.LogLevel.Warning);
+ }
+
+ asset.Encode();
+
+ archive.WriteFile(
+ ArchiveConstants.ASSETS_PATH + uuid.ToString() + extension,
+ asset.AssetData);
+
+ assetsAdded++;
+ }
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/Archiving/OarFile.cs b/OpenMetaverse/Assets/Archiving/OarFile.cs
new file mode 100644
index 00000000..13e974c2
--- /dev/null
+++ b/OpenMetaverse/Assets/Archiving/OarFile.cs
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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.IO;
+using System.IO.Compression;
+using System.Text;
+using System.Xml;
+using OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ public static class OarFile
+ {
+ public delegate void AssetLoadedCallback(Asset asset);
+ public delegate void TerrainLoadedCallback(float[,] terrain);
+
+ #region Archive Loading
+
+ public static void UnpackageArchive(string filename, AssetLoadedCallback assetCallback, TerrainLoadedCallback terrainCallback)
+ {
+ int successfulAssetRestores = 0;
+ int failedAssetRestores = 0;
+ List serialisedSceneObjects = new List();
+
+ try
+ {
+ using (Stream loadStream = new GZipStream(new FileStream(filename, FileMode.Open, FileAccess.Read), CompressionMode.Decompress))
+ {
+ TarArchiveReader archive = new TarArchiveReader(loadStream);
+
+ string filePath = "ERROR";
+
+ byte[] data;
+ TarArchiveReader.TarEntryType entryType;
+
+ while ((data = archive.ReadEntry(out filePath, out entryType)) != null)
+ {
+ if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
+ {
+ serialisedSceneObjects.Add(data);
+ }
+ else if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH))
+ {
+ if (LoadAsset(filePath, data, assetCallback))
+ successfulAssetRestores++;
+ else
+ failedAssetRestores++;
+ }
+ else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
+ {
+ LoadTerrain(filePath, data, terrainCallback);
+ }
+ else if (filePath.StartsWith(ArchiveConstants.SETTINGS_PATH))
+ {
+ // FIXME: Support this
+ //LoadRegionSettings(filePath, data);
+ }
+ }
+
+ archive.Close();
+ }
+ }
+ catch (Exception e)
+ {
+ Logger.Log("[OarFile] Error loading OAR file: " + e.Message, Helpers.LogLevel.Error);
+ return;
+ }
+
+ if (failedAssetRestores > 0)
+ Logger.Log(String.Format("[OarFile]: Failed to load {0} assets", failedAssetRestores), Helpers.LogLevel.Warning);
+
+ for (int i = 0; i < serialisedSceneObjects.Count; i++)
+ {
+ byte[] objectData = serialisedSceneObjects[i];
+
+ // Deserialize the XML bytes
+ LoadObjects(objectData, assetCallback);
+ }
+ }
+
+ private static bool LoadAsset(string assetPath, byte[] data, AssetLoadedCallback assetCallback)
+ {
+ // Right now we're nastily obtaining the UUID from the filename
+ string filename = assetPath.Remove(0, ArchiveConstants.ASSETS_PATH.Length);
+ int i = filename.LastIndexOf(ArchiveConstants.ASSET_EXTENSION_SEPARATOR);
+
+ if (i == -1)
+ {
+ Logger.Log(String.Format(
+ "[OarFile]: Could not find extension information in asset path {0} since it's missing the separator {1}. Skipping",
+ assetPath, ArchiveConstants.ASSET_EXTENSION_SEPARATOR), Helpers.LogLevel.Warning);
+ return false;
+ }
+
+ string extension = filename.Substring(i);
+ UUID uuid;
+ UUID.TryParse(filename.Remove(filename.Length - extension.Length), out uuid);
+
+ if (ArchiveConstants.EXTENSION_TO_ASSET_TYPE.ContainsKey(extension))
+ {
+ AssetType assetType = ArchiveConstants.EXTENSION_TO_ASSET_TYPE[extension];
+ Asset asset = null;
+
+ switch (assetType)
+ {
+ case AssetType.Animation:
+ asset = new AssetAnimation(uuid, data);
+ break;
+ case AssetType.Bodypart:
+ asset = new AssetBodypart(uuid, data);
+ break;
+ case AssetType.Clothing:
+ asset = new AssetClothing(uuid, data);
+ break;
+ case AssetType.LSLBytecode:
+ asset = new AssetScriptBinary(uuid, data);
+ break;
+ case AssetType.LSLText:
+ asset = new AssetScriptText(uuid, data);
+ break;
+ case AssetType.Notecard:
+ asset = new AssetNotecard(uuid, data);
+ break;
+ case AssetType.Sound:
+ asset = new AssetSound(uuid, data);
+ break;
+ case AssetType.Texture:
+ asset = new AssetTexture(uuid, data);
+ break;
+ default:
+ Logger.Log("[OarFile] Unhandled asset type " + assetType, Helpers.LogLevel.Error);
+ break;
+ }
+
+ if (asset != null)
+ {
+ asset.Decode();
+ assetCallback(asset);
+ return true;
+ }
+ }
+
+ Logger.Log("[OarFile] Failed to load asset", Helpers.LogLevel.Warning);
+ return false;
+ }
+
+ private static bool LoadTerrain(string filePath, byte[] data, TerrainLoadedCallback terrainCallback)
+ {
+ float[,] terrain = new float[256, 256];
+ bool loaded = false;
+
+ switch (Path.GetExtension(filePath))
+ {
+ case ".r32":
+ case ".f32":
+ // RAW32
+ if (data.Length == 256 * 256 * 4)
+ {
+ int pos = 0;
+ for (int y = 0; y < 256; y++)
+ {
+ for (int x = 0; x < 256; x++)
+ {
+ terrain[y, x] = Utils.Clamp(Utils.BytesToFloat(data, pos), 0.0f, 255.0f);
+ pos += 4;
+ }
+ }
+
+ loaded = true;
+ }
+ else
+ {
+ Logger.Log("[OarFile] RAW32 terrain file " + filePath + " has the wrong number of bytes: " + data.Length,
+ Helpers.LogLevel.Warning);
+ }
+ break;
+ case ".ter":
+ // Terragen
+ case ".raw":
+ // LLRAW
+ case ".jpg":
+ case ".jpeg":
+ // JPG
+ case ".bmp":
+ // BMP
+ case ".png":
+ // PNG
+ case ".gif":
+ // GIF
+ case ".tif":
+ case ".tiff":
+ // TIFF
+ default:
+ Logger.Log("[OarFile] Unrecognized terrain format in " + filePath, Helpers.LogLevel.Warning);
+ break;
+ }
+
+ if (loaded)
+ terrainCallback(terrain);
+
+ return loaded;
+ }
+
+ private static void LoadObjects(byte[] objectData, AssetLoadedCallback assetCallback)
+ {
+ // TODO: If we can get by without XmlDocument it will fix the memory problems when loading large XML files
+ XmlDocument doc = new XmlDocument();
+
+ using (XmlTextReader reader = new XmlTextReader(new MemoryStream(objectData)))
+ {
+ reader.WhitespaceHandling = WhitespaceHandling.None;
+ doc.Load(reader);
+ }
+
+ XmlNode rootNode = doc.FirstChild;
+
+ if (rootNode.LocalName.Equals("scene"))
+ {
+ foreach (XmlNode node in rootNode.ChildNodes)
+ {
+ AssetPrim linkset = new AssetPrim(node.OuterXml);
+ if (linkset != null)
+ assetCallback(linkset);
+ }
+ }
+ else
+ {
+ AssetPrim linkset = new AssetPrim(rootNode.OuterXml);
+ if (linkset != null)
+ assetCallback(linkset);
+ }
+ }
+
+ #endregion Archive Loading
+
+ #region Archive Saving
+
+ public static void PackageArchive(string directoryName, string filename)
+ {
+ const string ARCHIVE_XML = "\n";
+
+ TarArchiveWriter archive = new TarArchiveWriter(new GZipStream(new FileStream(filename, FileMode.Create), CompressionMode.Compress));
+
+ // Create the archive.xml file
+ archive.WriteFile("archive.xml", ARCHIVE_XML);
+
+ // Add the assets
+ string[] files = Directory.GetFiles(directoryName + "/assets");
+ foreach (string file in files)
+ archive.WriteFile("assets/" + Path.GetFileName(file), File.ReadAllBytes(file));
+
+ // Add the objects
+ files = Directory.GetFiles(directoryName + "/objects");
+ foreach (string file in files)
+ archive.WriteFile("objects/" + Path.GetFileName(file), File.ReadAllBytes(file));
+
+ // Add the terrain(s)
+ files = Directory.GetFiles(directoryName + "/terrains");
+ foreach (string file in files)
+ archive.WriteFile("terrains/" + Path.GetFileName(file), File.ReadAllBytes(file));
+
+ archive.Close();
+ }
+
+ public static void SavePrims(IList prims, string primsPath, string assetsPath, string textureCacheFolder)
+ {
+ Dictionary textureList = new Dictionary();
+
+ // Delete all of the old linkset files
+ try { Directory.Delete(primsPath, true); }
+ catch (Exception) { }
+
+ // Create a new folder for the linkset files
+ try { Directory.CreateDirectory(primsPath); }
+ catch (Exception ex)
+ {
+ Logger.Log("Failed saving prims: " + ex.Message, Helpers.LogLevel.Error);
+ return;
+ }
+
+ foreach (AssetPrim assetPrim in prims)
+ {
+ SavePrim(assetPrim, Path.Combine(primsPath, "Primitive_" + assetPrim.Parent.ID + ".xml"));
+
+ CollectTextures(assetPrim.Parent, textureList);
+ if (assetPrim.Children != null)
+ {
+ foreach (PrimObject child in assetPrim.Children)
+ CollectTextures(child, textureList);
+ }
+ }
+
+ SaveTextures(new List(textureList.Keys), assetsPath, textureCacheFolder);
+ }
+
+ static void CollectTextures(PrimObject prim, Dictionary textureList)
+ {
+ if (prim.Faces != null)
+ {
+ // Add all of the textures on this prim to the save list
+ for (int i = 0; i < prim.Faces.Length; i++)
+ {
+ PrimObject.FaceBlock face = prim.Faces[i];
+ if (!textureList.ContainsKey(face.ImageID))
+ textureList.Add(face.ImageID, face.ImageID);
+ }
+ }
+ }
+
+ public static void SaveTextures(IList textures, string assetsPath, string textureCacheFolder)
+ {
+ int count = 0;
+
+ // Delete the assets folder
+ try { Directory.Delete(assetsPath, true); }
+ catch (Exception) { }
+
+ // Create a new assets folder
+ try { Directory.CreateDirectory(assetsPath); }
+ catch (Exception ex)
+ {
+ Logger.Log("Failed saving assets: " + ex.Message, Helpers.LogLevel.Error);
+ return;
+ }
+
+ // Create a map of all of the textures in the cache
+ string[] files = Directory.GetFiles(textureCacheFolder, "*.texture", SearchOption.TopDirectoryOnly);
+ Dictionary idToFiles = new Dictionary(files.Length);
+ for (int i = 0; i < files.Length; i++)
+ {
+ string file = files[i];
+ UUID id;
+
+ if (UUID.TryParse(Path.GetFileNameWithoutExtension(file), out id))
+ idToFiles[id] = file;
+ }
+
+ for (int i = 0; i < textures.Count; i++)
+ {
+ UUID texture = textures[i];
+
+ if (idToFiles.ContainsKey(texture))
+ {
+ try
+ {
+ File.Copy(idToFiles[texture], Path.Combine(assetsPath, texture.ToString() + "_texture.jp2"));
+ ++count;
+ }
+ catch (Exception ex)
+ {
+ Logger.Log("Failed to save texture " + texture.ToString() + ": " + ex.Message, Helpers.LogLevel.Error);
+ }
+ }
+ else
+ {
+ Logger.Log("Skipping missing texture " + texture.ToString(), Helpers.LogLevel.Warning);
+ }
+ }
+
+ Logger.Log("Copied " + count + " textures to the asset archive folder", Helpers.LogLevel.Info);
+ }
+
+ static void SavePrim(AssetPrim prim, string filename)
+ {
+ try
+ {
+ using (StreamWriter stream = new StreamWriter(filename))
+ {
+ XmlTextWriter writer = new XmlTextWriter(stream);
+ SOGToXml2(writer, prim);
+ writer.Flush();
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Log("Failed saving linkset: " + ex.Message, Helpers.LogLevel.Error);
+ }
+ }
+
+ public static void SOGToXml2(XmlTextWriter writer, AssetPrim prim)
+ {
+ writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
+ SOPToXml(writer, prim.Parent, null);
+ writer.WriteStartElement(String.Empty, "OtherParts", String.Empty);
+
+ foreach (PrimObject child in prim.Children)
+ SOPToXml(writer, child, prim.Parent);
+
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ }
+
+ static void SOPToXml(XmlTextWriter writer, PrimObject prim, PrimObject parent)
+ {
+ writer.WriteStartElement("SceneObjectPart");
+ writer.WriteAttributeString("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance");
+ writer.WriteAttributeString("xmlns:xsd", "http://www.w3.org/2001/XMLSchema");
+
+ UUID creatorID, groupID, ownerID, lastOwnerID;
+ UUID.TryParse(prim.CreatorIdentity, out creatorID);
+ UUID.TryParse(prim.GroupIdentity, out groupID);
+ UUID.TryParse(prim.OwnerIdentity, out ownerID);
+ UUID.TryParse(prim.LastOwnerIdentity, out lastOwnerID);
+
+ WriteUUID(writer, "CreatorID", creatorID);
+ WriteUUID(writer, "FolderID", prim.FolderID);
+ writer.WriteElementString("InventorySerial", (prim.Inventory != null) ? prim.Inventory.Serial.ToString() : "0");
+
+ // FIXME: Task inventory
+ writer.WriteStartElement("TaskInventory"); writer.WriteEndElement();
+
+ PrimFlags flags = PrimFlags.None;
+ if (prim.UsePhysics) flags |= PrimFlags.Physics;
+ if (prim.Phantom) flags |= PrimFlags.Phantom;
+ if (prim.DieAtEdge) flags |= PrimFlags.DieAtEdge;
+ if (prim.ReturnAtEdge) flags |= PrimFlags.ReturnAtEdge;
+ if (prim.Temporary) flags |= PrimFlags.Temporary;
+ if (prim.Sandbox) flags |= PrimFlags.Sandbox;
+ writer.WriteElementString("ObjectFlags", ((int)flags).ToString());
+
+ WriteUUID(writer, "UUID", prim.ID);
+ writer.WriteElementString("LocalId", prim.LocalID.ToString());
+ writer.WriteElementString("Name", prim.Name);
+ writer.WriteElementString("Material", ((int)prim.Material).ToString());
+ writer.WriteElementString("RegionHandle", prim.RegionHandle.ToString());
+ writer.WriteElementString("ScriptAccessPin", prim.RemoteScriptAccessPIN.ToString());
+
+ Vector3 groupPosition;
+ if (parent == null)
+ groupPosition = prim.Position;
+ else
+ groupPosition = parent.Position;
+
+ WriteVector(writer, "GroupPosition", groupPosition);
+ if (prim.ParentID == 0)
+ WriteVector(writer, "OffsetPosition", Vector3.Zero);
+ else
+ WriteVector(writer, "OffsetPosition", prim.Position);
+ WriteQuaternion(writer, "RotationOffset", prim.Rotation);
+ WriteVector(writer, "Velocity", prim.Velocity);
+ WriteVector(writer, "RotationalVelocity", Vector3.Zero);
+ WriteVector(writer, "AngularVelocity", prim.AngularVelocity);
+ WriteVector(writer, "Acceleration", prim.Acceleration);
+ writer.WriteElementString("Description", prim.Description);
+ writer.WriteStartElement("Color");
+ writer.WriteElementString("R", prim.TextColor.R.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("G", prim.TextColor.G.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("B", prim.TextColor.B.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("A", prim.TextColor.G.ToString(Utils.EnUsCulture));
+ writer.WriteEndElement();
+ writer.WriteElementString("Text", prim.Text);
+ writer.WriteElementString("SitName", prim.SitName);
+ writer.WriteElementString("TouchName", prim.TouchName);
+
+ writer.WriteElementString("LinkNum", prim.LinkNumber.ToString());
+ writer.WriteElementString("ClickAction", prim.ClickAction.ToString());
+ writer.WriteStartElement("Shape");
+
+ writer.WriteElementString("PathBegin", Primitive.PackBeginCut(prim.Shape.PathBegin).ToString());
+ writer.WriteElementString("PathCurve", prim.Shape.PathCurve.ToString());
+ writer.WriteElementString("PathEnd", Primitive.PackEndCut(prim.Shape.PathEnd).ToString());
+ writer.WriteElementString("PathRadiusOffset", Primitive.PackPathTwist(prim.Shape.PathRadiusOffset).ToString());
+ writer.WriteElementString("PathRevolutions", Primitive.PackPathRevolutions(prim.Shape.PathRevolutions).ToString());
+ writer.WriteElementString("PathScaleX", Primitive.PackPathScale(prim.Shape.PathScaleX).ToString());
+ writer.WriteElementString("PathScaleY", Primitive.PackPathScale(prim.Shape.PathScaleY).ToString());
+ writer.WriteElementString("PathShearX", ((byte)Primitive.PackPathShear(prim.Shape.PathShearX)).ToString());
+ writer.WriteElementString("PathShearY", ((byte)Primitive.PackPathShear(prim.Shape.PathShearY)).ToString());
+ writer.WriteElementString("PathSkew", Primitive.PackPathTwist(prim.Shape.PathSkew).ToString());
+ writer.WriteElementString("PathTaperX", Primitive.PackPathTaper(prim.Shape.PathTaperX).ToString());
+ writer.WriteElementString("PathTaperY", Primitive.PackPathTaper(prim.Shape.PathTaperY).ToString());
+ writer.WriteElementString("PathTwist", Primitive.PackPathTwist(prim.Shape.PathTwist).ToString());
+ writer.WriteElementString("PathTwistBegin", Primitive.PackPathTwist(prim.Shape.PathTwistBegin).ToString());
+ writer.WriteElementString("PCode", prim.PCode.ToString());
+ writer.WriteElementString("ProfileBegin", Primitive.PackBeginCut(prim.Shape.ProfileBegin).ToString());
+ writer.WriteElementString("ProfileEnd", Primitive.PackEndCut(prim.Shape.ProfileEnd).ToString());
+ writer.WriteElementString("ProfileHollow", Primitive.PackProfileHollow(prim.Shape.ProfileHollow).ToString());
+ WriteVector(writer, "Scale", prim.Scale);
+ writer.WriteElementString("State", prim.State.ToString());
+
+ AssetPrim.ProfileShape shape = (AssetPrim.ProfileShape)(prim.Shape.ProfileCurve & 0x0F);
+ HoleType hole = (HoleType)(prim.Shape.ProfileCurve & 0xF0);
+ writer.WriteElementString("ProfileShape", shape.ToString());
+ writer.WriteElementString("HollowShape", hole.ToString());
+ writer.WriteElementString("ProfileCurve", prim.Shape.ProfileCurve.ToString());
+
+ writer.WriteStartElement("TextureEntry");
+
+ byte[] te;
+ if (prim.Faces != null)
+ te = AssetPrim.ToTextureEntry(prim.Faces).GetBytes();
+ else
+ te = Utils.EmptyBytes;
+
+ writer.WriteBase64(te, 0, te.Length);
+ writer.WriteEndElement();
+
+ // FIXME: ExtraParams
+ writer.WriteStartElement("ExtraParams"); writer.WriteEndElement();
+
+ writer.WriteEndElement();
+
+ WriteVector(writer, "Scale", prim.Scale);
+ writer.WriteElementString("UpdateFlag", "0");
+ WriteVector(writer, "SitTargetOrientation", Vector3.UnitZ); // TODO: Is this really a vector and not a quaternion?
+ WriteVector(writer, "SitTargetPosition", prim.SitOffset);
+ WriteVector(writer, "SitTargetPositionLL", prim.SitOffset);
+ WriteQuaternion(writer, "SitTargetOrientationLL", prim.SitRotation);
+ writer.WriteElementString("ParentID", prim.ParentID.ToString());
+ writer.WriteElementString("CreationDate", ((int)Utils.DateTimeToUnixTime(prim.CreationDate)).ToString());
+ writer.WriteElementString("Category", "0");
+ writer.WriteElementString("SalePrice", prim.SalePrice.ToString());
+ writer.WriteElementString("ObjectSaleType", ((int)prim.SaleType).ToString());
+ writer.WriteElementString("OwnershipCost", "0");
+ WriteUUID(writer, "GroupID", groupID);
+ WriteUUID(writer, "OwnerID", ownerID);
+ WriteUUID(writer, "LastOwnerID", lastOwnerID);
+ writer.WriteElementString("BaseMask", ((uint)PermissionMask.All).ToString());
+ writer.WriteElementString("OwnerMask", ((uint)PermissionMask.All).ToString());
+ writer.WriteElementString("GroupMask", ((uint)PermissionMask.All).ToString());
+ writer.WriteElementString("EveryoneMask", ((uint)PermissionMask.All).ToString());
+ writer.WriteElementString("NextOwnerMask", ((uint)PermissionMask.All).ToString());
+ writer.WriteElementString("Flags", "None");
+ WriteUUID(writer, "SitTargetAvatar", UUID.Zero);
+
+ writer.WriteEndElement();
+ }
+
+ static void WriteUUID(XmlTextWriter writer, string name, UUID id)
+ {
+ writer.WriteStartElement(name);
+ writer.WriteElementString("UUID", id.ToString());
+ writer.WriteEndElement();
+ }
+
+ static void WriteVector(XmlTextWriter writer, string name, Vector3 vec)
+ {
+ writer.WriteStartElement(name);
+ writer.WriteElementString("X", vec.X.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("Y", vec.Y.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("Z", vec.Z.ToString(Utils.EnUsCulture));
+ writer.WriteEndElement();
+ }
+
+ static void WriteQuaternion(XmlTextWriter writer, string name, Quaternion quat)
+ {
+ writer.WriteStartElement(name);
+ writer.WriteElementString("X", quat.X.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("Y", quat.Y.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("Z", quat.Z.ToString(Utils.EnUsCulture));
+ writer.WriteElementString("W", quat.W.ToString(Utils.EnUsCulture));
+ writer.WriteEndElement();
+ }
+
+ #endregion Archive Saving
+ }
+}
diff --git a/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs b/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs
new file mode 100644
index 00000000..efd911d4
--- /dev/null
+++ b/OpenMetaverse/Assets/Archiving/TarArchiveReader.cs
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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.IO;
+using System.Reflection;
+using System.Text;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Temporary code to do the bare minimum required to read a tar archive for our purposes
+ ///
+ public class TarArchiveReader
+ {
+ public enum TarEntryType
+ {
+ TYPE_UNKNOWN = 0,
+ TYPE_NORMAL_FILE = 1,
+ TYPE_HARD_LINK = 2,
+ TYPE_SYMBOLIC_LINK = 3,
+ TYPE_CHAR_SPECIAL = 4,
+ TYPE_BLOCK_SPECIAL = 5,
+ TYPE_DIRECTORY = 6,
+ TYPE_FIFO = 7,
+ TYPE_CONTIGUOUS_FILE = 8,
+ }
+
+ protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
+
+ ///
+ /// Binary reader for the underlying stream
+ ///
+ protected BinaryReader m_br;
+
+ ///
+ /// Used to trim off null chars
+ ///
+ protected char[] m_nullCharArray = new char[] { '\0' };
+
+ ///
+ /// Generate a tar reader which reads from the given stream.
+ ///
+ ///
+ public TarArchiveReader(Stream s)
+ {
+ m_br = new BinaryReader(s);
+ }
+
+ ///
+ /// Read the next entry in the tar file.
+ ///
+ ///
+ /// the data for the entry. Returns null if there are no more entries
+ public byte[] ReadEntry(out string filePath, out TarEntryType entryType)
+ {
+ filePath = String.Empty;
+ entryType = TarEntryType.TYPE_UNKNOWN;
+ TarHeader header = ReadHeader();
+
+ if (null == header)
+ return null;
+
+ entryType = header.EntryType;
+ filePath = header.FilePath;
+ return ReadData(header.FileSize);
+ }
+
+ ///
+ /// Read the next 512 byte chunk of data as a tar header.
+ ///
+ /// A tar header struct. null if we have reached the end of the archive.
+ protected TarHeader ReadHeader()
+ {
+ byte[] header = m_br.ReadBytes(512);
+
+ // If we've reached the end of the archive we'll be in null block territory, which means
+ // the next byte will be 0
+ if (header[0] == 0)
+ return null;
+
+ TarHeader tarHeader = new TarHeader();
+
+ // If we're looking at a GNU tar long link then extract the long name and pull up the next header
+ if (header[156] == (byte)'L')
+ {
+ int longNameLength = ConvertOctalBytesToDecimal(header, 124, 11);
+ tarHeader.FilePath = m_asciiEncoding.GetString(ReadData(longNameLength));
+ //m_log.DebugFormat("[TAR ARCHIVE READER]: Got long file name {0}", tarHeader.FilePath);
+ header = m_br.ReadBytes(512);
+ }
+ else
+ {
+ tarHeader.FilePath = m_asciiEncoding.GetString(header, 0, 100);
+ tarHeader.FilePath = tarHeader.FilePath.Trim(m_nullCharArray);
+ //m_log.DebugFormat("[TAR ARCHIVE READER]: Got short file name {0}", tarHeader.FilePath);
+ }
+
+ tarHeader.FileSize = ConvertOctalBytesToDecimal(header, 124, 11);
+
+ switch (header[156])
+ {
+ case 0:
+ tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
+ break;
+ case (byte)'0':
+ tarHeader.EntryType = TarEntryType.TYPE_NORMAL_FILE;
+ break;
+ case (byte)'1':
+ tarHeader.EntryType = TarEntryType.TYPE_HARD_LINK;
+ break;
+ case (byte)'2':
+ tarHeader.EntryType = TarEntryType.TYPE_SYMBOLIC_LINK;
+ break;
+ case (byte)'3':
+ tarHeader.EntryType = TarEntryType.TYPE_CHAR_SPECIAL;
+ break;
+ case (byte)'4':
+ tarHeader.EntryType = TarEntryType.TYPE_BLOCK_SPECIAL;
+ break;
+ case (byte)'5':
+ tarHeader.EntryType = TarEntryType.TYPE_DIRECTORY;
+ break;
+ case (byte)'6':
+ tarHeader.EntryType = TarEntryType.TYPE_FIFO;
+ break;
+ case (byte)'7':
+ tarHeader.EntryType = TarEntryType.TYPE_CONTIGUOUS_FILE;
+ break;
+ }
+
+ return tarHeader;
+ }
+
+ ///
+ /// Read data following a header
+ ///
+ ///
+ ///
+ protected byte[] ReadData(int fileSize)
+ {
+ byte[] data = m_br.ReadBytes(fileSize);
+
+ //m_log.DebugFormat("[TAR ARCHIVE READER]: fileSize {0}", fileSize);
+
+ // Read the rest of the empty padding in the 512 byte block
+ if (fileSize % 512 != 0)
+ {
+ int paddingLeft = 512 - (fileSize % 512);
+
+ //m_log.DebugFormat("[TAR ARCHIVE READER]: Reading {0} padding bytes", paddingLeft);
+
+ m_br.ReadBytes(paddingLeft);
+ }
+
+ return data;
+ }
+
+ public void Close()
+ {
+ m_br.Close();
+ }
+
+ ///
+ /// Convert octal bytes to a decimal representation
+ ///
+ ///
+ ///
+ public static int ConvertOctalBytesToDecimal(byte[] bytes, int startIndex, int count)
+ {
+ string oString = m_asciiEncoding.GetString(bytes, startIndex, count);
+
+ int d = 0;
+
+ foreach (char c in oString)
+ {
+ d <<= 3;
+ d |= c - '0';
+ }
+
+ return d;
+ }
+ }
+
+ public class TarHeader
+ {
+ public string FilePath;
+ public int FileSize;
+ public TarArchiveReader.TarEntryType EntryType;
+ }
+}
diff --git a/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs b/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs
new file mode 100644
index 00000000..6da6091f
--- /dev/null
+++ b/OpenMetaverse/Assets/Archiving/TarArchiveWriter.cs
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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.IO;
+using System.Text;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Temporary code to produce a tar archive in tar v7 format
+ ///
+ public class TarArchiveWriter
+ {
+ protected static ASCIIEncoding m_asciiEncoding = new ASCIIEncoding();
+
+ ///
+ /// Binary writer for the underlying stream
+ ///
+ protected BinaryWriter m_bw;
+
+ public TarArchiveWriter(Stream s)
+ {
+ m_bw = new BinaryWriter(s);
+ }
+
+ ///
+ /// Write a directory entry to the tar archive. We can only handle one path level right now!
+ ///
+ ///
+ public void WriteDir(string dirName)
+ {
+ // Directories are signalled by a final /
+ if (!dirName.EndsWith("/"))
+ dirName += "/";
+
+ WriteFile(dirName, new byte[0]);
+ }
+
+ ///
+ /// Write a file to the tar archive
+ ///
+ ///
+ ///
+ public void WriteFile(string filePath, string data)
+ {
+ WriteFile(filePath, m_asciiEncoding.GetBytes(data));
+ }
+
+ ///
+ /// Write a file to the tar archive
+ ///
+ ///
+ ///
+ public void WriteFile(string filePath, byte[] data)
+ {
+ if (filePath.Length > 100)
+ WriteEntry("././@LongLink", m_asciiEncoding.GetBytes(filePath), 'L');
+
+ char fileType;
+
+ if (filePath.EndsWith("/"))
+ {
+ fileType = '5';
+ }
+ else
+ {
+ fileType = '0';
+ }
+
+ WriteEntry(filePath, data, fileType);
+ }
+
+ ///
+ /// Finish writing the raw tar archive data to a stream. The stream will be closed on completion.
+ ///
+ /// Stream to which to write the data
+ ///
+ public void Close()
+ {
+ //m_log.Debug("[TAR ARCHIVE WRITER]: Writing final consecutive 0 blocks");
+
+ // Write two consecutive 0 blocks to end the archive
+ byte[] finalZeroPadding = new byte[1024];
+ m_bw.Write(finalZeroPadding);
+
+ m_bw.Flush();
+ m_bw.Close();
+ }
+
+ public static byte[] ConvertDecimalToPaddedOctalBytes(int d, int padding)
+ {
+ string oString = "";
+
+ while (d > 0)
+ {
+ oString = Convert.ToString((byte)'0' + d & 7) + oString;
+ d >>= 3;
+ }
+
+ while (oString.Length < padding)
+ {
+ oString = "0" + oString;
+ }
+
+ byte[] oBytes = m_asciiEncoding.GetBytes(oString);
+
+ return oBytes;
+ }
+
+ ///
+ /// Write a particular entry
+ ///
+ ///
+ ///
+ ///
+ protected void WriteEntry(string filePath, byte[] data, char fileType)
+ {
+ byte[] header = new byte[512];
+
+ // file path field (100)
+ byte[] nameBytes = m_asciiEncoding.GetBytes(filePath);
+ int nameSize = (nameBytes.Length >= 100) ? 100 : nameBytes.Length;
+ Array.Copy(nameBytes, header, nameSize);
+
+ // file mode (8)
+ byte[] modeBytes = m_asciiEncoding.GetBytes("0000777");
+ Array.Copy(modeBytes, 0, header, 100, 7);
+
+ // owner user id (8)
+ byte[] ownerIdBytes = m_asciiEncoding.GetBytes("0000764");
+ Array.Copy(ownerIdBytes, 0, header, 108, 7);
+
+ // group user id (8)
+ byte[] groupIdBytes = m_asciiEncoding.GetBytes("0000764");
+ Array.Copy(groupIdBytes, 0, header, 116, 7);
+
+ // file size in bytes (12)
+ int fileSize = data.Length;
+ //m_log.DebugFormat("[TAR ARCHIVE WRITER]: File size of {0} is {1}", filePath, fileSize);
+
+ byte[] fileSizeBytes = ConvertDecimalToPaddedOctalBytes(fileSize, 11);
+
+ Array.Copy(fileSizeBytes, 0, header, 124, 11);
+
+ // last modification time (12)
+ byte[] lastModTimeBytes = m_asciiEncoding.GetBytes("11017037332");
+ Array.Copy(lastModTimeBytes, 0, header, 136, 11);
+
+ // entry type indicator (1)
+ header[156] = m_asciiEncoding.GetBytes(new char[] { fileType })[0];
+
+ Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 329, 7);
+ Array.Copy(m_asciiEncoding.GetBytes("0000000"), 0, header, 337, 7);
+
+ // check sum for header block (8) [calculated last]
+ Array.Copy(m_asciiEncoding.GetBytes(" "), 0, header, 148, 8);
+
+ int checksum = 0;
+ foreach (byte b in header)
+ {
+ checksum += b;
+ }
+
+ //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Decimal header checksum is {0}", checksum);
+
+ byte[] checkSumBytes = ConvertDecimalToPaddedOctalBytes(checksum, 6);
+
+ Array.Copy(checkSumBytes, 0, header, 148, 6);
+
+ header[154] = 0;
+
+ // Write out header
+ m_bw.Write(header);
+
+ // Write out data
+ m_bw.Write(data);
+
+ if (data.Length % 512 != 0)
+ {
+ int paddingRequired = 512 - (data.Length % 512);
+
+ //m_log.DebugFormat("[TAR ARCHIVE WRITER]: Padding data with {0} bytes", paddingRequired);
+
+ byte[] padding = new byte[paddingRequired];
+ m_bw.Write(padding);
+ }
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/Asset.cs b/OpenMetaverse/Assets/Asset.cs
new file mode 100644
index 00000000..468c9873
--- /dev/null
+++ b/OpenMetaverse/Assets/Asset.cs
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Base class for all Asset types
+ ///
+ public abstract class Asset
+ {
+ /// A byte array containing the raw asset data
+ public byte[] AssetData;
+ /// True if the asset it only stored on the server temporarily
+ public bool Temporary;
+ /// A unique ID
+ private UUID _AssetID;
+ /// The assets unique ID
+ public UUID AssetID
+ {
+ get { return _AssetID; }
+ internal set { _AssetID = value; }
+ }
+
+ ///
+ /// The "type" of asset, Notecard, Animation, etc
+ ///
+ public abstract AssetType AssetType
+ {
+ get;
+ }
+
+ ///
+ /// Construct a new Asset object
+ ///
+ public Asset() { }
+
+ ///
+ /// Construct a new Asset object
+ ///
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public Asset(UUID assetID, byte[] assetData)
+ {
+ _AssetID = assetID;
+ AssetData = assetData;
+ }
+
+ ///
+ /// Regenerates the AssetData byte array from the properties
+ /// of the derived class.
+ ///
+ public abstract void Encode();
+
+ ///
+ /// Decodes the AssetData, placing it in appropriate properties of the derived
+ /// class.
+ ///
+ /// True if the asset decoding succeeded, otherwise false
+ public abstract bool Decode();
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs b/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs
new file mode 100644
index 00000000..f9b54733
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetAnimation.cs
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents an Animation
+ ///
+ public class AssetAnimation : Asset
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Animation; } }
+
+ /// Default Constructor
+ public AssetAnimation() { }
+
+ ///
+ /// Construct an Asset object of type Animation
+ ///
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetAnimation(UUID assetID, byte[] assetData)
+ : base(assetID, assetData)
+ {
+ AssetData = assetData;
+ }
+
+ public override void Encode() { }
+ public override bool Decode() { return true; }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs b/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs
new file mode 100644
index 00000000..d092d946
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetBodypart.cs
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents an that represents an avatars body ie: Hair, Etc.
+ ///
+ public class AssetBodypart : AssetWearable
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Bodypart; } }
+
+ /// Initializes a new instance of an AssetBodyPart object
+ public AssetBodypart() { }
+
+ /// Initializes a new instance of an AssetBodyPart object with parameters
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetBodypart(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
+
+ /// Initializes a new instance of an AssetBodyPart object with parameters
+ /// A string representing the values of the Bodypart
+ public AssetBodypart(string source) : base(source) { }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs b/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs
new file mode 100644
index 00000000..ad6ecb45
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetClothing.cs
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents an that can be worn on an avatar
+ /// such as a Shirt, Pants, etc.
+ ///
+ public class AssetClothing : AssetWearable
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Clothing; } }
+
+ /// Initializes a new instance of an AssetScriptBinary object
+ public AssetClothing() { }
+
+ /// Initializes a new instance of an AssetScriptBinary object with parameters
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetClothing(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
+
+ /// Initializes a new instance of an AssetScriptBinary object with parameters
+ /// A string containing the Clothings data
+ public AssetClothing(string source) : base(source) { }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs b/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs
new file mode 100644
index 00000000..02bec33f
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetLandmark.cs
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents a Landmark with RegionID and Position vector
+ ///
+ public class AssetLandmark : Asset
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Landmark; } }
+
+ /// UUID of the Landmark target region
+ public UUID RegionID = UUID.Zero;
+ /// Local position of the target
+ public Vector3 Position = Vector3.Zero;
+
+ /// Construct an Asset of type Landmark
+ public AssetLandmark() { }
+
+ ///
+ /// Construct an Asset object of type Landmark
+ ///
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetLandmark(UUID assetID, byte[] assetData)
+ : base(assetID, assetData)
+ {
+ Decode();
+ }
+
+ ///
+ /// Constuct an asset of type Landmark
+ ///
+ /// UUID of the target region
+ /// Local position of landmark
+ public AssetLandmark(UUID regionID, Vector3 pos)
+ {
+ RegionID = regionID;
+ Position = pos;
+ Encode();
+ }
+
+ ///
+ /// Encode the raw contents of a string with the specific Landmark format
+ ///
+ public override void Encode()
+ {
+ string temp = "Landmark version 2\n";
+ temp += "region_id " + RegionID + "\n";
+ temp += String.Format("local_pos {0:0.00} {1:0.00} {2:0.00}\n", Position.X, Position.Y, Position.Z);
+ AssetData = Utils.StringToBytes(temp);
+ }
+
+ ///
+ /// Decode the raw asset data, populating the RegionID and Position
+ ///
+ /// true if the AssetData was successfully decoded to a UUID and Vector
+ public override bool Decode()
+ {
+ String text = Utils.BytesToString(AssetData);
+ if (text.ToLower().Contains("landmark version 2"))
+ {
+ RegionID = new UUID(text.Substring(text.IndexOf("region_id") + 10, 36));
+ String vecDelim = " ";
+ String[] vecStrings = text.Substring(text.IndexOf("local_pos") + 10).Split(vecDelim.ToCharArray());
+ if (vecStrings.Length == 3)
+ {
+ Position = new Vector3(float.Parse(vecStrings[0]), float.Parse(vecStrings[1]), float.Parse(vecStrings[2]));
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs b/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs
new file mode 100644
index 00000000..14389648
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetNotecard.cs
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents a string of characters encoded with specific formatting properties
+ ///
+ public class AssetNotecard : Asset
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Notecard; } }
+
+ /// A text string containing the raw contents of the notecard
+ public string Text = null;
+
+ /// Construct an Asset of type Notecard
+ public AssetNotecard() { }
+
+ ///
+ /// Construct an Asset object of type Notecard
+ ///
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetNotecard(UUID assetID, byte[] assetData)
+ : base(assetID, assetData)
+ {
+ Decode();
+ }
+
+ ///
+ /// Construct an Asset object of type Notecard
+ ///
+ /// A text string containing the raw contents of the notecard
+ public AssetNotecard(string text)
+ {
+ Text = text;
+ Encode();
+ }
+
+ ///
+ /// Encode the raw contents of a string with the specific Linden Text properties
+ ///
+ public override void Encode()
+ {
+ string temp = "Linden text version 2\n{\nLLEmbeddedItems version 1\n{\ncount 0\n}\nText length ";
+ temp += Text.Length + "\n";
+ temp += Text;
+ temp += "}";
+ AssetData = Utils.StringToBytes(temp);
+ }
+
+ ///
+ /// Decode the raw asset data including the Linden Text properties
+ ///
+ /// true if the AssetData was successfully decoded to a string
+ public override bool Decode()
+ {
+ Text = Utils.BytesToString(AssetData);
+ return true;
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs b/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs
new file mode 100644
index 00000000..d2ce7f94
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetPrim.cs
@@ -0,0 +1,989 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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.IO;
+using System.Xml;
+using OpenMetaverse;
+using OpenMetaverse.StructuredData;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents a primitive asset
+ ///
+ public class AssetPrim : Asset
+ {
+ ///
+ /// Only used internally for XML serialization/deserialization
+ ///
+ internal enum ProfileShape : byte
+ {
+ Circle = 0,
+ Square = 1,
+ IsometricTriangle = 2,
+ EquilateralTriangle = 3,
+ RightTriangle = 4,
+ HalfCircle = 5
+ }
+
+ public PrimObject Parent;
+ public List Children;
+
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Object; } }
+
+ /// Initializes a new instance of an AssetPrim object
+ public AssetPrim() { }
+
+ public AssetPrim(string xmlData)
+ {
+ DecodeXml(xmlData);
+ }
+
+ public AssetPrim(PrimObject parent, List children)
+ {
+ Parent = parent;
+ if (children != null)
+ Children = children;
+ else
+ Children = new List(0);
+ }
+
+ ///
+ ///
+ ///
+ public override void Encode()
+ {
+ // FIXME:
+ }
+
+ ///
+ ///
+ ///
+ ///
+ public override bool Decode()
+ {
+ // FIXME:
+ return false;
+ }
+
+ public string EncodeXml()
+ {
+ TextWriter textWriter = new StringWriter();
+ XmlTextWriter xmlWriter = new XmlTextWriter(textWriter);
+ OarFile.SOGToXml2(xmlWriter, this);
+ xmlWriter.Flush();
+ return textWriter.ToString();
+ }
+
+ public bool DecodeXml(string xmlData)
+ {
+ using (XmlTextReader reader = new XmlTextReader(new StringReader(xmlData)))
+ {
+ reader.Read();
+ reader.ReadStartElement("SceneObjectGroup");
+ Parent = LoadPrim(reader);
+
+ if (Parent != null)
+ {
+ List children = new List();
+
+ reader.Read();
+
+ while (!reader.EOF)
+ {
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.Element:
+ if (reader.Name == "SceneObjectPart")
+ {
+ PrimObject child = LoadPrim(reader);
+ if (child != null)
+ children.Add(child);
+ }
+ else
+ {
+ Logger.Log("Found unexpected prim XML element " + reader.Name, Helpers.LogLevel.Warning);
+ reader.Read();
+ }
+ break;
+ case XmlNodeType.EndElement:
+ reader.Read();
+ break;
+ }
+ }
+
+ Children = children;
+ return true;
+ }
+ else
+ {
+ Logger.Log("Failed to load root linkset prim", Helpers.LogLevel.Error);
+ return false;
+ }
+ }
+ }
+
+ public static PrimObject LoadPrim(XmlTextReader reader)
+ {
+ PrimObject obj = new PrimObject();
+ obj.Shape = new PrimObject.ShapeBlock();
+ obj.Inventory = new PrimObject.InventoryBlock();
+
+ reader.ReadStartElement("SceneObjectPart");
+ obj.CreatorIdentity = ReadUUID(reader, "CreatorID").ToString();
+ UUID folderID = ReadUUID(reader, "FolderID");
+ obj.Inventory.Serial = reader.ReadElementContentAsInt("InventorySerial", String.Empty);
+
+ // FIXME: Parse TaskInventory
+ obj.Inventory.Items = new PrimObject.InventoryBlock.ItemBlock[0];
+ reader.ReadInnerXml();
+
+ PrimFlags flags = (PrimFlags)reader.ReadElementContentAsInt("ObjectFlags", String.Empty);
+ obj.UsePhysics = (flags & PrimFlags.Physics) != 0;
+ obj.Phantom = (flags & PrimFlags.Phantom) != 0;
+ obj.DieAtEdge = (flags & PrimFlags.DieAtEdge) != 0;
+ obj.ReturnAtEdge = (flags & PrimFlags.ReturnAtEdge) != 0;
+ obj.Temporary = (flags & PrimFlags.Temporary) != 0;
+ obj.Sandbox = (flags & PrimFlags.Sandbox) != 0;
+
+ obj.ID = ReadUUID(reader, "UUID");
+ obj.LocalID = (uint)reader.ReadElementContentAsLong("LocalId", String.Empty);
+ obj.Name = reader.ReadElementString("Name");
+ obj.Material = reader.ReadElementContentAsInt("Material", String.Empty);
+
+ reader.ReadInnerXml(); // RegionHandle
+
+ obj.RemoteScriptAccessPIN = reader.ReadElementContentAsInt("ScriptAccessPin", String.Empty);
+
+ Vector3 groupPosition = ReadVector(reader, "GroupPosition");
+ Vector3 offsetPosition = ReadVector(reader, "OffsetPosition");
+ obj.Rotation = ReadQuaternion(reader, "RotationOffset");
+ obj.Velocity = ReadVector(reader, "Velocity");
+ Vector3 rotationalVelocity = ReadVector(reader, "RotationalVelocity");
+ obj.AngularVelocity = ReadVector(reader, "AngularVelocity");
+ obj.Acceleration = ReadVector(reader, "Acceleration");
+ obj.Description = reader.ReadElementString("Description");
+ reader.ReadStartElement("Color");
+ if (reader.Name == "R")
+ {
+ obj.TextColor.R = reader.ReadElementContentAsFloat("R", String.Empty);
+ obj.TextColor.G = reader.ReadElementContentAsFloat("G", String.Empty);
+ obj.TextColor.B = reader.ReadElementContentAsFloat("B", String.Empty);
+ obj.TextColor.A = reader.ReadElementContentAsFloat("A", String.Empty);
+ reader.ReadEndElement();
+ }
+ obj.Text = reader.ReadElementString("Text", String.Empty);
+ obj.SitName = reader.ReadElementString("SitName", String.Empty);
+ obj.TouchName = reader.ReadElementString("TouchName", String.Empty);
+
+ obj.LinkNumber = reader.ReadElementContentAsInt("LinkNum", String.Empty);
+ obj.ClickAction = reader.ReadElementContentAsInt("ClickAction", String.Empty);
+
+ reader.ReadStartElement("Shape");
+ obj.Shape.ProfileCurve = reader.ReadElementContentAsInt("ProfileCurve", String.Empty);
+
+ byte[] teData = Convert.FromBase64String(reader.ReadElementString("TextureEntry"));
+ Primitive.TextureEntry te = new Primitive.TextureEntry(teData, 0, teData.Length);
+ obj.Faces = FromTextureEntry(te);
+
+ reader.ReadInnerXml(); // ExtraParams
+
+ obj.Shape.PathBegin = Primitive.UnpackBeginCut((ushort)reader.ReadElementContentAsInt("PathBegin", String.Empty));
+ obj.Shape.PathCurve = reader.ReadElementContentAsInt("PathCurve", String.Empty);
+ obj.Shape.PathEnd = Primitive.UnpackEndCut((ushort)reader.ReadElementContentAsInt("PathEnd", String.Empty));
+ obj.Shape.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathRadiusOffset", String.Empty));
+ obj.Shape.PathRevolutions = Primitive.UnpackPathRevolutions((byte)reader.ReadElementContentAsInt("PathRevolutions", String.Empty));
+ obj.Shape.PathScaleX = Primitive.UnpackPathScale((byte)reader.ReadElementContentAsInt("PathScaleX", String.Empty));
+ obj.Shape.PathScaleY = Primitive.UnpackPathScale((byte)reader.ReadElementContentAsInt("PathScaleY", String.Empty));
+ obj.Shape.PathShearX = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathShearX", String.Empty));
+ obj.Shape.PathShearY = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathShearY", String.Empty));
+ obj.Shape.PathSkew = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathSkew", String.Empty));
+ obj.Shape.PathTaperX = Primitive.UnpackPathTaper((sbyte)reader.ReadElementContentAsInt("PathTaperX", String.Empty));
+ obj.Shape.PathTaperY = Primitive.UnpackPathShear((sbyte)reader.ReadElementContentAsInt("PathTaperY", String.Empty));
+ obj.Shape.PathTwist = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathTwist", String.Empty));
+ obj.Shape.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)reader.ReadElementContentAsInt("PathTwistBegin", String.Empty));
+ obj.PCode = reader.ReadElementContentAsInt("PCode", String.Empty);
+ obj.Shape.ProfileBegin = Primitive.UnpackBeginCut((ushort)reader.ReadElementContentAsInt("ProfileBegin", String.Empty));
+ obj.Shape.ProfileEnd = Primitive.UnpackEndCut((ushort)reader.ReadElementContentAsInt("ProfileEnd", String.Empty));
+ obj.Shape.ProfileHollow = Primitive.UnpackProfileHollow((ushort)reader.ReadElementContentAsInt("ProfileHollow", String.Empty));
+ obj.Scale = ReadVector(reader, "Scale");
+ obj.State = (byte)reader.ReadElementContentAsInt("State", String.Empty);
+
+ ProfileShape profileShape = (ProfileShape)Enum.Parse(typeof(ProfileShape), reader.ReadElementString("ProfileShape"));
+ HoleType holeType = (HoleType)Enum.Parse(typeof(HoleType), reader.ReadElementString("HollowShape"));
+ obj.Shape.ProfileCurve = (int)profileShape | (int)holeType;
+
+ UUID sculptTexture = ReadUUID(reader, "SculptTexture");
+ SculptType sculptType = (SculptType)reader.ReadElementContentAsInt("SculptType", String.Empty);
+ if (sculptTexture != UUID.Zero)
+ {
+ obj.Sculpt = new PrimObject.SculptBlock();
+ obj.Sculpt.Texture = sculptTexture;
+ obj.Sculpt.Type = (int)sculptType;
+ }
+
+ PrimObject.FlexibleBlock flexible = new PrimObject.FlexibleBlock();
+ PrimObject.LightBlock light = new PrimObject.LightBlock();
+
+ reader.ReadInnerXml(); // SculptData
+
+ flexible.Softness = reader.ReadElementContentAsInt("FlexiSoftness", String.Empty);
+ flexible.Tension = reader.ReadElementContentAsFloat("FlexiTension", String.Empty);
+ flexible.Drag = reader.ReadElementContentAsFloat("FlexiDrag", String.Empty);
+ flexible.Gravity = reader.ReadElementContentAsFloat("FlexiGravity", String.Empty);
+ flexible.Wind = reader.ReadElementContentAsFloat("FlexiWind", String.Empty);
+ flexible.Force.X = reader.ReadElementContentAsFloat("FlexiForceX", String.Empty);
+ flexible.Force.Y = reader.ReadElementContentAsFloat("FlexiForceY", String.Empty);
+ flexible.Force.Z = reader.ReadElementContentAsFloat("FlexiForceZ", String.Empty);
+
+ light.Color.R = reader.ReadElementContentAsFloat("LightColorR", String.Empty);
+ light.Color.G = reader.ReadElementContentAsFloat("LightColorG", String.Empty);
+ light.Color.B = reader.ReadElementContentAsFloat("LightColorB", String.Empty);
+ light.Color.A = reader.ReadElementContentAsFloat("LightColorA", String.Empty);
+ light.Radius = reader.ReadElementContentAsFloat("LightRadius", String.Empty);
+ light.Cutoff = reader.ReadElementContentAsFloat("LightCutoff", String.Empty);
+ light.Falloff = reader.ReadElementContentAsFloat("LightFalloff", String.Empty);
+ light.Intensity = reader.ReadElementContentAsFloat("LightIntensity", String.Empty);
+
+ reader.ReadInnerXml(); // FlexiTension
+ reader.ReadInnerXml(); // FlexiDrag
+ reader.ReadInnerXml(); // FlexiGravity
+ reader.ReadInnerXml(); // FlexiWind
+ reader.ReadInnerXml(); // FlexiForceX
+ reader.ReadInnerXml(); // FlexiForceY
+ reader.ReadInnerXml(); // FlexiForceZ
+ reader.ReadInnerXml(); // LightColorR
+ reader.ReadInnerXml(); // LightColorG
+ reader.ReadInnerXml(); // LightColorB
+ reader.ReadInnerXml(); // LightColorA
+ reader.ReadInnerXml(); // LightRadius
+ reader.ReadInnerXml(); // LightCutoff
+ reader.ReadInnerXml(); // LightFalloff
+ reader.ReadInnerXml(); // LightIntensity
+ bool hasFlexi = reader.ReadElementContentAsBoolean("FlexiEntry", String.Empty);
+ bool hasLight = reader.ReadElementContentAsBoolean("LightEntry", String.Empty);
+ reader.ReadInnerXml(); // SculptEntry
+
+ if (hasFlexi)
+ obj.Flexible = flexible;
+ if (hasLight)
+ obj.Light = light;
+
+ reader.ReadEndElement();
+
+ obj.Scale = ReadVector(reader, "Scale"); // Yes, again
+ reader.ReadInnerXml(); // UpdateFlag
+
+ reader.ReadInnerXml(); // SitTargetOrientation
+ reader.ReadInnerXml(); // SitTargetPosition
+ obj.SitOffset = ReadVector(reader, "SitTargetPositionLL");
+ obj.SitRotation = ReadQuaternion(reader, "SitTargetOrientationLL");
+ obj.ParentID = (uint)reader.ReadElementContentAsLong("ParentID", String.Empty);
+ obj.CreationDate = Utils.UnixTimeToDateTime(reader.ReadElementContentAsInt("CreationDate", String.Empty));
+ //obj.Category = reader.ReadElementContentAsInt("Category", String.Empty);
+ int category = reader.ReadElementContentAsInt("Category", String.Empty);
+ obj.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty);
+ obj.SaleType = reader.ReadElementContentAsInt("ObjectSaleType", String.Empty);
+ int ownershipCost = reader.ReadElementContentAsInt("OwnershipCost", String.Empty);
+ obj.GroupIdentity = ReadUUID(reader, "GroupID").ToString();
+ obj.OwnerIdentity = ReadUUID(reader, "OwnerID").ToString();
+ obj.LastOwnerIdentity = ReadUUID(reader, "LastOwnerID").ToString();
+ obj.PermsBase = (uint)reader.ReadElementContentAsInt("BaseMask", String.Empty);
+ obj.PermsOwner = (uint)reader.ReadElementContentAsInt("OwnerMask", String.Empty);
+ obj.PermsGroup = (uint)reader.ReadElementContentAsInt("GroupMask", String.Empty);
+ obj.PermsEveryone = (uint)reader.ReadElementContentAsInt("EveryoneMask", String.Empty);
+ obj.PermsNextOwner = (uint)reader.ReadElementContentAsInt("NextOwnerMask", String.Empty);
+
+ reader.ReadInnerXml(); // Flags
+ reader.ReadInnerXml(); // CollisionSound
+ reader.ReadInnerXml(); // CollisionSoundVolume
+
+ reader.ReadEndElement();
+
+ if (obj.ParentID == 0)
+ obj.Position = groupPosition;
+ else
+ obj.Position = offsetPosition;
+
+ return obj;
+ }
+
+ public static PrimObject.FaceBlock[] FromTextureEntry(Primitive.TextureEntry te)
+ {
+ // FIXME:
+ return new PrimObject.FaceBlock[0];
+ }
+
+ public static Primitive.TextureEntry ToTextureEntry(PrimObject.FaceBlock[] faces)
+ {
+ // FIXME:
+ return new Primitive.TextureEntry(UUID.Zero);
+ }
+
+ static UUID ReadUUID(XmlTextReader reader, string name)
+ {
+ UUID id;
+ string idStr;
+
+ reader.ReadStartElement(name);
+
+ if (reader.Name == "Guid")
+ idStr = reader.ReadElementString("Guid");
+ else // UUID
+ idStr = reader.ReadElementString("UUID");
+
+ UUID.TryParse(idStr, out id);
+ reader.ReadEndElement();
+
+ return id;
+ }
+
+ static Vector3 ReadVector(XmlTextReader reader, string name)
+ {
+ Vector3 vec;
+
+ reader.ReadStartElement(name);
+ vec.X = reader.ReadElementContentAsFloat("X", String.Empty);
+ vec.Y = reader.ReadElementContentAsFloat("Y", String.Empty);
+ vec.Z = reader.ReadElementContentAsFloat("Z", String.Empty);
+ reader.ReadEndElement();
+
+ return vec;
+ }
+
+ static Quaternion ReadQuaternion(XmlTextReader reader, string name)
+ {
+ Quaternion quat;
+
+ reader.ReadStartElement(name);
+ quat.X = reader.ReadElementContentAsFloat("X", String.Empty);
+ quat.Y = reader.ReadElementContentAsFloat("Y", String.Empty);
+ quat.Z = reader.ReadElementContentAsFloat("Z", String.Empty);
+ quat.W = reader.ReadElementContentAsFloat("W", String.Empty);
+ reader.ReadEndElement();
+
+ return quat;
+ }
+ }
+
+ public class PrimObject
+ {
+ public class FlexibleBlock
+ {
+ public int Softness;
+ public float Gravity;
+ public float Drag;
+ public float Wind;
+ public float Tension;
+ public Vector3 Force;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["softness"] = OSD.FromInteger(Softness);
+ map["gravity"] = OSD.FromReal(Gravity);
+ map["drag"] = OSD.FromReal(Drag);
+ map["wind"] = OSD.FromReal(Wind);
+ map["tension"] = OSD.FromReal(Tension);
+ map["force"] = OSD.FromVector3(Force);
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ Softness = map["softness"].AsInteger();
+ Gravity = (float)map["gravity"].AsReal();
+ Drag = (float)map["drag"].AsReal();
+ Wind = (float)map["wind"].AsReal();
+ Tension = (float)map["tension"].AsReal();
+ Force = map["force"].AsVector3();
+ }
+ }
+
+ public class LightBlock
+ {
+ public Color4 Color;
+ public float Intensity;
+ public float Radius;
+ public float Falloff;
+ public float Cutoff;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["color"] = OSD.FromColor4(Color);
+ map["intensity"] = OSD.FromReal(Intensity);
+ map["radius"] = OSD.FromReal(Radius);
+ map["falloff"] = OSD.FromReal(Falloff);
+ map["cutoff"] = OSD.FromReal(Cutoff);
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ Color = map["color"].AsColor4();
+ Intensity = (float)map["intensity"].AsReal();
+ Radius = (float)map["radius"].AsReal();
+ Falloff = (float)map["falloff"].AsReal();
+ Cutoff = (float)map["cutoff"].AsReal();
+ }
+ }
+
+ public class SculptBlock
+ {
+ public UUID Texture;
+ public int Type;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["texture"] = OSD.FromUUID(Texture);
+ map["type"] = OSD.FromInteger(Type);
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ Texture = map["texture"].AsUUID();
+ Type = map["type"].AsInteger();
+ }
+ }
+
+ public class ParticlesBlock
+ {
+ public int Flags;
+ public int Pattern;
+ public float MaxAge;
+ public float StartAge;
+ public float InnerAngle;
+ public float OuterAngle;
+ public float BurstRate;
+ public float BurstRadius;
+ public float BurstSpeedMin;
+ public float BurstSpeedMax;
+ public int BurstParticleCount;
+ public Vector3 AngularVelocity;
+ public Vector3 Acceleration;
+ public UUID TextureID;
+ public UUID TargetID;
+ public int DataFlags;
+ public float ParticleMaxAge;
+ public Color4 ParticleStartColor;
+ public Color4 ParticleEndColor;
+ public Vector2 ParticleStartScale;
+ public Vector2 ParticleEndScale;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["flags"] = OSD.FromInteger(Flags);
+ map["pattern"] = OSD.FromInteger(Pattern);
+ map["max_age"] = OSD.FromReal(MaxAge);
+ map["start_age"] = OSD.FromReal(StartAge);
+ map["inner_angle"] = OSD.FromReal(InnerAngle);
+ map["outer_angle"] = OSD.FromReal(OuterAngle);
+ map["burst_rate"] = OSD.FromReal(BurstRate);
+ map["burst_radius"] = OSD.FromReal(BurstRadius);
+ map["burst_speed_min"] = OSD.FromReal(BurstSpeedMin);
+ map["burst_speed_max"] = OSD.FromReal(BurstSpeedMax);
+ map["burst_particle_count"] = OSD.FromInteger(BurstParticleCount);
+ map["angular_velocity"] = OSD.FromVector3(AngularVelocity);
+ map["acceleration"] = OSD.FromVector3(Acceleration);
+ map["texture_id"] = OSD.FromUUID(TextureID);
+ map["target_id"] = OSD.FromUUID(TargetID);
+ map["data_flags"] = OSD.FromInteger(DataFlags);
+ map["particle_max_age"] = OSD.FromReal(ParticleMaxAge);
+ map["particle_start_color"] = OSD.FromColor4(ParticleStartColor);
+ map["particle_end_color"] = OSD.FromColor4(ParticleEndColor);
+ map["particle_start_scale"] = OSD.FromVector2(ParticleStartScale);
+ map["particle_end_scale"] = OSD.FromVector2(ParticleEndScale);
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ Flags = map["flags"].AsInteger();
+ Pattern = map["pattern"].AsInteger();
+ MaxAge = (float)map["max_age"].AsReal();
+ StartAge = (float)map["start_age"].AsReal();
+ InnerAngle = (float)map["inner_angle"].AsReal();
+ OuterAngle = (float)map["outer_angle"].AsReal();
+ BurstRate = (float)map["burst_rate"].AsReal();
+ BurstRadius = (float)map["burst_radius"].AsReal();
+ BurstSpeedMin = (float)map["burst_speed_min"].AsReal();
+ BurstSpeedMax = (float)map["burst_speed_max"].AsReal();
+ BurstParticleCount = map["burst_particle_count"].AsInteger();
+ AngularVelocity = map["angular_velocity"].AsVector3();
+ Acceleration = map["acceleration"].AsVector3();
+ TextureID = map["texture_id"].AsUUID();
+ DataFlags = map["data_flags"].AsInteger();
+ ParticleMaxAge = (float)map["particle_max_age"].AsReal();
+ ParticleStartColor = map["particle_start_color"].AsColor4();
+ ParticleEndColor = map["particle_end_color"].AsColor4();
+ ParticleStartScale = map["particle_start_scale"].AsVector2();
+ ParticleEndScale = map["particle_end_scale"].AsVector2();
+ }
+ }
+
+ public class ShapeBlock
+ {
+ public int PathCurve;
+ public float PathBegin;
+ public float PathEnd;
+ public float PathScaleX;
+ public float PathScaleY;
+ public float PathShearX;
+ public float PathShearY;
+ public float PathTwist;
+ public float PathTwistBegin;
+ public float PathRadiusOffset;
+ public float PathTaperX;
+ public float PathTaperY;
+ public float PathRevolutions;
+ public float PathSkew;
+ public int ProfileCurve;
+ public float ProfileBegin;
+ public float ProfileEnd;
+ public float ProfileHollow;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["path_curve"] = OSD.FromInteger(PathCurve);
+ map["path_begin"] = OSD.FromReal(PathBegin);
+ map["path_end"] = OSD.FromReal(PathEnd);
+ map["path_scale_x"] = OSD.FromReal(PathScaleX);
+ map["path_scale_y"] = OSD.FromReal(PathScaleY);
+ map["path_shear_x"] = OSD.FromReal(PathShearX);
+ map["path_shear_y"] = OSD.FromReal(PathShearY);
+ map["path_twist"] = OSD.FromReal(PathTwist);
+ map["path_twist_begin"] = OSD.FromReal(PathTwistBegin);
+ map["path_radius_offset"] = OSD.FromReal(PathRadiusOffset);
+ map["path_taper_x"] = OSD.FromReal(PathTaperX);
+ map["path_taper_y"] = OSD.FromReal(PathTaperY);
+ map["path_revolutions"] = OSD.FromReal(PathRevolutions);
+ map["path_skew"] = OSD.FromReal(PathSkew);
+ map["profile_curve"] = OSD.FromInteger(ProfileCurve);
+ map["profile_begin"] = OSD.FromReal(ProfileBegin);
+ map["profile_end"] = OSD.FromReal(ProfileEnd);
+ map["profile_hollow"] = OSD.FromReal(ProfileHollow);
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ PathCurve = map["path_curve"].AsInteger();
+ PathBegin = (float)map["path_begin"].AsReal();
+ PathEnd = (float)map["path_end"].AsReal();
+ PathScaleX = (float)map["path_scale_x"].AsReal();
+ PathScaleY = (float)map["path_scale_y"].AsReal();
+ PathShearX = (float)map["path_shear_x"].AsReal();
+ PathShearY = (float)map["path_shear_y"].AsReal();
+ PathTwist = (float)map["path_twist"].AsReal();
+ PathTwistBegin = (float)map["path_twist_begin"].AsReal();
+ PathRadiusOffset = (float)map["path_radius_offset"].AsReal();
+ PathTaperX = (float)map["path_taper_x"].AsReal();
+ PathTaperY = (float)map["path_taper_y"].AsReal();
+ PathRevolutions = (float)map["path_revolutions"].AsReal();
+ PathSkew = (float)map["path_skew"].AsReal();
+ ProfileCurve = map["profile_curve"].AsInteger();
+ ProfileBegin = (float)map["profile_begin"].AsReal();
+ ProfileEnd = (float)map["profile_end"].AsReal();
+ ProfileHollow = (float)map["profile_hollow"].AsReal();
+ }
+ }
+
+ public class FaceBlock
+ {
+ public int FaceIndex;
+ public UUID ImageID;
+ public Color4 Color;
+ public float ScaleS;
+ public float ScaleT;
+ public float OffsetS;
+ public float OffsetT;
+ public float ImageRot;
+ public int Bump;
+ public bool FullBright;
+ public int MediaFlags;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["face_index"] = OSD.FromInteger(FaceIndex);
+ map["image_id"] = OSD.FromUUID(ImageID);
+ map["color"] = OSD.FromColor4(Color);
+ map["scale_s"] = OSD.FromReal(ScaleS);
+ map["scale_t"] = OSD.FromReal(ScaleT);
+ map["offset_s"] = OSD.FromReal(OffsetS);
+ map["offset_t"] = OSD.FromReal(OffsetT);
+ map["image_rot"] = OSD.FromReal(ImageRot);
+ map["bump"] = OSD.FromInteger(Bump);
+ map["full_bright"] = OSD.FromBoolean(FullBright);
+ map["media_flags"] = OSD.FromInteger(MediaFlags);
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ FaceIndex = map["face_index"].AsInteger();
+ ImageID = map["image_id"].AsUUID();
+ Color = map["color"].AsColor4();
+ ScaleS = (float)map["scale_s"].AsReal();
+ ScaleT = (float)map["scale_t"].AsReal();
+ OffsetS = (float)map["offset_s"].AsReal();
+ OffsetT = (float)map["offset_t"].AsReal();
+ ImageRot = (float)map["image_rot"].AsReal();
+ Bump = map["bump"].AsInteger();
+ FullBright = map["full_bright"].AsBoolean();
+ MediaFlags = map["media_flags"].AsInteger();
+ }
+ }
+
+ public class InventoryBlock
+ {
+ public class ItemBlock
+ {
+ public UUID ID;
+ public string Name;
+ public string OwnerIdentity;
+ public string CreatorIdentity;
+ public string GroupIdentity;
+ public UUID AssetID;
+ public string ContentType;
+ public string Description;
+ public uint PermsBase;
+ public uint PermsOwner;
+ public uint PermsGroup;
+ public uint PermsEveryone;
+ public uint PermsNextOwner;
+ public int SalePrice;
+ public int SaleType;
+ public int Flags;
+ public DateTime CreationDate;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["id"] = OSD.FromUUID(ID);
+ map["name"] = OSD.FromString(Name);
+ map["owner_identity"] = OSD.FromString(OwnerIdentity);
+ map["creator_identity"] = OSD.FromString(CreatorIdentity);
+ map["group_identity"] = OSD.FromString(GroupIdentity);
+ map["asset_id"] = OSD.FromUUID(AssetID);
+ map["content_type"] = OSD.FromString(ContentType);
+ map["description"] = OSD.FromString(Description);
+ map["perms_base"] = OSD.FromInteger(PermsBase);
+ map["perms_owner"] = OSD.FromInteger(PermsOwner);
+ map["perms_group"] = OSD.FromInteger(PermsGroup);
+ map["perms_everyone"] = OSD.FromInteger(PermsEveryone);
+ map["perms_next_owner"] = OSD.FromInteger(PermsNextOwner);
+ map["sale_price"] = OSD.FromInteger(SalePrice);
+ map["sale_type"] = OSD.FromInteger(SaleType);
+ map["flags"] = OSD.FromInteger(Flags);
+ map["creation_date"] = OSD.FromDate(CreationDate);
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ ID = map["id"].AsUUID();
+ Name = map["name"].AsString();
+ OwnerIdentity = map["owner_identity"].AsString();
+ CreatorIdentity = map["creator_identity"].AsString();
+ GroupIdentity = map["group_identity"].AsString();
+ AssetID = map["asset_id"].AsUUID();
+ ContentType = map["content_type"].AsString();
+ Description = map["description"].AsString();
+ PermsBase = (uint)map["perms_base"].AsInteger();
+ PermsOwner = (uint)map["perms_owner"].AsInteger();
+ PermsGroup = (uint)map["perms_group"].AsInteger();
+ PermsEveryone = (uint)map["perms_everyone"].AsInteger();
+ PermsNextOwner = (uint)map["perms_next_owner"].AsInteger();
+ SalePrice = map["sale_price"].AsInteger();
+ SaleType = map["sale_type"].AsInteger();
+ Flags = map["flags"].AsInteger();
+ CreationDate = map["creation_date"].AsDate();
+ }
+ }
+
+ public int Serial;
+ public ItemBlock[] Items;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["serial"] = OSD.FromInteger(Serial);
+
+ if (Items != null)
+ {
+ OSDArray array = new OSDArray(Items.Length);
+ for (int i = 0; i < Items.Length; i++)
+ array.Add(Items[i].Serialize());
+ map["items"] = array;
+ }
+
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ Serial = map["serial"].AsInteger();
+
+ if (map.ContainsKey("items"))
+ {
+ OSDArray array = (OSDArray)map["items"];
+ Items = new ItemBlock[array.Count];
+
+ for (int i = 0; i < array.Count; i++)
+ {
+ ItemBlock item = new ItemBlock();
+ item.Deserialize((OSDMap)array[i]);
+ Items[i] = item;
+ }
+ }
+ else
+ {
+ Items = new ItemBlock[0];
+ }
+ }
+ }
+
+ public UUID ID;
+ public Vector3 AttachmentPosition;
+ public Quaternion AttachmentRotation;
+ public Quaternion BeforeAttachmentRotation;
+ public string Name;
+ public string Description;
+ public uint PermsBase;
+ public uint PermsOwner;
+ public uint PermsGroup;
+ public uint PermsEveryone;
+ public uint PermsNextOwner;
+ public string CreatorIdentity;
+ public string OwnerIdentity;
+ public string LastOwnerIdentity;
+ public string GroupIdentity;
+ public UUID FolderID;
+ public ulong RegionHandle;
+ public int ClickAction;
+ public int LastAttachmentPoint;
+ public int LinkNumber;
+ public uint LocalID;
+ public uint ParentID;
+ public Vector3 Position;
+ public Quaternion Rotation;
+ public Vector3 Velocity;
+ public Vector3 AngularVelocity;
+ public Vector3 Acceleration;
+ public Vector3 Scale;
+ public Vector3 SitOffset;
+ public Quaternion SitRotation;
+ public Vector3 CameraEyeOffset;
+ public Vector3 CameraAtOffset;
+ public int State;
+ public int PCode;
+ public int Material;
+ public UUID SoundID;
+ public float SoundGain;
+ public float SoundRadius;
+ public int SoundFlags;
+ public Color4 TextColor;
+ public string Text;
+ public string SitName;
+ public string TouchName;
+ public bool Selected;
+ public UUID SelectorID;
+ public bool UsePhysics;
+ public bool Phantom;
+ public int RemoteScriptAccessPIN;
+ public bool VolumeDetect;
+ public bool DieAtEdge;
+ public bool ReturnAtEdge;
+ public bool Temporary;
+ public bool Sandbox;
+ public DateTime CreationDate;
+ public DateTime RezDate;
+ public int SalePrice;
+ public int SaleType;
+ public byte[] ScriptState;
+ public FlexibleBlock Flexible;
+ public LightBlock Light;
+ public SculptBlock Sculpt;
+ public ParticlesBlock Particles;
+ public ShapeBlock Shape;
+ public FaceBlock[] Faces;
+ public InventoryBlock Inventory;
+
+ public OSDMap Serialize()
+ {
+ OSDMap map = new OSDMap();
+ map["id"] = OSD.FromUUID(ID);
+ map["attachment_position"] = OSD.FromVector3(AttachmentPosition);
+ map["attachment_rotation"] = OSD.FromQuaternion(AttachmentRotation);
+ map["before_attachment_rotation"] = OSD.FromQuaternion(BeforeAttachmentRotation);
+ map["name"] = OSD.FromString(Name);
+ map["description"] = OSD.FromString(Description);
+ map["perms_base"] = OSD.FromInteger(PermsBase);
+ map["perms_owner"] = OSD.FromInteger(PermsOwner);
+ map["perms_group"] = OSD.FromInteger(PermsGroup);
+ map["perms_everyone"] = OSD.FromInteger(PermsEveryone);
+ map["perms_next_owner"] = OSD.FromInteger(PermsNextOwner);
+ map["creator_identity"] = OSD.FromString(CreatorIdentity);
+ map["owner_identity"] = OSD.FromString(OwnerIdentity);
+ map["last_owner_identity"] = OSD.FromString(LastOwnerIdentity);
+ map["group_identity"] = OSD.FromString(GroupIdentity);
+ map["folder_id"] = OSD.FromUUID(FolderID);
+ map["region_handle"] = OSD.FromULong(RegionHandle);
+ map["click_action"] = OSD.FromInteger(ClickAction);
+ map["last_attachment_point"] = OSD.FromInteger(LastAttachmentPoint);
+ map["link_number"] = OSD.FromInteger(LinkNumber);
+ map["local_id"] = OSD.FromInteger(LocalID);
+ map["parent_id"] = OSD.FromInteger(ParentID);
+ map["position"] = OSD.FromVector3(Position);
+ map["rotation"] = OSD.FromQuaternion(Rotation);
+ map["velocity"] = OSD.FromVector3(Velocity);
+ map["angular_velocity"] = OSD.FromVector3(AngularVelocity);
+ map["acceleration"] = OSD.FromVector3(Acceleration);
+ map["scale"] = OSD.FromVector3(Scale);
+ map["sit_offset"] = OSD.FromVector3(SitOffset);
+ map["sit_rotation"] = OSD.FromQuaternion(SitRotation);
+ map["camera_eye_offset"] = OSD.FromVector3(CameraEyeOffset);
+ map["camera_at_offset"] = OSD.FromVector3(CameraAtOffset);
+ map["state"] = OSD.FromInteger(State);
+ map["prim_code"] = OSD.FromInteger(PCode);
+ map["material"] = OSD.FromInteger(Material);
+ map["sound_id"] = OSD.FromUUID(SoundID);
+ map["sound_gain"] = OSD.FromReal(SoundGain);
+ map["sound_radius"] = OSD.FromReal(SoundRadius);
+ map["sound_flags"] = OSD.FromInteger(SoundFlags);
+ map["text_color"] = OSD.FromColor4(TextColor);
+ map["text"] = OSD.FromString(Text);
+ map["sit_name"] = OSD.FromString(SitName);
+ map["touch_name"] = OSD.FromString(TouchName);
+ map["selected"] = OSD.FromBoolean(Selected);
+ map["selector_id"] = OSD.FromUUID(SelectorID);
+ map["use_physics"] = OSD.FromBoolean(UsePhysics);
+ map["phantom"] = OSD.FromBoolean(Phantom);
+ map["remote_script_access_pin"] = OSD.FromInteger(RemoteScriptAccessPIN);
+ map["volume_detect"] = OSD.FromBoolean(VolumeDetect);
+ map["die_at_edge"] = OSD.FromBoolean(DieAtEdge);
+ map["return_at_edge"] = OSD.FromBoolean(ReturnAtEdge);
+ map["temporary"] = OSD.FromBoolean(Temporary);
+ map["sandbox"] = OSD.FromBoolean(Sandbox);
+ map["creation_date"] = OSD.FromDate(CreationDate);
+ map["rez_date"] = OSD.FromDate(RezDate);
+ map["sale_price"] = OSD.FromInteger(SalePrice);
+ map["sale_type"] = OSD.FromInteger(SaleType);
+
+ if (Flexible != null)
+ map["flexible"] = Flexible.Serialize();
+ if (Light != null)
+ map["light"] = Light.Serialize();
+ if (Sculpt != null)
+ map["sculpt"] = Sculpt.Serialize();
+ if (Particles != null)
+ map["particles"] = Particles.Serialize();
+ if (Shape != null)
+ map["shape"] = Shape.Serialize();
+ if (Faces != null)
+ {
+ OSDArray array = new OSDArray(Faces.Length);
+ for (int i = 0; i < Faces.Length; i++)
+ array.Add(Faces[i].Serialize());
+ map["faces"] = array;
+ }
+ if (Inventory != null)
+ map["inventory"] = Inventory.Serialize();
+
+ return map;
+ }
+
+ public void Deserialize(OSDMap map)
+ {
+ ID = map["id"].AsUUID();
+ AttachmentPosition = map["attachment_position"].AsVector3();
+ AttachmentRotation = map["attachment_rotation"].AsQuaternion();
+ BeforeAttachmentRotation = map["before_attachment_rotation"].AsQuaternion();
+ Name = map["name"].AsString();
+ Description = map["description"].AsString();
+ PermsBase = (uint)map["perms_base"].AsInteger();
+ PermsOwner = (uint)map["perms_owner"].AsInteger();
+ PermsGroup = (uint)map["perms_group"].AsInteger();
+ PermsEveryone = (uint)map["perms_everyone"].AsInteger();
+ PermsNextOwner = (uint)map["perms_next_owner"].AsInteger();
+ CreatorIdentity = map["creator_identity"].AsString();
+ OwnerIdentity = map["owner_identity"].AsString();
+ LastOwnerIdentity = map["last_owner_identity"].AsString();
+ GroupIdentity = map["group_identity"].AsString();
+ FolderID = map["folder_id"].AsUUID();
+ RegionHandle = map["region_handle"].AsULong();
+ ClickAction = map["click_action"].AsInteger();
+ LastAttachmentPoint = map["last_attachment_point"].AsInteger();
+ LinkNumber = map["link_number"].AsInteger();
+ LocalID = (uint)map["local_id"].AsInteger();
+ ParentID = (uint)map["parent_id"].AsInteger();
+ Position = map["position"].AsVector3();
+ Rotation = map["rotation"].AsQuaternion();
+ Velocity = map["velocity"].AsVector3();
+ AngularVelocity = map["angular_velocity"].AsVector3();
+ Acceleration = map["acceleration"].AsVector3();
+ Scale = map["scale"].AsVector3();
+ SitOffset = map["sit_offset"].AsVector3();
+ SitRotation = map["sit_rotation"].AsQuaternion();
+ CameraEyeOffset = map["camera_eye_offset"].AsVector3();
+ CameraAtOffset = map["camera_at_offset"].AsVector3();
+ State = map["state"].AsInteger();
+ PCode = map["prim_code"].AsInteger();
+ Material = map["material"].AsInteger();
+ SoundID = map["sound_id"].AsUUID();
+ SoundGain = (float)map["sound_gain"].AsReal();
+ SoundRadius = (float)map["sound_radius"].AsReal();
+ SoundFlags = map["sound_flags"].AsInteger();
+ TextColor = map["text_color"].AsColor4();
+ Text = map["text"].AsString();
+ SitName = map["sit_name"].AsString();
+ TouchName = map["touch_name"].AsString();
+ Selected = map["selected"].AsBoolean();
+ SelectorID = map["selector_id"].AsUUID();
+ UsePhysics = map["use_physics"].AsBoolean();
+ Phantom = map["phantom"].AsBoolean();
+ RemoteScriptAccessPIN = map["remote_script_access_pin"].AsInteger();
+ VolumeDetect = map["volume_detect"].AsBoolean();
+ DieAtEdge = map["die_at_edge"].AsBoolean();
+ ReturnAtEdge = map["return_at_edge"].AsBoolean();
+ Temporary = map["temporary"].AsBoolean();
+ Sandbox = map["sandbox"].AsBoolean();
+ CreationDate = map["creation_date"].AsDate();
+ RezDate = map["rez_date"].AsDate();
+ SalePrice = map["sale_price"].AsInteger();
+ SaleType = map["sale_type"].AsInteger();
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs b/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs
new file mode 100644
index 00000000..5f080b11
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetScriptBinary.cs
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents an AssetScriptBinary object containing the
+ /// LSO compiled bytecode of an LSL script
+ ///
+ public class AssetScriptBinary : Asset
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.LSLBytecode; } }
+
+ /// Initializes a new instance of an AssetScriptBinary object
+ public AssetScriptBinary() { }
+
+ /// Initializes a new instance of an AssetScriptBinary object with parameters
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetScriptBinary(UUID assetID, byte[] assetData)
+ : base(assetID, assetData)
+ {
+ AssetData = assetData;
+ }
+
+ ///
+ /// TODO: Encodes a scripts contents into a LSO Bytecode file
+ ///
+ public override void Encode() { }
+
+ ///
+ /// TODO: Decode LSO Bytecode into a string
+ ///
+ /// true
+ public override bool Decode() { return true; }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs b/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs
new file mode 100644
index 00000000..08ab9a0c
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetScriptText.cs
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents an LSL Text object containing a string of UTF encoded characters
+ ///
+ public class AssetScriptText : Asset
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.LSLText; } }
+
+ /// A string of characters represting the script contents
+ public string Source;
+
+ /// Initializes a new AssetScriptText object
+ public AssetScriptText() { }
+
+ ///
+ /// Initializes a new AssetScriptText object with parameters
+ ///
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetScriptText(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
+
+ ///
+ /// Initializes a new AssetScriptText object with parameters
+ ///
+ /// A string containing the scripts contents
+ public AssetScriptText(string source)
+ {
+ Source = source;
+ }
+
+ ///
+ /// Encode a string containing the scripts contents into byte encoded AssetData
+ ///
+ public override void Encode()
+ {
+ AssetData = Utils.StringToBytes(Source);
+ }
+
+ ///
+ /// Decode a byte array containing the scripts contents into a string
+ ///
+ /// true if decoding is successful
+ public override bool Decode()
+ {
+ Source = Utils.BytesToString(AssetData);
+ return true;
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetSound.cs b/OpenMetaverse/Assets/AssetTypes/AssetSound.cs
new file mode 100644
index 00000000..50a4b42e
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetSound.cs
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents a Sound Asset
+ ///
+ public class AssetSound : Asset
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Sound; } }
+
+ /// Initializes a new instance of an AssetSound object
+ public AssetSound() { }
+
+ /// Initializes a new instance of an AssetSound object with parameters
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetSound(UUID assetID, byte[] assetData)
+ : base(assetID, assetData)
+ {
+ AssetData = assetData;
+ }
+
+ ///
+ /// TODO: Encodes a sound file
+ ///
+ public override void Encode() { }
+
+ ///
+ /// TODO: Decode a sound file
+ ///
+ /// true
+ public override bool Decode() { return true; }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs b/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs
new file mode 100644
index 00000000..2ece85f6
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetTexture.cs
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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 OpenMetaverse;
+using OpenMetaverse.Imaging;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents a texture
+ ///
+ public class AssetTexture : Asset
+ {
+ /// Override the base classes AssetType
+ public override AssetType AssetType { get { return AssetType.Texture; } }
+
+ /// A object containing image data
+ public ManagedImage Image;
+
+ ///
+ public OpenJPEG.J2KLayerInfo[] LayerInfo;
+
+ ///
+ public int Components;
+
+ /// Initializes a new instance of an AssetTexture object
+ public AssetTexture() { }
+
+ ///
+ /// Initializes a new instance of an AssetTexture object
+ ///
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetTexture(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
+
+ ///
+ /// Initializes a new instance of an AssetTexture object
+ ///
+ /// A object containing texture data
+ public AssetTexture(ManagedImage image)
+ {
+ Image = image;
+ Components = 0;
+ if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
+ Components += 3;
+ if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
+ ++Components;
+ }
+
+ ///
+ /// Populates the byte array with a JPEG2000
+ /// encoded image created from the data in
+ ///
+ public override void Encode()
+ {
+ AssetData = OpenJPEG.Encode(Image);
+ }
+
+ ///
+ /// Decodes the JPEG2000 data in AssetData to the
+ /// object
+ ///
+ /// True if the decoding was successful, otherwise false
+ public override bool Decode()
+ {
+ Components = 0;
+
+ if (OpenJPEG.DecodeToImage(AssetData, out Image))
+ {
+ if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
+ Components += 3;
+ if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
+ ++Components;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Decodes the begin and end byte positions for each quality layer in
+ /// the image
+ ///
+ ///
+ public bool DecodeLayerBoundaries()
+ {
+ return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo, out Components);
+ }
+ }
+}
diff --git a/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs b/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs
new file mode 100644
index 00000000..0adb20fc
--- /dev/null
+++ b/OpenMetaverse/Assets/AssetTypes/AssetWearable.cs
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2009, openmetaverse.org
+ * 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 openmetaverse.org 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.Text;
+using OpenMetaverse;
+
+namespace OpenMetaverse.Assets
+{
+ ///
+ /// Represents a Wearable Asset, Clothing, Hair, Skin, Etc
+ ///
+ public abstract class AssetWearable : Asset
+ {
+ /// A string containing the name of the asset
+ public string Name = String.Empty;
+ /// A string containing a short description of the asset
+ public string Description = String.Empty;
+ /// The Assets WearableType
+ public WearableType WearableType = WearableType.Shape;
+ /// The For-Sale status of the object
+ public SaleType ForSale;
+ /// An Integer representing the purchase price of the asset
+ public int SalePrice;
+ /// The of the assets creator
+ public UUID Creator;
+ /// The of the assets current owner
+ public UUID Owner;
+ /// The of the assets prior owner
+ public UUID LastOwner;
+ /// The of the Group this asset is set to
+ public UUID Group;
+ /// True if the asset is owned by a
+ public bool GroupOwned;
+ /// The Permissions mask of the asset
+ public Permissions Permissions;
+ /// A Dictionary containing Key/Value pairs of the objects parameters
+ public Dictionary Params = new Dictionary();
+ /// A Dictionary containing Key/Value pairs where the Key is the textures Index and the Value is the Textures
+ public Dictionary Textures = new Dictionary();
+
+ /// Initializes a new instance of an AssetWearable object
+ public AssetWearable() { }
+
+ /// Initializes a new instance of an AssetWearable object with parameters
+ /// A unique specific to this asset
+ /// A byte array containing the raw asset data
+ public AssetWearable(UUID assetID, byte[] assetData) : base(assetID, assetData) { }
+
+ /// Initializes a new instance of an AssetWearable object with parameters
+ /// A string containing the asset parameters
+ public AssetWearable(string source)
+ {
+ AssetData = Utils.StringToBytes(source);
+ }
+
+ ///
+ /// Decode an assets byte encoded data to a string
+ ///
+ /// true if the asset data was decoded successfully
+ public override bool Decode()
+ {
+ int version = -1;
+ Permissions = new Permissions();
+ string data = Utils.BytesToString(AssetData);
+
+ data = data.Replace("\r", String.Empty);
+ string[] lines = data.Split('\n');
+ for (int stri = 0; stri < lines.Length; stri++)
+ {
+ if (stri == 0)
+ {
+ string versionstring = lines[stri];
+ version = Int32.Parse(versionstring.Split(' ')[2]);
+ if (version != 22 && version != 18)
+ return false;
+ }
+ else if (stri == 1)
+ {
+ Name = lines[stri];
+ }
+ else if (stri == 2)
+ {
+ Description = lines[stri];
+ }
+ else
+ {
+ string line = lines[stri].Trim();
+ string[] fields = line.Split('\t');
+
+ if (fields.Length == 1)
+ {
+ fields = line.Split(' ');
+ if (fields[0] == "parameters")
+ {
+ int count = Int32.Parse(fields[1]) + stri;
+ for (; stri < count; )
+ {
+ stri++;
+ line = lines[stri].Trim();
+ fields = line.Split(' ');
+
+ int id = Int32.Parse(fields[0]);
+ if (fields[1] == ",")
+ fields[1] = "0";
+ else
+ fields[1] = fields[1].Replace(',', '.');
+
+ float weight = float.Parse(fields[1], System.Globalization.NumberStyles.Float,
+ Utils.EnUsCulture.NumberFormat);
+
+ Params[id] = weight;
+ }
+ }
+ else if (fields[0] == "textures")
+ {
+ int count = Int32.Parse(fields[1]) + stri;
+ for (; stri < count; )
+ {
+ stri++;
+ line = lines[stri].Trim();
+ fields = line.Split(' ');
+
+ AppearanceManager.TextureIndex id = (AppearanceManager.TextureIndex)Int32.Parse(fields[0]);
+ UUID texture = new UUID(fields[1]);
+
+ Textures[id] = texture;
+ }
+ }
+ else if (fields[0] == "type")
+ {
+ WearableType = (WearableType)Int32.Parse(fields[1]);
+ }
+
+ }
+ else if (fields.Length == 2)
+ {
+ switch (fields[0])
+ {
+ case "creator_mask":
+ // Deprecated, apply this as the base mask
+ Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
+ break;
+ case "base_mask":
+ Permissions.BaseMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
+ break;
+ case "owner_mask":
+ Permissions.OwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
+ break;
+ case "group_mask":
+ Permissions.GroupMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
+ break;
+ case "everyone_mask":
+ Permissions.EveryoneMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
+ break;
+ case "next_owner_mask":
+ Permissions.NextOwnerMask = (PermissionMask)UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber);
+ break;
+ case "creator_id":
+ Creator = new UUID(fields[1]);
+ break;
+ case "owner_id":
+ Owner = new UUID(fields[1]);
+ break;
+ case "last_owner_id":
+ LastOwner = new UUID(fields[1]);
+ break;
+ case "group_id":
+ Group = new UUID(fields[1]);
+ break;
+ case "group_owned":
+ GroupOwned = (Int32.Parse(fields[1]) != 0);
+ break;
+ case "sale_type":
+ ForSale = Utils.StringToSaleType(fields[1]);
+ break;
+ case "sale_price":
+ SalePrice = Int32.Parse(fields[1]);
+ break;
+ case "sale_info":
+ // Container for sale_type and sale_price, ignore
+ break;
+ default:
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+
+ ///
+ /// Encode the assets string represantion into a format consumable by the asset server
+ ///
+ public override void Encode()
+ {
+ const string NL = "\n";
+
+ StringBuilder data = new StringBuilder("LLWearable version 22\n");
+ data.Append(Name); data.Append(NL); data.Append(NL);
+ data.Append("\tpermissions 0\n\t{\n");
+ data.Append("\t\tbase_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.BaseMask)); data.Append(NL);
+ data.Append("\t\towner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.OwnerMask)); data.Append(NL);
+ data.Append("\t\tgroup_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.GroupMask)); data.Append(NL);
+ data.Append("\t\teveryone_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.EveryoneMask)); data.Append(NL);
+ data.Append("\t\tnext_owner_mask\t"); data.Append(Utils.UIntToHexString((uint)Permissions.NextOwnerMask)); data.Append(NL);
+ data.Append("\t\tcreator_id\t"); data.Append(Creator.ToString()); data.Append(NL);
+ data.Append("\t\towner_id\t"); data.Append(Owner.ToString()); data.Append(NL);
+ data.Append("\t\tlast_owner_id\t"); data.Append(LastOwner.ToString()); data.Append(NL);
+ data.Append("\t\tgroup_id\t"); data.Append(Group.ToString()); data.Append(NL);
+ if (GroupOwned) data.Append("\t\tgroup_owned\t1\n");
+ data.Append("\t}\n");
+ data.Append("\tsale_info\t0\n");
+ data.Append("\t{\n");
+ data.Append("\t\tsale_type\t"); data.Append(Utils.SaleTypeToString(ForSale)); data.Append(NL);
+ data.Append("\t\tsale_price\t"); data.Append(SalePrice); data.Append(NL);
+ data.Append("\t}\n");
+ data.Append("type "); data.Append((int)WearableType); data.Append(NL);
+
+ data.Append("parameters "); data.Append(Params.Count); data.Append(NL);
+ foreach (KeyValuePair param in Params)
+ {
+ data.Append(param.Key); data.Append(" "); data.Append(Helpers.FloatToTerseString(param.Value)); data.Append(NL);
+ }
+
+ data.Append("textures "); data.Append(Textures.Count); data.Append(NL);
+ foreach (KeyValuePair texture in Textures)
+ {
+ data.Append((byte)texture.Key); data.Append(" "); data.Append(texture.Value.ToString()); data.Append(NL);
+ }
+
+ AssetData = Utils.StringToBytes(data.ToString());
+ }
+ }
+}
diff --git a/OpenMetaverse/Imaging/BakeLayer.cs b/OpenMetaverse/Imaging/BakeLayer.cs
index f7fde542..f38b6dc3 100644
--- a/OpenMetaverse/Imaging/BakeLayer.cs
+++ b/OpenMetaverse/Imaging/BakeLayer.cs
@@ -30,7 +30,7 @@ using System.IO;
using System.Reflection;
using System.Drawing;
using System.Drawing.Imaging;
-//using OpenMetaverse.Assets;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.Imaging
{
diff --git a/OpenMetaverse/TexturePipeline.cs b/OpenMetaverse/TexturePipeline.cs
index 1d9a947e..9c9ca4af 100644
--- a/OpenMetaverse/TexturePipeline.cs
+++ b/OpenMetaverse/TexturePipeline.cs
@@ -30,6 +30,7 @@ using System;
using System.Collections.Generic;
using System.Threading;
using OpenMetaverse.Packets;
+using OpenMetaverse.Assets;
namespace OpenMetaverse
{
diff --git a/Programs/AvatarPreview/frmAvatar.cs b/Programs/AvatarPreview/frmAvatar.cs
index c11ce28b..6519c19a 100644
--- a/Programs/AvatarPreview/frmAvatar.cs
+++ b/Programs/AvatarPreview/frmAvatar.cs
@@ -14,6 +14,7 @@ using Tao.Platform.Windows;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Rendering;
+using OpenMetaverse.Assets;
namespace AvatarPreview
{
diff --git a/Programs/PrimWorkshop/frmBrowser.cs b/Programs/PrimWorkshop/frmBrowser.cs
index 572813ee..83a98765 100644
--- a/Programs/PrimWorkshop/frmBrowser.cs
+++ b/Programs/PrimWorkshop/frmBrowser.cs
@@ -13,6 +13,7 @@ using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Imaging;
using OpenMetaverse.Rendering;
+using OpenMetaverse.Assets;
namespace PrimWorkshop
{
diff --git a/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs b/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs
index 44a6d900..03e51e54 100644
--- a/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs
+++ b/Programs/examples/TestClient/Commands/Inventory/BackupCommand.cs
@@ -9,6 +9,7 @@ using System.Xml.Serialization;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.TestClient;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
diff --git a/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs
index 2fb82247..17d446e8 100644
--- a/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs
+++ b/Programs/examples/TestClient/Commands/Inventory/DownloadCommand.cs
@@ -2,6 +2,7 @@
using System.IO;
using System.Threading;
using OpenMetaverse;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
diff --git a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
index ee5a560f..acde1d1f 100644
--- a/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
+++ b/Programs/examples/TestClient/Commands/Inventory/DumpOutfitCommand.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Imaging;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
diff --git a/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs b/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs
index ea824540..1a083139 100644
--- a/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs
+++ b/Programs/examples/TestClient/Commands/Inventory/ViewNotecardCommand.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using OpenMetaverse;
using OpenMetaverse.Packets;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
diff --git a/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs b/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs
index bc9b2437..1d55e451 100644
--- a/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs
+++ b/Programs/examples/TestClient/Commands/Prims/DownloadTextureCommand.cs
@@ -2,6 +2,7 @@ using System;
using System.IO;
using System.Threading;
using OpenMetaverse;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
diff --git a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
index c2dc5db4..dd3cc310 100644
--- a/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
+++ b/Programs/examples/TestClient/Commands/Prims/ExportCommand.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Threading;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
diff --git a/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs b/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs
index e6920e56..4fcb6b4e 100644
--- a/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs
+++ b/Programs/examples/TestClient/Commands/Prims/TexturesCommand.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using OpenMetaverse;
+using OpenMetaverse.Assets;
namespace OpenMetaverse.TestClient
{
diff --git a/Programs/examples/groupmanager/frmGroupInfo.cs b/Programs/examples/groupmanager/frmGroupInfo.cs
index b74c0465..40768b13 100644
--- a/Programs/examples/groupmanager/frmGroupInfo.cs
+++ b/Programs/examples/groupmanager/frmGroupInfo.cs
@@ -8,6 +8,7 @@ using System.Windows.Forms;
using System.IO;
using OpenMetaverse;
using OpenMetaverse.Imaging;
+using OpenMetaverse.Assets;
namespace groupmanager
{