diff --git a/libsecondlife-cs/AssetSystem/AppearanceManager.cs b/libsecondlife-cs/AssetSystem/AppearanceManager.cs
index 072c3e1f..dd3ec57e 100644
--- a/libsecondlife-cs/AssetSystem/AppearanceManager.cs
+++ b/libsecondlife-cs/AssetSystem/AppearanceManager.cs
@@ -32,12 +32,12 @@ namespace libsecondlife.AssetSystem
Invalid = 255
};
- private SecondLife Client;
- private AssetManager AManager;
+ protected SecondLife Client;
+ protected AssetManager AManager;
- private uint SerialNum = 1;
+ protected uint SerialNum = 1;
- private ManualResetEvent AgentWearablesSignal = null;
+ protected ManualResetEvent AgentWearablesSignal = null;
// This data defines all appearance info for an avatar
public AgentWearablesUpdatePacket.WearableDataBlock[] AgentWearablesData;
@@ -45,21 +45,21 @@ namespace libsecondlife.AssetSystem
public TextureEntry AgentTextureEntry = new TextureEntry("C228D1CF4B5D4BA884F4899A0796AA97"); // if this isn't valid, blame JH ;-)
-
+ ///
+ ///
+ ///
+ ///
public AppearanceManager(SecondLife client)
{
Client = client;
AManager = client.Assets;
- RegisterCallbacks();
-
- }
-
- private void RegisterCallbacks()
- {
Client.Network.RegisterCallback(libsecondlife.Packets.PacketType.AgentWearablesUpdate, new NetworkManager.PacketCallback(AgentWearablesUpdateCallbackHandler));
+
}
+ #region Wear Stuff
+
///
/// Add a single wearable to your outfit, replacing if nessesary.
///
@@ -159,10 +159,13 @@ namespace libsecondlife.AssetSystem
SendAgentSetAppearance();
}
+ #endregion
+
+
///
/// Creates and sends an AgentIsNowWearing packet based on the local cached AgentWearablesData array.
///
- private void SendAgentIsNowWearing()
+ protected void SendAgentIsNowWearing()
{
AgentIsNowWearingPacket nowWearing = new AgentIsNowWearingPacket();
nowWearing.AgentData.AgentID = Client.Network.AgentID;
@@ -182,7 +185,7 @@ namespace libsecondlife.AssetSystem
/// Request from the server what wearables we're currently wearing. Update cached info.
///
/// The wearable info for what we're currently wearing
- public AgentWearablesUpdatePacket.WearableDataBlock[] GetWearables()
+ protected AgentWearablesUpdatePacket.WearableDataBlock[] GetWearables()
{
AgentWearablesSignal = new ManualResetEvent(false);
@@ -199,7 +202,7 @@ namespace libsecondlife.AssetSystem
///
/// Update the local Avatar Appearance information based on the contents of the assets as defined in the cached wearable data info.
///
- public void GetAvatarAppearanceInfoFromWearableAssets()
+ protected void GetAvatarAppearanceInfoFromWearableAssets()
{
// Only request wearable data, if we have to.
if ((AgentWearablesData == null) || (AgentWearablesData.Length == 0))
@@ -230,8 +233,12 @@ namespace libsecondlife.AssetSystem
break;
}
-
- AManager.GetInventoryAsset(wearableAsset);
+ AssetRequestDownload request = Client.Assets.RequestInventoryAsset(wearableAsset);
+ if (request.Wait(AssetManager.DefaultTimeout) != AssetRequestDownload.RequestStatus.Success)
+ {
+ throw new Exception("Asset (" + wearableAsset.AssetID.ToStringHyphenated() + ") unavailable (" + request.StatusMsg + ")");
+ }
+
if ((wearableAsset.AssetData == null) || (wearableAsset.AssetData.Length == 0))
{
Client.Log("Asset retrieval failed for AssetID: " + wearableAsset.AssetID, Helpers.LogLevel.Warning);
@@ -312,60 +319,6 @@ namespace libsecondlife.AssetSystem
AgentTextureEntry = te2;
}
- ///
- /// Convert the morph params as they are stored in assets, to the byte values needed for
- /// AgentSetAppearance packet
- ///
- /// Visual Param information for AgentSetAppearance packets
- private Dictionary GetAssetParamsAsVisualParams()
- {
- Dictionary VisualParams = new Dictionary();
-
- float maxVal = 0;
- float minVal = 0;
- uint packetIdx = 0;
- float range = 0;
- float percentage = 0;
- byte packetVal = 0;
-
- foreach (KeyValuePair kvp in AgentAppearanceParams)
- {
- packetIdx = AppearanceManager.GetAgentSetAppearanceIndex(kvp.Key) - 1; //TODO/FIXME: this should be zero indexed, not 1 based.
- maxVal = BodyShapeParams.GetValueMax(kvp.Key);
- minVal = BodyShapeParams.GetValueMin(kvp.Key);
-
- range = maxVal - minVal;
-
- percentage = (kvp.Value - minVal) / range;
-
- packetVal = (byte)(percentage * (byte)255);
-
- VisualParams[packetIdx] = packetVal;
-
- }
-
- return VisualParams;
- }
-
- ///
- /// Determine agent size for AgentSetAppearance based on Visual Param data.
- ///
- ///
- ///
- private LLVector3 GetAgentSizeFromVisualParams(Dictionary VisualParams)
- {
- if (VisualParams.ContainsKey(25))
- {
- float AV_Height_Range = 2.025506f - 1.50856f;
- float AV_Height = 1.50856f + (((float)VisualParams[25] / 255.0f) * AV_Height_Range);
- return new LLVector3(0.45f, 0.6f, AV_Height);
- }
- else
- {
- return new LLVector3(0.45f, 0.6f, 1.0f);
- }
- }
-
///
/// Send an AgentSetAppearance packet to the server to update your appearance.
///
@@ -420,6 +373,63 @@ namespace libsecondlife.AssetSystem
}
+ ///
+ /// Convert the morph params as they are stored in assets, to the byte values needed for
+ /// AgentSetAppearance packet
+ ///
+ /// Visual Param information for AgentSetAppearance packets
+ protected Dictionary GetAssetParamsAsVisualParams()
+ {
+ Dictionary VisualParams = new Dictionary();
+
+ float maxVal = 0;
+ float minVal = 0;
+ uint packetIdx = 0;
+ float range = 0;
+ float percentage = 0;
+ byte packetVal = 0;
+
+ foreach (KeyValuePair kvp in AgentAppearanceParams)
+ {
+ packetIdx = AppearanceManager.GetAgentSetAppearanceIndex(kvp.Key) - 1; //TODO/FIXME: this should be zero indexed, not 1 based.
+ maxVal = BodyShapeParams.GetValueMax(kvp.Key);
+ minVal = BodyShapeParams.GetValueMin(kvp.Key);
+
+ range = maxVal - minVal;
+
+ percentage = (kvp.Value - minVal) / range;
+
+ packetVal = (byte)(percentage * (byte)255);
+
+ VisualParams[packetIdx] = packetVal;
+
+ }
+
+ return VisualParams;
+ }
+
+ ///
+ /// Determine agent size for AgentSetAppearance based on Visual Param data.
+ ///
+ ///
+ ///
+ protected LLVector3 GetAgentSizeFromVisualParams(Dictionary VisualParams)
+ {
+ if (VisualParams.ContainsKey(25))
+ {
+ float AV_Height_Range = 2.025506f - 1.50856f;
+ float AV_Height = 1.50856f + (((float)VisualParams[25] / 255.0f) * AV_Height_Range);
+ return new LLVector3(0.45f, 0.6f, AV_Height);
+ }
+ else
+ {
+ return new LLVector3(0.45f, 0.6f, 1.0f);
+ }
+ }
+
+
+
+ #region Callback Handlers
private void AgentWearablesUpdateCallbackHandler(Packet packet, Simulator simulator)
{
@@ -429,12 +439,16 @@ namespace libsecondlife.AssetSystem
AgentWearablesSignal.Set();
}
+ #endregion
+
+ #region Lookup Tables
+
///
/// Convert a Visual Params index number from the ParamID provided in Assets and from avatar_lad.xml
///
///
///
- private static uint GetAgentSetAppearanceIndex(uint AssetParamID)
+ protected static uint GetAgentSetAppearanceIndex(uint AssetParamID)
{
switch (AssetParamID)
{
@@ -667,7 +681,7 @@ namespace libsecondlife.AssetSystem
///
///
///
- public static uint GetParamID(uint VisualParamIdx)
+ protected static uint GetParamID(uint VisualParamIdx)
{
switch (VisualParamIdx)
{
@@ -894,5 +908,7 @@ namespace libsecondlife.AssetSystem
throw new Exception("Unknown Visual Param (AgentSetApperance) index: " + VisualParamIdx);
}
}
+
+ #endregion
}
}
diff --git a/libsecondlife-cs/AssetSystem/AssetManager.cs b/libsecondlife-cs/AssetSystem/AssetManager.cs
index 11a80642..6c636835 100644
--- a/libsecondlife-cs/AssetSystem/AssetManager.cs
+++ b/libsecondlife-cs/AssetSystem/AssetManager.cs
@@ -73,10 +73,19 @@ namespace libsecondlife.AssetSystem
///
public class AssetManager
{
- private SecondLife slClient;
+ protected SecondLife slClient;
- private AssetRequestUpload curUploadRequest = null;
- private Dictionary htDownloadRequests = new Dictionary();
+ protected AssetRequestUpload curUploadRequest = null;
+ protected Dictionary htDownloadRequests = new Dictionary();
+
+ public readonly static int DefaultTimeout = 15000;
+
+ ///
+ /// Event singaling an asset transfer request has completed.
+ ///
+ ///
+ public delegate void On_TransferRequestCompleted(AssetRequest request);
+ public event On_TransferRequestCompleted TransferRequestCompletedEvent;
///
///
@@ -97,31 +106,27 @@ namespace libsecondlife.AssetSystem
// XFer packets for uploading large assets
slClient.Network.RegisterCallback(PacketType.ConfirmXferPacket, new NetworkManager.PacketCallback(ConfirmXferPacketCallbackHandler));
slClient.Network.RegisterCallback(PacketType.RequestXfer, new NetworkManager.PacketCallback(RequestXferCallbackHandler));
- }
+ }
- void Network_OnConnected(object sender)
+ #region State Handling
+ private void Network_OnConnected(object sender)
{
ClearState();
}
- void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message)
+ private void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message)
{
ClearState();
}
- private void ClearState()
+ protected void ClearState()
{
htDownloadRequests.Clear();
curUploadRequest = null;
}
+ #endregion
- ///
- /// Handle the appropriate sink fee associated with an asset upload
- ///
- public void SinkFee()
- {
- slClient.Self.GiveMoney(LLUUID.Zero, slClient.Settings.UPLOAD_COST, "Image Upload");
- }
+ #region Asset Uploading
///
/// Upload an asset to Second Life
@@ -150,13 +155,25 @@ namespace libsecondlife.AssetSystem
{
curUploadRequest = null;
}
- }
+ }
+
+ ///
+ /// Handle the appropriate sink fee associated with an asset upload
+ ///
+ protected void SinkFee()
+ {
+ slClient.Self.GiveMoney(LLUUID.Zero, slClient.Settings.UPLOAD_COST, "Image Upload");
+ }
+
+ #endregion
+
+ #region Download Assets
///
/// Get the Asset data for an item, must be used when requesting a Notecard
///
///
- public void GetInventoryAsset( InventoryItem item )
+ public AssetRequestDownload RequestInventoryAsset(InventoryItem item)
{
if ( (item.OwnerMask & (uint)AssetPermission.Copy) == 0 )
throw new AssetPermissionException(item, slClient, "Asset data refused, Copy permission needed.");
@@ -165,9 +182,7 @@ namespace libsecondlife.AssetSystem
LLUUID TransferID = LLUUID.Random();
- AssetRequestDownload request = new AssetRequestDownload(TransferID);
- request.Size = int.MaxValue; // Number of bytes expected
- request.Received = 0; // Number of bytes received
+ AssetRequestDownload request = new AssetRequestDownload(slClient.Assets, TransferID, item._Asset);
request.UpdateLastPacketTime(); // last time we recevied a packet for this request
htDownloadRequests[TransferID] = request;
@@ -189,25 +204,21 @@ namespace libsecondlife.AssetSystem
slClient.Network.SendPacket(packet);
#if DEBUG_PACKETS
- slClient.DebugLog(packet);
+ slClient.Log(packet.ToString(), Helpers.LogLevel.Info);
#endif
- request.Completed.WaitOne();
-
- item.SetAssetData(request.AssetData);
- }
+ return request;
+ }
///
/// Get Asset data, works with BodyShapes (type 13) but does not work with Notecards(type 7)
///
///
- public void GetInventoryAsset(Asset asset)
+ public AssetRequestDownload RequestInventoryAsset(Asset asset)
{
LLUUID TransferID = LLUUID.Random();
- AssetRequestDownload request = new AssetRequestDownload(TransferID);
- request.Size = int.MaxValue; // Number of bytes expected
- request.Received = 0; // Number of bytes received
+ AssetRequestDownload request = new AssetRequestDownload(slClient.Assets, TransferID, asset);
request.UpdateLastPacketTime(); // last time we recevied a packet for this request
htDownloadRequests[TransferID] = request;
@@ -216,31 +227,69 @@ namespace libsecondlife.AssetSystem
slClient.Network.SendPacket(packet);
#if DEBUG_PACKETS
- slClient.DebugLog(packet);
+ slClient.Log(packet.ToString(), Helpers.LogLevel.Info);
#endif
- request.Completed.WaitOne();
+ return request;
- asset.SetAssetData(request.AssetData);
-
- }
+ }
+ #endregion
+
+ #region Event Generation
+ internal void FireTransferRequestCompletedEvent(AssetRequest request)
+ {
+ TransferRequestCompletedEvent(request);
+ }
+ #endregion
+
+ #region Deprecated Methods
+ ///
+ /// Get the Asset data for an item, must be used when requesting a Notecard
+ ///
+ ///
+ [Obsolete("Use RequestInventoryAsset instead.", false)]
+ public void GetInventoryAsset(InventoryItem item)
+ {
+ RequestInventoryAsset(item).Wait(-1);
+ }
+
+ ///
+ /// Get Asset data, works with BodyShapes (type 13) but does not work with Notecards(type 7)
+ ///
+ ///
+ [Obsolete("Use RequestInventoryAsset instead.", false)]
+ public void GetInventoryAsset(Asset asset)
+ {
+ RequestInventoryAsset(asset).Wait(-1);
+ }
+ #endregion
+
+ #region Callback Handlers
private void AssetUploadCompleteCallbackHandler(Packet packet, Simulator simulator)
{
#if DEBUG_PACKETS
- slClient.DebugLog(packet);
+ slClient.Log(packet.ToString(), Helpers.LogLevel.Info);
#endif
Packets.AssetUploadCompletePacket reply = (AssetUploadCompletePacket)packet;
+ if (reply.AssetBlock.Success)
+ {
+ curUploadRequest.UploadComplete(reply.AssetBlock.UUID, AssetRequest.RequestStatus.Success);
+ }
+ else
+ {
+ curUploadRequest.UploadComplete(reply.AssetBlock.UUID, AssetRequest.RequestStatus.Failure);
+ }
- curUploadRequest.UploadComplete(reply.AssetBlock.UUID, reply.AssetBlock.Success);
+ TransferRequestCompletedEvent(curUploadRequest);
}
private void RequestXferCallbackHandler(Packet packet, Simulator simulator)
{
#if DEBUG_PACKETS
- slClient.DebugLog(packet);
+ slClient.Log(packet.ToString(), Helpers.LogLevel.Info);
#endif
RequestXferPacket reply = (RequestXferPacket)packet;
@@ -254,7 +303,7 @@ namespace libsecondlife.AssetSystem
private void ConfirmXferPacketCallbackHandler(Packet packet, Simulator simulator)
{
#if DEBUG_PACKETS
- slClient.DebugLog(packet);
+ slClient.Log(packet.ToString(), Helpers.LogLevel.Info);
#endif
ConfirmXferPacketPacket reply = (ConfirmXferPacketPacket)packet;
@@ -263,10 +312,11 @@ namespace libsecondlife.AssetSystem
}
+ // Download stuff
private void TransferInfoCallbackHandler(Packet packet, Simulator simulator)
{
#if DEBUG_PACKETS
- slClient.DebugLog(packet);
+ slClient.Log(packet.ToString(), Helpers.LogLevel.Info);
#endif
TransferInfoPacket reply = (TransferInfoPacket)packet;
@@ -276,33 +326,29 @@ namespace libsecondlife.AssetSystem
int Status = reply.TransferInfo.Status;
// Lookup the request for this packet
- AssetRequestDownload request = htDownloadRequests[TransferID];
- if (request == null)
+ if (!htDownloadRequests.ContainsKey(TransferID))
{
+ slClient.Log("Received unexpected TransferInfo packet." + Environment.NewLine + packet.ToString(), Helpers.LogLevel.Warning);
return;
}
+ AssetRequestDownload request = htDownloadRequests[TransferID];
// Mark it as either not found or update the request information
if (Status == -2)
{
- request.Status = false;
- request.StatusMsg = "Asset Status -2 :: Likely Status Not Found";
-
- request.Size = 0;
- request.AssetData = new byte[0];
- request.Completed.Set();
+ request.SetExpectedSize(Size);
+ request.Fail("Asset Status -2 :: Likely Status Not Found");
}
else
{
- request.Size = Size;
- request.AssetData = new byte[Size];
+ request.SetExpectedSize(Size);
}
}
private void TransferPacketCallbackHandler(Packet packet, Simulator simulator)
{
#if DEBUG_PACKETS
- slClient.DebugLog(packet);
+ slClient.Log(packet.ToString(), Helpers.LogLevel.Info);
#endif
TransferPacketPacket reply = (TransferPacketPacket)packet;
@@ -311,31 +357,18 @@ namespace libsecondlife.AssetSystem
byte[] Data = reply.TransferData.Data;
- // Append data to data received.
- AssetRequestDownload request = htDownloadRequests[TransferID];
- if (request == null)
+ // Lookup the request for this packet
+ if (!htDownloadRequests.ContainsKey(TransferID))
{
+ slClient.Log("Received unexpected TransferPacket packet." + Environment.NewLine + packet.ToString(), Helpers.LogLevel.Warning);
return;
}
+ AssetRequestDownload request = htDownloadRequests[TransferID];
- // Add data to data dictionary.
- request.AssetDataReceived[reply.TransferData.Packet] = Data;
- request.Received += Data.Length;
-
-
-
- // If we've gotten all the data, mark it completed.
- if (request.Received >= request.Size)
- {
- int curPos = 0;
- foreach (KeyValuePair kvp in request.AssetDataReceived)
- {
- Array.Copy(kvp.Value, 0, request.AssetData, curPos, kvp.Value.Length);
- curPos += kvp.Value.Length;
- }
-
- request.Completed.Set();
- }
+ // Append data to data received.
+ request.AddDownloadedData(reply.TransferData.Packet, Data);
}
- }
+
+ #endregion
+ }
}
diff --git a/libsecondlife-cs/AssetSystem/AssetRequest.cs b/libsecondlife-cs/AssetSystem/AssetRequest.cs
new file mode 100644
index 00000000..994aa1e2
--- /dev/null
+++ b/libsecondlife-cs/AssetSystem/AssetRequest.cs
@@ -0,0 +1,167 @@
+/*
+ * 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 void UpdateLastPacketTime()
+ {
+ _LastPacketTime = Helpers.GetUnixTime();
+ }
+
+ ///
+ /// Wait for this Request to be completed.
+ ///
+ /// milliseconds to wait, -1 to wait indefinitely
+ ///
+ public RequestStatus Wait(int timeout)
+ {
+ if (!_Completed.WaitOne(timeout, false))
+ {
+ _StatusMsg += "Timeout Failure";
+ return RequestStatus.Failure;
+ }
+ else
+ {
+ 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();
+
+ public AssetRequestDownload(AssetManager Manager, LLUUID TransID, Asset Asset2Update)
+ : base(Manager, TransID, Asset2Update)
+ {
+ _Received = 0;
+ }
+
+ 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;
+ }
+
+ AssetBeingTransferd.SetAssetData(_AssetData);
+
+ MarkCompleted(AssetRequestDownload.RequestStatus.Success, "Download Completed");
+ }
+
+ }
+
+ internal void SetExpectedSize(int size)
+ {
+ _Size = size;
+ _AssetData = new byte[_Size];
+ }
+ }
+}
diff --git a/libsecondlife-cs/AssetSystem/AssetRequestDownload.cs b/libsecondlife-cs/AssetSystem/AssetRequestDownload.cs
deleted file mode 100644
index e0aaed21..00000000
--- a/libsecondlife-cs/AssetSystem/AssetRequestDownload.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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
-{
- class AssetRequestDownload
- {
- public LLUUID TransactionID;
-
- public ManualResetEvent Completed = new ManualResetEvent(false);
- public bool Status;
- public string StatusMsg;
-
- public int Size;
- public int Received;
- public byte[] AssetData;
- public SortedList AssetDataReceived = new SortedList();
-
- private uint _LastPacketTime;
- public uint LastPacketTime { get { return _LastPacketTime; } }
-
- public uint SecondsSinceLastPacket { get { return Helpers.GetUnixTime() - _LastPacketTime; } }
-
- public AssetRequestDownload(LLUUID TransID)
- {
-
- TransactionID = TransID;
- UpdateLastPacketTime();
- }
-
- public void UpdateLastPacketTime()
- {
- _LastPacketTime = Helpers.GetUnixTime();
- }
- }
-}
diff --git a/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs b/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs
index 9f6c237c..ec8a0db6 100644
--- a/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs
+++ b/libsecondlife-cs/AssetSystem/AssetRequestUpload.cs
@@ -39,109 +39,87 @@ using System.Threading;
namespace libsecondlife.AssetSystem
{
- class AssetRequestUpload
+ public class AssetRequestUpload : AssetRequest
{
- public ManualResetEvent Completed = new ManualResetEvent(false);
- public bool Status;
- public string StatusMsg;
+ protected SecondLife _Client;
+ protected readonly int _MaxResendAttempts = 20;
- public Asset MyAsset;
+ protected ulong _XferID;
- public LLUUID TransactionID;
- public ulong XferID;
+ protected int _ResendCount;
+ protected uint _CurrentPacket;
- SecondLife slClient;
+ protected int _NumPackets2Send;
- public int resendCount;
- public uint CurrentPacket;
- private uint _LastPacketTime;
- public uint LastPacketTime
+ public AssetRequestUpload(SecondLife Client, LLUUID TransID, Asset Asset2Upload) : base(Client.Assets, TransID, Asset2Upload)
{
- get { return _LastPacketTime; }
- }
-
- public uint SecondsSinceLastPacket
- {
- get { return Helpers.GetUnixTime() - _LastPacketTime; }
- }
-
- private int _NumPackets;
- public int NumPackets { get { return _NumPackets; } }
-
- public AssetRequestUpload(SecondLife slClient, LLUUID TransID, Asset asset)
- {
- this.slClient = slClient;
- TransactionID = TransID;
- UpdateLastPacketTime();
-
- MyAsset = asset;
-
- CurrentPacket = 0;
- resendCount = 0;
- _NumPackets = asset._AssetData.Length / 1000;
- if (_NumPackets < 1)
+ if ((AssetBeingTransferd._AssetData == null) || (AssetBeingTransferd._AssetData.Length == 0))
{
- _NumPackets = 1;
+ 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()
{
- this.SendFirstPacket();
+ SendFirstPacket();
- while (this.Completed.WaitOne(1000, true) == false && this.resendCount < 20) // only resend 20 times
+ while ((_Completed.WaitOne(1000, true) == false) && (_ResendCount < _MaxResendAttempts))
{
if (this.SecondsSinceLastPacket > 2)
{
- slClient.Log("Resending Packet (more than 2 seconds since last confirm)", Helpers.LogLevel.Info);
+ _Client.Log("Resending Packet (more than 2 seconds since last confirm)", Helpers.LogLevel.Info);
this.SendCurrentPacket();
- resendCount++;
+ _ResendCount++;
}
}
- if (this.Status == false)
+ if (_Status == RequestStatus.Failure)
{
- throw new Exception(this.StatusMsg);
+ throw new Exception(_StatusMsg);
}
else
{
- return this.TransactionID;
+ return _TransactionID;
}
}
- public void UpdateLastPacketTime()
- {
- _LastPacketTime = Helpers.GetUnixTime();
- }
-
-
- internal void SendFirstPacket()
+ protected void SendFirstPacket()
{
Packet packet;
- if (this.MyAsset._AssetData.Length > 1000)
+ if (AssetBeingTransferd._AssetData.Length > 1000)
{
- packet = AssetPacketHelpers.AssetUploadRequestHeaderOnly(this.MyAsset, this.TransactionID);
+ packet = AssetPacketHelpers.AssetUploadRequestHeaderOnly(AssetBeingTransferd, _TransactionID);
}
else
{
- packet = AssetPacketHelpers.AssetUploadRequest(this.MyAsset, this.TransactionID);
+ packet = AssetPacketHelpers.AssetUploadRequest(AssetBeingTransferd, _TransactionID);
}
- slClient.Network.SendPacket(packet);
+ _Client.Network.SendPacket(packet);
#if DEBUG_PACKETS
slClient.DebugLog(packet);
#endif
#if DEBUG_HEADERS
- slClient.DebugLog(packet.Header.ToString());
+ _Client.DebugLog(packet.Header.ToString());
#endif
}
internal void RequestXfer(ulong XferID)
{
- this.XferID = XferID;
+ _XferID = XferID;
// Setup to send the first packet
SendCurrentPacket();
}
@@ -151,11 +129,11 @@ namespace libsecondlife.AssetSystem
// TODO should check that this is the same transfer?
this.UpdateLastPacketTime();
- if (PacketNumConfirmed == CurrentPacket)
+ if (PacketNumConfirmed == _CurrentPacket)
{
// Increment Packet #
- this.CurrentPacket++;
- this.resendCount = 0;
+ this._CurrentPacket++;
+ this._ResendCount = 0;
SendCurrentPacket();
}
else
@@ -164,72 +142,72 @@ namespace libsecondlife.AssetSystem
}
}
- private void SendCurrentPacket()
+ protected void SendCurrentPacket()
{
Packet uploadPacket;
- // technically we don't need this lock, because no state is updated here!
- // lock (this)
+ // THREADING: snapshot this num so we use a consistent value throughout
+ uint packetNum = _CurrentPacket;
+ if (packetNum == 0)
{
- // THREADING: snapshot this num so we use a consistent value throughout
- uint packetNum = CurrentPacket;
- if (packetNum == 0)
+ if (AssetBeingTransferd._AssetData.Length <= 1000)
{
- if (MyAsset._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)MyAsset._AssetData.Length), 0, packetData, 0, 4);
- Array.Copy(MyAsset._AssetData, 0, packetData, 4, dataSize);
-
- uploadPacket = AssetPacketHelpers.SendXferPacket(XferID, packetData, packetNum);
+ throw new Exception("Should not use xfer for small assets");
}
- else if (packetNum < this.NumPackets)
- {
- byte[] packetData = new byte[1000];
- Array.Copy(this.MyAsset._AssetData, packetNum * 1000, packetData, 0, 1000);
+ int dataSize = 1000;
- uploadPacket = AssetPacketHelpers.SendXferPacket(this.XferID, packetData, packetNum);
- }
- else
- {
- // The last packet has to be handled slightly differently
- int lastLen = this.MyAsset._AssetData.Length - (this.NumPackets * 1000);
- byte[] packetData = new byte[lastLen];
- Array.Copy(this.MyAsset._AssetData, this.NumPackets * 1000, packetData, 0, lastLen);
+ byte[] packetData = new byte[dataSize + 4]; // Extra space is for leading data length bytes
- uint lastPacket = (uint)int.MaxValue + (uint)this.NumPackets + (uint)1;
- uploadPacket = AssetPacketHelpers.SendXferPacket(this.XferID, packetData, lastPacket);
- }
+ // 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);
}
- slClient.Network.SendPacket(uploadPacket);
+ _Client.Network.SendPacket(uploadPacket);
#if DEBUG_PACKETS
slClient.DebugLog(uploadPacket);
#endif
#if DEBUG_HEADERS
- slClient.DebugLog(uploadPacket.Header.ToString());
+ _Client.DebugLog(uploadPacket.Header.ToString());
#endif
}
- internal void UploadComplete(LLUUID assetID, bool success)
+ internal void UploadComplete(LLUUID assetID, RequestStatus success)
{
- MyAsset.AssetID = assetID;
- this.Status = success;
+ AssetBeingTransferd.AssetID = assetID;
UpdateLastPacketTime();
+ _Client.Log("Upload complete", Helpers.LogLevel.Info);
- if (Status)
- StatusMsg = "Success";
+ if (_Status == RequestStatus.Success)
+ {
+ MarkCompleted(success, "Success");
+ }
else
- StatusMsg = "Server returned failed";
+ {
+ MarkCompleted(success, "Server returned failed");
+ }
- slClient.Log("Upload complete", Helpers.LogLevel.Info);
- Completed.Set();
}
}
}
diff --git a/libsecondlife-cs/InventorySystem/InventoryImage.cs b/libsecondlife-cs/InventorySystem/InventoryImage.cs
index 0016bf18..877ae610 100644
--- a/libsecondlife-cs/InventorySystem/InventoryImage.cs
+++ b/libsecondlife-cs/InventorySystem/InventoryImage.cs
@@ -22,8 +22,12 @@ namespace libsecondlife.InventorySystem
{
if ((AssetID != null) && (AssetID != LLUUID.Zero))
{
- base.iManager.AssetManager.GetInventoryAsset( this );
- return ((AssetImage)Asset).J2CData;
+ 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);
+ }
+ return ((AssetImage)Asset).J2CData;
}
}
diff --git a/libsecondlife-cs/InventorySystem/InventoryItem.cs b/libsecondlife-cs/InventorySystem/InventoryItem.cs
index 146aa7bd..1974fa86 100644
--- a/libsecondlife-cs/InventorySystem/InventoryItem.cs
+++ b/libsecondlife-cs/InventorySystem/InventoryItem.cs
@@ -130,7 +130,11 @@ namespace libsecondlife.InventorySystem
{
if ((AssetID != null) && (AssetID != LLUUID.Zero))
{
- base.iManager.AssetManager.GetInventoryAsset(this);
+ 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);
+ }
return Asset;
}
}
diff --git a/libsecondlife-cs/InventorySystem/InventoryManager.cs b/libsecondlife-cs/InventorySystem/InventoryManager.cs
index b5c0fd3d..992a1d60 100644
--- a/libsecondlife-cs/InventorySystem/InventoryManager.cs
+++ b/libsecondlife-cs/InventorySystem/InventoryManager.cs
@@ -697,6 +697,11 @@ namespace libsecondlife.InventorySystem
}
}
+ protected void FireRequestDownloadFinishedEvent(object o, EventArgs e)
+ {
+ RequestDownloadFinishedEvent(o, e);
+ }
+
#endregion
#region libsecondlife callback handlers
@@ -948,7 +953,7 @@ namespace libsecondlife.InventorySystem
{
DownloadRequest_EventArgs e = new DownloadRequest_EventArgs();
e.DownloadRequest = dr;
- RequestDownloadFinishedEvent(InvFolderUpdating, e);
+ FireRequestDownloadFinishedEvent(InvFolderUpdating, e);
}
}
}
diff --git a/libsecondlife-cs/InventorySystem/InventoryNotecard.cs b/libsecondlife-cs/InventorySystem/InventoryNotecard.cs
index 47883dd0..77684e18 100644
--- a/libsecondlife-cs/InventorySystem/InventoryNotecard.cs
+++ b/libsecondlife-cs/InventorySystem/InventoryNotecard.cs
@@ -20,8 +20,12 @@ namespace libsecondlife.InventorySystem
} else {
if ((AssetID != null) && (AssetID != LLUUID.Zero))
{
- base.iManager.AssetManager.GetInventoryAsset( this );
- return ((AssetNotecard)Asset).Body;
+ 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);
+ }
+ return ((AssetNotecard)Asset).Body;
}
}
diff --git a/libsecondlife-cs/InventorySystem/InventoryScript.cs b/libsecondlife-cs/InventorySystem/InventoryScript.cs
index 7c0b8228..9438f70d 100644
--- a/libsecondlife-cs/InventorySystem/InventoryScript.cs
+++ b/libsecondlife-cs/InventorySystem/InventoryScript.cs
@@ -19,7 +19,11 @@ namespace libsecondlife.InventorySystem
{
if ( (AssetID != null) && (AssetID != LLUUID.Zero) )
{
- base.iManager.AssetManager.GetInventoryAsset(this);
+ 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);
+ }
return ((AssetScript)Asset).Source;
}
}
diff --git a/libsecondlife-cs/InventorySystem/InventoryWearable.cs b/libsecondlife-cs/InventorySystem/InventoryWearable.cs
index e141a68b..48d23d28 100644
--- a/libsecondlife-cs/InventorySystem/InventoryWearable.cs
+++ b/libsecondlife-cs/InventorySystem/InventoryWearable.cs
@@ -11,7 +11,6 @@ namespace libsecondlife.InventorySystem
public class InventoryWearable : InventoryItem
{
// Wearable Inventory/Asset constants
- public enum WearableAssetType { Shape = 0, Skin = 1, Hair = 2, Eyes = 3, Socks = 7, Gloves = 9, Pants = 5, Shirt = 4, Shoes = 6, Jacket = 8, Skirt = 12, Underpants = 11 };
public enum WearableType : sbyte { Clothing = 5, Body = 13 };
diff --git a/libsecondlife-cs/libsecondlife.csproj b/libsecondlife-cs/libsecondlife.csproj
index ce92fef9..88f92109 100644
--- a/libsecondlife-cs/libsecondlife.csproj
+++ b/libsecondlife-cs/libsecondlife.csproj
@@ -97,12 +97,12 @@
-
+