From 20e26f76df0947d64e36b69c7bfc8ac2629743bb Mon Sep 17 00:00:00 2001 From: bushing Date: Sun, 11 Mar 2007 06:17:24 +0000 Subject: [PATCH] IM IN UR CODEZ KILLIN ALL UR WARNINGS git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@1050 52acb1d6-8a22-11de-b505-999d5b087335 --- .../AssetSystem/AppearanceManager.cs | 1322 ++++----- libsecondlife-cs/AssetSystem/AssetRequest.cs | 434 +-- .../AssetSystem/AssetRequestUpload.cs | 426 +-- libsecondlife-cs/AssetSystem/AssetScript.cs | 86 +- libsecondlife-cs/AssetSystem/AssetWearable.cs | 1067 ++++---- .../AssetSystem/AssetWearable_Body.cs | 96 +- .../AssetSystem/AssetWearable_Clothing.cs | 96 +- .../AssetSystem/BodyPart_Depricated.cs | 454 ++-- libsecondlife-cs/AvatarManager.cs | 4 +- libsecondlife-cs/BakeLayer.cs | 2 + libsecondlife-cs/Caps.cs | 2 - .../InventorySystem/DownloadRequest_Folder.cs | 170 +- .../InventorySystem/InventoryFolder.cs | 6 +- .../InventorySystem/InventoryManager.cs | 9 +- .../InventorySystem/InventoryScript.cs | 286 +- .../InventorySystem/InventoryWearable.cs | 338 +-- libsecondlife-cs/Simulator.cs | 4 +- libsecondlife-cs/TerrainManager.cs | 8 +- .../VisualParamGenerator.cs | 306 +-- .../VisualParamGenerator/template.cs | 130 +- .../XmlRpcCS/SimpleHttpRequest.cs | 408 +-- .../XmlRpcCS/XmlRpcBoxcarRequest.cs | 102 +- .../XmlRpcCS/XmlRpcClientProxy.cs | 122 +- .../XmlRpcCS/XmlRpcExposedAttribute.cs | 120 +- libsecondlife-cs/XmlRpcCS/XmlRpcResponder.cs | 196 +- libsecondlife-cs/XmlRpcCS/XmlRpcServer.cs | 478 ++-- .../XmlRpcCS/XmlRpcSystemObject.cs | 504 ++-- .../libsecondlife.Tests/NetworkTests.cs | 244 +- .../libsecondlife.Tests/PacketTests.cs | 136 +- .../libsecondlife.Tests/PrimObjectTests.cs | 286 +- .../libsecondlife.Tests/TypeTests.cs | 308 +-- .../libsecondlife.Utilities/Appearance.cs | 2384 ++++++++--------- .../libsecondlife.Utilities/Assets.cs | 1561 ++++++----- .../libsecondlife.Utilities/Inventory.cs | 324 +-- .../libsecondlife.Utilities/Utilities.cs | 1175 ++++---- 35 files changed, 6784 insertions(+), 6810 deletions(-) diff --git a/libsecondlife-cs/AssetSystem/AppearanceManager.cs b/libsecondlife-cs/AssetSystem/AppearanceManager.cs index 4efb9faa..0550f472 100644 --- a/libsecondlife-cs/AssetSystem/AppearanceManager.cs +++ b/libsecondlife-cs/AssetSystem/AppearanceManager.cs @@ -1,661 +1,661 @@ -using System; -using System.Collections.Generic; -using System.Threading; - -using libsecondlife; -using libsecondlife.AssetSystem; -using libsecondlife.InventorySystem; -using libsecondlife.Packets; - -using System.Text; - - -namespace libsecondlife.AssetSystem -{ - public class AppearanceManager - { - public enum WearableType - { - Shape = 0, - Skin = 1, - Hair = 2, - Eyes = 3, - Shirt = 4, - Pants = 5, - Shoes = 6, - Socks = 7, - Jacket = 8, - Gloves = 9, - Undershirt = 10, - Underpants = 11, - Skirt = 12, - Count = 13, - Invalid = 255 - }; - - protected SecondLife Client; - protected AssetManager AManager; - - protected uint SerialNum = 1; - - protected ManualResetEvent AgentWearablesSignal = new ManualResetEvent(false); - - protected Dictionary WearableCache = new Dictionary(); - protected List WearableAssetQueue = new List(); - protected Mutex WearableCacheQueueMutex = new Mutex(); - - // This data defines all appearance info for an avatar - public AgentWearablesUpdatePacket.WearableDataBlock[] AgentWearablesData; - public SerializableDictionary AgentAppearanceParams = new SerializableDictionary(); - public LLObject.TextureEntry AgentTextureEntry = new LLObject.TextureEntry("C228D1CF4B5D4BA884F4899A0796AA97"); // if this isn't valid, blame JH ;-) - - public bool LogWearableAssetQueue = false; - - /// - /// - /// - /// - public AppearanceManager(SecondLife client) - { - Client = client; - Client.Network.RegisterCallback(libsecondlife.Packets.PacketType.AgentWearablesUpdate, new NetworkManager.PacketCallback(AgentWearablesUpdateCallbackHandler)); - - AManager = client.Assets; - AManager.TransferRequestCompletedEvent += new AssetManager.On_TransferRequestCompleted(AManager_TransferRequestCompletedEvent); - } - - #region Wear Stuff - - /// - /// Add a single wearable to your outfit, replacing if nessesary. - /// - /// - public void Wear(InventoryWearable wearable) - { - List x = new List(); - x.Add(wearable); - Wear(x); - } - - /// - /// Add the specified wearables to your outfit, replace existing ones if nessesary. - /// - /// - public void Wear(List wearables) - { - // Make sure we have some Wearable Data to start with. - if (AgentWearablesSignal.WaitOne(1000, false) == false) - { - Client.Log("You must have set appearance at least once, before calling Wear(). AgentWearablesSignal not set.", Helpers.LogLevel.Error); - return; - } - - // Update with specified wearables - foreach (InventoryWearable iw in wearables) - { - byte type = (byte)((AssetWearable)iw.Asset).AppearanceLayer; - AgentWearablesData[type].ItemID = iw.ItemID; - AgentWearablesData[type].AssetID = iw.AssetID; - } - - // Create AgentIsNowWearing Packet, and send it - SendAgentIsNowWearing(); - - // Update local Appearance Info - GetAvatarAppearanceInfoFromWearableAssets(); - - // Send updated AgentSetAppearance to the grid - BeginAgentSendAppearance(); - } - - /// - /// Equivalent to the SL "Replace Outfit" command. All clothing is removed, and replaced with wearables in given folder. Body wearables will be replaced if provided. - /// - /// Contains the wearable items to put on. - public void WearOutfit(InventoryFolder outfitFolder) - { - WearOutfit(outfitFolder, 10000, true); - } - - - /// - /// Equivalent to the SL "Replace Outfit" command. All clothing is removed, and replaced with wearables in given folder. Body wearables will be replaced if provided. - /// - /// Contains the wearable items to put on. - /// How long to wait for outfit directory information to download - public void WearOutfit(InventoryFolder outfitFolder, int TimeOut, bool removeExistingAttachments) - { - // Refresh download of outfit folder - if (!outfitFolder.RequestDownloadContents(false, false, true).RequestComplete.WaitOne(TimeOut, false)) - { - Client.Log("Outfit not changed. An error occured while downloads the folder contents of : " + outfitFolder.Name, Helpers.LogLevel.Error); - return; - } - - // Make sure we have some Wearable Data to start with. - if (AgentWearablesSignal.WaitOne(1000, false) == false) - { - Client.Log("You must have set appearance at least once, before calling WearOutfit(). AgentWearablesSignal not set.", Helpers.LogLevel.Error); - return; - } - - // Flush the cached clothing wearables so we can redefine them - for (byte i = 4; i <= 12; i++) - { - AgentWearablesData[i].ItemID = LLUUID.Zero; - AgentWearablesData[i].AssetID = LLUUID.Zero; - } - - List attachments = new List(); - - // Replace with wearables from Outfit folder - foreach (InventoryBase ib in outfitFolder.GetContents()) - { - if (ib is InventoryWearable) - { - try - { - InventoryWearable iw = (InventoryWearable)ib; - Client.Log("Retrieving asset for " + iw.Name + "("+iw.AssetID+")", Helpers.LogLevel.Info); - AssetWearable.AppearanceLayerType AppearanceLayer = ((AssetWearable)iw.Asset).AppearanceLayer; - - Client.Log("Adding skin/clothing layer for " + AppearanceLayer, Helpers.LogLevel.Info); - AgentWearablesData[(byte)AppearanceLayer].ItemID = iw.ItemID; - AgentWearablesData[(byte)AppearanceLayer].AssetID = iw.AssetID; - - } - catch (Exception e) - { - Client.Log("Asset for " + ib._Name + " unavailable: " + e.Message, Helpers.LogLevel.Error); - } - } - else if (ib is InventoryItem) - { - InventoryItem ii = (InventoryItem)ib; - attachments.Add(ii); - } - } - - // Change attachments - AddAttachments(attachments, removeExistingAttachments); - - // Create AgentIsNowWearing Packet, and send it - SendAgentIsNowWearing(); - - // Send updated AgentSetAppearance to the grid - SendAgentSetAppearance(); - } - - public void AddAttachments(List attachments, bool removeExistingFirst) - { - // Use RezMultipleAttachmentsFromInv to clear out current attachments, and attach new ones - RezMultipleAttachmentsFromInvPacket attachmentsPacket = new RezMultipleAttachmentsFromInvPacket(); - attachmentsPacket.AgentData.AgentID = Client.Network.AgentID; - attachmentsPacket.AgentData.SessionID = Client.Network.SessionID; - - attachmentsPacket.HeaderData.CompoundMsgID = LLUUID.Random(); - attachmentsPacket.HeaderData.FirstDetachAll = true; - attachmentsPacket.HeaderData.TotalObjects = (byte)attachments.Count; - - attachmentsPacket.ObjectData = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[attachments.Count]; - for (int i = 0; i < attachments.Count; i++) - { - attachmentsPacket.ObjectData[i] = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock(); - attachmentsPacket.ObjectData[i].AttachmentPt = 0; - attachmentsPacket.ObjectData[i].EveryoneMask = attachments[i].EveryoneMask; - attachmentsPacket.ObjectData[i].GroupMask = attachments[i].GroupMask; - attachmentsPacket.ObjectData[i].ItemFlags = attachments[i].Flags; - attachmentsPacket.ObjectData[i].ItemID = attachments[i].ItemID; - attachmentsPacket.ObjectData[i].Name = Helpers.StringToField(attachments[i].Name); - attachmentsPacket.ObjectData[i].Description = Helpers.StringToField(attachments[i].Description); - attachmentsPacket.ObjectData[i].NextOwnerMask = attachments[i].NextOwnerMask; - attachmentsPacket.ObjectData[i].OwnerID = attachments[i].OwnerID; - } - - Client.Network.SendPacket(attachmentsPacket); - } - - #endregion - - - /// - /// Creates and sends an AgentIsNowWearing packet based on the local cached AgentWearablesData array. - /// - protected void SendAgentIsNowWearing() - { - AgentIsNowWearingPacket nowWearing = new AgentIsNowWearingPacket(); - nowWearing.AgentData.AgentID = Client.Network.AgentID; - nowWearing.AgentData.SessionID = Client.Network.SessionID; - nowWearing.WearableData = new AgentIsNowWearingPacket.WearableDataBlock[13]; - for (byte i = 0; i <= 12; i++) - { - nowWearing.WearableData[i] = new AgentIsNowWearingPacket.WearableDataBlock(); - nowWearing.WearableData[i].WearableType = i; - nowWearing.WearableData[i].ItemID = AgentWearablesData[i].ItemID; - } - - Client.Network.SendPacket(nowWearing); - } - - /// - /// Update the local Avatar Appearance information based on the contents of the assets as defined in the cached wearable data info. - /// - protected void GetAvatarAppearanceInfoFromWearableAssets() - { - // Make sure we have some Wearable Data to start with. - if (AgentWearablesSignal.WaitOne(1000, false) == false) - { - Client.Log("Cannot get Visual Param data from wearable assets. AgentWearablesSignal not set.", Helpers.LogLevel.Error); - return; - } - - // Clear current look - AgentTextureEntry = new LLObject.TextureEntry("C228D1CF4B5D4BA884F4899A0796AA97"); // if this isn't valid, blame JH ;-) - AgentAppearanceParams = new SerializableDictionary(); - - - // Build params and texture entries from wearable data - foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in AgentWearablesData) - { - if (wdb.ItemID == LLUUID.Zero) - { - continue; - } - - - AssetWearable wearableAsset; - - switch (wdb.WearableType) - { - case 0: - case 1: - case 2: - case 3: - wearableAsset = new AssetWearable_Body(wdb.AssetID, null); - break; - default: - wearableAsset = new AssetWearable_Clothing(wdb.AssetID, null); - break; - } - - AssetRequestDownload request = Client.Assets.RequestInventoryAsset(wearableAsset.AssetID, wearableAsset.Type); - if (request.Wait(AssetManager.DefaultTimeout) != AssetRequestDownload.RequestStatus.Success) - { - Client.Log("Asset (" + wearableAsset.AssetID.ToStringHyphenated() + ") unavailable (" + request.StatusMsg + ")", Helpers.LogLevel.Error); - } - else - { - wearableAsset.SetAssetData(request.GetAssetData()); - } - - if ((wearableAsset.AssetData == null) || (wearableAsset.AssetData.Length == 0)) - { - Client.Log("Asset retrieval failed for AssetID: " + wearableAsset.AssetID, Helpers.LogLevel.Warning); - } - - UpdateAgentTextureEntryAndAppearanceParams(wearableAsset); - - } - - - UpdateAgentTextureEntryOrder(); - } - - /// - /// TextureEntry must have it's face textures in a specific order for avatars. - /// Should be called at least once before sending an AgentSetAppearance packet. - /// - protected void UpdateAgentTextureEntryOrder() - { - // Correct the order of the textures - foreach (uint faceid in AgentTextureEntry.FaceTextures.Keys) - { - if (faceid > 18) - { - Client.Log("Unknown order for FaceID: " + faceid + Environment.NewLine + - "Your wearables define a face that we don't know the order of. Please " + - "capture a AgentSetAppearance packet for your current outfit and submit to " + - "static.sprocket@gmail.com, thanks!", Helpers.LogLevel.Info); - break; - } - } - - //Re-order texture faces to match Linden Labs internal data structure. - LLObject.TextureEntry te2 = new LLObject.TextureEntry(AgentTextureEntry.DefaultTexture.TextureID); - te2.CreateFace(18).TextureID = AgentTextureEntry.GetFace(18).TextureID; - te2.CreateFace(17).TextureID = AgentTextureEntry.GetFace(17).TextureID; - te2.CreateFace(16).TextureID = AgentTextureEntry.GetFace(16).TextureID; - te2.CreateFace(15).TextureID = AgentTextureEntry.GetFace(15).TextureID; - te2.CreateFace(14).TextureID = AgentTextureEntry.GetFace(14).TextureID; - te2.CreateFace(13).TextureID = AgentTextureEntry.GetFace(13).TextureID; - te2.CreateFace(12).TextureID = AgentTextureEntry.GetFace(12).TextureID; - // I wonder if shoes are somewhere in here? - te2.CreateFace(7).TextureID = AgentTextureEntry.GetFace(7).TextureID; - te2.CreateFace(6).TextureID = AgentTextureEntry.GetFace(6).TextureID; - te2.CreateFace(5).TextureID = AgentTextureEntry.GetFace(5).TextureID; - te2.CreateFace(4).TextureID = AgentTextureEntry.GetFace(4).TextureID; - te2.CreateFace(3).TextureID = AgentTextureEntry.GetFace(3).TextureID; - te2.CreateFace(2).TextureID = AgentTextureEntry.GetFace(2).TextureID; - te2.CreateFace(1).TextureID = AgentTextureEntry.GetFace(1).TextureID; - te2.CreateFace(0).TextureID = AgentTextureEntry.GetFace(0).TextureID; - - AgentTextureEntry = te2; - } - - /// - /// Updates the TextureEntry and Appearance Param structures with the data from an asset wearable. - /// Called once for each weable asset. - /// - /// - protected void UpdateAgentTextureEntryAndAppearanceParams(AssetWearable wearableAsset) - { - - try - { - foreach (KeyValuePair texture in wearableAsset.Textures) - { - AgentTextureEntry.CreateFace(texture.Key).TextureID = texture.Value; - } - - lock (AgentAppearanceParams) - { - foreach (KeyValuePair kvp in wearableAsset.Parameters) - { - AgentAppearanceParams[kvp.Key] = kvp.Value; - } - } - } - catch (Exception e) - { - Client.Log(e.ToString() + Environment.NewLine + wearableAsset.AssetDataToString(), Helpers.LogLevel.Error); - } - } - - /// - /// Non-blocking async request of wearables, construction and sending of AgentSetAppearance - /// - public void BeginAgentSendAppearance() - { - AgentWearablesSignal.Reset(); - - AgentWearablesRequestPacket p = new AgentWearablesRequestPacket(); - p.AgentData.AgentID = Client.Network.AgentID; - p.AgentData.SessionID = Client.Network.SessionID; - Client.Network.SendPacket(p); - } - - /// - /// Send an AgentSetAppearance packet to the server to update your appearance. - /// - - protected void SendAgentSetAppearance() - { - // Get latest appearance info - GetAvatarAppearanceInfoFromWearableAssets(); - - AgentSetAppearancePacket p = new AgentSetAppearancePacket(); - p.AgentData.AgentID = Client.Network.AgentID; - p.AgentData.SessionID = Client.Network.SessionID; - p.AgentData.SerialNum = SerialNum++; - - // Add Texture Data - p.ObjectData.TextureEntry = AgentTextureEntry.ToBytes(); - - - p.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[218]; - - string visualParamData = ""; - - // Add Visual Params - lock (AgentAppearanceParams) - { - for (int i = 0; i < 218; i++) - { - VisualParam param = VisualParams.Params[i]; - p.VisualParam[i] = new AgentSetAppearancePacket.VisualParamBlock(); - - visualParamData += i + "," + param.ParamID + ","; - - if (AgentAppearanceParams.ContainsKey(param.ParamID)) - { - p.VisualParam[i].ParamValue = Helpers.FloatToByte(AgentAppearanceParams[param.ParamID], - param.MinValue, param.MaxValue); - - visualParamData += AgentAppearanceParams[param.ParamID] + "," + p.VisualParam[i].ParamValue + Environment.NewLine; - } - else - { - // Use the default value for this parameter - p.VisualParam[i].ParamValue = Helpers.FloatToByte(param.DefaultValue, param.MinValue, - param.MaxValue); - - visualParamData += "NA," + p.VisualParam[i].ParamValue + Environment.NewLine; - - } - } - - - } - - // Add Size Data - p.AgentData.Size = GetAgentSizeFromVisualParam(Helpers.ByteToFloat(p.VisualParam[25].ParamValue, - VisualParams.Params[25].MinValue, VisualParams.Params[25].MaxValue)); - - Client.Network.SendPacket(p); - } - - /// - /// Determine agent size for AgentSetAppearance based on Visual Param data. - /// - /// - /// - protected LLVector3 GetAgentSizeFromVisualParam(float heightParam) - { - float AV_Height_Range = 2.025506f - 1.50856f; - float AV_Height = 1.50856f + ((heightParam / 255.0f) * AV_Height_Range); - return new LLVector3(0.45f, 0.6f, AV_Height); - //return new LLVector3(0.45f, 0.6f, 1.0f); - } - - #region Callback Handlers - - private void AgentWearablesUpdateCallbackHandler(Packet packet, Simulator simulator) - { - AgentWearablesUpdatePacket wearablesPacket = (AgentWearablesUpdatePacket)packet; - - AgentWearablesData = wearablesPacket.WearableData; - AgentWearablesSignal.Set(); - - // Grab access mutex... - WearableCacheQueueMutex.WaitOne(); - - // Queue download of wearables - foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in AgentWearablesData) - { - - // Don't try to download if AssetID is zero - if (wdb.AssetID == LLUUID.Zero) - { - continue; - } - - // Don't try to download, if it's already cached. - if (WearableCache.ContainsKey(wdb.AssetID)) - { - AssetWearable aw = WearableCache[wdb.AssetID]; - if (aw._AssetData != null) - { - continue; - } - } - - // Don't try to download, if it's already in the download queue - lock (WearableAssetQueue) - { - if (WearableAssetQueue.Contains(wdb.AssetID)) - { - continue; - } - } - - AssetWearable wearableAsset; - - switch (wdb.WearableType) - { - case 0: - case 1: - case 2: - case 3: - wearableAsset = new AssetWearable_Body(wdb.AssetID, null); - break; - default: - wearableAsset = new AssetWearable_Clothing(wdb.AssetID, null); - break; - } - - WearableCache[wdb.AssetID] = wearableAsset; - - lock (WearableAssetQueue) - { - if (!WearableAssetQueue.Contains(wdb.AssetID)) - { - WearableAssetQueue.Add(wdb.AssetID); - - LogWearableAssetQueueActivity("Added wearable asset to download queue: " + wearableAsset.GetType().Name + " : " + wdb.AssetID); - } - } - } - - RequestNextQueuedWearableAsset(); - - WearableCacheQueueMutex.ReleaseMutex(); - } - - /// - /// Sends a request for the next wearable asset. - /// - protected void RequestNextQueuedWearableAsset() - { - lock (WearableAssetQueue) - { - if (WearableAssetQueue.Count > 0) - { - AssetWearable wearableAsset = WearableCache[WearableAssetQueue[0]]; - AssetRequestDownload request = Client.Assets.RequestInventoryAsset(wearableAsset.AssetID, wearableAsset.Type); - LogWearableAssetQueueActivity("Requesting: " + wearableAsset.AssetID); - } - else - { - if (AgentWearablesSignal.WaitOne(0, false) == true) - { - // Send updated AgentSetAppearance - SendAgentSetAppearance(); - } - } - } - } - - /// - /// use to debug wearable asset queue activity - /// - /// - protected void LogWearableAssetQueueActivity(string msg) - { - if (LogWearableAssetQueue) - { - StringBuilder sb = new StringBuilder(); - sb.AppendLine("=================="); - sb.AppendLine(msg); - sb.AppendLine("Current Queue:"); - foreach (LLUUID uuid in WearableAssetQueue) - { - sb.AppendLine(" ** " + uuid.ToStringHyphenated()); - } - Client.Log(sb.ToString(), Helpers.LogLevel.Info); - } - } - - /// - /// Called each time a wearable asset is done downloading - /// - /// - void AManager_TransferRequestCompletedEvent(AssetRequest request) - { - if( !(request is AssetRequestDownload) ) - { - return; - } - - AssetRequestDownload dlrequest = (AssetRequestDownload)request; - - if (dlrequest.AssetID == null) - { - Client.Log("AssetID is null in AssetRequestDownload: " + dlrequest.StatusMsg, Helpers.LogLevel.Error); - } - - WearableCacheQueueMutex.WaitOne(); - - // Remove from the download queue - lock (WearableAssetQueue) - { - if (!WearableAssetQueue.Contains(dlrequest.AssetID)) - { - // Looks like we got an asset for something other then what we're waiting for, ignore it - WearableCacheQueueMutex.ReleaseMutex(); - - return; - } - } - - // Since we got a response for this asset, remove it from the queue - WearableAssetQueue.Remove(dlrequest.AssetID); - LogWearableAssetQueueActivity("Received queued asset, and removed: " + dlrequest.AssetID); - - // If the request wasn't successful, then don't try to process it. - if (request.Status != AssetRequest.RequestStatus.Success) - { - Client.Log("Error downloading wearable asset: " + dlrequest.AssetID, Helpers.LogLevel.Error); - WearableCacheQueueMutex.ReleaseMutex(); - - return; - } - - - AssetWearable wearableAsset = WearableCache[dlrequest.AssetID]; - wearableAsset.SetAssetData(dlrequest.GetAssetData()); - - if ((wearableAsset.AssetData == null) || (wearableAsset.AssetData.Length == 0)) - { - Client.Log("Asset retrieval failed for AssetID: " + wearableAsset.AssetID, Helpers.LogLevel.Error); - WearableCacheQueueMutex.ReleaseMutex(); - return; - } - else - { - UpdateAgentTextureEntryAndAppearanceParams(wearableAsset); - - UpdateAgentTextureEntryOrder(); - - lock(WearableAssetQueue) - { - if (WearableAssetQueue.Count > 0) - { - RequestNextQueuedWearableAsset(); - WearableCacheQueueMutex.ReleaseMutex(); - return; - - } - } - - // Now that all the wearable assets are done downloading, - // send an appearance packet - SendAgentSetAppearance(); - - WearableCacheQueueMutex.ReleaseMutex(); - return; - } - } - - #endregion - } -} +using System; +using System.Collections.Generic; +using System.Threading; + +using libsecondlife; +using libsecondlife.AssetSystem; +using libsecondlife.InventorySystem; +using libsecondlife.Packets; + +using System.Text; + + +namespace libsecondlife.AssetSystem +{ + public class AppearanceManager + { + public enum WearableType + { + Shape = 0, + Skin = 1, + Hair = 2, + Eyes = 3, + Shirt = 4, + Pants = 5, + Shoes = 6, + Socks = 7, + Jacket = 8, + Gloves = 9, + Undershirt = 10, + Underpants = 11, + Skirt = 12, + Count = 13, + Invalid = 255 + }; + + protected SecondLife Client; + protected AssetManager AManager; + + protected uint SerialNum = 1; + + protected ManualResetEvent AgentWearablesSignal = new ManualResetEvent(false); + + protected Dictionary WearableCache = new Dictionary(); + protected List WearableAssetQueue = new List(); + protected Mutex WearableCacheQueueMutex = new Mutex(); + + // This data defines all appearance info for an avatar + public AgentWearablesUpdatePacket.WearableDataBlock[] AgentWearablesData; + public SerializableDictionary AgentAppearanceParams = new SerializableDictionary(); + public LLObject.TextureEntry AgentTextureEntry = new LLObject.TextureEntry("C228D1CF4B5D4BA884F4899A0796AA97"); // if this isn't valid, blame JH ;-) + + public bool LogWearableAssetQueue = false; + + /// + /// + /// + /// + public AppearanceManager(SecondLife client) + { + Client = client; + Client.Network.RegisterCallback(libsecondlife.Packets.PacketType.AgentWearablesUpdate, new NetworkManager.PacketCallback(AgentWearablesUpdateCallbackHandler)); + + AManager = client.Assets; + AManager.TransferRequestCompletedEvent += new AssetManager.On_TransferRequestCompleted(AManager_TransferRequestCompletedEvent); + } + + #region Wear Stuff + + /// + /// Add a single wearable to your outfit, replacing if nessesary. + /// + /// + public void Wear(InventoryWearable wearable) + { + List x = new List(); + x.Add(wearable); + Wear(x); + } + + /// + /// Add the specified wearables to your outfit, replace existing ones if nessesary. + /// + /// + public void Wear(List wearables) + { + // Make sure we have some Wearable Data to start with. + if (AgentWearablesSignal.WaitOne(1000, false) == false) + { + Client.Log("You must have set appearance at least once, before calling Wear(). AgentWearablesSignal not set.", Helpers.LogLevel.Error); + return; + } + + // Update with specified wearables + foreach (InventoryWearable iw in wearables) + { + byte type = (byte)((AssetWearable)iw.Asset).AppearanceLayer; + AgentWearablesData[type].ItemID = iw.ItemID; + AgentWearablesData[type].AssetID = iw.AssetID; + } + + // Create AgentIsNowWearing Packet, and send it + SendAgentIsNowWearing(); + + // Update local Appearance Info + GetAvatarAppearanceInfoFromWearableAssets(); + + // Send updated AgentSetAppearance to the grid + BeginAgentSendAppearance(); + } + + /// + /// Equivalent to the SL "Replace Outfit" command. All clothing is removed, and replaced with wearables in given folder. Body wearables will be replaced if provided. + /// + /// Contains the wearable items to put on. + public void WearOutfit(InventoryFolder outfitFolder) + { + WearOutfit(outfitFolder, 10000, true); + } + + + /// + /// Equivalent to the SL "Replace Outfit" command. All clothing is removed, and replaced with wearables in given folder. Body wearables will be replaced if provided. + /// + /// Contains the wearable items to put on. + /// How long to wait for outfit directory information to download + public void WearOutfit(InventoryFolder outfitFolder, int TimeOut, bool removeExistingAttachments) + { + // Refresh download of outfit folder + if (!outfitFolder.RequestDownloadContents(false, false, true).RequestComplete.WaitOne(TimeOut, false)) + { + Client.Log("Outfit not changed. An error occured while downloads the folder contents of : " + outfitFolder.Name, Helpers.LogLevel.Error); + return; + } + + // Make sure we have some Wearable Data to start with. + if (AgentWearablesSignal.WaitOne(1000, false) == false) + { + Client.Log("You must have set appearance at least once, before calling WearOutfit(). AgentWearablesSignal not set.", Helpers.LogLevel.Error); + return; + } + + // Flush the cached clothing wearables so we can redefine them + for (byte i = 4; i <= 12; i++) + { + AgentWearablesData[i].ItemID = LLUUID.Zero; + AgentWearablesData[i].AssetID = LLUUID.Zero; + } + + List attachments = new List(); + + // Replace with wearables from Outfit folder + foreach (InventoryBase ib in outfitFolder.GetContents()) + { + if (ib is InventoryWearable) + { + try + { + InventoryWearable iw = (InventoryWearable)ib; + Client.Log("Retrieving asset for " + iw.Name + "("+iw.AssetID+")", Helpers.LogLevel.Info); + AssetWearable.AppearanceLayerType AppearanceLayer = ((AssetWearable)iw.Asset).AppearanceLayer; + + Client.Log("Adding skin/clothing layer for " + AppearanceLayer, Helpers.LogLevel.Info); + AgentWearablesData[(byte)AppearanceLayer].ItemID = iw.ItemID; + AgentWearablesData[(byte)AppearanceLayer].AssetID = iw.AssetID; + + } + catch (Exception e) + { + Client.Log("Asset for " + ib._Name + " unavailable: " + e.Message, Helpers.LogLevel.Error); + } + } + else if (ib is InventoryItem) + { + InventoryItem ii = (InventoryItem)ib; + attachments.Add(ii); + } + } + + // Change attachments + AddAttachments(attachments, removeExistingAttachments); + + // Create AgentIsNowWearing Packet, and send it + SendAgentIsNowWearing(); + + // Send updated AgentSetAppearance to the grid + SendAgentSetAppearance(); + } + + public void AddAttachments(List attachments, bool removeExistingFirst) + { + // Use RezMultipleAttachmentsFromInv to clear out current attachments, and attach new ones + RezMultipleAttachmentsFromInvPacket attachmentsPacket = new RezMultipleAttachmentsFromInvPacket(); + attachmentsPacket.AgentData.AgentID = Client.Network.AgentID; + attachmentsPacket.AgentData.SessionID = Client.Network.SessionID; + + attachmentsPacket.HeaderData.CompoundMsgID = LLUUID.Random(); + attachmentsPacket.HeaderData.FirstDetachAll = true; + attachmentsPacket.HeaderData.TotalObjects = (byte)attachments.Count; + + attachmentsPacket.ObjectData = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock[attachments.Count]; + for (int i = 0; i < attachments.Count; i++) + { + attachmentsPacket.ObjectData[i] = new RezMultipleAttachmentsFromInvPacket.ObjectDataBlock(); + attachmentsPacket.ObjectData[i].AttachmentPt = 0; + attachmentsPacket.ObjectData[i].EveryoneMask = attachments[i].EveryoneMask; + attachmentsPacket.ObjectData[i].GroupMask = attachments[i].GroupMask; + attachmentsPacket.ObjectData[i].ItemFlags = attachments[i].Flags; + attachmentsPacket.ObjectData[i].ItemID = attachments[i].ItemID; + attachmentsPacket.ObjectData[i].Name = Helpers.StringToField(attachments[i].Name); + attachmentsPacket.ObjectData[i].Description = Helpers.StringToField(attachments[i].Description); + attachmentsPacket.ObjectData[i].NextOwnerMask = attachments[i].NextOwnerMask; + attachmentsPacket.ObjectData[i].OwnerID = attachments[i].OwnerID; + } + + Client.Network.SendPacket(attachmentsPacket); + } + + #endregion + + + /// + /// Creates and sends an AgentIsNowWearing packet based on the local cached AgentWearablesData array. + /// + protected void SendAgentIsNowWearing() + { + AgentIsNowWearingPacket nowWearing = new AgentIsNowWearingPacket(); + nowWearing.AgentData.AgentID = Client.Network.AgentID; + nowWearing.AgentData.SessionID = Client.Network.SessionID; + nowWearing.WearableData = new AgentIsNowWearingPacket.WearableDataBlock[13]; + for (byte i = 0; i <= 12; i++) + { + nowWearing.WearableData[i] = new AgentIsNowWearingPacket.WearableDataBlock(); + nowWearing.WearableData[i].WearableType = i; + nowWearing.WearableData[i].ItemID = AgentWearablesData[i].ItemID; + } + + Client.Network.SendPacket(nowWearing); + } + + /// + /// Update the local Avatar Appearance information based on the contents of the assets as defined in the cached wearable data info. + /// + protected void GetAvatarAppearanceInfoFromWearableAssets() + { + // Make sure we have some Wearable Data to start with. + if (AgentWearablesSignal.WaitOne(1000, false) == false) + { + Client.Log("Cannot get Visual Param data from wearable assets. AgentWearablesSignal not set.", Helpers.LogLevel.Error); + return; + } + + // Clear current look + AgentTextureEntry = new LLObject.TextureEntry("C228D1CF4B5D4BA884F4899A0796AA97"); // if this isn't valid, blame JH ;-) + AgentAppearanceParams = new SerializableDictionary(); + + + // Build params and texture entries from wearable data + foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in AgentWearablesData) + { + if (wdb.ItemID == LLUUID.Zero) + { + continue; + } + + + AssetWearable wearableAsset; + + switch (wdb.WearableType) + { + case 0: + case 1: + case 2: + case 3: + wearableAsset = new AssetWearable_Body(wdb.AssetID, null); + break; + default: + wearableAsset = new AssetWearable_Clothing(wdb.AssetID, null); + break; + } + + AssetRequestDownload request = Client.Assets.RequestInventoryAsset(wearableAsset.AssetID, wearableAsset.Type); + if (request.Wait(AssetManager.DefaultTimeout) != AssetRequestDownload.RequestStatus.Success) + { + Client.Log("Asset (" + wearableAsset.AssetID.ToStringHyphenated() + ") unavailable (" + request.StatusMsg + ")", Helpers.LogLevel.Error); + } + else + { + wearableAsset.SetAssetData(request.GetAssetData()); + } + + if ((wearableAsset.AssetData == null) || (wearableAsset.AssetData.Length == 0)) + { + Client.Log("Asset retrieval failed for AssetID: " + wearableAsset.AssetID, Helpers.LogLevel.Warning); + } + + UpdateAgentTextureEntryAndAppearanceParams(wearableAsset); + + } + + + UpdateAgentTextureEntryOrder(); + } + + /// + /// TextureEntry must have it's face textures in a specific order for avatars. + /// Should be called at least once before sending an AgentSetAppearance packet. + /// + protected void UpdateAgentTextureEntryOrder() + { + // Correct the order of the textures + foreach (uint faceid in AgentTextureEntry.FaceTextures.Keys) + { + if (faceid > 18) + { + Client.Log("Unknown order for FaceID: " + faceid + Environment.NewLine + + "Your wearables define a face that we don't know the order of. Please " + + "capture a AgentSetAppearance packet for your current outfit and submit to " + + "static.sprocket@gmail.com, thanks!", Helpers.LogLevel.Info); + break; + } + } + + //Re-order texture faces to match Linden Labs internal data structure. + LLObject.TextureEntry te2 = new LLObject.TextureEntry(AgentTextureEntry.DefaultTexture.TextureID); + te2.CreateFace(18).TextureID = AgentTextureEntry.GetFace(18).TextureID; + te2.CreateFace(17).TextureID = AgentTextureEntry.GetFace(17).TextureID; + te2.CreateFace(16).TextureID = AgentTextureEntry.GetFace(16).TextureID; + te2.CreateFace(15).TextureID = AgentTextureEntry.GetFace(15).TextureID; + te2.CreateFace(14).TextureID = AgentTextureEntry.GetFace(14).TextureID; + te2.CreateFace(13).TextureID = AgentTextureEntry.GetFace(13).TextureID; + te2.CreateFace(12).TextureID = AgentTextureEntry.GetFace(12).TextureID; + // I wonder if shoes are somewhere in here? + te2.CreateFace(7).TextureID = AgentTextureEntry.GetFace(7).TextureID; + te2.CreateFace(6).TextureID = AgentTextureEntry.GetFace(6).TextureID; + te2.CreateFace(5).TextureID = AgentTextureEntry.GetFace(5).TextureID; + te2.CreateFace(4).TextureID = AgentTextureEntry.GetFace(4).TextureID; + te2.CreateFace(3).TextureID = AgentTextureEntry.GetFace(3).TextureID; + te2.CreateFace(2).TextureID = AgentTextureEntry.GetFace(2).TextureID; + te2.CreateFace(1).TextureID = AgentTextureEntry.GetFace(1).TextureID; + te2.CreateFace(0).TextureID = AgentTextureEntry.GetFace(0).TextureID; + + AgentTextureEntry = te2; + } + + /// + /// Updates the TextureEntry and Appearance Param structures with the data from an asset wearable. + /// Called once for each weable asset. + /// + /// + protected void UpdateAgentTextureEntryAndAppearanceParams(AssetWearable wearableAsset) + { + + try + { + foreach (KeyValuePair texture in wearableAsset.Textures) + { + AgentTextureEntry.CreateFace(texture.Key).TextureID = texture.Value; + } + + lock (AgentAppearanceParams) + { + foreach (KeyValuePair kvp in wearableAsset.Parameters) + { + AgentAppearanceParams[kvp.Key] = kvp.Value; + } + } + } + catch (Exception e) + { + Client.Log(e.ToString() + Environment.NewLine + wearableAsset.AssetDataToString(), Helpers.LogLevel.Error); + } + } + + /// + /// Non-blocking async request of wearables, construction and sending of AgentSetAppearance + /// + public void BeginAgentSendAppearance() + { + AgentWearablesSignal.Reset(); + + AgentWearablesRequestPacket p = new AgentWearablesRequestPacket(); + p.AgentData.AgentID = Client.Network.AgentID; + p.AgentData.SessionID = Client.Network.SessionID; + Client.Network.SendPacket(p); + } + + /// + /// Send an AgentSetAppearance packet to the server to update your appearance. + /// + + protected void SendAgentSetAppearance() + { + // Get latest appearance info + GetAvatarAppearanceInfoFromWearableAssets(); + + AgentSetAppearancePacket p = new AgentSetAppearancePacket(); + p.AgentData.AgentID = Client.Network.AgentID; + p.AgentData.SessionID = Client.Network.SessionID; + p.AgentData.SerialNum = SerialNum++; + + // Add Texture Data + p.ObjectData.TextureEntry = AgentTextureEntry.ToBytes(); + + + p.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[218]; + + string visualParamData = ""; + + // Add Visual Params + lock (AgentAppearanceParams) + { + for (int i = 0; i < 218; i++) + { + VisualParam param = VisualParams.Params[i]; + p.VisualParam[i] = new AgentSetAppearancePacket.VisualParamBlock(); + + visualParamData += i + "," + param.ParamID + ","; + + if (AgentAppearanceParams.ContainsKey(param.ParamID)) + { + p.VisualParam[i].ParamValue = Helpers.FloatToByte(AgentAppearanceParams[param.ParamID], + param.MinValue, param.MaxValue); + + visualParamData += AgentAppearanceParams[param.ParamID] + "," + p.VisualParam[i].ParamValue + Environment.NewLine; + } + else + { + // Use the default value for this parameter + p.VisualParam[i].ParamValue = Helpers.FloatToByte(param.DefaultValue, param.MinValue, + param.MaxValue); + + visualParamData += "NA," + p.VisualParam[i].ParamValue + Environment.NewLine; + + } + } + + + } + + // Add Size Data + p.AgentData.Size = GetAgentSizeFromVisualParam(Helpers.ByteToFloat(p.VisualParam[25].ParamValue, + VisualParams.Params[25].MinValue, VisualParams.Params[25].MaxValue)); + + Client.Network.SendPacket(p); + } + + /// + /// Determine agent size for AgentSetAppearance based on Visual Param data. + /// + /// + /// + protected LLVector3 GetAgentSizeFromVisualParam(float heightParam) + { + float AV_Height_Range = 2.025506f - 1.50856f; + float AV_Height = 1.50856f + ((heightParam / 255.0f) * AV_Height_Range); + return new LLVector3(0.45f, 0.6f, AV_Height); + //return new LLVector3(0.45f, 0.6f, 1.0f); + } + + #region Callback Handlers + + private void AgentWearablesUpdateCallbackHandler(Packet packet, Simulator simulator) + { + AgentWearablesUpdatePacket wearablesPacket = (AgentWearablesUpdatePacket)packet; + + AgentWearablesData = wearablesPacket.WearableData; + AgentWearablesSignal.Set(); + + // Grab access mutex... + WearableCacheQueueMutex.WaitOne(); + + // Queue download of wearables + foreach (AgentWearablesUpdatePacket.WearableDataBlock wdb in AgentWearablesData) + { + + // Don't try to download if AssetID is zero + if (wdb.AssetID == LLUUID.Zero) + { + continue; + } + + // Don't try to download, if it's already cached. + if (WearableCache.ContainsKey(wdb.AssetID)) + { + AssetWearable aw = WearableCache[wdb.AssetID]; + if (aw._AssetData != null) + { + continue; + } + } + + // Don't try to download, if it's already in the download queue + lock (WearableAssetQueue) + { + if (WearableAssetQueue.Contains(wdb.AssetID)) + { + continue; + } + } + + AssetWearable wearableAsset; + + switch (wdb.WearableType) + { + case 0: + case 1: + case 2: + case 3: + wearableAsset = new AssetWearable_Body(wdb.AssetID, null); + break; + default: + wearableAsset = new AssetWearable_Clothing(wdb.AssetID, null); + break; + } + + WearableCache[wdb.AssetID] = wearableAsset; + + lock (WearableAssetQueue) + { + if (!WearableAssetQueue.Contains(wdb.AssetID)) + { + WearableAssetQueue.Add(wdb.AssetID); + + LogWearableAssetQueueActivity("Added wearable asset to download queue: " + wearableAsset.GetType().Name + " : " + wdb.AssetID); + } + } + } + + RequestNextQueuedWearableAsset(); + + WearableCacheQueueMutex.ReleaseMutex(); + } + + /// + /// Sends a request for the next wearable asset. + /// + protected void RequestNextQueuedWearableAsset() + { + lock (WearableAssetQueue) + { + if (WearableAssetQueue.Count > 0) + { + AssetWearable wearableAsset = WearableCache[WearableAssetQueue[0]]; + /*AssetRequestDownload request =*/Client.Assets.RequestInventoryAsset(wearableAsset.AssetID, wearableAsset.Type); + LogWearableAssetQueueActivity("Requesting: " + wearableAsset.AssetID); + } + else + { + if (AgentWearablesSignal.WaitOne(0, false) == true) + { + // Send updated AgentSetAppearance + SendAgentSetAppearance(); + } + } + } + } + + /// + /// use to debug wearable asset queue activity + /// + /// + protected void LogWearableAssetQueueActivity(string msg) + { + if (LogWearableAssetQueue) + { + StringBuilder sb = new StringBuilder(); + sb.AppendLine("=================="); + sb.AppendLine(msg); + sb.AppendLine("Current Queue:"); + foreach (LLUUID uuid in WearableAssetQueue) + { + sb.AppendLine(" ** " + uuid.ToStringHyphenated()); + } + Client.Log(sb.ToString(), Helpers.LogLevel.Info); + } + } + + /// + /// Called each time a wearable asset is done downloading + /// + /// + void AManager_TransferRequestCompletedEvent(AssetRequest request) + { + if( !(request is AssetRequestDownload) ) + { + return; + } + + AssetRequestDownload dlrequest = (AssetRequestDownload)request; + + if (dlrequest.AssetID == null) + { + Client.Log("AssetID is null in AssetRequestDownload: " + dlrequest.StatusMsg, Helpers.LogLevel.Error); + } + + WearableCacheQueueMutex.WaitOne(); + + // Remove from the download queue + lock (WearableAssetQueue) + { + if (!WearableAssetQueue.Contains(dlrequest.AssetID)) + { + // Looks like we got an asset for something other then what we're waiting for, ignore it + WearableCacheQueueMutex.ReleaseMutex(); + + return; + } + } + + // Since we got a response for this asset, remove it from the queue + WearableAssetQueue.Remove(dlrequest.AssetID); + LogWearableAssetQueueActivity("Received queued asset, and removed: " + dlrequest.AssetID); + + // If the request wasn't successful, then don't try to process it. + if (request.Status != AssetRequest.RequestStatus.Success) + { + Client.Log("Error downloading wearable asset: " + dlrequest.AssetID, Helpers.LogLevel.Error); + WearableCacheQueueMutex.ReleaseMutex(); + + return; + } + + + AssetWearable wearableAsset = WearableCache[dlrequest.AssetID]; + wearableAsset.SetAssetData(dlrequest.GetAssetData()); + + if ((wearableAsset.AssetData == null) || (wearableAsset.AssetData.Length == 0)) + { + Client.Log("Asset retrieval failed for AssetID: " + wearableAsset.AssetID, Helpers.LogLevel.Error); + WearableCacheQueueMutex.ReleaseMutex(); + return; + } + else + { + UpdateAgentTextureEntryAndAppearanceParams(wearableAsset); + + UpdateAgentTextureEntryOrder(); + + lock(WearableAssetQueue) + { + if (WearableAssetQueue.Count > 0) + { + RequestNextQueuedWearableAsset(); + WearableCacheQueueMutex.ReleaseMutex(); + return; + + } + } + + // Now that all the wearable assets are done downloading, + // send an appearance packet + SendAgentSetAppearance(); + + WearableCacheQueueMutex.ReleaseMutex(); + return; + } + } + + #endregion + } +} diff --git a/libsecondlife-cs/AssetSystem/AssetRequest.cs b/libsecondlife-cs/AssetSystem/AssetRequest.cs index b2a1135d..79c99e57 100644 --- a/libsecondlife-cs/AssetSystem/AssetRequest.cs +++ b/libsecondlife-cs/AssetSystem/AssetRequest.cs @@ -1,217 +1,217 @@ -/* - * Copyright (c) 2006, Second Life Reverse Engineering Team - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the Second Life Reverse Engineering Team nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -//#define DEBUG_PACKETS - -using System; -using System.Collections.Generic; - -using libsecondlife; - -using libsecondlife.InventorySystem; - -using libsecondlife.Packets; -using System.Threading; - -namespace libsecondlife.AssetSystem -{ - public class AssetRequest - { - public enum RequestStatus { Success, Failure }; - - protected AssetManager _AssetManager; - - protected LLUUID _TransactionID; - public Asset AssetBeingTransferd; - - - protected ManualResetEvent _Completed = new ManualResetEvent(false); - - protected RequestStatus _Status; - public RequestStatus Status - { - get { return _Status; } - } - - protected string _StatusMsg = ""; - public string StatusMsg - { - get { return _StatusMsg; } - } - - protected int _Size; - protected byte[] _AssetData; - - protected uint _LastPacketTime; - public uint LastPacketTime { get { return _LastPacketTime; } } - - public uint SecondsSinceLastPacket { get { return Helpers.GetUnixTime() - _LastPacketTime; } } - - public AssetRequest(AssetManager Manager, LLUUID TransID, Asset Asset) - { - _AssetManager = Manager; - _TransactionID = TransID; - AssetBeingTransferd = Asset; - - _Size = int.MaxValue; - - UpdateLastPacketTime(); - } - - public AssetRequest(AssetManager Manager, LLUUID TransID) - { - _AssetManager = Manager; - _TransactionID = TransID; - AssetBeingTransferd = null; - - _Size = int.MaxValue; - - UpdateLastPacketTime(); - } - - - public void UpdateLastPacketTime() - { - _LastPacketTime = Helpers.GetUnixTime(); - } - - /// - /// Wait for this Request to be completed - /// - /// milliseconds to wait for next packet in download, -1 to wait indefinitely - /// - public RequestStatus Wait(int timeout) - { - return Wait(-1, timeout); - } - - /// - /// Wait for this Request to be completed. - /// - /// Hard Timeout should only be specified if you really can't wait for the download, even though it's still going and may be successful. - /// Return after hardTimeout milliseconds even if download is still in progress, -1 to wait indefinitely - /// How long to wait, before deciding download is stalled, -1 to wait indefinitely - /// - public RequestStatus Wait(int hardTimeout, int softTimeout) - { - UpdateLastPacketTime(); - - uint TimeStarted = LastPacketTime; - - while (!_Completed.WaitOne(900, false)) - { - if ((hardTimeout != -1) && (SecondsSinceLastPacket > hardTimeout)) - { - _StatusMsg += "Timeout Failure - Hard timeout reached (" + SecondsSinceLastPacket + " > " + hardTimeout + ")"; - return RequestStatus.Failure; - } - else - { - if ((softTimeout != -1) && (SecondsSinceLastPacket > softTimeout)) - { - _StatusMsg += "Timeout Failure - Soft Timeout ( " + SecondsSinceLastPacket + " > " + softTimeout + ")"; - return RequestStatus.Failure; - } - } - } - - return _Status; - } - - protected void MarkCompleted(RequestStatus status, string status_msg) - { - _StatusMsg += status_msg; - _Status = status; - - _Completed.Set(); - - _AssetManager.FireTransferRequestCompletedEvent(this); - } - - internal void Fail(string status_msg) - { - MarkCompleted(RequestStatus.Failure, status_msg); - } - - } - - - public class AssetRequestDownload : AssetRequest - { - protected int _Received; - protected SortedList _AssetDataReceived = new SortedList(); - protected LLUUID _AssetID; - public LLUUID AssetID - { - get { return _AssetID; } - } - - public AssetRequestDownload(AssetManager Manager, LLUUID TransID, LLUUID AssetID) - : base(Manager, TransID) - { - _Received = 0; - _AssetID = AssetID; - } - - internal void AddDownloadedData(int packetNum, byte[] data) - { - if (!_AssetDataReceived.ContainsKey(packetNum)) - { - _AssetDataReceived[packetNum] = data; - _Received += data.Length; - } - - // If we've gotten all the data, mark it completed. - if (_Received >= _Size) - { - int curPos = 0; - foreach (KeyValuePair kvp in _AssetDataReceived) - { - Array.Copy(kvp.Value, 0, _AssetData, curPos, kvp.Value.Length); - curPos += kvp.Value.Length; - } - - MarkCompleted(AssetRequestDownload.RequestStatus.Success, "Download Completed"); - } - - } - - internal void SetExpectedSize(int size) - { - _Size = size; - _AssetData = new byte[_Size]; - } - - /// - /// Get the asset data downloaded by this request. - /// - /// - public byte[] GetAssetData() - { - return _AssetData; - } - } -} +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#define DEBUG_PACKETS + +using System; +using System.Collections.Generic; + +using libsecondlife; + +using libsecondlife.InventorySystem; + +using libsecondlife.Packets; +using System.Threading; + +namespace libsecondlife.AssetSystem +{ + public class AssetRequest + { + public enum RequestStatus { Success, Failure }; + + protected AssetManager _AssetManager; + + protected LLUUID _TransactionID; + public Asset AssetBeingTransferd; + + + protected ManualResetEvent _Completed = new ManualResetEvent(false); + + protected RequestStatus _Status; + public RequestStatus Status + { + get { return _Status; } + } + + protected string _StatusMsg = ""; + public string StatusMsg + { + get { return _StatusMsg; } + } + + protected int _Size; + protected byte[] _AssetData; + + protected uint _LastPacketTime; + public uint LastPacketTime { get { return _LastPacketTime; } } + + public uint SecondsSinceLastPacket { get { return Helpers.GetUnixTime() - _LastPacketTime; } } + + public AssetRequest(AssetManager Manager, LLUUID TransID, Asset Asset) + { + _AssetManager = Manager; + _TransactionID = TransID; + AssetBeingTransferd = Asset; + + _Size = int.MaxValue; + + UpdateLastPacketTime(); + } + + public AssetRequest(AssetManager Manager, LLUUID TransID) + { + _AssetManager = Manager; + _TransactionID = TransID; + AssetBeingTransferd = null; + + _Size = int.MaxValue; + + UpdateLastPacketTime(); + } + + + public void UpdateLastPacketTime() + { + _LastPacketTime = Helpers.GetUnixTime(); + } + + /// + /// Wait for this Request to be completed + /// + /// milliseconds to wait for next packet in download, -1 to wait indefinitely + /// + public RequestStatus Wait(int timeout) + { + return Wait(-1, timeout); + } + + /// + /// Wait for this Request to be completed. + /// + /// Hard Timeout should only be specified if you really can't wait for the download, even though it's still going and may be successful. + /// Return after hardTimeout milliseconds even if download is still in progress, -1 to wait indefinitely + /// How long to wait, before deciding download is stalled, -1 to wait indefinitely + /// + public RequestStatus Wait(int hardTimeout, int softTimeout) + { + UpdateLastPacketTime(); + +// uint TimeStarted = LastPacketTime; + + while (!_Completed.WaitOne(900, false)) + { + if ((hardTimeout != -1) && (SecondsSinceLastPacket > hardTimeout)) + { + _StatusMsg += "Timeout Failure - Hard timeout reached (" + SecondsSinceLastPacket + " > " + hardTimeout + ")"; + return RequestStatus.Failure; + } + else + { + if ((softTimeout != -1) && (SecondsSinceLastPacket > softTimeout)) + { + _StatusMsg += "Timeout Failure - Soft Timeout ( " + SecondsSinceLastPacket + " > " + softTimeout + ")"; + return RequestStatus.Failure; + } + } + } + + return _Status; + } + + protected void MarkCompleted(RequestStatus status, string status_msg) + { + _StatusMsg += status_msg; + _Status = status; + + _Completed.Set(); + + _AssetManager.FireTransferRequestCompletedEvent(this); + } + + internal void Fail(string status_msg) + { + MarkCompleted(RequestStatus.Failure, status_msg); + } + + } + + + public class AssetRequestDownload : AssetRequest + { + protected int _Received; + protected SortedList _AssetDataReceived = new SortedList(); + protected LLUUID _AssetID; + public LLUUID AssetID + { + get { return _AssetID; } + } + + public AssetRequestDownload(AssetManager Manager, LLUUID TransID, LLUUID AssetID) + : base(Manager, TransID) + { + _Received = 0; + _AssetID = AssetID; + } + + internal void AddDownloadedData(int packetNum, byte[] data) + { + if (!_AssetDataReceived.ContainsKey(packetNum)) + { + _AssetDataReceived[packetNum] = data; + _Received += data.Length; + } + + // If we've gotten all the data, mark it completed. + if (_Received >= _Size) + { + int curPos = 0; + foreach (KeyValuePair kvp in _AssetDataReceived) + { + Array.Copy(kvp.Value, 0, _AssetData, curPos, kvp.Value.Length); + curPos += kvp.Value.Length; + } + + MarkCompleted(AssetRequestDownload.RequestStatus.Success, "Download Completed"); + } + + } + + internal void SetExpectedSize(int size) + { + _Size = size; + _AssetData = new byte[_Size]; + } + + /// + /// Get the asset data downloaded by this request. + /// + /// + public byte[] GetAssetData() + { + return _AssetData; + } + } +} diff --git a/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs b/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs index ec8a0db6..ff4a7c7f 100644 --- a/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs +++ b/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs @@ -1,213 +1,213 @@ -/* - * Copyright (c) 2006, Second Life Reverse Engineering Team - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the Second Life Reverse Engineering Team nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -//#define DEBUG_PACKETS -#define DEBUG_HEADERS - -using System; -using System.Collections.Generic; - -using libsecondlife; - -using libsecondlife.InventorySystem; - -using libsecondlife.Packets; -using System.Threading; - -namespace libsecondlife.AssetSystem -{ - public class AssetRequestUpload : AssetRequest - { - protected SecondLife _Client; - protected readonly int _MaxResendAttempts = 20; - - protected ulong _XferID; - - protected int _ResendCount; - protected uint _CurrentPacket; - - protected int _NumPackets2Send; - - public AssetRequestUpload(SecondLife Client, LLUUID TransID, Asset Asset2Upload) : base(Client.Assets, TransID, Asset2Upload) - { - if ((AssetBeingTransferd._AssetData == null) || (AssetBeingTransferd._AssetData.Length == 0)) - { - throw new Exception("Asset data cannot be null."); - } - - _Client = Client; - - _CurrentPacket = 0; - _ResendCount = 0; - _NumPackets2Send = AssetBeingTransferd._AssetData.Length / 1000; - if (_NumPackets2Send < 1) - { - _NumPackets2Send = 1; - } - } - - internal LLUUID DoUpload() - { - SendFirstPacket(); - - while ((_Completed.WaitOne(1000, true) == false) && (_ResendCount < _MaxResendAttempts)) - { - if (this.SecondsSinceLastPacket > 2) - { - _Client.Log("Resending Packet (more than 2 seconds since last confirm)", Helpers.LogLevel.Info); - this.SendCurrentPacket(); - _ResendCount++; - } - } - - - if (_Status == RequestStatus.Failure) - { - throw new Exception(_StatusMsg); - } - else - { - return _TransactionID; - } - } - - protected void SendFirstPacket() - { - Packet packet; - - if (AssetBeingTransferd._AssetData.Length > 1000) - { - packet = AssetPacketHelpers.AssetUploadRequestHeaderOnly(AssetBeingTransferd, _TransactionID); - } - else - { - packet = AssetPacketHelpers.AssetUploadRequest(AssetBeingTransferd, _TransactionID); - } - - _Client.Network.SendPacket(packet); - - #if DEBUG_PACKETS - slClient.DebugLog(packet); - #endif - #if DEBUG_HEADERS - _Client.DebugLog(packet.Header.ToString()); - #endif - } - - internal void RequestXfer(ulong XferID) - { - _XferID = XferID; - // Setup to send the first packet - SendCurrentPacket(); - } - - internal void ConfirmXferPacket(ulong XferID, uint PacketNumConfirmed) - { - // TODO should check that this is the same transfer? - this.UpdateLastPacketTime(); - - if (PacketNumConfirmed == _CurrentPacket) - { - // Increment Packet # - this._CurrentPacket++; - this._ResendCount = 0; - SendCurrentPacket(); - } - else - { - throw new Exception("Something is wrong with uploading assets, a confirmation came in for a packet we didn't send."); - } - } - - protected void SendCurrentPacket() - { - Packet uploadPacket; - - // THREADING: snapshot this num so we use a consistent value throughout - uint packetNum = _CurrentPacket; - if (packetNum == 0) - { - if (AssetBeingTransferd._AssetData.Length <= 1000) - { - throw new Exception("Should not use xfer for small assets"); - } - int dataSize = 1000; - - byte[] packetData = new byte[dataSize + 4]; // Extra space is for leading data length bytes - - // Prefix the first Xfer packet with the data length - // FIXME: Apply endianness patch - Array.Copy(BitConverter.GetBytes((int)AssetBeingTransferd._AssetData.Length), 0, packetData, 0, 4); - Array.Copy(AssetBeingTransferd._AssetData, 0, packetData, 4, dataSize); - - uploadPacket = AssetPacketHelpers.SendXferPacket(_XferID, packetData, packetNum); - } - else if (packetNum < _NumPackets2Send) - { - byte[] packetData = new byte[1000]; - Array.Copy(AssetBeingTransferd._AssetData, packetNum * 1000, packetData, 0, 1000); - - uploadPacket = AssetPacketHelpers.SendXferPacket(_XferID, packetData, packetNum); - } - else - { - // The last packet has to be handled slightly differently - int lastLen = this.AssetBeingTransferd._AssetData.Length - (_NumPackets2Send * 1000); - byte[] packetData = new byte[lastLen]; - Array.Copy(this.AssetBeingTransferd._AssetData, _NumPackets2Send * 1000, packetData, 0, lastLen); - - uint lastPacket = (uint)int.MaxValue + (uint)_NumPackets2Send + (uint)1; - uploadPacket = AssetPacketHelpers.SendXferPacket(_XferID, packetData, lastPacket); - } - - _Client.Network.SendPacket(uploadPacket); - - #if DEBUG_PACKETS - slClient.DebugLog(uploadPacket); - #endif - #if DEBUG_HEADERS - _Client.DebugLog(uploadPacket.Header.ToString()); - #endif - } - - internal void UploadComplete(LLUUID assetID, RequestStatus success) - { - AssetBeingTransferd.AssetID = assetID; - UpdateLastPacketTime(); - _Client.Log("Upload complete", Helpers.LogLevel.Info); - - if (_Status == RequestStatus.Success) - { - MarkCompleted(success, "Success"); - } - else - { - MarkCompleted(success, "Server returned failed"); - } - - } - } -} +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +//#define DEBUG_PACKETS +#define DEBUG_HEADERS + +using System; +using System.Collections.Generic; + +using libsecondlife; + +using libsecondlife.InventorySystem; + +using libsecondlife.Packets; +using System.Threading; + +namespace libsecondlife.AssetSystem +{ + public class AssetRequestUpload : AssetRequest + { + protected SecondLife _Client; + protected readonly int _MaxResendAttempts = 20; + + protected ulong _XferID; + + protected int _ResendCount; + protected uint _CurrentPacket; + + protected int _NumPackets2Send; + + public AssetRequestUpload(SecondLife Client, LLUUID TransID, Asset Asset2Upload) : base(Client.Assets, TransID, Asset2Upload) + { + if ((AssetBeingTransferd._AssetData == null) || (AssetBeingTransferd._AssetData.Length == 0)) + { + throw new Exception("Asset data cannot be null."); + } + + _Client = Client; + + _CurrentPacket = 0; + _ResendCount = 0; + _NumPackets2Send = AssetBeingTransferd._AssetData.Length / 1000; + if (_NumPackets2Send < 1) + { + _NumPackets2Send = 1; + } + } + + internal LLUUID DoUpload() + { + SendFirstPacket(); + + while ((_Completed.WaitOne(1000, true) == false) && (_ResendCount < _MaxResendAttempts)) + { + if (this.SecondsSinceLastPacket > 2) + { + _Client.Log("Resending Packet (more than 2 seconds since last confirm)", Helpers.LogLevel.Info); + this.SendCurrentPacket(); + _ResendCount++; + } + } + + + if (_Status == RequestStatus.Failure) + { + throw new Exception(_StatusMsg); + } + else + { + return _TransactionID; + } + } + + protected void SendFirstPacket() + { + Packet packet; + + if (AssetBeingTransferd._AssetData.Length > 1000) + { + packet = AssetPacketHelpers.AssetUploadRequestHeaderOnly(AssetBeingTransferd, _TransactionID); + } + else + { + packet = AssetPacketHelpers.AssetUploadRequest(AssetBeingTransferd, _TransactionID); + } + + _Client.Network.SendPacket(packet); + + #if DEBUG_PACKETS + slClient.DebugLog(packet); + #endif + #if DEBUG_HEADERS + _Client.DebugLog(packet.Header.ToString()); + #endif + } + + internal void RequestXfer(ulong XferID) + { + _XferID = XferID; + // Setup to send the first packet + SendCurrentPacket(); + } + + internal void ConfirmXferPacket(ulong XferID, uint PacketNumConfirmed) + { + // TODO should check that this is the same transfer? + this.UpdateLastPacketTime(); + + if (PacketNumConfirmed == _CurrentPacket) + { + // Increment Packet # + this._CurrentPacket++; + this._ResendCount = 0; + SendCurrentPacket(); + } + else + { + throw new Exception("Something is wrong with uploading assets, a confirmation came in for a packet we didn't send."); + } + } + + protected void SendCurrentPacket() + { + Packet uploadPacket; + + // THREADING: snapshot this num so we use a consistent value throughout + uint packetNum = _CurrentPacket; + if (packetNum == 0) + { + if (AssetBeingTransferd._AssetData.Length <= 1000) + { + throw new Exception("Should not use xfer for small assets"); + } + int dataSize = 1000; + + byte[] packetData = new byte[dataSize + 4]; // Extra space is for leading data length bytes + + // Prefix the first Xfer packet with the data length + // FIXME: Apply endianness patch + Array.Copy(BitConverter.GetBytes((int)AssetBeingTransferd._AssetData.Length), 0, packetData, 0, 4); + Array.Copy(AssetBeingTransferd._AssetData, 0, packetData, 4, dataSize); + + uploadPacket = AssetPacketHelpers.SendXferPacket(_XferID, packetData, packetNum); + } + else if (packetNum < _NumPackets2Send) + { + byte[] packetData = new byte[1000]; + Array.Copy(AssetBeingTransferd._AssetData, packetNum * 1000, packetData, 0, 1000); + + uploadPacket = AssetPacketHelpers.SendXferPacket(_XferID, packetData, packetNum); + } + else + { + // The last packet has to be handled slightly differently + int lastLen = this.AssetBeingTransferd._AssetData.Length - (_NumPackets2Send * 1000); + byte[] packetData = new byte[lastLen]; + Array.Copy(this.AssetBeingTransferd._AssetData, _NumPackets2Send * 1000, packetData, 0, lastLen); + + uint lastPacket = (uint)int.MaxValue + (uint)_NumPackets2Send + (uint)1; + uploadPacket = AssetPacketHelpers.SendXferPacket(_XferID, packetData, lastPacket); + } + + _Client.Network.SendPacket(uploadPacket); + + #if DEBUG_PACKETS + slClient.DebugLog(uploadPacket); + #endif + #if DEBUG_HEADERS + _Client.DebugLog(uploadPacket.Header.ToString()); + #endif + } + + internal void UploadComplete(LLUUID assetID, RequestStatus success) + { + AssetBeingTransferd.AssetID = assetID; + UpdateLastPacketTime(); + _Client.Log("Upload complete", Helpers.LogLevel.Info); + + if (_Status == RequestStatus.Success) + { + MarkCompleted(success, "Success"); + } + else + { + MarkCompleted(success, "Server returned failed"); + } + + } + } +} diff --git a/libsecondlife-cs/AssetSystem/AssetScript.cs b/libsecondlife-cs/AssetSystem/AssetScript.cs index ee79e165..fcc47b35 100644 --- a/libsecondlife-cs/AssetSystem/AssetScript.cs +++ b/libsecondlife-cs/AssetSystem/AssetScript.cs @@ -1,43 +1,43 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace libsecondlife.AssetSystem -{ - public class AssetScript : Asset - { - private string _Source; - public string Source - { - get { return _Source; } - set - { - _Source = value.Replace("\r", ""); - setAsset(_Source); - } - } - - public AssetScript(LLUUID assetID, string source) - : base(assetID, (sbyte)Asset.AssetType.LSLText, false, null) - { - _Source = source; - setAsset(source); - } - - public AssetScript(LLUUID assetID, byte[] assetData) - : base(assetID, (sbyte)Asset.AssetType.LSLText, false, assetData) - { - _Source = System.Text.Encoding.UTF8.GetString(assetData).Trim(); - } - - private void setAsset(string source) - { - // Assume this is a string, add 1 for the null terminator - byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(source); - byte[] assetData = new byte[stringBytes.Length + 1]; - Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length); - SetAssetData(assetData); - } - - } -} +using System; +using System.Collections.Generic; +using System.Text; + +namespace libsecondlife.AssetSystem +{ + public class AssetScript : Asset + { + private string _Source; + public string Source + { + get { return _Source; } + set + { + _Source = value.Replace("\r", ""); + setAsset(_Source); + } + } + + public AssetScript(LLUUID assetID, string source) + : base(assetID, (sbyte)Asset.AssetType.LSLText, false, null) + { + _Source = source; + setAsset(source); + } + + public AssetScript(LLUUID assetID, byte[] assetData) + : base(assetID, (sbyte)Asset.AssetType.LSLText, false, assetData) + { + _Source = System.Text.Encoding.UTF8.GetString(assetData).Trim(); + } + + private void setAsset(string source) + { + // Assume this is a string, add 1 for the null terminator + byte[] stringBytes = System.Text.Encoding.UTF8.GetBytes(source); + byte[] assetData = new byte[stringBytes.Length + 1]; + Array.Copy(stringBytes, 0, assetData, 0, stringBytes.Length); + SetAssetData(assetData); + } + + } +} diff --git a/libsecondlife-cs/AssetSystem/AssetWearable.cs b/libsecondlife-cs/AssetSystem/AssetWearable.cs index ef3d4759..98626de8 100644 --- a/libsecondlife-cs/AssetSystem/AssetWearable.cs +++ b/libsecondlife-cs/AssetSystem/AssetWearable.cs @@ -1,540 +1,527 @@ -/* - * Copyright (c) 2006, Second Life Reverse Engineering Team - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the Second Life Reverse Engineering Team nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -using System.Threading; -using System.Globalization; - -using libsecondlife; - -namespace libsecondlife.AssetSystem -{ - /// - /// Asset for wearables such as Socks, Eyes, Gloves, Hair, Pants, Shape, Shirt, Shoes, Skin, Jacket, Skirt, Underpants - /// - public class AssetWearable : Asset - { - private string _Name = ""; - public string Name - { - get { return _Name; } - set - { - _Name = value; - UpdateAssetData(); - } - } - private string _Description = ""; - public string Description - { - get { return _Description; } - set - { - _Description = value; - UpdateAssetData(); - } - } - - private AppearanceLayerType _AppearanceLayer = 0; - public AppearanceLayerType AppearanceLayer - { - get { return _AppearanceLayer; } - set - { - _AppearanceLayer = value; - UpdateAssetData(); - } - } - - private string _Sale_Type = "not"; - public string Sale_Type - { - get { return _Sale_Type; } - set - { - _Sale_Type = value; - UpdateAssetData(); - } - } - - private uint _Sale_Price = 10; - public uint Sale_Price - { - get { return _Sale_Price; } - set - { - _Sale_Price = value; - UpdateAssetData(); - } - } - - private LLUUID _Creator_ID = new LLUUID(); - public LLUUID Creator_ID - { - get { return _Creator_ID; } - set - { - _Creator_ID = value; - UpdateAssetData(); - } - } - private LLUUID _Owner_ID = new LLUUID(); - public LLUUID Owner_ID - { - get { return _Owner_ID; } - set - { - _Owner_ID = value; - UpdateAssetData(); - } - } - private LLUUID _Last_Owner_ID = new LLUUID(); - public LLUUID Last_Owner_ID - { - get { return _Last_Owner_ID; } - set - { - _Last_Owner_ID = value; - UpdateAssetData(); - } - } - - private LLUUID _Group_ID = new LLUUID(); - public LLUUID Group_ID - { - get { return _Group_ID; } - set - { - _Group_ID = value; - UpdateAssetData(); - } - } - - private bool _Group_Owned = false; - public bool Group_Owned - { - get { return _Group_Owned; } - set - { - _Group_Owned = value; - UpdateAssetData(); - } - } - - - private uint _Permission_Base_Mask = 0; - public uint Permission_Base_Mask - { - get { return _Permission_Base_Mask; } - set - { - _Permission_Base_Mask = value; - UpdateAssetData(); - } - } - - private uint _Permission_Owner_Mask = 0; - public uint Permission_Owner_Mask - { - get { return _Permission_Owner_Mask; } - set - { - _Permission_Owner_Mask = value; - UpdateAssetData(); - } - } - - private uint _Permission_Group_Mask = 0; - public uint Permission_Group_Mask - { - get { return _Permission_Group_Mask; } - set - { - _Permission_Group_Mask = value; - UpdateAssetData(); - } - } - - private uint _Permission_Everyone_Mask = 0; - public uint Permission_Everyone_Mask - { - get { return _Permission_Everyone_Mask; } - set - { - _Permission_Everyone_Mask = value; - UpdateAssetData(); - } - } - - private uint _Permission_Next_Owner_Mask = 0; - public uint Permission_Next_Owner_Mask - { - get { return _Permission_Next_Owner_Mask; } - set - { - _Permission_Next_Owner_Mask = value; - UpdateAssetData(); - } - } - - private Dictionary _Parameters = new Dictionary(); - public Dictionary Parameters - { - get { return _Parameters; } - set - { - _Parameters = value; - UpdateAssetData(); - } - } - - private Dictionary _Textures = new Dictionary(); - public Dictionary Textures - { - get { return _Textures; } - set - { - _Textures = value; - UpdateAssetData(); - } - } - - private string[] _ForSaleNames = new string[] - { - "not", - "orig", - "copy", - "cntn" - }; - - private enum _ForSale - { - /// Not for sale - Not = 0, - /// The original is for sale - Original = 1, - /// Copies are for sale - Copy = 2, - /// The contents of the object are for sale - Contents = 3 - } - - private _ForSale _Sale = _ForSale.Not; - private int _SalePrice = 0; - - - public enum AppearanceLayerType : byte - { - /// - Shape = 0, - /// - Skin, - /// - Hair, - /// - Eyes, - /// - Shirt, - /// - Pants, - /// - Shoes, - /// - Socks, - /// - Jacket, - /// - Gloves, - /// - Undershirt, - /// - Underpants, - /// - Skirt, - /// - Invalid = 255 - }; - - - /// - /// - /// - /// - public AssetWearable(LLUUID assetID, sbyte assetType, byte[] assetData) - : base(assetID, assetType, false, assetData) - { - UpdateFromAssetData(); - } - - /// - /// Converts byte[] data from a data transfer into a bodypart class - /// - /// - internal void UpdateFromAssetData() - { - Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us"); - Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us"); - - if ( AssetData == null || AssetData.Length == 0) - { - return; - } - - string wearableData = Helpers.FieldToUTF8String(this._AssetData); - - int version = -1; - int n = -1; - - try - { - n = wearableData.IndexOf('\n'); - version = Int32.Parse(wearableData.Substring(19, n - 18)); - wearableData = wearableData.Remove(0, n); - - if (version != 22) - { - Console.WriteLine("** WARNING ** : Wearable asset has unrecognized version " + version); - return; - } - - n = wearableData.IndexOf('\n'); - Name = wearableData.Substring(0, n); - wearableData = wearableData.Remove(0, n); - - n = wearableData.IndexOf('\n'); - Description = wearableData.Substring(0, n); - wearableData = wearableData.Remove(0, n); - - // Split in to an upper and lower half - string[] parts = wearableData.Split(new string[] { "parameters" }, StringSplitOptions.None); - parts[1] = "parameters" + parts[1]; - - // Parse the upper half - string[] lines = parts[0].Split('\n'); - foreach (string thisline in lines) - { - string line = thisline.Trim(); - string[] fields = line.Split('\t'); - - if (fields.Length == 2) - { - if (fields[0] == "creator_mask") - { - // Deprecated, apply this as the base mask - _Permission_Base_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - } - else if (fields[0] == "base_mask") - { - _Permission_Base_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - } - else if (fields[0] == "owner_mask") - { - _Permission_Owner_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - } - else if (fields[0] == "group_mask") - { - _Permission_Group_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - } - else if (fields[0] == "everyone_mask") - { - _Permission_Everyone_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - } - else if (fields[0] == "next_owner_mask") - { - _Permission_Next_Owner_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); - } - else if (fields[0] == "creator_id") - { - _Creator_ID = new LLUUID(fields[1]); - } - else if (fields[0] == "owner_id") - { - _Owner_ID = new LLUUID(fields[1]); - } - else if (fields[0] == "last_owner_id") - { - _Last_Owner_ID = new LLUUID(fields[1]); - } - else if (fields[0] == "group_id") - { - _Group_ID = new LLUUID(fields[1]); - } - else if (fields[0] == "group_owned") - { - - _Group_Owned = (Int32.Parse(fields[1]) != 0); - } - else if (fields[0] == "sale_type") - { - for (int i = 0; i < _ForSaleNames.Length; i++) - { - if (fields[1] == _ForSaleNames[i]) - { - _Sale = (_ForSale)i; - break; - } - } - } - else if (fields[0] == "sale_price") - { - _SalePrice = Int32.Parse(fields[1]); - } - else if (fields[0] == "perm_mask") - { - Console.WriteLine("** WARNING ** : Wearable asset has deprecated perm_mask field, ignoring"); - } - } - else if (line.StartsWith("type ")) - { - AppearanceLayer = (AppearanceLayerType)Int32.Parse(line.Substring(5)); - break; - } - } - - // Break up the lower half in to parameters and textures - string[] lowerparts = parts[1].Split(new string[] { "textures" }, StringSplitOptions.None); - lowerparts[1] = "textures" + lowerparts[1]; - - // Parse the parameters - lines = lowerparts[0].Split('\n'); - foreach (string line in lines) - { - string[] fields = line.Split(' '); - - // Use exception handling to deal with all the lines we aren't interested in - try - { - int id = Int32.Parse(fields[0]); - float weight; Single.Parse(fields[1], System.Globalization.NumberStyles.Float); - if (Single.TryParse(fields[1], System.Globalization.NumberStyles.Float, new CultureInfo("en-us").NumberFormat, out weight) == false) - { - weight = 0.0f; - } - - _Parameters[id] = weight; - } - catch (Exception) - { - } - } - - // Parse the textures - lines = lowerparts[1].Split('\n'); - foreach (string line in lines) - { - string[] fields = line.Split(' '); - - // Use exception handling to deal with all the lines we aren't interested in - try - { - uint id = UInt32.Parse(fields[0]); - LLUUID texture = LLUUID.Parse(fields[1]); - - _Textures[id] = texture; - } - catch (Exception) - { - } - } - - return; - } - catch (Exception e) - { - Console.WriteLine("** WARNING **", "Failed to parse wearable asset: " + e.ToString()); - } - - return; - } - - private void UpdateAssetData() - { - string data = "LLWearable version 22\n"; - data += this._Name + "\n\n"; - data += "\tpermissions 0\n\t{\n"; - data += "\t\tbase_mask\t" + uintToHex(this._Permission_Base_Mask); - data += "\n\t\towner_mask\t" + uintToHex(this._Permission_Owner_Mask); - data += "\n\t\tgroup_mask\t" + uintToHex(this._Permission_Group_Mask); - data += "\n\t\teveryone_mask\t" + uintToHex(this._Permission_Everyone_Mask); - data += "\n\t\tnext_owner_mask\t" + uintToHex(this._Permission_Next_Owner_Mask); - data += "\n\t\tcreator_id\t" + this._Creator_ID.ToStringHyphenated(); - data += "\n\t\towner_id\t" + this._Owner_ID.ToStringHyphenated(); - data += "\n\t\tlast_owner_id\t" + this._Last_Owner_ID.ToStringHyphenated(); - data += "\n\t\tgroup_id\t" + this._Group_ID.ToStringHyphenated(); - data += "\n\t}"; - data += "\n\tsale_info\t0"; - data += "\n\t{"; - data += "\n\t\tsale_type\t" + this._Sale_Type; - data += "\n\t\tsale_price\t" + this._Sale_Price; - data += "\n\t}"; - data += "\ntype " + this._AppearanceLayer; - data += "\nparameters " + this._Parameters.Count; - foreach (KeyValuePair param in this._Parameters) - { - string prm = string.Format("{0:f1}", param.Value); - if (prm == "-1.0" || prm == "1.0" || prm == "0.0") - { - switch (prm) - { - case "-1.0": - prm = "-1"; - break; - case "0.0": - prm = "0"; - break; - case "1.0": - prm = "1"; - break; - } - } - data += "\n" + param.Key + " " + prm; - } - data += "\ntextures " + this._Textures.Count; - foreach (KeyValuePair texture in this._Textures) - { - data += "\n" + texture.Key + " " + texture.Value.ToStringHyphenated(); - } - - _AssetData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray()); - } - - private static string uintToHex(uint i) - { - return string.Format("{0:x8}", i); - } - - public override void SetAssetData(byte[] data) - { - _AssetData = data; - if ( (_AssetData != null) && (_AssetData.Length > 0) ) - { - UpdateFromAssetData(); - } - } - } -} +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +using System.Threading; +using System.Globalization; + +using libsecondlife; + +namespace libsecondlife.AssetSystem +{ + /// + /// Asset for wearables such as Socks, Eyes, Gloves, Hair, Pants, Shape, Shirt, Shoes, Skin, Jacket, Skirt, Underpants + /// + public class AssetWearable : Asset + { + private string _Name = ""; + public string Name + { + get { return _Name; } + set + { + _Name = value; + UpdateAssetData(); + } + } + private string _Description = ""; + public string Description + { + get { return _Description; } + set + { + _Description = value; + UpdateAssetData(); + } + } + + private AppearanceLayerType _AppearanceLayer = 0; + public AppearanceLayerType AppearanceLayer + { + get { return _AppearanceLayer; } + set + { + _AppearanceLayer = value; + UpdateAssetData(); + } + } + + private uint _Sale_Price = 10; + public uint Sale_Price + { + get { return _Sale_Price; } + set + { + _Sale_Price = value; + UpdateAssetData(); + } + } + + private LLUUID _Creator_ID = new LLUUID(); + public LLUUID Creator_ID + { + get { return _Creator_ID; } + set + { + _Creator_ID = value; + UpdateAssetData(); + } + } + private LLUUID _Owner_ID = new LLUUID(); + public LLUUID Owner_ID + { + get { return _Owner_ID; } + set + { + _Owner_ID = value; + UpdateAssetData(); + } + } + private LLUUID _Last_Owner_ID = new LLUUID(); + public LLUUID Last_Owner_ID + { + get { return _Last_Owner_ID; } + set + { + _Last_Owner_ID = value; + UpdateAssetData(); + } + } + + private LLUUID _Group_ID = new LLUUID(); + public LLUUID Group_ID + { + get { return _Group_ID; } + set + { + _Group_ID = value; + UpdateAssetData(); + } + } + + private bool _Group_Owned = false; + public bool Group_Owned + { + get { return _Group_Owned; } + set + { + _Group_Owned = value; + UpdateAssetData(); + } + } + + + private uint _Permission_Base_Mask = 0; + public uint Permission_Base_Mask + { + get { return _Permission_Base_Mask; } + set + { + _Permission_Base_Mask = value; + UpdateAssetData(); + } + } + + private uint _Permission_Owner_Mask = 0; + public uint Permission_Owner_Mask + { + get { return _Permission_Owner_Mask; } + set + { + _Permission_Owner_Mask = value; + UpdateAssetData(); + } + } + + private uint _Permission_Group_Mask = 0; + public uint Permission_Group_Mask + { + get { return _Permission_Group_Mask; } + set + { + _Permission_Group_Mask = value; + UpdateAssetData(); + } + } + + private uint _Permission_Everyone_Mask = 0; + public uint Permission_Everyone_Mask + { + get { return _Permission_Everyone_Mask; } + set + { + _Permission_Everyone_Mask = value; + UpdateAssetData(); + } + } + + private uint _Permission_Next_Owner_Mask = 0; + public uint Permission_Next_Owner_Mask + { + get { return _Permission_Next_Owner_Mask; } + set + { + _Permission_Next_Owner_Mask = value; + UpdateAssetData(); + } + } + + private Dictionary _Parameters = new Dictionary(); + public Dictionary Parameters + { + get { return _Parameters; } + set + { + _Parameters = value; + UpdateAssetData(); + } + } + + private Dictionary _Textures = new Dictionary(); + public Dictionary Textures + { + get { return _Textures; } + set + { + _Textures = value; + UpdateAssetData(); + } + } + + private string[] _ForSaleNames = new string[] + { + "not", + "orig", + "copy", + "cntn" + }; + + private enum _ForSale + { + /// Not for sale + Not = 0, + /// The original is for sale + Original = 1, + /// Copies are for sale + Copy = 2, + /// The contents of the object are for sale + Contents = 3 + } + + private _ForSale _Sale = _ForSale.Not; + + public enum AppearanceLayerType : byte + { + /// + Shape = 0, + /// + Skin, + /// + Hair, + /// + Eyes, + /// + Shirt, + /// + Pants, + /// + Shoes, + /// + Socks, + /// + Jacket, + /// + Gloves, + /// + Undershirt, + /// + Underpants, + /// + Skirt, + /// + Invalid = 255 + }; + + + /// + /// + /// + /// + public AssetWearable(LLUUID assetID, sbyte assetType, byte[] assetData) + : base(assetID, assetType, false, assetData) + { + UpdateFromAssetData(); + } + + /// + /// Converts byte[] data from a data transfer into a bodypart class + /// + /// + internal void UpdateFromAssetData() + { + Thread.CurrentThread.CurrentCulture = new CultureInfo("en-us"); + Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-us"); + + if ( AssetData == null || AssetData.Length == 0) + { + return; + } + + string wearableData = Helpers.FieldToUTF8String(this._AssetData); + + int version = -1; + int n = -1; + + try + { + n = wearableData.IndexOf('\n'); + version = Int32.Parse(wearableData.Substring(19, n - 18)); + wearableData = wearableData.Remove(0, n); + + if (version != 22) + { + Console.WriteLine("** WARNING ** : Wearable asset has unrecognized version " + version); + return; + } + + n = wearableData.IndexOf('\n'); + Name = wearableData.Substring(0, n); + wearableData = wearableData.Remove(0, n); + + n = wearableData.IndexOf('\n'); + Description = wearableData.Substring(0, n); + wearableData = wearableData.Remove(0, n); + + // Split in to an upper and lower half + string[] parts = wearableData.Split(new string[] { "parameters" }, StringSplitOptions.None); + parts[1] = "parameters" + parts[1]; + + // Parse the upper half + string[] lines = parts[0].Split('\n'); + foreach (string thisline in lines) + { + string line = thisline.Trim(); + string[] fields = line.Split('\t'); + + if (fields.Length == 2) + { + if (fields[0] == "creator_mask") + { + // Deprecated, apply this as the base mask + _Permission_Base_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + } + else if (fields[0] == "base_mask") + { + _Permission_Base_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + } + else if (fields[0] == "owner_mask") + { + _Permission_Owner_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + } + else if (fields[0] == "group_mask") + { + _Permission_Group_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + } + else if (fields[0] == "everyone_mask") + { + _Permission_Everyone_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + } + else if (fields[0] == "next_owner_mask") + { + _Permission_Next_Owner_Mask = UInt32.Parse(fields[1], System.Globalization.NumberStyles.HexNumber); + } + else if (fields[0] == "creator_id") + { + _Creator_ID = new LLUUID(fields[1]); + } + else if (fields[0] == "owner_id") + { + _Owner_ID = new LLUUID(fields[1]); + } + else if (fields[0] == "last_owner_id") + { + _Last_Owner_ID = new LLUUID(fields[1]); + } + else if (fields[0] == "group_id") + { + _Group_ID = new LLUUID(fields[1]); + } + else if (fields[0] == "group_owned") + { + + _Group_Owned = (Int32.Parse(fields[1]) != 0); + } + else if (fields[0] == "sale_type") + { + for (int i = 0; i < _ForSaleNames.Length; i++) + { + if (fields[1] == _ForSaleNames[i]) + { + _Sale = (_ForSale)i; + break; + } + } + } + else if (fields[0] == "sale_price") + { + _Sale_Price = UInt32.Parse(fields[1]); + } + else if (fields[0] == "perm_mask") + { + Console.WriteLine("** WARNING ** : Wearable asset has deprecated perm_mask field, ignoring"); + } + } + else if (line.StartsWith("type ")) + { + AppearanceLayer = (AppearanceLayerType)Int32.Parse(line.Substring(5)); + break; + } + } + + // Break up the lower half in to parameters and textures + string[] lowerparts = parts[1].Split(new string[] { "textures" }, StringSplitOptions.None); + lowerparts[1] = "textures" + lowerparts[1]; + + // Parse the parameters + lines = lowerparts[0].Split('\n'); + foreach (string line in lines) + { + string[] fields = line.Split(' '); + + // Use exception handling to deal with all the lines we aren't interested in + try + { + int id = Int32.Parse(fields[0]); + float weight; Single.Parse(fields[1], System.Globalization.NumberStyles.Float); + if (Single.TryParse(fields[1], System.Globalization.NumberStyles.Float, new CultureInfo("en-us").NumberFormat, out weight) == false) + { + weight = 0.0f; + } + + _Parameters[id] = weight; + } + catch (Exception) + { + } + } + + // Parse the textures + lines = lowerparts[1].Split('\n'); + foreach (string line in lines) + { + string[] fields = line.Split(' '); + + // Use exception handling to deal with all the lines we aren't interested in + try + { + uint id = UInt32.Parse(fields[0]); + LLUUID texture = LLUUID.Parse(fields[1]); + + _Textures[id] = texture; + } + catch (Exception) + { + } + } + + return; + } + catch (Exception e) + { + Console.WriteLine("** WARNING **", "Failed to parse wearable asset: " + e.ToString()); + } + + return; + } + + private void UpdateAssetData() + { + string data = "LLWearable version 22\n"; + data += this._Name + "\n\n"; + data += "\tpermissions 0\n\t{\n"; + data += "\t\tbase_mask\t" + uintToHex(this._Permission_Base_Mask); + data += "\n\t\towner_mask\t" + uintToHex(this._Permission_Owner_Mask); + data += "\n\t\tgroup_mask\t" + uintToHex(this._Permission_Group_Mask); + data += "\n\t\teveryone_mask\t" + uintToHex(this._Permission_Everyone_Mask); + data += "\n\t\tnext_owner_mask\t" + uintToHex(this._Permission_Next_Owner_Mask); + data += "\n\t\tcreator_id\t" + this._Creator_ID.ToStringHyphenated(); + data += "\n\t\towner_id\t" + this._Owner_ID.ToStringHyphenated(); + data += "\n\t\tlast_owner_id\t" + this._Last_Owner_ID.ToStringHyphenated(); + data += "\n\t\tgroup_id\t" + this._Group_ID.ToStringHyphenated(); + data += "\n\t}"; + data += "\n\tsale_info\t0"; + data += "\n\t{"; + data += "\n\t\tsale_type\t" + _ForSaleNames[(int)this._Sale]; + data += "\n\t\tsale_price\t" + this._Sale_Price; + data += "\n\t}"; + data += "\ntype " + this._AppearanceLayer; + data += "\nparameters " + this._Parameters.Count; + foreach (KeyValuePair param in this._Parameters) + { + string prm = string.Format("{0:f1}", param.Value); + if (prm == "-1.0" || prm == "1.0" || prm == "0.0") + { + switch (prm) + { + case "-1.0": + prm = "-1"; + break; + case "0.0": + prm = "0"; + break; + case "1.0": + prm = "1"; + break; + } + } + data += "\n" + param.Key + " " + prm; + } + data += "\ntextures " + this._Textures.Count; + foreach (KeyValuePair texture in this._Textures) + { + data += "\n" + texture.Key + " " + texture.Value.ToStringHyphenated(); + } + + _AssetData = System.Text.Encoding.ASCII.GetBytes(data.ToCharArray()); + } + + private static string uintToHex(uint i) + { + return string.Format("{0:x8}", i); + } + + public override void SetAssetData(byte[] data) + { + _AssetData = data; + if ( (_AssetData != null) && (_AssetData.Length > 0) ) + { + UpdateFromAssetData(); + } + } + } +} diff --git a/libsecondlife-cs/AssetSystem/AssetWearable_Body.cs b/libsecondlife-cs/AssetSystem/AssetWearable_Body.cs index d6d122b7..dc01eff0 100644 --- a/libsecondlife-cs/AssetSystem/AssetWearable_Body.cs +++ b/libsecondlife-cs/AssetSystem/AssetWearable_Body.cs @@ -1,48 +1,48 @@ -/* - * Copyright (c) 2006, Second Life Reverse Engineering Team - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the Second Life Reverse Engineering Team nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -using libsecondlife; - -namespace libsecondlife.AssetSystem -{ - /// - /// Asset for a body wearables (Skin, Eyes, Hair, Bodyshape) - /// - internal class AssetWearable_Body : AssetWearable - { - /// - /// - /// - /// - public AssetWearable_Body(LLUUID assetID, byte[] assetData) - : base(assetID, (sbyte)Asset.AssetType.Bodypart, assetData) - { - } - } -} +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +using libsecondlife; + +namespace libsecondlife.AssetSystem +{ + /// + /// Asset for a body wearables (Skin, Eyes, Hair, Bodyshape) + /// + internal class AssetWearable_Body : AssetWearable + { + /// + /// + /// + /// + public AssetWearable_Body(LLUUID assetID, byte[] assetData) + : base(assetID, (sbyte)Asset.AssetType.Bodypart, assetData) + { + } + } +} diff --git a/libsecondlife-cs/AssetSystem/AssetWearable_Clothing.cs b/libsecondlife-cs/AssetSystem/AssetWearable_Clothing.cs index 41ebd6a9..3a23c0dd 100644 --- a/libsecondlife-cs/AssetSystem/AssetWearable_Clothing.cs +++ b/libsecondlife-cs/AssetSystem/AssetWearable_Clothing.cs @@ -1,48 +1,48 @@ -/* - * Copyright (c) 2006, Second Life Reverse Engineering Team - * All rights reserved. - * - * - Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * - Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - Neither the name of the Second Life Reverse Engineering Team nor the names - * of its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -using System; -using System.Collections.Generic; - -using libsecondlife; - -namespace libsecondlife.AssetSystem -{ - /// - /// Asset for a clothing wearables (Shirt, Pants, Socks, etc) - /// - internal class AssetWearable_Clothing : AssetWearable - { - /// - /// - /// - /// - public AssetWearable_Clothing(LLUUID assetID, byte[] assetData) - : base(assetID, (sbyte)Asset.AssetType.Clothing, assetData) - { - } - } -} +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * - Neither the name of the Second Life Reverse Engineering Team nor the names + * of its contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections.Generic; + +using libsecondlife; + +namespace libsecondlife.AssetSystem +{ + /// + /// Asset for a clothing wearables (Shirt, Pants, Socks, etc) + /// + internal class AssetWearable_Clothing : AssetWearable + { + /// + /// + /// + /// + public AssetWearable_Clothing(LLUUID assetID, byte[] assetData) + : base(assetID, (sbyte)Asset.AssetType.Clothing, assetData) + { + } + } +} diff --git a/libsecondlife-cs/AssetSystem/BodyPart_Depricated.cs b/libsecondlife-cs/AssetSystem/BodyPart_Depricated.cs index 8f941fd8..b67d13ca 100644 --- a/libsecondlife-cs/AssetSystem/BodyPart_Depricated.cs +++ b/libsecondlife-cs/AssetSystem/BodyPart_Depricated.cs @@ -1,227 +1,227 @@ -using System; -using System.Collections.Generic; -using System.Text; -using libsecondlife; -using libsecondlife.Packets; - -namespace libsecondlife.AssetSystem -{ - class BodyPart_Deprecated - { - public string name = ""; - public uint type = 0; - - public string sale_type = "not"; - public uint sale_price = 10; - - public LLUUID creator_id = new LLUUID(); - public LLUUID owner_id = new LLUUID(); - public LLUUID last_owner_id = new LLUUID(); - public LLUUID group_id = new LLUUID(); - - public uint base_mask = 0; - public uint owner_mask = 0; - public uint group_mask = 0; - public uint everyone_mask = 0; - public uint next_owner_mask = 0; - - public Dictionary parameters = new Dictionary(); - public Dictionary textures = new Dictionary(); - - private static string intToHex(uint i) - { - return string.Format("{0:x8}", i); - } - - public static byte[] BodyPartToByteData(BodyPart_Deprecated bp) - { - string data = "LLWearable version 22\n"; - data += bp.name + "\n\n"; - data += "\tpermissions 0\n\t{\n"; - data += "\t\tbase_mask\t" + intToHex(bp.base_mask); - data += "\n\t\towner_mask\t" + intToHex(bp.owner_mask); - data += "\n\t\tgroup_mask\t" + intToHex(bp.group_mask); - data += "\n\t\teveryone_mask\t" + intToHex(bp.everyone_mask); - data += "\n\t\tnext_owner_mask\t" + intToHex(bp.next_owner_mask); - data += "\n\t\tcreator_id\t" + bp.creator_id.ToStringHyphenated(); - data += "\n\t\towner_id\t" + bp.owner_id.ToStringHyphenated(); - data += "\n\t\tlast_owner_id\t" + bp.last_owner_id.ToStringHyphenated(); - data += "\n\t\tgroup_id\t" + bp.group_id.ToStringHyphenated(); - data += "\n\t}"; - data += "\n\tsale_info\t0"; - data += "\n\t{"; - data += "\n\t\tsale_type\t" + bp.sale_type; - data += "\n\t\tsale_price\t" + bp.sale_price; - data += "\n\t}"; - data += "\ntype " + bp.type; - data += "\nparameters " + bp.parameters.Count; - foreach (KeyValuePair param in bp.parameters) - { - string prm = string.Format("{0:f1}", param.Value); - if(prm == "-1.0" || prm == "1.0" || prm == "0.0") - { - switch(prm) - { - case "-1.0": - prm = "-1"; - break; - case "0.0": - prm = "0"; - break; - case "1.0": - prm = "1"; - break; - } - } - data += "\n" + param.Key + " " + prm; - } - data += "\ntextures " + bp.textures.Count; - foreach (KeyValuePair texture in bp.textures) - { - data += "\n" + texture.Key + " " + texture.Value.ToStringHyphenated(); - } - - return System.Text.Encoding.ASCII.GetBytes(data.ToCharArray()); - } - /// - /// Converts byte[] data from a data transfer into a bodypart class - /// - /// - /// - public static BodyPart_Deprecated ByteDataToBodyPart(byte[] data) - { - BodyPart_Deprecated bp = new BodyPart_Deprecated(); - - byte state = 0; - const byte parameters_block = 4; - const byte textures_block = 6; - - Exception Corrupted = new Exception("Corrupted Body Part data"); - string whole_enchilada = System.Text.Encoding.ASCII.GetString(data); - - //this seperates the whole enchilada into two, the header and the body. - string[] seperated_enchilada = whole_enchilada.Split(new string[] { "permissions" }, StringSplitOptions.RemoveEmptyEntries); - if (seperated_enchilada.Length != 2) throw Corrupted; - - //this parses out the name out of the header - string[] header = seperated_enchilada[0].Split('\n'); - if (header.Length < 2) throw Corrupted; - bp.name = header[1]; - - seperated_enchilada[1] = "permissions" + seperated_enchilada[1]; - string[] body = seperated_enchilada[1].Split('\n'); - foreach(string blk in body) - { - string block = blk.Trim(); - if (block == "{" || block == "}") continue; //I hate those things.. - if (block == "") continue; - //use the markers... - if(block.StartsWith("parameters ")) - { - state = parameters_block; - continue; - } - else if(block.StartsWith("textures ")) - { - state = textures_block; - continue; - } - - if(state == 0) - { - if(block.StartsWith("type ")) - { - bp.type = uint.Parse(block.Substring(5)); - } - else - { - string[] split_field = block.Split('\t'); - - if(split_field.Length == 2) - { - switch(split_field[0]) - { - case "base_mask": - bp.base_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); - break; - case "owner_mask": - bp.owner_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); - break; - case "group_mask": - bp.group_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); - break; - case "everyone_mask": - bp.everyone_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); - break; - case "next_owner_mask": - bp.next_owner_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); - break; - case "creator_id": - bp.creator_id = new LLUUID(split_field[1]); - break; - case "owner_id": - bp.owner_id = new LLUUID(split_field[1]); - break; - case "last_owner_id": - bp.last_owner_id = new LLUUID(split_field[1]); - break; - case "group_id": - bp.group_id = new LLUUID(split_field[1]); - break; - case "sale_type": - bp.sale_type = split_field[1]; - break; - case "sale_price": - bp.sale_price = uint.Parse(split_field[1]); - break; - default: break; - } - } - } - } - else if (state == parameters_block) - { - string[] split_up = block.Split(' '); - // if (split_up.Length != 2) throw Corrupted; - if (split_up.Length == 2) - { - if (bp.parameters.ContainsKey(uint.Parse(split_up[0]))) bp.parameters.Remove(uint.Parse(split_up[0])); - bp.parameters.Add(uint.Parse(split_up[0]), float.Parse(split_up[1])); - } - } - else if (state == textures_block) - { - string[] split_up = block.Split(' '); - if (split_up.Length != 2) throw Corrupted; - - if (bp.parameters.ContainsKey(uint.Parse(split_up[0]))) bp.parameters.Remove(uint.Parse(split_up[0])); - bp.textures.Add(uint.Parse(split_up[0]), new LLUUID(split_up[1])); - } - - } - - return bp; - } - public BodyPart_Deprecated() { } //blank construction - - public BodyPart_Deprecated(byte[] data) - { - BodyPart_Deprecated bp = BodyPart_Deprecated.ByteDataToBodyPart(data); - this.base_mask = bp.base_mask; - this.creator_id = bp.creator_id; - this.everyone_mask = bp.everyone_mask; - this.group_id = bp.group_id; - this.group_mask = bp.group_mask; - this.last_owner_id = bp.last_owner_id; - this.name = bp.name; - this.next_owner_mask = bp.next_owner_mask; - this.owner_id = bp.owner_id; - this.owner_mask = bp.owner_mask; - this.parameters = bp.parameters; - this.textures = bp.textures; - this.type = bp.type; - this.sale_price = bp.sale_price; - this.sale_type = bp.sale_type; - } - } -} +using System; +using System.Collections.Generic; +using System.Text; +using libsecondlife; +using libsecondlife.Packets; + +namespace libsecondlife.AssetSystem +{ + class BodyPart_Deprecated + { + public string name = ""; + public uint type = 0; + + public string sale_type = "not"; + public uint sale_price = 10; + + public LLUUID creator_id = new LLUUID(); + public LLUUID owner_id = new LLUUID(); + public LLUUID last_owner_id = new LLUUID(); + public LLUUID group_id = new LLUUID(); + + public uint base_mask = 0; + public uint owner_mask = 0; + public uint group_mask = 0; + public uint everyone_mask = 0; + public uint next_owner_mask = 0; + + public Dictionary parameters = new Dictionary(); + public Dictionary textures = new Dictionary(); + + private static string intToHex(uint i) + { + return string.Format("{0:x8}", i); + } + + public static byte[] BodyPartToByteData(BodyPart_Deprecated bp) + { + string data = "LLWearable version 22\n"; + data += bp.name + "\n\n"; + data += "\tpermissions 0\n\t{\n"; + data += "\t\tbase_mask\t" + intToHex(bp.base_mask); + data += "\n\t\towner_mask\t" + intToHex(bp.owner_mask); + data += "\n\t\tgroup_mask\t" + intToHex(bp.group_mask); + data += "\n\t\teveryone_mask\t" + intToHex(bp.everyone_mask); + data += "\n\t\tnext_owner_mask\t" + intToHex(bp.next_owner_mask); + data += "\n\t\tcreator_id\t" + bp.creator_id.ToStringHyphenated(); + data += "\n\t\towner_id\t" + bp.owner_id.ToStringHyphenated(); + data += "\n\t\tlast_owner_id\t" + bp.last_owner_id.ToStringHyphenated(); + data += "\n\t\tgroup_id\t" + bp.group_id.ToStringHyphenated(); + data += "\n\t}"; + data += "\n\tsale_info\t0"; + data += "\n\t{"; + data += "\n\t\tsale_type\t" + bp.sale_type; + data += "\n\t\tsale_price\t" + bp.sale_price; + data += "\n\t}"; + data += "\ntype " + bp.type; + data += "\nparameters " + bp.parameters.Count; + foreach (KeyValuePair param in bp.parameters) + { + string prm = string.Format("{0:f1}", param.Value); + if(prm == "-1.0" || prm == "1.0" || prm == "0.0") + { + switch(prm) + { + case "-1.0": + prm = "-1"; + break; + case "0.0": + prm = "0"; + break; + case "1.0": + prm = "1"; + break; + } + } + data += "\n" + param.Key + " " + prm; + } + data += "\ntextures " + bp.textures.Count; + foreach (KeyValuePair texture in bp.textures) + { + data += "\n" + texture.Key + " " + texture.Value.ToStringHyphenated(); + } + + return System.Text.Encoding.ASCII.GetBytes(data.ToCharArray()); + } + /// + /// Converts byte[] data from a data transfer into a bodypart class + /// + /// + /// + public static BodyPart_Deprecated ByteDataToBodyPart(byte[] data) + { + BodyPart_Deprecated bp = new BodyPart_Deprecated(); + + byte state = 0; + const byte parameters_block = 4; + const byte textures_block = 6; + + Exception Corrupted = new Exception("Corrupted Body Part data"); + string whole_enchilada = System.Text.Encoding.ASCII.GetString(data); + + //this seperates the whole enchilada into two, the header and the body. + string[] seperated_enchilada = whole_enchilada.Split(new string[] { "permissions" }, StringSplitOptions.RemoveEmptyEntries); + if (seperated_enchilada.Length != 2) throw Corrupted; + + //this parses out the name out of the header + string[] header = seperated_enchilada[0].Split('\n'); + if (header.Length < 2) throw Corrupted; + bp.name = header[1]; + + seperated_enchilada[1] = "permissions" + seperated_enchilada[1]; + string[] body = seperated_enchilada[1].Split('\n'); + foreach(string blk in body) + { + string block = blk.Trim(); + if (block == "{" || block == "}") continue; //I hate those things.. + if (block == "") continue; + //use the markers... + if(block.StartsWith("parameters ")) + { + state = parameters_block; + continue; + } + else if(block.StartsWith("textures ")) + { + state = textures_block; + continue; + } + + if(state == 0) + { + if(block.StartsWith("type ")) + { + bp.type = uint.Parse(block.Substring(5)); + } + else + { + string[] split_field = block.Split('\t'); + + if(split_field.Length == 2) + { + switch(split_field[0]) + { + case "base_mask": + bp.base_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); + break; + case "owner_mask": + bp.owner_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); + break; + case "group_mask": + bp.group_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); + break; + case "everyone_mask": + bp.everyone_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); + break; + case "next_owner_mask": + bp.next_owner_mask = uint.Parse(split_field[1], System.Globalization.NumberStyles.HexNumber); + break; + case "creator_id": + bp.creator_id = new LLUUID(split_field[1]); + break; + case "owner_id": + bp.owner_id = new LLUUID(split_field[1]); + break; + case "last_owner_id": + bp.last_owner_id = new LLUUID(split_field[1]); + break; + case "group_id": + bp.group_id = new LLUUID(split_field[1]); + break; + case "sale_type": + bp.sale_type = split_field[1]; + break; + case "sale_price": + bp.sale_price = uint.Parse(split_field[1]); + break; + default: break; + } + } + } + } + else if (state == parameters_block) + { + string[] split_up = block.Split(' '); + // if (split_up.Length != 2) throw Corrupted; + if (split_up.Length == 2) + { + if (bp.parameters.ContainsKey(uint.Parse(split_up[0]))) bp.parameters.Remove(uint.Parse(split_up[0])); + bp.parameters.Add(uint.Parse(split_up[0]), float.Parse(split_up[1])); + } + } + else if (state == textures_block) + { + string[] split_up = block.Split(' '); + if (split_up.Length != 2) throw Corrupted; + + if (bp.parameters.ContainsKey(uint.Parse(split_up[0]))) bp.parameters.Remove(uint.Parse(split_up[0])); + bp.textures.Add(uint.Parse(split_up[0]), new LLUUID(split_up[1])); + } + + } + + return bp; + } + public BodyPart_Deprecated() { } //blank construction + + public BodyPart_Deprecated(byte[] data) + { + BodyPart_Deprecated bp = BodyPart_Deprecated.ByteDataToBodyPart(data); + this.base_mask = bp.base_mask; + this.creator_id = bp.creator_id; + this.everyone_mask = bp.everyone_mask; + this.group_id = bp.group_id; + this.group_mask = bp.group_mask; + this.last_owner_id = bp.last_owner_id; + this.name = bp.name; + this.next_owner_mask = bp.next_owner_mask; + this.owner_id = bp.owner_id; + this.owner_mask = bp.owner_mask; + this.parameters = bp.parameters; + this.textures = bp.textures; + this.type = bp.type; + this.sale_price = bp.sale_price; + this.sale_type = bp.sale_type; + } + } +} diff --git a/libsecondlife-cs/AvatarManager.cs b/libsecondlife-cs/AvatarManager.cs index b56bb381..1f90a629 100644 --- a/libsecondlife-cs/AvatarManager.cs +++ b/libsecondlife-cs/AvatarManager.cs @@ -443,7 +443,7 @@ namespace libsecondlife //Client.DebugLog("Received a ViewerEffect of type " + type.ToString() + ", implement me!"); break; case MainAvatar.EffectType.PointAt: - if (block.TypeData.Length == 57) +/* if (block.TypeData.Length == 57) { LLUUID sourceAvatar = new LLUUID(block.TypeData, 0); LLUUID targetObject = new LLUUID(block.TypeData, 16); @@ -465,7 +465,7 @@ namespace libsecondlife { Client.Log("Received a PointAt ViewerEffect with an incorrect TypeData size of " + block.TypeData.Length + " bytes", Helpers.LogLevel.Warning); - } + } */ break; } } diff --git a/libsecondlife-cs/BakeLayer.cs b/libsecondlife-cs/BakeLayer.cs index 70ea4386..27a075b8 100644 --- a/libsecondlife-cs/BakeLayer.cs +++ b/libsecondlife-cs/BakeLayer.cs @@ -156,6 +156,8 @@ namespace libsecondlife if (TotalLayers == 1) { // FIXME: Create a properly formatted JP2 bake (5 comps) + // to silence the warning: + GetResource("fixme"); } else { diff --git a/libsecondlife-cs/Caps.cs b/libsecondlife-cs/Caps.cs index e3c7d5d3..71ea4471 100644 --- a/libsecondlife-cs/Caps.cs +++ b/libsecondlife-cs/Caps.cs @@ -70,7 +70,6 @@ namespace libsecondlife /// /// /// - /// internal Caps(SecondLife client, Simulator simulator, string seedcaps) { Client = client; @@ -181,7 +180,6 @@ namespace libsecondlife } catch (WebException e) { - string extstring=e.Message; if (e.Message.IndexOf("502") < 0) Client.DebugLog("EventQueue response: " + e.Message); } diff --git a/libsecondlife-cs/InventorySystem/DownloadRequest_Folder.cs b/libsecondlife-cs/InventorySystem/DownloadRequest_Folder.cs index 6f680d10..a50cf9d9 100644 --- a/libsecondlife-cs/InventorySystem/DownloadRequest_Folder.cs +++ b/libsecondlife-cs/InventorySystem/DownloadRequest_Folder.cs @@ -1,85 +1,85 @@ -using System; -using System.Collections.Generic; -using System.Threading; - -namespace libsecondlife.InventorySystem -{ - public class DownloadRequest_Folder - { - public string Name; - public LLUUID FolderID; - - public int Expected = int.MaxValue; - public int Received = 0; - public int LastReceivedAtTick = 0; - - public bool FetchFolders = true; - public bool FetchItems = true; - - public bool IsCompleted - { - get { return (Received >= Expected);} - } - - /// - /// Do we want to recursively download this folder? - /// - public bool Recurse = true; - - public ManualResetEvent RequestComplete = new ManualResetEvent(false); - - internal DownloadRequest_Folder(LLUUID folderID, bool recurse, bool fetchFolders, bool fetchItems, string requestName) - { - FolderID = folderID; - Recurse = recurse; - FetchFolders = fetchFolders; - FetchItems = fetchItems; - LastReceivedAtTick = Environment.TickCount; - Name = requestName; - } - - public override string ToString() - { - // return FolderID.ToStringHyphenated() + " [Pg:" + Received + "/" + Expected + "](R:" + Recurse + ",F:" + FetchFolders + ",I:" + FetchItems + ")" + Name; - return " [Pg:" + Received + "/" + Expected + "](R:" + Recurse + ",F:" + FetchFolders + ",I:" + FetchItems + ")\t" + Name; - } - - public bool Equals(object obj) - { - if (obj is DownloadRequest_Folder) - { - DownloadRequest_Folder df = (DownloadRequest_Folder)obj; - - if ((this.FolderID == df.FolderID) - && (this.Recurse == df.Recurse) - && (this.FetchFolders == df.FetchFolders) - && (this.FetchItems == df.FetchItems) - && (this.Received == df.Received) - && (this.Expected == df.Expected) - ) - { - return true; - } - else - { - return false; - } - } - else - { - return base.Equals(obj); - } - } - - public override int GetHashCode() - { - string Compound = FolderID.ToString() + Recurse + Received + FetchFolders + Expected + FetchItems; - return Compound.GetHashCode(); - } - } - - public class DownloadRequest_EventArgs : EventArgs - { - public DownloadRequest_Folder DownloadRequest; - } -} +using System; +using System.Collections.Generic; +using System.Threading; + +namespace libsecondlife.InventorySystem +{ + public class DownloadRequest_Folder + { + public string Name; + public LLUUID FolderID; + + public int Expected = int.MaxValue; + public int Received = 0; + public int LastReceivedAtTick = 0; + + public bool FetchFolders = true; + public bool FetchItems = true; + + public bool IsCompleted + { + get { return (Received >= Expected);} + } + + /// + /// Do we want to recursively download this folder? + /// + public bool Recurse = true; + + public ManualResetEvent RequestComplete = new ManualResetEvent(false); + + internal DownloadRequest_Folder(LLUUID folderID, bool recurse, bool fetchFolders, bool fetchItems, string requestName) + { + FolderID = folderID; + Recurse = recurse; + FetchFolders = fetchFolders; + FetchItems = fetchItems; + LastReceivedAtTick = Environment.TickCount; + Name = requestName; + } + + public override string ToString() + { + // return FolderID.ToStringHyphenated() + " [Pg:" + Received + "/" + Expected + "](R:" + Recurse + ",F:" + FetchFolders + ",I:" + FetchItems + ")" + Name; + return " [Pg:" + Received + "/" + Expected + "](R:" + Recurse + ",F:" + FetchFolders + ",I:" + FetchItems + ")\t" + Name; + } + + public override bool Equals(object obj) + { + if (obj is DownloadRequest_Folder) + { + DownloadRequest_Folder df = (DownloadRequest_Folder)obj; + + if ((this.FolderID == df.FolderID) + && (this.Recurse == df.Recurse) + && (this.FetchFolders == df.FetchFolders) + && (this.FetchItems == df.FetchItems) + && (this.Received == df.Received) + && (this.Expected == df.Expected) + ) + { + return true; + } + else + { + return false; + } + } + else + { + return base.Equals(obj); + } + } + + public override int GetHashCode() + { + string Compound = FolderID.ToString() + Recurse + Received + FetchFolders + Expected + FetchItems; + return Compound.GetHashCode(); + } + } + + public class DownloadRequest_EventArgs : EventArgs + { + public DownloadRequest_Folder DownloadRequest; + } +} diff --git a/libsecondlife-cs/InventorySystem/InventoryFolder.cs b/libsecondlife-cs/InventorySystem/InventoryFolder.cs index 30f8148a..e7e118bb 100644 --- a/libsecondlife-cs/InventorySystem/InventoryFolder.cs +++ b/libsecondlife-cs/InventorySystem/InventoryFolder.cs @@ -79,8 +79,8 @@ namespace libsecondlife.InventorySystem /// Request a download of this folder's content information. /// /// Indicate if we should recursively download content information. - /// Indicate if item data should be downloaded too (true), or only folders(false) - /// Indicate if item data should be downloaded too (true), or only folders(false) + /// Indicate if folders data should be downloaded + /// Indicate if item data should be downloaded /// The Request object for this download public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items) { @@ -100,9 +100,7 @@ namespace libsecondlife.InventorySystem /// Indicate if we should recursively download content information. /// Indicate if sub-folder data should be downloaded (true) /// Indicate if item data should be downloaded too (true) - /// Delete locale cache information for the this folder and it's children, before downloading /// Milliseconds to wait before timing out, or -1 to wait indefinately. - /// Name to assign to this request for debug output /// The Request object for this download public DownloadRequest_Folder RequestDownloadContents(bool recurse, bool folders, bool items, int timeout) { diff --git a/libsecondlife-cs/InventorySystem/InventoryManager.cs b/libsecondlife-cs/InventorySystem/InventoryManager.cs index af1fb31d..fb3cbc07 100644 --- a/libsecondlife-cs/InventorySystem/InventoryManager.cs +++ b/libsecondlife-cs/InventorySystem/InventoryManager.cs @@ -48,7 +48,7 @@ namespace libsecondlife.InventorySystem // Reference to the SLClient Library private SecondLife slClient; - private ManualResetEvent InventoryManagerInitialized = new ManualResetEvent(false); +// private ManualResetEvent InventoryManagerInitialized = new ManualResetEvent(false); // Reference to the Asset Manager internal AssetManager AssetManager @@ -77,7 +77,7 @@ namespace libsecondlife.InventorySystem public ManualResetEvent ItemCreationCompleted; // Used to track to see if a download has timed out or not - private int LastPacketRecievedAtTick; +// private int LastPacketRecievedAtTick; public enum InventoryType : sbyte { @@ -272,7 +272,6 @@ namespace libsecondlife.InventorySystem /// /// Recursive helper function for public InventoryFolder getFolder(String sFolderPath) /// - /// /// /// /// @@ -745,7 +744,6 @@ namespace libsecondlife.InventorySystem /// /// Append a request to the end of the queue. /// - /// internal DownloadRequest_Folder FolderRequestAppend(LLUUID folderID, bool recurse, bool fetchFolders, bool fetchItems, string requestName) { @@ -1081,7 +1079,6 @@ namespace libsecondlife.InventorySystem /// Returned in response to a FetchInventoryDescendents request. Contains information about the /// contents of a folder. /// - /// /// /// public void InventoryDescendentsHandler(Packet packet, Simulator simulator) @@ -1112,7 +1109,7 @@ namespace libsecondlife.InventorySystem // Update Inventory Manager's last tick point, used for timeouts and such - LastPacketRecievedAtTick = Environment.TickCount; +// LastPacketRecievedAtTick = Environment.TickCount; // Used to count the number of descendants received to see if we're finished or not. int iDescendentsExpected = reply.AgentData.Descendents; diff --git a/libsecondlife-cs/InventorySystem/InventoryScript.cs b/libsecondlife-cs/InventorySystem/InventoryScript.cs index b98505ac..9d352efd 100644 --- a/libsecondlife-cs/InventorySystem/InventoryScript.cs +++ b/libsecondlife-cs/InventorySystem/InventoryScript.cs @@ -1,143 +1,143 @@ -using System; -using System.Collections.Generic; -using System.Text; -using libsecondlife.AssetSystem; - -namespace libsecondlife.InventorySystem -{ - public class InventoryScript : InventoryItem - { - public string Source - { - get - { - if (_Asset != null) - { - return ((AssetScript)Asset).Source; - } - else - { - if ( (AssetID != null) ) - { - AssetRequestDownload request = base.iManager.AssetManager.RequestInventoryAsset(this); - if (request.Wait(AssetManager.DefaultTimeout) != AssetRequestDownload.RequestStatus.Success) - { - throw new Exception("Asset (" + AssetID.ToStringHyphenated() + ") unavailable (" + request.StatusMsg + ") for " + this.Name); - } - _Asset = new AssetScript(AssetID, request.GetAssetData()); - return ((AssetScript)Asset).Source; - } - } - return null; - } - set - { - base._Asset = new AssetScript(LLUUID.Random(), value); - LLUUID TransactionID = base.iManager.AssetManager.UploadAsset(Asset); - base.SetAssetTransactionIDs(Asset.AssetID, TransactionID); - } - } - - public InventoryScript(InventoryManager manager, string name, string description, LLUUID folderID, LLUUID uuidOwnerCreater) - : base(manager, name, description, folderID, 10, 10, uuidOwnerCreater) - { - } - - public InventoryScript(InventoryManager manager, InventoryItem ii) - : base(manager, ii.Name, ii.Description, ii.FolderID, ii.InvType, ii.Type, ii.CreatorID) - { - if (ii.InvType != 10 || ii.Type != (sbyte)Asset.AssetType.LSLText) - throw new Exception("The InventoryItem cannot be converted to a Script, wrong InvType/Type."); - this.iManager = manager; - this._ItemID = ii._ItemID; - this._Asset = ii._Asset; - this._AssetID = ii._AssetID; - this._BaseMask = ii._BaseMask; - this._CRC = ii._CRC; - this._CreationDate = ii._CreationDate; - this._EveryoneMask = ii._EveryoneMask; - this._Flags = ii._Flags; - this._GroupID = ii._GroupID; - this._GroupMask = ii._GroupMask; - this._GroupOwned = ii._GroupOwned; - this._InvType = ii._InvType; - this._NextOwnerMask = ii._NextOwnerMask; - this._OwnerID = ii._OwnerID; - this._OwnerMask = ii._OwnerMask; - this._SalePrice = ii._SalePrice; - this._SaleType = ii._SaleType; - this._Type = ii._Type; - } - - internal override void SetAssetData(byte[] assetData) - { - if ( _Asset == null ) - { - if ( AssetID == null ) - { - _Asset = new AssetScript(AssetID, assetData); - } - else - { - _Asset = new AssetScript(LLUUID.Random(), assetData); - _AssetID = _Asset.AssetID; - } - } - else - { - _Asset.SetAssetData(assetData); - } - } - - public override string GetDisplayType() - { - return "Script"; - } - - override public string toXML(bool outputAssets) - { - string output = "