* Split up asset store and transfer manager in Simian into two extensions

* Added PeriscopeTransferManager to handle animation and sound transfers
* Misc. transfer bugfixes in libomv
* Misc. improvement to TexturePipeline and some numbers tweaking
* Attempted to pass object touch events through to foreign grid in Periscope, may not be working
* Added new chat commands in Periscope

git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2385 52acb1d6-8a22-11de-b505-999d5b087335
This commit is contained in:
John Hurliman
2008-12-19 03:39:29 +00:00
parent 344d327a15
commit 1df78cb074
12 changed files with 1025 additions and 715 deletions

View File

@@ -4,7 +4,6 @@ using System.IO;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Packets;
namespace Simian.Extensions
{
@@ -14,7 +13,6 @@ namespace Simian.Extensions
Simian server;
Dictionary<UUID, Asset> AssetStore = new Dictionary<UUID, Asset>();
Dictionary<ulong, Asset> CurrentUploads = new Dictionary<ulong, Asset>();
string UploadDir;
public AssetManager()
@@ -41,11 +39,6 @@ namespace Simian.Extensions
LoadAssets(server.DataDir);
LoadAssets(UploadDir);
server.UDP.RegisterPacketCallback(PacketType.AssetUploadRequest, new PacketCallback(AssetUploadRequestHandler));
server.UDP.RegisterPacketCallback(PacketType.SendXferPacket, new PacketCallback(SendXferPacketHandler));
server.UDP.RegisterPacketCallback(PacketType.AbortXfer, new PacketCallback(AbortXferHandler));
server.UDP.RegisterPacketCallback(PacketType.TransferRequest, new PacketCallback(TransferRequestHandler));
}
public void Stop()
@@ -93,290 +86,6 @@ namespace Simian.Extensions
return AssetStore.TryGetValue(id, out asset);
}
#region Xfer System
void AssetUploadRequestHandler(Packet packet, Agent agent)
{
AssetUploadRequestPacket request = (AssetUploadRequestPacket)packet;
UUID assetID = UUID.Combine(request.AssetBlock.TransactionID, agent.SecureSessionID);
// Check if the asset is small enough to fit in a single packet
if (request.AssetBlock.AssetData.Length != 0)
{
// Create a new asset from the completed upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, request.AssetBlock.AssetData);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Storing uploaded asset {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
// Store the asset
StoreAsset(asset);
// Send a success response
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = request.AssetBlock.Type;
complete.AssetBlock.UUID = assetID;
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Inventory);
}
else
{
// Create a new (empty) asset for the upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, null);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Starting upload for {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
RequestXferPacket xfer = new RequestXferPacket();
xfer.XferID.DeleteOnCompletion = request.AssetBlock.Tempfile;
xfer.XferID.FilePath = 0;
xfer.XferID.Filename = new byte[0];
xfer.XferID.ID = request.AssetBlock.TransactionID.GetULong();
xfer.XferID.UseBigPackets = false;
xfer.XferID.VFileID = asset.AssetID;
xfer.XferID.VFileType = request.AssetBlock.Type;
// Add this asset to the current upload list
lock (CurrentUploads)
CurrentUploads[xfer.XferID.ID] = asset;
server.UDP.SendPacket(agent.AgentID, xfer, PacketCategory.Inventory);
}
}
void SendXferPacketHandler(Packet packet, Agent agent)
{
SendXferPacketPacket xfer = (SendXferPacketPacket)packet;
Asset asset;
if (CurrentUploads.TryGetValue(xfer.XferID.ID, out asset))
{
if (asset.AssetData == null)
{
if (xfer.XferID.Packet != 0)
{
Logger.Log(String.Format("Received Xfer packet {0} before the first packet!",
xfer.XferID.Packet), Helpers.LogLevel.Error);
return;
}
uint size = Utils.BytesToUInt(xfer.DataPacket.Data);
asset.AssetData = new byte[size];
Buffer.BlockCopy(xfer.DataPacket.Data, 4, asset.AssetData, 0, xfer.DataPacket.Data.Length - 4);
// Confirm the first upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
}
else
{
Buffer.BlockCopy(xfer.DataPacket.Data, 0, asset.AssetData, (int)xfer.XferID.Packet * 1000,
xfer.DataPacket.Data.Length);
// Confirm this upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
if ((xfer.XferID.Packet & (uint)0x80000000) != 0)
{
// Asset upload finished
Logger.DebugLog(String.Format("Completed Xfer upload of asset {0} ({1}", asset.AssetID, asset.AssetType));
lock (CurrentUploads)
CurrentUploads.Remove(xfer.XferID.ID);
StoreAsset(asset);
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = (sbyte)asset.AssetType;
complete.AssetBlock.UUID = asset.AssetID;
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Asset);
}
}
}
else
{
Logger.DebugLog("Received a SendXferPacket for an unknown upload");
}
}
void AbortXferHandler(Packet packet, Agent agent)
{
AbortXferPacket abort = (AbortXferPacket)packet;
lock (CurrentUploads)
{
if (CurrentUploads.ContainsKey(abort.XferID.ID))
{
Logger.DebugLog(String.Format("Aborting Xfer {0}, result: {1}", abort.XferID.ID,
(TransferError)abort.XferID.Result));
CurrentUploads.Remove(abort.XferID.ID);
}
else
{
Logger.DebugLog(String.Format("Received an AbortXfer for an unknown xfer {0}",
abort.XferID.ID));
}
}
}
#endregion Xfer System
#region Transfer System
void TransferRequestHandler(Packet packet, Agent agent)
{
TransferRequestPacket request = (TransferRequestPacket)packet;
ChannelType channel = (ChannelType)request.TransferInfo.ChannelType;
SourceType source = (SourceType)request.TransferInfo.SourceType;
if (channel == ChannelType.Asset)
{
// Construct the response packet
TransferInfoPacket response = new TransferInfoPacket();
response.TransferInfo = new TransferInfoPacket.TransferInfoBlock();
response.TransferInfo.TransferID = request.TransferInfo.TransferID;
if (source == SourceType.Asset)
{
// Parse the request
UUID assetID = new UUID(request.TransferInfo.Params, 0);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 16);
// Set the response channel type
response.TransferInfo.ChannelType = (int)ChannelType.Asset;
// Params
response.TransferInfo.Params = new byte[20];
Buffer.BlockCopy(assetID.GetBytes(), 0, response.TransferInfo.Params, 0, 16);
Buffer.BlockCopy(Utils.IntToBytes((int)type), 0, response.TransferInfo.Params, 16, 4);
// Check if we have this asset
Asset asset;
if (AssetStore.TryGetValue(assetID, out asset))
{
if (asset.AssetType == type)
{
Logger.DebugLog(String.Format("Transferring asset {0} ({1})", asset.AssetID, asset.AssetType));
// Asset found
response.TransferInfo.Size = asset.AssetData.Length;
response.TransferInfo.Status = (int)StatusCode.OK;
response.TransferInfo.TargetType = (int)TargetType.Unknown; // Doesn't seem to be used by the client
server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
// Transfer system does not wait for ACKs, just sends all of the
// packets for this transfer out
const int MAX_CHUNK_SIZE = Settings.MAX_PACKET_SIZE - 100;
int processedLength = 0;
int packetNum = 0;
while (processedLength < asset.AssetData.Length)
{
TransferPacketPacket transfer = new TransferPacketPacket();
transfer.TransferData.ChannelType = (int)ChannelType.Asset;
transfer.TransferData.TransferID = request.TransferInfo.TransferID;
transfer.TransferData.Packet = packetNum++;
int chunkSize = Math.Min(asset.AssetData.Length - processedLength, MAX_CHUNK_SIZE);
transfer.TransferData.Data = new byte[chunkSize];
Buffer.BlockCopy(asset.AssetData, processedLength, transfer.TransferData.Data, 0, chunkSize);
processedLength += chunkSize;
if (processedLength >= asset.AssetData.Length)
transfer.TransferData.Status = (int)StatusCode.Done;
else
transfer.TransferData.Status = (int)StatusCode.OK;
server.UDP.SendPacket(agent.AgentID, transfer, PacketCategory.Asset);
}
}
else
{
Logger.Log(String.Format(
"Request for asset {0} with type {1} does not match actual asset type {2}",
assetID, type, asset.AssetType), Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format("Request for missing asset {0} with type {1}",
assetID, type), Helpers.LogLevel.Warning);
// Asset not found
response.TransferInfo.Size = 0;
response.TransferInfo.Status = (int)StatusCode.UnknownSource;
response.TransferInfo.TargetType = (int)TargetType.Unknown;
server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
}
}
else if (source == SourceType.SimEstate)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
EstateAssetType type = (EstateAssetType)Utils.BytesToInt(request.TransferInfo.Params, 32);
Logger.Log("Please implement estate asset transfers", Helpers.LogLevel.Warning);
}
else if (source == SourceType.SimInventoryItem)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
UUID ownerID = new UUID(request.TransferInfo.Params, 32);
UUID taskID = new UUID(request.TransferInfo.Params, 48);
UUID itemID = new UUID(request.TransferInfo.Params, 64);
UUID assetID = new UUID(request.TransferInfo.Params, 80);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 96);
if (taskID != UUID.Zero)
{
// Task (prim) inventory request
Logger.Log("Please implement task inventory transfers", Helpers.LogLevel.Warning);
}
else
{
// Agent inventory request
Logger.Log("Please implement agent inventory transfer", Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
#endregion Transfer System
void SaveAsset(Asset asset)
{
try

View File

@@ -23,15 +23,15 @@ namespace Simian.Extensions
{
this.server = server;
server.UDP.RegisterPacketCallback(PacketType.AvatarPropertiesRequest, new PacketCallback(AvatarPropertiesRequestHandler));
server.UDP.RegisterPacketCallback(PacketType.AgentWearablesRequest, new PacketCallback(AgentWearablesRequestHandler));
server.UDP.RegisterPacketCallback(PacketType.AgentIsNowWearing, new PacketCallback(AgentIsNowWearingHandler));
server.UDP.RegisterPacketCallback(PacketType.AgentSetAppearance, new PacketCallback(AgentSetAppearanceHandler));
server.UDP.RegisterPacketCallback(PacketType.AgentCachedTexture, new PacketCallback(AgentCachedTextureHandler));
server.UDP.RegisterPacketCallback(PacketType.AgentAnimation, new PacketCallback(AgentAnimationHandler));
server.UDP.RegisterPacketCallback(PacketType.SoundTrigger, new PacketCallback(SoundTriggerHandler));
server.UDP.RegisterPacketCallback(PacketType.ViewerEffect, new PacketCallback(ViewerEffectHandler));
server.UDP.RegisterPacketCallback(PacketType.UUIDNameRequest, new PacketCallback(UUIDNameRequestHandler));
server.UDP.RegisterPacketCallback(PacketType.AvatarPropertiesRequest, AvatarPropertiesRequestHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentWearablesRequest, AgentWearablesRequestHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentIsNowWearing, AgentIsNowWearingHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentSetAppearance, AgentSetAppearanceHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentCachedTexture, AgentCachedTextureHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentAnimation, AgentAnimationHandler);
server.UDP.RegisterPacketCallback(PacketType.SoundTrigger, SoundTriggerHandler);
server.UDP.RegisterPacketCallback(PacketType.ViewerEffect, ViewerEffectHandler);
server.UDP.RegisterPacketCallback(PacketType.UUIDNameRequest, UUIDNameRequestHandler);
if (CoarseLocationTimer != null) CoarseLocationTimer.Dispose();
CoarseLocationTimer = new Timer(CoarseLocationTimer_Elapsed);

View File

@@ -15,6 +15,7 @@ namespace Simian.Extensions
GridClient client;
PeriscopeImageDelivery imageDelivery;
PeriscopeMovement movement;
PeriscopeTransferManager transferManager;
object loginLock = new object();
public Periscope()
@@ -30,13 +31,13 @@ namespace Simian.Extensions
client.Settings.MULTIPLE_SIMS = false;
client.Settings.SEND_AGENT_UPDATES = false;
client.Network.OnCurrentSimChanged += new NetworkManager.CurrentSimChangedCallback(Network_OnCurrentSimChanged);
client.Objects.OnNewPrim += new OpenMetaverse.ObjectManager.NewPrimCallback(Objects_OnNewPrim);
client.Objects.OnNewAvatar += new OpenMetaverse.ObjectManager.NewAvatarCallback(Objects_OnNewAvatar);
client.Objects.OnNewAttachment += new OpenMetaverse.ObjectManager.NewAttachmentCallback(Objects_OnNewAttachment);
client.Objects.OnObjectKilled += new OpenMetaverse.ObjectManager.KillObjectCallback(Objects_OnObjectKilled);
client.Objects.OnObjectUpdated += new OpenMetaverse.ObjectManager.ObjectUpdatedCallback(Objects_OnObjectUpdated);
client.Avatars.OnAvatarAppearance += new OpenMetaverse.AvatarManager.AvatarAppearanceCallback(Avatars_OnAvatarAppearance);
client.Network.OnCurrentSimChanged += Network_OnCurrentSimChanged;
client.Objects.OnNewPrim += Objects_OnNewPrim;
client.Objects.OnNewAvatar += Objects_OnNewAvatar;
client.Objects.OnNewAttachment += Objects_OnNewAttachment;
client.Objects.OnObjectKilled += Objects_OnObjectKilled;
client.Objects.OnObjectUpdated += Objects_OnObjectUpdated;
client.Avatars.OnAvatarAppearance += Avatars_OnAvatarAppearance;
client.Terrain.OnLandPatch += new TerrainManager.LandPatchCallback(Terrain_OnLandPatch);
client.Self.OnChat += new AgentManager.ChatCallback(Self_OnChat);
client.Self.OnTeleport += new AgentManager.TeleportCallback(Self_OnTeleport);
@@ -45,13 +46,20 @@ namespace Simian.Extensions
server.UDP.RegisterPacketCallback(PacketType.AgentUpdate, AgentUpdateHandler);
server.UDP.RegisterPacketCallback(PacketType.ChatFromViewer, ChatFromViewerHandler);
server.UDP.RegisterPacketCallback(PacketType.ObjectGrab, ObjectGrabHandler);
server.UDP.RegisterPacketCallback(PacketType.ObjectGrabUpdate, ObjectGrabUpdateHandler);
server.UDP.RegisterPacketCallback(PacketType.ObjectDeGrab, ObjectDeGrabHandler);
server.UDP.RegisterPacketCallback(PacketType.ViewerEffect, ViewerEffectHandler);
server.UDP.RegisterPacketCallback(PacketType.AgentAnimation, AgentAnimationHandler);
imageDelivery = new PeriscopeImageDelivery(server, client);
movement = new PeriscopeMovement(server, this);
transferManager = new PeriscopeTransferManager(server, client);
}
public void Stop()
{
transferManager.Stop();
movement.Stop();
imageDelivery.Stop();
@@ -62,6 +70,8 @@ namespace Simian.Extensions
void Objects_OnNewPrim(Simulator simulator, Primitive prim, ulong regionHandle, ushort timeDilation)
{
SimulationObject simObj = new SimulationObject(prim, server);
if (MasterAgent != null)
simObj.Prim.OwnerID = MasterAgent.AgentID;
server.Scene.ObjectAdd(this, simObj, PrimFlags.None);
}
@@ -244,7 +254,6 @@ namespace Simian.Extensions
switch (messageParts[0])
{
case "/teleport":
//string simName;
float x, y, z;
if (messageParts.Length == 5 &&
@@ -261,6 +270,40 @@ namespace Simian.Extensions
server.Avatars.SendAlert(agent, "Usage: /teleport \"sim name\" x y z");
}
return;
case "/stats":
server.Avatars.SendAlert(agent, String.Format("Downloading textures: {0}, Queued textures: {1}",
imageDelivery.Pipeline.CurrentCount, imageDelivery.Pipeline.QueuedCount));
return;
case "/nudemod":
int count = 0;
Dictionary<UUID, Agent> agents;
lock (server.Agents)
agents = new Dictionary<UUID, Agent>(server.Agents);
foreach (Agent curAgent in agents.Values)
{
if (curAgent != agent && curAgent.VisualParams != null)
{
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.LowerBaked] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.LowerJacket] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.LowerPants] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.LowerShoes] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.LowerSocks] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.LowerUnderpants] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.UpperBaked] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.UpperGloves] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.UpperJacket] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.UpperShirt] = null;
curAgent.Avatar.Textures.FaceTextures[(int)AppearanceManager.TextureIndex.UpperUndershirt] = null;
server.Scene.AvatarAppearance(this, curAgent, curAgent.Avatar.Textures, curAgent.VisualParams);
++count;
}
}
server.Avatars.SendAlert(agent, String.Format("Modified appearances for {0} avatar(s)", count));
return;
}
}
@@ -273,6 +316,12 @@ namespace Simian.Extensions
client.Self.Chat(finalMessage, chat.ChatData.Channel, (ChatType)chat.ChatData.Type);
}
static void EraseTexture(Avatar avatar, AppearanceManager.TextureIndex texture)
{
Primitive.TextureEntryFace face = avatar.Textures.FaceTextures[(int)texture];
if (face != null) face.TextureID = UUID.Zero;
}
void AgentUpdateHandler(Packet packet, Agent agent)
{
AgentUpdatePacket update = (AgentUpdatePacket)packet;
@@ -308,13 +357,77 @@ namespace Simian.Extensions
if (MasterAgent == null || update.AgentData.AgentID == MasterAgent.AgentID)
{
// Forward AgentUpdate packets with the AgentID/SessionID set to the bots ID
update.AgentData.AgentID = client.Self.AgentID;
update.AgentData.SessionID = client.Self.SessionID;
client.Network.SendPacket(update);
}
}
void ObjectGrabHandler(Packet packet, Agent agent)
{
ObjectGrabPacket grab = (ObjectGrabPacket)packet;
if (MasterAgent == null || grab.AgentData.AgentID == MasterAgent.AgentID)
{
grab.AgentData.AgentID = client.Self.AgentID;
grab.AgentData.SessionID = client.Self.SessionID;
client.Network.SendPacket(grab);
}
}
void ObjectGrabUpdateHandler(Packet packet, Agent agent)
{
ObjectGrabUpdatePacket grabUpdate = (ObjectGrabUpdatePacket)packet;
if (MasterAgent == null || grabUpdate.AgentData.AgentID == MasterAgent.AgentID)
{
grabUpdate.AgentData.AgentID = client.Self.AgentID;
grabUpdate.AgentData.SessionID = client.Self.SessionID;
client.Network.SendPacket(grabUpdate);
}
}
void ObjectDeGrabHandler(Packet packet, Agent agent)
{
ObjectDeGrabPacket degrab = (ObjectDeGrabPacket)packet;
if (MasterAgent == null || degrab.AgentData.AgentID == MasterAgent.AgentID)
{
degrab.AgentData.AgentID = client.Self.AgentID;
degrab.AgentData.SessionID = client.Self.SessionID;
client.Network.SendPacket(degrab);
}
}
void ViewerEffectHandler(Packet packet, Agent agent)
{
ViewerEffectPacket effect = (ViewerEffectPacket)packet;
if (MasterAgent == null || effect.AgentData.AgentID == MasterAgent.AgentID)
{
effect.AgentData.AgentID = client.Self.AgentID;
effect.AgentData.SessionID = client.Self.SessionID;
client.Network.SendPacket(effect);
}
}
void AgentAnimationHandler(Packet packet, Agent agent)
{
AgentAnimationPacket animation = (AgentAnimationPacket)packet;
if (MasterAgent == null || animation.AgentData.AgentID == MasterAgent.AgentID)
{
animation.AgentData.AgentID = client.Self.AgentID;
animation.AgentData.SessionID = client.Self.SessionID;
client.Network.SendPacket(animation);
}
}
#endregion Simian client packet handlers
}

View File

@@ -9,9 +9,10 @@ namespace Simian.Extensions
{
public class PeriscopeImageDelivery
{
public TexturePipeline Pipeline;
Simian server;
GridClient client;
TexturePipeline pipeline;
Dictionary<UUID, ImageDownload> currentDownloads = new Dictionary<UUID, ImageDownload>();
public PeriscopeImageDelivery(Simian server, GridClient client)
@@ -19,15 +20,15 @@ namespace Simian.Extensions
this.server = server;
this.client = client;
pipeline = new TexturePipeline(client, 10);
pipeline.OnDownloadFinished += new TexturePipeline.DownloadFinishedCallback(pipeline_OnDownloadFinished);
Pipeline = new TexturePipeline(client, 12);
Pipeline.OnDownloadFinished += new TexturePipeline.DownloadFinishedCallback(pipeline_OnDownloadFinished);
server.UDP.RegisterPacketCallback(PacketType.RequestImage, RequestImageHandler);
}
public void Stop()
{
pipeline.Shutdown();
Pipeline.Shutdown();
}
void RequestImageHandler(Packet packet, Agent agent)
@@ -54,7 +55,8 @@ namespace Simian.Extensions
}
else if (block.DiscardLevel == -1 && block.DownloadPriority == 0.0f)
{
// Aborting a download we are not tracking, ignore
// Aborting a download we are not tracking, this may be in the pipeline
Pipeline.AbortDownload(block.Image);
}
else
{
@@ -73,7 +75,7 @@ namespace Simian.Extensions
lock (currentDownloads)
currentDownloads[block.Image] = download;
pipeline.RequestTexture(block.Image, (ImageType)block.Type);
Pipeline.RequestTexture(block.Image, (ImageType)block.Type);
}
}
}
@@ -90,10 +92,10 @@ namespace Simian.Extensions
if (success)
{
// Set the texture to the downloaded texture data
AssetTexture texture = new AssetTexture(id, pipeline.GetTextureToRender(id).AssetData);
AssetTexture texture = new AssetTexture(id, Pipeline.GetTextureToRender(id).AssetData);
download.Texture = texture;
pipeline.RemoveFromPipeline(id);
Pipeline.RemoveFromPipeline(id);
// Store this texture in the local asset store for later
server.Assets.StoreAsset(texture);

View File

@@ -0,0 +1,407 @@
using System;
using System.Collections.Generic;
using System.IO;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Packets;
namespace Simian.Extensions
{
public class PeriscopeTransferManager
{
public const string UPLOAD_DIR = "uploadedAssets";
Simian server;
GridClient client;
Dictionary<ulong, Asset> CurrentUploads = new Dictionary<ulong, Asset>();
/// <summary>A map from TransactionIDs to AvatarIDs</summary>
Dictionary<UUID, KeyValuePair<UUID, UUID>> currentDownloads = new Dictionary<UUID, KeyValuePair<UUID, UUID>>();
public PeriscopeTransferManager(Simian server, GridClient client)
{
this.server = server;
this.client = client;
client.Assets.OnAssetReceived += new OpenMetaverse.AssetManager.AssetReceivedCallback(Assets_OnAssetReceived);
server.UDP.RegisterPacketCallback(PacketType.AssetUploadRequest, new PacketCallback(AssetUploadRequestHandler));
server.UDP.RegisterPacketCallback(PacketType.SendXferPacket, new PacketCallback(SendXferPacketHandler));
server.UDP.RegisterPacketCallback(PacketType.AbortXfer, new PacketCallback(AbortXferHandler));
server.UDP.RegisterPacketCallback(PacketType.TransferRequest, new PacketCallback(TransferRequestHandler));
}
public void Stop()
{
}
#region Xfer System
void AssetUploadRequestHandler(Packet packet, Agent agent)
{
AssetUploadRequestPacket request = (AssetUploadRequestPacket)packet;
UUID assetID = UUID.Combine(request.AssetBlock.TransactionID, agent.SecureSessionID);
// Check if the asset is small enough to fit in a single packet
if (request.AssetBlock.AssetData.Length != 0)
{
// Create a new asset from the completed upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, request.AssetBlock.AssetData);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Storing uploaded asset {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
// Store the asset
server.Assets.StoreAsset(asset);
// Send a success response
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = request.AssetBlock.Type;
complete.AssetBlock.UUID = assetID;
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Inventory);
}
else
{
// Create a new (empty) asset for the upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, null);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Starting upload for {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
RequestXferPacket xfer = new RequestXferPacket();
xfer.XferID.DeleteOnCompletion = request.AssetBlock.Tempfile;
xfer.XferID.FilePath = 0;
xfer.XferID.Filename = new byte[0];
xfer.XferID.ID = request.AssetBlock.TransactionID.GetULong();
xfer.XferID.UseBigPackets = false;
xfer.XferID.VFileID = asset.AssetID;
xfer.XferID.VFileType = request.AssetBlock.Type;
// Add this asset to the current upload list
lock (CurrentUploads)
CurrentUploads[xfer.XferID.ID] = asset;
server.UDP.SendPacket(agent.AgentID, xfer, PacketCategory.Inventory);
}
}
void SendXferPacketHandler(Packet packet, Agent agent)
{
SendXferPacketPacket xfer = (SendXferPacketPacket)packet;
Asset asset;
if (CurrentUploads.TryGetValue(xfer.XferID.ID, out asset))
{
if (asset.AssetData == null)
{
if (xfer.XferID.Packet != 0)
{
Logger.Log(String.Format("Received Xfer packet {0} before the first packet!",
xfer.XferID.Packet), Helpers.LogLevel.Error);
return;
}
uint size = Utils.BytesToUInt(xfer.DataPacket.Data);
asset.AssetData = new byte[size];
Buffer.BlockCopy(xfer.DataPacket.Data, 4, asset.AssetData, 0, xfer.DataPacket.Data.Length - 4);
// Confirm the first upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
}
else
{
Buffer.BlockCopy(xfer.DataPacket.Data, 0, asset.AssetData, (int)xfer.XferID.Packet * 1000,
xfer.DataPacket.Data.Length);
// Confirm this upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
if ((xfer.XferID.Packet & (uint)0x80000000) != 0)
{
// Asset upload finished
Logger.DebugLog(String.Format("Completed Xfer upload of asset {0} ({1}", asset.AssetID, asset.AssetType));
lock (CurrentUploads)
CurrentUploads.Remove(xfer.XferID.ID);
server.Assets.StoreAsset(asset);
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = (sbyte)asset.AssetType;
complete.AssetBlock.UUID = asset.AssetID;
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Asset);
}
}
}
else
{
Logger.DebugLog("Received a SendXferPacket for an unknown upload");
}
}
void AbortXferHandler(Packet packet, Agent agent)
{
AbortXferPacket abort = (AbortXferPacket)packet;
lock (CurrentUploads)
{
if (CurrentUploads.ContainsKey(abort.XferID.ID))
{
Logger.DebugLog(String.Format("Aborting Xfer {0}, result: {1}", abort.XferID.ID,
(TransferError)abort.XferID.Result));
CurrentUploads.Remove(abort.XferID.ID);
}
else
{
Logger.DebugLog(String.Format("Received an AbortXfer for an unknown xfer {0}",
abort.XferID.ID));
}
}
}
#endregion Xfer System
#region Transfer System
void TransferRequestHandler(Packet packet, Agent agent)
{
TransferRequestPacket request = (TransferRequestPacket)packet;
ChannelType channel = (ChannelType)request.TransferInfo.ChannelType;
SourceType source = (SourceType)request.TransferInfo.SourceType;
if (channel == ChannelType.Asset)
{
if (source == SourceType.Asset)
{
// Parse the request
UUID assetID = new UUID(request.TransferInfo.Params, 0);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 16);
// Check if we have this asset
Asset asset;
if (server.Assets.TryGetAsset(assetID, out asset))
{
if (asset.AssetType == type)
{
TransferToClient(asset, agent, request.TransferInfo.TransferID);
}
else
{
Logger.Log(String.Format(
"Request for asset {0} with type {1} does not match actual asset type {2}",
assetID, type, asset.AssetType), Helpers.LogLevel.Warning);
}
}
else
{
// Use the bot to try and request this asset
lock (currentDownloads)
{
currentDownloads.Add(client.Assets.RequestAsset(assetID, type, false),
new KeyValuePair<UUID, UUID>(agent.AgentID, request.TransferInfo.TransferID));
}
}
}
else if (source == SourceType.SimEstate)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
EstateAssetType type = (EstateAssetType)Utils.BytesToInt(request.TransferInfo.Params, 32);
Logger.Log("Please implement estate asset transfers", Helpers.LogLevel.Warning);
}
else if (source == SourceType.SimInventoryItem)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
UUID ownerID = new UUID(request.TransferInfo.Params, 32);
UUID taskID = new UUID(request.TransferInfo.Params, 48);
UUID itemID = new UUID(request.TransferInfo.Params, 64);
UUID assetID = new UUID(request.TransferInfo.Params, 80);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 96);
if (taskID != UUID.Zero)
{
// Task (prim) inventory request
Logger.Log("Please implement task inventory transfers", Helpers.LogLevel.Warning);
}
else
{
// Agent inventory request
Logger.Log("Please implement agent inventory transfer", Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
void TransferToClient(Asset asset, Agent agent, UUID transferID)
{
Logger.Log(String.Format("Transferring asset {0} ({1})", asset.AssetID, asset.AssetType), Helpers.LogLevel.Info);
TransferInfoPacket response = new TransferInfoPacket();
response.TransferInfo = new TransferInfoPacket.TransferInfoBlock();
response.TransferInfo.TransferID = transferID;
response.TransferInfo.Params = new byte[20];
Buffer.BlockCopy(asset.AssetID.GetBytes(), 0, response.TransferInfo.Params, 0, 16);
Buffer.BlockCopy(Utils.IntToBytes((int)asset.AssetType), 0, response.TransferInfo.Params, 16, 4);
response.TransferInfo.ChannelType = (int)ChannelType.Asset;
response.TransferInfo.Size = asset.AssetData.Length;
response.TransferInfo.Status = (int)StatusCode.OK;
response.TransferInfo.TargetType = (int)TargetType.Unknown; // Doesn't seem to be used by the client
server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
// Transfer system does not wait for ACKs, just sends all of the
// packets for this transfer out
const int MAX_CHUNK_SIZE = Settings.MAX_PACKET_SIZE - 100;
int processedLength = 0;
int packetNum = 0;
while (processedLength < asset.AssetData.Length)
{
TransferPacketPacket transfer = new TransferPacketPacket();
transfer.TransferData.ChannelType = (int)ChannelType.Asset;
transfer.TransferData.TransferID = transferID;
transfer.TransferData.Packet = packetNum++;
int chunkSize = Math.Min(asset.AssetData.Length - processedLength, MAX_CHUNK_SIZE);
transfer.TransferData.Data = new byte[chunkSize];
Buffer.BlockCopy(asset.AssetData, processedLength, transfer.TransferData.Data, 0, chunkSize);
processedLength += chunkSize;
if (processedLength >= asset.AssetData.Length)
transfer.TransferData.Status = (int)StatusCode.Done;
else
transfer.TransferData.Status = (int)StatusCode.OK;
server.UDP.SendPacket(agent.AgentID, transfer, PacketCategory.Asset);
}
}
#endregion Transfer System
void Assets_OnAssetReceived(AssetDownload transfer, Asset asset)
{
KeyValuePair<UUID, UUID> kvp;
Agent agent;
if (currentDownloads.TryGetValue(transfer.ID, out kvp))
{
currentDownloads.Remove(transfer.ID);
if (server.Agents.TryGetValue(kvp.Key, out agent))
{
if (transfer.Success)
{
server.Assets.StoreAsset(asset);
TransferToClient(asset, agent, kvp.Value);
}
else
{
Logger.Log("Request for missing asset " + transfer.AssetID.ToString(), Helpers.LogLevel.Warning);
// Asset not found
TransferInfoPacket response = new TransferInfoPacket();
response.TransferInfo = new TransferInfoPacket.TransferInfoBlock();
response.TransferInfo.TransferID = kvp.Value;
response.TransferInfo.Params = new byte[20];
Buffer.BlockCopy(transfer.AssetID.GetBytes(), 0, response.TransferInfo.Params, 0, 16);
Buffer.BlockCopy(Utils.IntToBytes((int)transfer.AssetType), 0, response.TransferInfo.Params, 16, 4);
response.TransferInfo.ChannelType = (int)ChannelType.Asset;
response.TransferInfo.Size = 0;
response.TransferInfo.Status = (int)StatusCode.UnknownSource;
response.TransferInfo.TargetType = (int)TargetType.Unknown;
server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
}
}
else
{
Logger.Log("Asset transfer finished for an untracked agent, ignoring", Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log("Asset transfer finished for an untracked download, ignoring", Helpers.LogLevel.Warning);
}
}
Asset CreateAsset(AssetType type, UUID assetID, byte[] data)
{
switch (type)
{
case AssetType.Bodypart:
return new AssetBodypart(assetID, data);
case AssetType.Clothing:
return new AssetClothing(assetID, data);
case AssetType.LSLBytecode:
return new AssetScriptBinary(assetID, data);
case AssetType.LSLText:
return new AssetScriptText(assetID, data);
case AssetType.Notecard:
return new AssetNotecard(assetID, data);
case AssetType.Texture:
return new AssetTexture(assetID, data);
case AssetType.Animation:
return new AssetAnimation(assetID, data);
case AssetType.CallingCard:
case AssetType.Folder:
case AssetType.Gesture:
case AssetType.ImageJPEG:
case AssetType.ImageTGA:
case AssetType.Landmark:
case AssetType.LostAndFoundFolder:
case AssetType.Object:
case AssetType.RootFolder:
case AssetType.Simstate:
case AssetType.SnapshotFolder:
case AssetType.Sound:
return new AssetSound(assetID, data);
case AssetType.SoundWAV:
case AssetType.TextureTGA:
case AssetType.TrashFolder:
case AssetType.Unknown:
default:
Logger.Log("Asset type " + type.ToString() + " not implemented!", Helpers.LogLevel.Warning);
return null;
}
}
}
}

View File

@@ -0,0 +1,358 @@
using System;
using System.Collections.Generic;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace Simian.Extensions
{
public class TransferManager : IExtension<Simian>
{
Simian server;
Dictionary<ulong, Asset> CurrentUploads = new Dictionary<ulong, Asset>();
public TransferManager()
{
}
public void Start(Simian server)
{
this.server = server;
server.UDP.RegisterPacketCallback(PacketType.AssetUploadRequest, new PacketCallback(AssetUploadRequestHandler));
server.UDP.RegisterPacketCallback(PacketType.SendXferPacket, new PacketCallback(SendXferPacketHandler));
server.UDP.RegisterPacketCallback(PacketType.AbortXfer, new PacketCallback(AbortXferHandler));
server.UDP.RegisterPacketCallback(PacketType.TransferRequest, new PacketCallback(TransferRequestHandler));
}
public void Stop()
{
}
#region Xfer System
void AssetUploadRequestHandler(Packet packet, Agent agent)
{
AssetUploadRequestPacket request = (AssetUploadRequestPacket)packet;
UUID assetID = UUID.Combine(request.AssetBlock.TransactionID, agent.SecureSessionID);
// Check if the asset is small enough to fit in a single packet
if (request.AssetBlock.AssetData.Length != 0)
{
// Create a new asset from the completed upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, request.AssetBlock.AssetData);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Storing uploaded asset {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
// Store the asset
server.Assets.StoreAsset(asset);
// Send a success response
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = request.AssetBlock.Type;
complete.AssetBlock.UUID = assetID;
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Inventory);
}
else
{
// Create a new (empty) asset for the upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, null);
if (asset == null)
{
Logger.Log("Failed to create asset from uploaded data", Helpers.LogLevel.Warning);
return;
}
Logger.DebugLog(String.Format("Starting upload for {0} ({1})", assetID, asset.AssetType));
asset.Temporary = (request.AssetBlock.Tempfile | request.AssetBlock.StoreLocal);
RequestXferPacket xfer = new RequestXferPacket();
xfer.XferID.DeleteOnCompletion = request.AssetBlock.Tempfile;
xfer.XferID.FilePath = 0;
xfer.XferID.Filename = new byte[0];
xfer.XferID.ID = request.AssetBlock.TransactionID.GetULong();
xfer.XferID.UseBigPackets = false;
xfer.XferID.VFileID = asset.AssetID;
xfer.XferID.VFileType = request.AssetBlock.Type;
// Add this asset to the current upload list
lock (CurrentUploads)
CurrentUploads[xfer.XferID.ID] = asset;
server.UDP.SendPacket(agent.AgentID, xfer, PacketCategory.Inventory);
}
}
void SendXferPacketHandler(Packet packet, Agent agent)
{
SendXferPacketPacket xfer = (SendXferPacketPacket)packet;
Asset asset;
if (CurrentUploads.TryGetValue(xfer.XferID.ID, out asset))
{
if (asset.AssetData == null)
{
if (xfer.XferID.Packet != 0)
{
Logger.Log(String.Format("Received Xfer packet {0} before the first packet!",
xfer.XferID.Packet), Helpers.LogLevel.Error);
return;
}
uint size = Utils.BytesToUInt(xfer.DataPacket.Data);
asset.AssetData = new byte[size];
Buffer.BlockCopy(xfer.DataPacket.Data, 4, asset.AssetData, 0, xfer.DataPacket.Data.Length - 4);
// Confirm the first upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
}
else
{
Buffer.BlockCopy(xfer.DataPacket.Data, 0, asset.AssetData, (int)xfer.XferID.Packet * 1000,
xfer.DataPacket.Data.Length);
// Confirm this upload packet
ConfirmXferPacketPacket confirm = new ConfirmXferPacketPacket();
confirm.XferID.ID = xfer.XferID.ID;
confirm.XferID.Packet = xfer.XferID.Packet;
server.UDP.SendPacket(agent.AgentID, confirm, PacketCategory.Asset);
if ((xfer.XferID.Packet & (uint)0x80000000) != 0)
{
// Asset upload finished
Logger.DebugLog(String.Format("Completed Xfer upload of asset {0} ({1}", asset.AssetID, asset.AssetType));
lock (CurrentUploads)
CurrentUploads.Remove(xfer.XferID.ID);
server.Assets.StoreAsset(asset);
AssetUploadCompletePacket complete = new AssetUploadCompletePacket();
complete.AssetBlock.Success = true;
complete.AssetBlock.Type = (sbyte)asset.AssetType;
complete.AssetBlock.UUID = asset.AssetID;
server.UDP.SendPacket(agent.AgentID, complete, PacketCategory.Asset);
}
}
}
else
{
Logger.DebugLog("Received a SendXferPacket for an unknown upload");
}
}
void AbortXferHandler(Packet packet, Agent agent)
{
AbortXferPacket abort = (AbortXferPacket)packet;
lock (CurrentUploads)
{
if (CurrentUploads.ContainsKey(abort.XferID.ID))
{
Logger.DebugLog(String.Format("Aborting Xfer {0}, result: {1}", abort.XferID.ID,
(TransferError)abort.XferID.Result));
CurrentUploads.Remove(abort.XferID.ID);
}
else
{
Logger.DebugLog(String.Format("Received an AbortXfer for an unknown xfer {0}",
abort.XferID.ID));
}
}
}
#endregion Xfer System
#region Transfer System
void TransferRequestHandler(Packet packet, Agent agent)
{
TransferRequestPacket request = (TransferRequestPacket)packet;
ChannelType channel = (ChannelType)request.TransferInfo.ChannelType;
SourceType source = (SourceType)request.TransferInfo.SourceType;
if (channel == ChannelType.Asset)
{
// Construct the response packet
TransferInfoPacket response = new TransferInfoPacket();
response.TransferInfo = new TransferInfoPacket.TransferInfoBlock();
response.TransferInfo.TransferID = request.TransferInfo.TransferID;
if (source == SourceType.Asset)
{
// Parse the request
UUID assetID = new UUID(request.TransferInfo.Params, 0);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 16);
// Set the response channel type
response.TransferInfo.ChannelType = (int)ChannelType.Asset;
// Params
response.TransferInfo.Params = new byte[20];
Buffer.BlockCopy(assetID.GetBytes(), 0, response.TransferInfo.Params, 0, 16);
Buffer.BlockCopy(Utils.IntToBytes((int)type), 0, response.TransferInfo.Params, 16, 4);
// Check if we have this asset
Asset asset;
if (server.Assets.TryGetAsset(assetID, out asset))
{
if (asset.AssetType == type)
{
Logger.DebugLog(String.Format("Transferring asset {0} ({1})", asset.AssetID, asset.AssetType));
// Asset found
response.TransferInfo.Size = asset.AssetData.Length;
response.TransferInfo.Status = (int)StatusCode.OK;
response.TransferInfo.TargetType = (int)TargetType.Unknown; // Doesn't seem to be used by the client
server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
// Transfer system does not wait for ACKs, just sends all of the
// packets for this transfer out
const int MAX_CHUNK_SIZE = Settings.MAX_PACKET_SIZE - 100;
int processedLength = 0;
int packetNum = 0;
while (processedLength < asset.AssetData.Length)
{
TransferPacketPacket transfer = new TransferPacketPacket();
transfer.TransferData.ChannelType = (int)ChannelType.Asset;
transfer.TransferData.TransferID = request.TransferInfo.TransferID;
transfer.TransferData.Packet = packetNum++;
int chunkSize = Math.Min(asset.AssetData.Length - processedLength, MAX_CHUNK_SIZE);
transfer.TransferData.Data = new byte[chunkSize];
Buffer.BlockCopy(asset.AssetData, processedLength, transfer.TransferData.Data, 0, chunkSize);
processedLength += chunkSize;
if (processedLength >= asset.AssetData.Length)
transfer.TransferData.Status = (int)StatusCode.Done;
else
transfer.TransferData.Status = (int)StatusCode.OK;
server.UDP.SendPacket(agent.AgentID, transfer, PacketCategory.Asset);
}
}
else
{
Logger.Log(String.Format(
"Request for asset {0} with type {1} does not match actual asset type {2}",
assetID, type, asset.AssetType), Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format("Request for missing asset {0} with type {1}",
assetID, type), Helpers.LogLevel.Warning);
// Asset not found
response.TransferInfo.Size = 0;
response.TransferInfo.Status = (int)StatusCode.UnknownSource;
response.TransferInfo.TargetType = (int)TargetType.Unknown;
server.UDP.SendPacket(agent.AgentID, response, PacketCategory.Asset);
}
}
else if (source == SourceType.SimEstate)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
EstateAssetType type = (EstateAssetType)Utils.BytesToInt(request.TransferInfo.Params, 32);
Logger.Log("Please implement estate asset transfers", Helpers.LogLevel.Warning);
}
else if (source == SourceType.SimInventoryItem)
{
UUID agentID = new UUID(request.TransferInfo.Params, 0);
UUID sessionID = new UUID(request.TransferInfo.Params, 16);
UUID ownerID = new UUID(request.TransferInfo.Params, 32);
UUID taskID = new UUID(request.TransferInfo.Params, 48);
UUID itemID = new UUID(request.TransferInfo.Params, 64);
UUID assetID = new UUID(request.TransferInfo.Params, 80);
AssetType type = (AssetType)(sbyte)Utils.BytesToInt(request.TransferInfo.Params, 96);
if (taskID != UUID.Zero)
{
// Task (prim) inventory request
Logger.Log("Please implement task inventory transfers", Helpers.LogLevel.Warning);
}
else
{
// Agent inventory request
Logger.Log("Please implement agent inventory transfer", Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
else
{
Logger.Log(String.Format(
"Received a TransferRequest that we don't know how to handle. Channel: {0}, Source: {1}",
channel, source), Helpers.LogLevel.Warning);
}
}
#endregion Transfer System
Asset CreateAsset(AssetType type, UUID assetID, byte[] data)
{
switch (type)
{
case AssetType.Bodypart:
return new AssetBodypart(assetID, data);
case AssetType.Clothing:
return new AssetClothing(assetID, data);
case AssetType.LSLBytecode:
return new AssetScriptBinary(assetID, data);
case AssetType.LSLText:
return new AssetScriptText(assetID, data);
case AssetType.Notecard:
return new AssetNotecard(assetID, data);
case AssetType.Texture:
return new AssetTexture(assetID, data);
case AssetType.Animation:
return new AssetAnimation(assetID, data);
case AssetType.CallingCard:
case AssetType.Folder:
case AssetType.Gesture:
case AssetType.ImageJPEG:
case AssetType.ImageTGA:
case AssetType.Landmark:
case AssetType.LostAndFoundFolder:
case AssetType.Object:
case AssetType.RootFolder:
case AssetType.Simstate:
case AssetType.SnapshotFolder:
case AssetType.Sound:
return new AssetSound(assetID, data);
case AssetType.SoundWAV:
case AssetType.TextureTGA:
case AssetType.TrashFolder:
case AssetType.Unknown:
default:
Logger.Log("Asset type " + type.ToString() + " not implemented!", Helpers.LogLevel.Warning);
return null;
}
}
}
}