diff --git a/OpenMetaverse/AssetTypes.cs b/OpenMetaverse/AssetTypes.cs
index d41c8a0d..1d24f9bd 100644
--- a/OpenMetaverse/AssetTypes.cs
+++ b/OpenMetaverse/AssetTypes.cs
@@ -99,6 +99,7 @@ namespace OpenMetaverse
public abstract class Asset
{
public byte[] AssetData;
+ public bool Temporary;
private UUID _AssetID;
public UUID AssetID
@@ -251,6 +252,7 @@ namespace OpenMetaverse
public ManagedImage Image;
public OpenJPEG.J2KLayerInfo[] LayerInfo;
+ public int Components;
public AssetTexture() { }
@@ -259,6 +261,15 @@ namespace OpenMetaverse
public AssetTexture(ManagedImage image)
{
Image = image;
+ Components = 0;
+ if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
+ Components += 3;
+ if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
+ ++Components;
}
///
@@ -277,7 +288,25 @@ namespace OpenMetaverse
/// True if the decoding was successful, otherwise false
public override bool Decode()
{
- return OpenJPEG.DecodeToImage(AssetData, out Image);
+ Components = 0;
+
+ if (OpenJPEG.DecodeToImage(AssetData, out Image))
+ {
+ if ((Image.Channels & ManagedImage.ImageChannels.Color) != 0)
+ Components += 3;
+ if ((Image.Channels & ManagedImage.ImageChannels.Gray) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Bump) != 0)
+ ++Components;
+ if ((Image.Channels & ManagedImage.ImageChannels.Alpha) != 0)
+ ++Components;
+
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
///
@@ -287,7 +316,7 @@ namespace OpenMetaverse
///
public bool DecodeLayerBoundaries()
{
- return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo);
+ return OpenJPEG.DecodeLayerBoundaries(AssetData, out LayerInfo, out Components);
}
}
diff --git a/OpenMetaverse/Imaging/OpenJPEG.cs b/OpenMetaverse/Imaging/OpenJPEG.cs
index f70592b7..41c183df 100644
--- a/OpenMetaverse/Imaging/OpenJPEG.cs
+++ b/OpenMetaverse/Imaging/OpenJPEG.cs
@@ -306,11 +306,13 @@ namespace OpenMetaverse.Imaging
///
///
///
+ ///
///
- public static bool DecodeLayerBoundaries(byte[] encoded, out J2KLayerInfo[] layerInfo)
+ public static bool DecodeLayerBoundaries(byte[] encoded, out J2KLayerInfo[] layerInfo, out int components)
{
bool success = false;
layerInfo = null;
+ components = 0;
MarshalledImage marshalled = new MarshalledImage();
// Allocate and copy to input buffer
@@ -321,6 +323,8 @@ namespace OpenMetaverse.Imaging
// Run the decode
if (DotNetDecodeWithInfo(ref marshalled))
{
+ components = marshalled.components;
+
// Sanity check
if (marshalled.layers * marshalled.resolutions * marshalled.components == marshalled.packet_count)
{
diff --git a/Programs/Simian/Agent.cs b/Programs/Simian/Agent.cs
index 6734b37d..dc58b292 100644
--- a/Programs/Simian/Agent.cs
+++ b/Programs/Simian/Agent.cs
@@ -50,31 +50,18 @@ namespace Simian
//public byte[] Texture;
public float Height;
public UUID ShapeItem;
- public UUID ShapeAsset;
public UUID SkinItem;
- public UUID SkinAsset;
public UUID HairItem;
- public UUID HairAsset;
public UUID EyesItem;
- public UUID EyesAsset;
public UUID ShirtItem;
- public UUID ShirtAsset;
public UUID PantsItem;
- public UUID PantsAsset;
public UUID ShoesItem;
- public UUID ShoesAsset;
public UUID SocksItem;
- public UUID SocksAsset;
public UUID JacketItem;
- public UUID JacketAsset;
public UUID GlovesItem;
- public UUID GlovesAsset;
public UUID UndershirtItem;
- public UUID UndershirtAsset;
public UUID UnderpantsItem;
- public UUID UnderpantsAsset;
public UUID SkirtItem;
- public UUID SkirtAsset;
// Temporary
[NonSerialized]
diff --git a/Programs/Simian/Extensions/AssetManager.cs b/Programs/Simian/Extensions/AssetManager.cs
index a37ac230..5fdeb25e 100644
--- a/Programs/Simian/Extensions/AssetManager.cs
+++ b/Programs/Simian/Extensions/AssetManager.cs
@@ -10,9 +10,12 @@ namespace Simian.Extensions
{
public class AssetManager : IExtension, IAssetProvider
{
+ public const string UPLOAD_DIR = "uploadedAssets";
+
Simian Server;
Dictionary AssetStore = new Dictionary();
Dictionary CurrentUploads = new Dictionary();
+ string UploadDir;
public AssetManager(Simian server)
{
@@ -21,7 +24,22 @@ namespace Simian.Extensions
public void Start()
{
- LoadDefaultAssets(Server.DataDir);
+ UploadDir = Path.Combine(Server.DataDir, UPLOAD_DIR);
+
+ // Try to create the data directories if they don't already exist
+ if (!Directory.Exists(Server.DataDir))
+ {
+ try { Directory.CreateDirectory(Server.DataDir); }
+ catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex); }
+ }
+ if (!Directory.Exists(UploadDir))
+ {
+ try { Directory.CreateDirectory(UploadDir); }
+ catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex); }
+ }
+
+ LoadAssets(Server.DataDir);
+ LoadAssets(UploadDir);
Server.UDP.RegisterPacketCallback(PacketType.AssetUploadRequest, new PacketCallback(AssetUploadRequestHandler));
Server.UDP.RegisterPacketCallback(PacketType.SendXferPacket, new PacketCallback(SendXferPacketHandler));
@@ -43,6 +61,8 @@ namespace Simian.Extensions
{
lock (AssetStore)
AssetStore[asset.AssetID] = texture;
+ if (!asset.Temporary)
+ SaveAsset(texture);
}
else
{
@@ -56,6 +76,8 @@ namespace Simian.Extensions
{
lock (AssetStore)
AssetStore[asset.AssetID] = asset;
+ if (!asset.Temporary)
+ SaveAsset(asset);
}
else
{
@@ -77,9 +99,10 @@ namespace Simian.Extensions
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 upload
+ // Create a new asset from the completed upload
Asset asset = CreateAsset((AssetType)request.AssetBlock.Type, assetID, request.AssetBlock.AssetData);
if (asset == null)
{
@@ -89,6 +112,8 @@ namespace Simian.Extensions
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);
@@ -101,15 +126,18 @@ namespace Simian.Extensions
}
else
{
- // Create a new asset for the upload
+ // 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;
@@ -168,7 +196,7 @@ namespace Simian.Extensions
if ((xfer.XferID.Packet & (uint)0x80000000) != 0)
{
// Asset upload finished
- Logger.DebugLog("Completed asset upload");
+ Logger.DebugLog(String.Format("Completed Xfer upload of asset {0} ({1}", asset.AssetID, asset.AssetType));
lock (CurrentUploads)
CurrentUploads.Remove(xfer.XferID.ID);
@@ -348,6 +376,19 @@ namespace Simian.Extensions
#endregion Transfer System
+ void SaveAsset(Asset asset)
+ {
+ try
+ {
+ File.WriteAllBytes(Path.Combine(UploadDir, String.Format("{0}.{1}", asset.AssetID,
+ asset.AssetType.ToString().ToLower())), asset.AssetData);
+ }
+ catch (Exception ex)
+ {
+ Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex);
+ }
+ }
+
Asset CreateAsset(AssetType type, UUID assetID, byte[] data)
{
switch (type)
@@ -389,38 +430,51 @@ namespace Simian.Extensions
}
}
- void LoadDefaultAssets(string path)
+ void LoadAssets(string path)
{
- string[] textures = Directory.GetFiles(path, "*.jp2", SearchOption.TopDirectoryOnly);
- string[] clothing = Directory.GetFiles(path, "*.clothing", SearchOption.TopDirectoryOnly);
- string[] bodyparts = Directory.GetFiles(path, "*.bodypart", SearchOption.TopDirectoryOnly);
- string[] sounds = Directory.GetFiles(path, "*.ogg", SearchOption.TopDirectoryOnly);
-
- for (int i = 0; i < textures.Length; i++)
+ try
{
- UUID assetID = ParseUUIDFromFilename(textures[i]);
- StoreAsset(new AssetTexture(assetID, File.ReadAllBytes(textures[i])));
- }
+ string[] textures = Directory.GetFiles(path, "*.jp2", SearchOption.TopDirectoryOnly);
+ string[] clothing = Directory.GetFiles(path, "*.clothing", SearchOption.TopDirectoryOnly);
+ string[] bodyparts = Directory.GetFiles(path, "*.bodypart", SearchOption.TopDirectoryOnly);
+ string[] sounds = Directory.GetFiles(path, "*.ogg", SearchOption.TopDirectoryOnly);
- for (int i = 0; i < clothing.Length; i++)
+ for (int i = 0; i < textures.Length; i++)
+ {
+ UUID assetID = ParseUUIDFromFilename(textures[i]);
+ Asset asset = new AssetTexture(assetID, File.ReadAllBytes(textures[i]));
+ asset.Temporary = true;
+ StoreAsset(asset);
+ }
+
+ for (int i = 0; i < clothing.Length; i++)
+ {
+ UUID assetID = ParseUUIDFromFilename(clothing[i]);
+ Asset asset = new AssetClothing(assetID, File.ReadAllBytes(clothing[i]));
+ asset.Temporary = true;
+ StoreAsset(asset);
+ }
+
+ for (int i = 0; i < bodyparts.Length; i++)
+ {
+ UUID assetID = ParseUUIDFromFilename(bodyparts[i]);
+ Asset asset = new AssetBodypart(assetID, File.ReadAllBytes(bodyparts[i]));
+ asset.Temporary = true;
+ StoreAsset(asset);
+ }
+
+ for (int i = 0; i < sounds.Length; i++)
+ {
+ UUID assetID = ParseUUIDFromFilename(sounds[i]);
+ Asset asset = new AssetSound(assetID, File.ReadAllBytes(sounds[i]));
+ asset.Temporary = true;
+ StoreAsset(asset);
+ }
+ }
+ catch (Exception ex)
{
- UUID assetID = ParseUUIDFromFilename(clothing[i]);
- StoreAsset(new AssetClothing(assetID, File.ReadAllBytes(clothing[i])));
+ Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex);
}
-
- for (int i = 0; i < bodyparts.Length; i++)
- {
- UUID assetID = ParseUUIDFromFilename(bodyparts[i]);
- StoreAsset(new AssetBodypart(assetID, File.ReadAllBytes(bodyparts[i])));
- }
-
- for (int i = 0; i < sounds.Length; i++)
- {
- UUID assetID = ParseUUIDFromFilename(sounds[i]);
- StoreAsset(new AssetSound(assetID, File.ReadAllBytes(sounds[i])));
- }
-
- Logger.DebugLog(String.Format("Loaded {0} assets", AssetStore.Count));
}
static UUID ParseUUIDFromFilename(string filename)
diff --git a/Programs/Simian/Extensions/AuthFreeForAll.cs b/Programs/Simian/Extensions/AuthFreeForAll.cs
index 706e4615..6ee414cf 100644
--- a/Programs/Simian/Extensions/AuthFreeForAll.cs
+++ b/Programs/Simian/Extensions/AuthFreeForAll.cs
@@ -66,39 +66,33 @@ namespace Simian.Extensions
UUID hairAsset = new UUID("dc675529-7ba5-4976-b91d-dcb9e5e36188");
UUID hairItem = server.Inventory.CreateItem(agent.AgentID, "Default Hair", "Default Hair",
InventoryType.Wearable, AssetType.Bodypart, hairAsset, defaultOutfitFolder,
- PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0);
+ PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0, false);
UUID pantsAsset = new UUID("3e8ee2d6-4f21-4a55-832d-77daa505edff");
UUID pantsItem = server.Inventory.CreateItem(agent.AgentID, "Default Pants", "Default Pants",
InventoryType.Wearable, AssetType.Clothing, pantsAsset, defaultOutfitFolder,
- PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0);
+ PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0, false);
UUID shapeAsset = new UUID("530a2614-052e-49a2-af0e-534bb3c05af0");
UUID shapeItem = server.Inventory.CreateItem(agent.AgentID, "Default Shape", "Default Shape",
InventoryType.Wearable, AssetType.Clothing, shapeAsset, defaultOutfitFolder,
- PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0);
+ PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0, false);
UUID shirtAsset = new UUID("6a714f37-fe53-4230-b46f-8db384465981");
UUID shirtItem = server.Inventory.CreateItem(agent.AgentID, "Default Shirt", "Default Shirt",
InventoryType.Wearable, AssetType.Clothing, shirtAsset, defaultOutfitFolder,
- PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0);
+ PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0, false);
UUID skinAsset = new UUID("5f787f25-f761-4a35-9764-6418ee4774c4");
UUID skinItem = server.Inventory.CreateItem(agent.AgentID, "Default Skin", "Default Skin",
InventoryType.Wearable, AssetType.Clothing, skinAsset, defaultOutfitFolder,
- PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0);
+ PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0, false);
UUID eyesAsset = new UUID("78d20332-9b07-44a2-bf74-3b368605f4b5");
UUID eyesItem = server.Inventory.CreateItem(agent.AgentID, "Default Eyes", "Default Eyes",
InventoryType.Wearable, AssetType.Bodypart, eyesAsset, defaultOutfitFolder,
- PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0);
+ PermissionMask.All, PermissionMask.All, agent.AgentID, agent.AgentID, UUID.Random(), 0, false);
- agent.HairAsset = hairAsset;
agent.HairItem = hairItem;
- agent.PantsAsset = pantsAsset;
agent.PantsItem = pantsItem;
- agent.ShapeAsset = shapeAsset;
agent.ShapeItem = shapeItem;
- agent.ShirtAsset = shirtAsset;
agent.ShirtItem = shirtItem;
- agent.SkinAsset = skinAsset;
agent.SkinItem = skinItem;
- agent.EyesAsset = eyesAsset;
agent.EyesItem = eyesItem;
server.Accounts.AddAccount(agent);
diff --git a/Programs/Simian/Extensions/AvatarManager.cs b/Programs/Simian/Extensions/AvatarManager.cs
index 9a5be626..5be11bb3 100644
--- a/Programs/Simian/Extensions/AvatarManager.cs
+++ b/Programs/Simian/Extensions/AvatarManager.cs
@@ -152,23 +152,38 @@ namespace Simian.Extensions
}
}
- int CountWearables(Agent agent)
+ bool TryAddWearable(UUID agentID, Dictionary wearables, WearableType type, UUID itemID)
{
- int wearables = 0;
+ InventoryObject obj;
+ if (itemID != UUID.Zero && Server.Inventory.TryGetInventory(agentID, itemID, out obj) &&
+ obj is InventoryItem)
+ {
+ wearables.Add(type, (InventoryItem)obj);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
- if (agent.ShapeAsset != UUID.Zero) ++wearables;
- if (agent.SkinAsset != UUID.Zero) ++wearables;
- if (agent.HairAsset != UUID.Zero) ++wearables;
- if (agent.EyesAsset != UUID.Zero) ++wearables;
- if (agent.ShirtAsset != UUID.Zero) ++wearables;
- if (agent.PantsAsset != UUID.Zero) ++wearables;
- if (agent.ShoesAsset != UUID.Zero) ++wearables;
- if (agent.SocksAsset != UUID.Zero) ++wearables;
- if (agent.JacketAsset != UUID.Zero) ++wearables;
- if (agent.GlovesAsset != UUID.Zero) ++wearables;
- if (agent.UndershirtAsset != UUID.Zero) ++wearables;
- if (agent.UnderpantsAsset != UUID.Zero) ++wearables;
- if (agent.SkirtAsset != UUID.Zero) ++wearables;
+ Dictionary GetCurrentWearables(Agent agent)
+ {
+ Dictionary wearables = new Dictionary();
+
+ TryAddWearable(agent.AgentID, wearables, WearableType.Shape, agent.ShapeItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Skin, agent.SkinItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Hair, agent.HairItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Eyes, agent.EyesItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Shirt, agent.ShirtItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Pants, agent.PantsItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Shoes, agent.ShoesItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Socks, agent.SocksItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Jacket, agent.JacketItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Gloves, agent.GlovesItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Undershirt, agent.UndershirtItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Underpants, agent.UnderpantsItem);
+ TryAddWearable(agent.AgentID, wearables, WearableType.Skirt, agent.SkirtItem);
return wearables;
}
@@ -178,126 +193,24 @@ namespace Simian.Extensions
AgentWearablesUpdatePacket update = new AgentWearablesUpdatePacket();
update.AgentData.AgentID = agent.AgentID;
- // Count the number of WearableData blocks needed
- int wearableCount = CountWearables(agent);
+ Dictionary wearables = GetCurrentWearables(agent);
+ update.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[wearables.Count];
int i = 0;
- update.WearableData = new AgentWearablesUpdatePacket.WearableDataBlock[wearableCount];
-
- #region WearableData Blocks
-
- if (agent.ShapeAsset != UUID.Zero)
+ foreach (KeyValuePair kvp in wearables)
{
update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.ShapeAsset;
- update.WearableData[i].ItemID = agent.ShapeItem;
- update.WearableData[i].WearableType = (byte)WearableType.Shape;
+ update.WearableData[i].AssetID = kvp.Value.AssetID;
+ update.WearableData[i].ItemID = kvp.Value.ID;
+ update.WearableData[i].WearableType = (byte)kvp.Key;
++i;
}
- if (agent.SkinAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.SkinAsset;
- update.WearableData[i].ItemID = agent.SkinItem;
- update.WearableData[i].WearableType = (byte)WearableType.Skin;
- ++i;
- }
- if (agent.HairAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.HairAsset;
- update.WearableData[i].ItemID = agent.HairItem;
- update.WearableData[i].WearableType = (byte)WearableType.Hair;
- ++i;
- }
- if (agent.EyesAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.EyesAsset;
- update.WearableData[i].ItemID = agent.EyesItem;
- update.WearableData[i].WearableType = (byte)WearableType.Eyes;
- ++i;
- }
- if (agent.ShirtAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.ShirtAsset;
- update.WearableData[i].ItemID = agent.ShirtItem;
- update.WearableData[i].WearableType = (byte)WearableType.Shirt;
- ++i;
- }
- if (agent.PantsAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.PantsAsset;
- update.WearableData[i].ItemID = agent.PantsItem;
- update.WearableData[i].WearableType = (byte)WearableType.Pants;
- ++i;
- }
- if (agent.ShoesAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.ShoesAsset;
- update.WearableData[i].ItemID = agent.ShoesItem;
- update.WearableData[i].WearableType = (byte)WearableType.Shoes;
- ++i;
- }
- if (agent.SocksAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.SocksAsset;
- update.WearableData[i].ItemID = agent.SocksItem;
- update.WearableData[i].WearableType = (byte)WearableType.Socks;
- ++i;
- }
- if (agent.JacketAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.JacketAsset;
- update.WearableData[i].ItemID = agent.JacketItem;
- update.WearableData[i].WearableType = (byte)WearableType.Jacket;
- ++i;
- }
- if (agent.GlovesAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.GlovesAsset;
- update.WearableData[i].ItemID = agent.GlovesItem;
- update.WearableData[i].WearableType = (byte)WearableType.Gloves;
- ++i;
- }
- if (agent.UndershirtAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.UndershirtAsset;
- update.WearableData[i].ItemID = agent.UndershirtItem;
- update.WearableData[i].WearableType = (byte)WearableType.Undershirt;
- ++i;
- }
- if (agent.UnderpantsAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.UnderpantsAsset;
- update.WearableData[i].ItemID = agent.UnderpantsItem;
- update.WearableData[i].WearableType = (byte)WearableType.Underpants;
- ++i;
- }
- if (agent.SkirtAsset != UUID.Zero)
- {
- update.WearableData[i] = new AgentWearablesUpdatePacket.WearableDataBlock();
- update.WearableData[i].AssetID = agent.SkirtAsset;
- update.WearableData[i].ItemID = agent.SkirtItem;
- update.WearableData[i].WearableType = (byte)WearableType.Skirt;
- ++i;
- }
-
- #endregion WearableData Blocks
// Technically this should be per-agent, but if the only requirement is that it
// increments this is easier
update.AgentData.SerialNum = (uint)Interlocked.Increment(ref currentWearablesSerialNum);
- Logger.DebugLog(String.Format("Sending info about {0} wearables", wearableCount));
+ Logger.DebugLog(String.Format("Sending info about {0} wearables", wearables.Count));
Server.UDP.SendPacket(agent.AgentID, update, PacketCategory.Asset);
}
@@ -313,67 +226,49 @@ namespace Simian.Extensions
for (int i = 0; i < wearing.WearableData.Length; i++)
{
- UUID assetID = UUID.Zero;
UUID itemID = wearing.WearableData[i].ItemID;
- InventoryObject invObj;
- if (Server.Inventory.TryGetInventory(agent.AgentID, itemID, out invObj) && invObj is InventoryItem)
- assetID = ((InventoryItem)invObj).AssetID;
-
#region Update Wearables
switch ((WearableType)wearing.WearableData[i].WearableType)
{
case WearableType.Shape:
- agent.ShapeAsset = assetID;
agent.ShapeItem = itemID;
break;
case WearableType.Skin:
- agent.SkinAsset = assetID;
agent.SkinItem = itemID;
break;
case WearableType.Hair:
- agent.HairAsset = assetID;
agent.HairItem = itemID;
break;
case WearableType.Eyes:
- agent.EyesAsset = assetID;
agent.EyesItem = itemID;
break;
case WearableType.Shirt:
- agent.ShirtAsset = assetID;
agent.ShirtItem = itemID;
break;
case WearableType.Pants:
- agent.PantsAsset = assetID;
agent.PantsItem = itemID;
break;
case WearableType.Shoes:
- agent.ShoesAsset = assetID;
agent.ShoesItem = itemID;
break;
case WearableType.Socks:
- agent.SocksAsset = assetID;
agent.SocksItem = itemID;
break;
case WearableType.Jacket:
- agent.JacketAsset = assetID;
agent.JacketItem = itemID;
break;
case WearableType.Gloves:
- agent.GlovesAsset = assetID;
agent.GlovesItem = itemID;
break;
case WearableType.Undershirt:
- agent.UndershirtAsset = assetID;
agent.UndershirtItem = itemID;
break;
case WearableType.Underpants:
- agent.UnderpantsAsset = assetID;
agent.UnderpantsItem = itemID;
break;
case WearableType.Skirt:
- agent.SkirtAsset = assetID;
agent.SkirtItem = itemID;
break;
}
@@ -381,7 +276,8 @@ namespace Simian.Extensions
#endregion Update Wearables
}
- Logger.DebugLog("Updated agent wearables, new count: " + CountWearables(agent));
+ // FIXME: GetCurrentWearables() is a very expensive call, remove it from this debug line
+ Logger.DebugLog("Updated agent wearables, new count: " + GetCurrentWearables(agent).Count);
}
void AgentSetAppearanceHandler(Packet packet, Agent agent)
diff --git a/Programs/Simian/Extensions/InventoryManager.cs b/Programs/Simian/Extensions/InventoryManager.cs
index 1bf459b7..892078de 100644
--- a/Programs/Simian/Extensions/InventoryManager.cs
+++ b/Programs/Simian/Extensions/InventoryManager.cs
@@ -81,7 +81,7 @@ namespace Simian.Extensions
CreateItem(agent.AgentID, Utils.BytesToString(create.InventoryBlock.Name), "Created in Simian",
(InventoryType)create.InventoryBlock.InvType, assetType, assetID, parentID,
PermissionMask.All, (PermissionMask)create.InventoryBlock.NextOwnerMask, agent.AgentID,
- agent.AgentID, create.InventoryBlock.TransactionID, create.InventoryBlock.CallbackID);
+ agent.AgentID, create.InventoryBlock.TransactionID, create.InventoryBlock.CallbackID, true);
}
void CreateInventoryFolderHandler(Packet packet, Agent agent)
@@ -137,6 +137,7 @@ namespace Simian.Extensions
item.SalePrice = block.SalePrice;
item.SaleType = (SaleType)block.SaleType;
item.AssetType = (AssetType)block.Type;
+ item.AssetID = UUID.Combine(block.TransactionID, agent.SecureSessionID);
Logger.DebugLog(String.Format(
"UpdateInventoryItem: CallbackID: {0}, TransactionID: {1}",
@@ -228,14 +229,7 @@ namespace Simian.Extensions
itemBlocks[i] = new InventoryDescendentsPacket.ItemDataBlock();
itemBlocks[i].AssetID = currentItem.AssetID;
itemBlocks[i].BaseMask = (uint)currentItem.Permissions.BaseMask;
- itemBlocks[i].CRC = Helpers.InventoryCRC(
- (int)Utils.DateTimeToUnixTime(currentItem.CreationDate),
- (byte)currentItem.SaleType, (sbyte)currentItem.InventoryType,
- (sbyte)currentItem.AssetType, currentItem.AssetID, currentItem.GroupID,
- currentItem.SalePrice, currentItem.OwnerID, currentItem.CreatorID, currentItem.ID,
- currentItem.ParentID, (uint)currentItem.Permissions.EveryoneMask, currentItem.Flags,
- (uint)currentItem.Permissions.NextOwnerMask, (uint)currentItem.Permissions.GroupMask,
- (uint)currentItem.Permissions.OwnerMask);
+ itemBlocks[i].CRC = currentItem.CRC;
itemBlocks[i].CreationDate = (int)Utils.DateTimeToUnixTime(currentItem.CreationDate);
itemBlocks[i].CreatorID = currentItem.CreatorID;
itemBlocks[i].Description = Utils.StringToBytes(currentItem.Description);
@@ -366,11 +360,7 @@ namespace Simian.Extensions
blocks[i].AssetID = item.AssetID;
blocks[i].BaseMask = (uint)item.Permissions.BaseMask;
- blocks[i].CRC = Helpers.InventoryCRC((int)Utils.DateTimeToUnixTime(item.CreationDate),
- (byte)item.SaleType, (sbyte)item.InventoryType, (sbyte)item.AssetType, item.AssetID, item.GroupID,
- item.SalePrice, item.OwnerID, item.CreatorID, item.ID, item.ParentID,
- (uint)item.Permissions.EveryoneMask, item.Flags, (uint)item.Permissions.NextOwnerMask,
- (uint)item.Permissions.GroupMask, (uint)item.Permissions.OwnerMask);
+ blocks[i].CRC = item.CRC;
blocks[i].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
blocks[i].CreatorID = item.CreatorID;
blocks[i].Description = Utils.StringToBytes(item.Description);
@@ -447,7 +437,7 @@ namespace Simian.Extensions
// Create the copy
CreateItem(agent.AgentID, newName, item.Description, item.InventoryType, item.AssetType,
item.AssetID, folderObj.ID, item.Permissions.OwnerMask, item.Permissions.NextOwnerMask,
- agent.AgentID, item.CreatorID, UUID.Zero, block.CallbackID);
+ agent.AgentID, item.CreatorID, UUID.Zero, block.CallbackID, true);
}
else
{
@@ -477,7 +467,8 @@ namespace Simian.Extensions
UUID newFolderID = block.FolderID;
if (newFolderID == UUID.Zero)
newFolderID = agent.InventoryRoot;
- MoveInventory(agentInventory, block.ItemID, newFolderID, Utils.BytesToString(block.NewName));
+ MoveInventory(agent, agentInventory, block.ItemID, newFolderID, Utils.BytesToString(block.NewName),
+ UUID.Zero, 0);
}
}
@@ -494,11 +485,64 @@ namespace Simian.Extensions
UUID newFolderID = block.ParentID;
if (newFolderID == UUID.Zero)
newFolderID = agent.InventoryRoot;
- MoveInventory(agentInventory, block.FolderID, newFolderID, null);
+ MoveInventory(agent, agentInventory, block.FolderID, newFolderID, null, UUID.Zero, 0);
}
}
- void MoveInventory(Dictionary agentInventory, UUID objectID, UUID newFolderID, string newName)
+ void SendBulkUpdate(Agent agent, InventoryObject obj, UUID transactionID, uint callbackID)
+ {
+ BulkUpdateInventoryPacket update = new BulkUpdateInventoryPacket();
+ update.AgentData.AgentID = agent.AgentID;
+ update.AgentData.TransactionID = transactionID;
+
+ if (obj is InventoryItem)
+ {
+ InventoryItem item = (InventoryItem)obj;
+
+ update.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[0];
+ update.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[1];
+ update.ItemData[0] = new BulkUpdateInventoryPacket.ItemDataBlock();
+ update.ItemData[0].AssetID = item.AssetID;
+ update.ItemData[0].BaseMask = (uint)item.Permissions.BaseMask;
+ update.ItemData[0].CallbackID = callbackID;
+ update.ItemData[0].CRC = item.CRC;
+ update.ItemData[0].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
+ update.ItemData[0].CreatorID = item.CreatorID;
+ update.ItemData[0].Description = Utils.StringToBytes(item.Description);
+ update.ItemData[0].EveryoneMask = (uint)item.Permissions.EveryoneMask;
+ update.ItemData[0].Flags = item.Flags;
+ update.ItemData[0].FolderID = item.ParentID;
+ update.ItemData[0].GroupID = item.GroupID;
+ update.ItemData[0].GroupMask = (uint)item.Permissions.GroupMask;
+ update.ItemData[0].GroupOwned = item.GroupOwned;
+ update.ItemData[0].InvType = (sbyte)item.InventoryType;
+ update.ItemData[0].ItemID = item.ID;
+ update.ItemData[0].Name = Utils.StringToBytes(item.Name);
+ update.ItemData[0].NextOwnerMask = (uint)item.Permissions.NextOwnerMask;
+ update.ItemData[0].OwnerID = item.OwnerID;
+ update.ItemData[0].OwnerMask = (uint)item.Permissions.OwnerMask;
+ update.ItemData[0].SalePrice = item.SalePrice;
+ update.ItemData[0].SaleType = (byte)item.SaleType;
+ update.ItemData[0].Type = (sbyte)item.InventoryType;
+ }
+ else
+ {
+ InventoryFolder folder = (InventoryFolder)obj;
+
+ update.ItemData = new BulkUpdateInventoryPacket.ItemDataBlock[0];
+ update.FolderData = new BulkUpdateInventoryPacket.FolderDataBlock[1];
+ update.FolderData[0] = new BulkUpdateInventoryPacket.FolderDataBlock();
+ update.FolderData[0].FolderID = folder.ID;
+ update.FolderData[0].Name = Utils.StringToBytes(folder.Name);
+ update.FolderData[0].ParentID = folder.ParentID;
+ update.FolderData[0].Type = (sbyte)folder.PreferredType;
+ }
+
+ Server.UDP.SendPacket(agent.AgentID, update, PacketCategory.Inventory);
+ }
+
+ void MoveInventory(Agent agent, Dictionary agentInventory, UUID objectID,
+ UUID newFolderID, string newName, UUID transactionID, uint callbackID)
{
InventoryObject obj;
if (agentInventory.TryGetValue(objectID, out obj))
@@ -531,6 +575,8 @@ namespace Simian.Extensions
Logger.Log("MoveInventory called with an unknown destination folder " + newFolderID,
Helpers.LogLevel.Warning);
}
+
+ SendBulkUpdate(agent, obj, transactionID, callbackID);
}
}
else
@@ -662,7 +708,7 @@ namespace Simian.Extensions
public UUID CreateItem(UUID agentID, string name, string description, InventoryType invType, AssetType type,
UUID assetID, UUID parentID, PermissionMask ownerMask, PermissionMask nextOwnerMask, UUID ownerID,
- UUID creatorID, UUID transactionID, uint callbackID)
+ UUID creatorID, UUID transactionID, uint callbackID, bool sendPacket)
{
Dictionary agentInventory = GetAgentInventory(agentID);
@@ -716,12 +762,7 @@ namespace Simian.Extensions
update.InventoryData[0].BaseMask = (uint)PermissionMask.All;
update.InventoryData[0].CallbackID = callbackID;
update.InventoryData[0].CreationDate = (int)Utils.DateTimeToUnixTime(item.CreationDate);
- update.InventoryData[0].CRC =
- Helpers.InventoryCRC((int)Utils.DateTimeToUnixTime(item.CreationDate), (byte)item.SaleType,
- (sbyte)item.InventoryType, (sbyte)item.AssetType, item.AssetID, item.GroupID, item.SalePrice,
- item.OwnerID, item.CreatorID, item.ID, item.ParentID, (uint)item.Permissions.EveryoneMask,
- item.Flags, (uint)item.Permissions.NextOwnerMask, (uint)item.Permissions.GroupMask,
- (uint)item.Permissions.OwnerMask);
+ update.InventoryData[0].CRC = item.CRC;
update.InventoryData[0].CreatorID = item.CreatorID;
update.InventoryData[0].Description = Utils.StringToBytes(item.Description);
update.InventoryData[0].EveryoneMask = (uint)item.Permissions.EveryoneMask;
@@ -740,7 +781,9 @@ namespace Simian.Extensions
update.InventoryData[0].SaleType = (byte)item.SaleType;
update.InventoryData[0].Type = (sbyte)item.AssetType;
- Server.UDP.SendPacket(agentID, update, PacketCategory.Inventory);
+ if (sendPacket)
+ Server.UDP.SendPacket(agentID, update, PacketCategory.Inventory);
+
return item.ID;
}
else
diff --git a/Programs/Simian/Extensions/ObjectManager.cs b/Programs/Simian/Extensions/ObjectManager.cs
index 2a64a0ed..a3073589 100644
--- a/Programs/Simian/Extensions/ObjectManager.cs
+++ b/Programs/Simian/Extensions/ObjectManager.cs
@@ -565,7 +565,7 @@ namespace Simian.Extensions
InventoryFolder trash = (InventoryFolder)invObj;
Server.Inventory.CreateItem(agent.AgentID, obj.Prim.Properties.Name, obj.Prim.Properties.Description, InventoryType.Object,
AssetType.Object, obj.Prim.ID, trash.ID, PermissionMask.All, PermissionMask.All, agent.AgentID,
- obj.Prim.Properties.CreatorID, derez.AgentBlock.TransactionID, 0);
+ obj.Prim.Properties.CreatorID, derez.AgentBlock.TransactionID, 0, true);
Server.Scene.ObjectRemove(this, obj);
Logger.DebugLog(String.Format("Derezzed prim {0} to agent inventory trash", obj.Prim.LocalID));
diff --git a/Programs/Simian/Interfaces/IInventoryProvider.cs b/Programs/Simian/Interfaces/IInventoryProvider.cs
index 7d7b7177..209965c0 100644
--- a/Programs/Simian/Interfaces/IInventoryProvider.cs
+++ b/Programs/Simian/Interfaces/IInventoryProvider.cs
@@ -7,7 +7,7 @@ namespace Simian
{
UUID CreateItem(UUID agentID, string name, string description, InventoryType invType, AssetType type,
UUID assetID, UUID parentID, PermissionMask ownerMask, PermissionMask nextOwnerMask, UUID ownerID,
- UUID creatorID, UUID transactionID, uint callbackID);
+ UUID creatorID, UUID transactionID, uint callbackID, bool sendPacket);
bool CreateFolder(UUID agentID, UUID folderID, string name, AssetType preferredType, UUID parentID,
UUID ownerID);
bool CreateRootFolder(UUID agentID, UUID folderID, string name, UUID ownerID);
diff --git a/Programs/Simian/InventoryDefinitions.cs b/Programs/Simian/InventoryDefinitions.cs
index edcb7893..6f6fa5bd 100644
--- a/Programs/Simian/InventoryDefinitions.cs
+++ b/Programs/Simian/InventoryDefinitions.cs
@@ -74,6 +74,20 @@ namespace Simian
/// UTC (Coordinated Universal Time)
public DateTime CreationDate;
+ /// Cyclic redundancy check for this inventory item, calculated by adding most of
+ /// the fields together
+ public uint CRC
+ {
+ get
+ {
+ return Helpers.InventoryCRC((int)Utils.DateTimeToUnixTime(CreationDate), (byte)SaleType,
+ (sbyte)InventoryType, (sbyte)AssetType, AssetID, GroupID, SalePrice,
+ OwnerID, CreatorID, ID, ParentID, (uint)Permissions.EveryoneMask,
+ Flags, (uint)Permissions.NextOwnerMask, (uint)Permissions.GroupMask,
+ (uint)Permissions.OwnerMask);
+ }
+ }
+
public override int GetHashCode()
{
return ID.GetHashCode();