All pastes #1480822 Raw Edit

Fixes all your toubles

public text v1 · immutable
#1480822 ·published 2009-07-01 15:17 UTC
rendered paste body
Index: OpenMetaverse.Http/EventQueueClient.cs
===================================================================
--- OpenMetaverse.Http/EventQueueClient.cs	(revision 2945)
+++ OpenMetaverse.Http/EventQueueClient.cs	(working copy)
@@ -143,13 +143,19 @@
                 if (error is WebException && ((WebException)error).Response != null)
                     code = ((HttpWebResponse)((WebException)error).Response).StatusCode;
 
-                if (code == HttpStatusCode.NotFound || code == HttpStatusCode.Gone)
+                if ( code == HttpStatusCode.Gone)
                 {
                     Logger.Log.InfoFormat("Closing event queue at {0} due to missing caps URI", _Address);
 
                     _Running = false;
                     _Dead = true;
                 }
+                else if (code == HttpStatusCode.NotFound)
+                {
+                    Logger.Log.InfoFormat("event queue at {0} got {1} message {2}", _Address, code, error.Message);
+                    _Running = false;
+                    _Dead = true;
+                }
                 else if (code == HttpStatusCode.BadGateway)
                 {
                     // This is not good (server) protocol design, but it's normal.
Index: OpenMetaverse/AgentManager.cs
===================================================================
--- OpenMetaverse/AgentManager.cs	(revision 2945)
+++ OpenMetaverse/AgentManager.cs	(working copy)
@@ -1049,16 +1049,15 @@
                 if (sittingOn != 0)
                 {
                     Primitive parent;
-                    if (Client.Network.CurrentSim != null && Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(sittingOn, out parent))
+                    if (Client.Network.CurrentSim != null)
                     {
-                        return parent.Position + Vector3.Transform(relativePosition, Matrix4.CreateFromQuaternion(parent.Rotation));
+                        lock (Client.Network.CurrentSim.ObjectsPrimitives.Dictionary)
+                            if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(sittingOn, out parent))
+                                return parent.Position + Vector3.Transform(relativePosition, Matrix4.CreateFromQuaternion(parent.Rotation));
                     }
-                    else
-                    {
-                        Logger.Log("Currently sitting on object " + sittingOn + " which is not tracked, SimPosition will be inaccurate",
-                            Helpers.LogLevel.Warning, Client);
-                        return relativePosition;
-                    }
+                    Logger.Log("Currently sitting on object " + sittingOn + " which is not tracked, SimPosition will be inaccurate",
+                        Helpers.LogLevel.Warning, Client);
+                    return relativePosition;
                 }
                 else
                 {
@@ -1076,16 +1075,15 @@
                 if (sittingOn != 0)
                 {
                     Primitive parent;
-                    if (Client.Network.CurrentSim != null && Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(sittingOn, out parent))
+                    if (Client.Network.CurrentSim != null)
                     {
-                        return relativeRotation * parent.Rotation;
+                        lock (Client.Network.CurrentSim.ObjectsPrimitives.Dictionary)
+                            if (Client.Network.CurrentSim.ObjectsPrimitives.TryGetValue(sittingOn, out parent))
+                                return relativeRotation*parent.Rotation;
                     }
-                    else
-                    {
-                        Logger.Log("Currently sitting on object " + sittingOn + " which is not tracked, SimRotation will be inaccurate",
-                            Helpers.LogLevel.Warning, Client);
-                        return relativeRotation;
-                    }
+                    Logger.Log("Currently sitting on object " + sittingOn + " which is not tracked, SimRotation will be inaccurate",
+                        Helpers.LogLevel.Warning, Client);
+                    return relativeRotation;
                 }
                 else
                 {
Index: OpenMetaverse/AgentManagerMovement.cs
===================================================================
--- OpenMetaverse/AgentManagerMovement.cs	(revision 2945)
+++ OpenMetaverse/AgentManagerMovement.cs	(working copy)
@@ -671,7 +671,7 @@
                 else agentControls &= ~((uint)flag);
             }
 
-            private void ResetControlFlags()
+            public void ResetControlFlags()
             {
                 // Reset all of the flags except for persistent settings like
                 // away, fly, mouselook, and crouching
Index: OpenMetaverse/AppearanceManager.cs
===================================================================
--- OpenMetaverse/AppearanceManager.cs	(revision 2945)
+++ OpenMetaverse/AppearanceManager.cs	(working copy)
@@ -110,6 +110,10 @@
         /// <summary></summary>
         public event AppearanceUpdatedCallback OnAppearanceUpdated;
 
+        /// <summary>
+        /// Time that wearable events will wait (140 secs)
+        /// </summary>
+        public static int WEARABLE_TIMEOUT = 140 * 1000;
         /// <summary>Total number of wearables for each avatar</summary>
         public const int WEARABLE_COUNT = 13;
         /// <summary>Total number of baked textures on each avatar</summary>
@@ -240,7 +244,7 @@
         {
             WearableData wearable;
 
-            if (Wearables.TryGetValue(type, out wearable))
+            if (Wearables.Dictionary.TryGetValue(type, out wearable))
                 return wearable.Item.AssetUUID;
             else
                 return UUID.Zero;
@@ -414,9 +418,19 @@
             List<InventoryBase> attachments;
 
             if (!GetFolderWearables(wearOutfitParams.Param, out wearables, out attachments)) // get wearables in outfit folder
-                return; // TODO: this error condition should be passed back to the client somehow
+            // TODO: this error condition should be passed back to the client somehow}
+            {
+                Logger.Log(
+                    "GetFolderWearables did not find wearables " + 
+                    wearOutfitParams.Param + " " + wearables + " " +
+                    attachments, Helpers.LogLevel.Error, Client);
+                return;
+            } 
 
-            WearablesRequestEvent.WaitOne(); // wait for current wearables
+            if (!WearablesRequestEvent.WaitOne(WEARABLE_TIMEOUT*2)) // wait for current wearables 
+            {
+                Logger.Log("StartWearOutfitFolder timed out.", Helpers.LogLevel.Error, Client);
+            }
             ReplaceOutfitWearables(wearables); // replace current wearables with outfit folder
             UpdateAppearanceFromWearables(wearOutfitParams.Bake);
             AddAttachments(attachments, wearOutfitParams.RemoveExistingAttachments);
@@ -433,7 +447,7 @@
                 string[] path = (string[])_folder;
 
                 folder = Client.Inventory.FindObjectByPath(
-                    Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID, String.Join("/", path), 1000 * 20);
+                    Client.Inventory.Store.RootFolder.UUID, Client.Self.AgentID, String.Join("/", path), 1000 * 200);
 
                 if (folder == UUID.Zero)
                 {
@@ -455,22 +469,22 @@
                 {
                     if (ib is InventoryWearable)
                     {
-                        Logger.DebugLog("Adding wearable " + ib.Name, Client);
+                        Logger.Log("Adding wearable " + ib.Name, Client);
                         wearables.Add((InventoryWearable)ib);
                     }
                     else if (ib is InventoryAttachment)
                     {
-                        Logger.DebugLog("Adding attachment (attachment) " + ib.Name, Client);
+                        Logger.Log("Adding attachment (attachment) " + ib.Name, Client);
                         attachments.Add(ib);
                     }
                     else if (ib is InventoryObject)
                     {
-                        Logger.DebugLog("Adding attachment (object) " + ib.Name, Client);
+                        Logger.Log("Adding attachment (object) " + ib.Name, Client);
                         attachments.Add(ib);
                     }
                     else
                     {
-                        Logger.DebugLog("Ignoring inventory item " + ib.Name, Client);
+                        Logger.Log("Ignoring inventory item " + ib.Name, Client);
                     }
                 }
             }
@@ -669,13 +683,18 @@
             SendAgentIsNowWearing();
 
             // Wait for cached layer check to finish
-            if (bake) CachedResponseEvent.WaitOne();
+            if (bake) if (!CachedResponseEvent.WaitOne(WEARABLE_TIMEOUT))
+            {
+                Logger.Log("Giving up on CachedResponseEvent didnt complete (in time)", Client);
+                Assets.OnAssetUploaded -= uploadCallback;
+                return;
+            }
 
             // Unregister the image download and asset upload callbacks
             //Assets.OnImageReceived -= imageCallback;
             Assets.OnAssetUploaded -= uploadCallback;
 
-            Logger.DebugLog("CachedResponseEvent completed", Client);
+            Logger.Log("CachedResponseEvent completed", Client);
 
             #region Send Appearance
 
@@ -705,7 +724,7 @@
                                 }
                                 else if (face.TextureID != AgentTextures[i] && face.TextureID != AppearanceManager.DEFAULT_AVATAR_TEXTURE)
                                 {
-                                    Logger.DebugLog("*** FACE is " + ((TextureIndex)i).ToString() + " " + face.TextureID.ToString() + " Agent Texture is " + AgentTextures[i].ToString());
+                                    Logger.Log("*** FACE is " + ((TextureIndex)i).ToString() + " " + face.TextureID.ToString() + " Agent Texture is " + AgentTextures[i].ToString(),Client);
                                     match = false;
                                     //break;
                                 }
@@ -730,7 +749,7 @@
             SendAgentSetAppearance();
 
             // Wait for the ObjectUpdate to come in for our avatar after changing appearance
-            if (UpdateEvent.WaitOne(1000 * 60, false))
+            if (UpdateEvent.WaitOne(1000 * 130, false))
             {
                 if (OnAppearanceUpdated != null)
                 {
@@ -755,7 +774,7 @@
         /// </summary>
         public void RequestCachedBakes()
         {
-            Logger.DebugLog("RequestCachedBakes()", Client);
+            Logger.Log("RequestCachedBakes()", Client);
             
             List<KeyValuePair<int, UUID>> hashes = new List<KeyValuePair<int,UUID>>();
 
@@ -768,6 +787,7 @@
             for (int bakedIndex = 0; bakedIndex < BAKED_TEXTURE_COUNT; bakedIndex++)
             {
                 // Don't do a cache request for a skirt bake if we're not wearing a skirt
+                lock (Wearables.Dictionary)
                 if (bakedIndex == (int)BakeType.Skirt && 
                     (!Wearables.ContainsKey(WearableType.Skirt) || Wearables.Dictionary[WearableType.Skirt].Asset.AssetID == UUID.Zero))
                     continue;
@@ -804,7 +824,7 @@
                     cache.WearableData[i].TextureIndex = (byte)hashes[i].Key;
                     cache.WearableData[i].ID = hashes[i].Value;
 
-                    Logger.DebugLog("Checking cache for index " + cache.WearableData[i].TextureIndex +
+                    Logger.Log("Checking cache for index " + cache.WearableData[i].TextureIndex +
                         ", ID: " + cache.WearableData[i].ID, Client);
                 }
 
@@ -825,6 +845,7 @@
             for (int i = 0; i < BAKED_TEXTURE_COUNT; i++)
             {
                 // Don't bake skirt if not wearing one
+                lock (Wearables.Dictionary)
                 if (i == (int)BakeType.Skirt && (!Wearables.ContainsKey(WearableType.Skirt) || Wearables.Dictionary[WearableType.Skirt].Asset.AssetID == UUID.Zero))
                 {
                     continue;
@@ -884,11 +905,12 @@
 
         private void SendAgentSetAppearance()
         {
+            const bool UseExtraParams = false;
             AgentSetAppearancePacket set = new AgentSetAppearancePacket();
             set.AgentData.AgentID = Client.Self.AgentID;
             set.AgentData.SessionID = Client.Self.SessionID;
             set.AgentData.SerialNum = SetAppearanceSerialNum++;
-            set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[218];
+            set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[UseExtraParams ? 258 : 218];
 
             float AgentSizeVPHeight = 0.0f;
             float AgentSizeVPHeelHeight = 0.0f;
@@ -952,6 +974,19 @@
 
                         ++vpIndex;
                     }
+                    else
+                    {
+                        if (UseExtraParams)
+                        {
+                            if ((vp.Wearable != null) && vp.Wearable.Equals("shape"))
+                            {
+                                set.VisualParam[vpIndex] = new AgentSetAppearancePacket.VisualParamBlock();
+                                set.VisualParam[vpIndex].ParamValue = Utils.FloatToByte(vp.DefaultValue, vp.MinValue,
+                                                                                        vp.MaxValue);
+                                ++vpIndex;
+                            }
+                        }
+                    }
                 }
 
                 // Build the texture entry for our agent
@@ -979,7 +1014,7 @@
                             Primitive.TextureEntryFace face = te.CreateFace((uint)texture.Key);
                             face.TextureID = texture.Value;
 
-                            Logger.DebugLog("Setting agent texture " + ((TextureIndex)texture.Key).ToString() + " to " +
+                            Logger.Log("Setting agent texture " + ((TextureIndex)texture.Key).ToString() + " to " +
                                 texture.Value.ToString(), Client);
                         }
                     }
@@ -1031,7 +1066,7 @@
                 set.WearableData[bakedIndex] = new AgentSetAppearancePacket.WearableDataBlock();
                 set.WearableData[bakedIndex].TextureIndex = (byte)bakedIndex;
                 set.WearableData[bakedIndex].CacheID = hash;
-                Logger.DebugLog("Setting baked agent texture hash " + ((BakeType)bakedIndex).ToString() + " to " + hash, Client);
+                Logger.Log("Setting baked agent texture hash " + ((BakeType)bakedIndex).ToString() + " to " + hash, Client);
 
             }
 
@@ -1042,7 +1077,7 @@
 
         private void SendAgentIsNowWearing()
         {
-            Logger.DebugLog("SendAgentIsNowWearing()", Client);
+            Logger.Log("SendAgentIsNowWearing()", Client);
 
             AgentIsNowWearingPacket wearing = new AgentIsNowWearingPacket();
             wearing.AgentData.AgentID = Client.Self.AgentID;
@@ -1055,6 +1090,7 @@
                 wearing.WearableData[i] = new AgentIsNowWearingPacket.WearableDataBlock();
                 wearing.WearableData[i].WearableType = (byte)i;
 
+                lock (Wearables.Dictionary) 
                 if (Wearables.ContainsKey(type))
                     wearing.WearableData[i].ItemID = Wearables.Dictionary[type].Item.UUID;
                 else
@@ -1091,7 +1127,7 @@
             {
                 foreach (KeyValuePair<WearableType, WearableData> kvp in Wearables.Dictionary)
                 {
-                    Logger.DebugLog("Requesting asset for wearable item " + kvp.Value.Item.WearableType + " (" + kvp.Value.Item.AssetUUID + ")", Client);
+                    Logger.Log("Requesting asset for wearable item " + kvp.Value.Item.WearableType + " (" + kvp.Value.Item.AssetUUID + ")", Client);
                     AssetDownloads.Enqueue(new PendingAssetDownload(kvp.Value.Item.AssetUUID, kvp.Value.Item.AssetType));
                 }
             }
@@ -1144,7 +1180,7 @@
                     PendingUploads.Add(UUID.Combine(id, Client.Self.SecureSessionID), BakeTypeToAgentTextureIndex(bake.BakeType));
             }
 
-            Logger.DebugLog(String.Format("Bake {0} completed. Uploading asset {1}", bake.BakeType,
+            Logger.Log(String.Format("Bake {0} completed. Uploading asset {1}", bake.BakeType,
                 bake.BakedTexture.AssetID.ToString()), Client);
 
         }
@@ -1157,7 +1193,7 @@
             {
                 if (!ImageDownloads.ContainsKey(image))
                 {
-                    Logger.DebugLog("Downloading layer " + index.ToString(), Client);
+                    Logger.Log("Downloading layer " + index.ToString(), Client);
                     ImageDownloads.Add(image, index);
                 }
 
@@ -1184,7 +1220,7 @@
                         // Try and find this value in our collection of downloaded wearables
                         foreach (WearableData data in Wearables.Dictionary.Values)
                         {
-                            if (data.Asset.Params.ContainsKey(vp.ParamID))
+                            if (data.Asset!=null && data.Asset.Params.ContainsKey(vp.ParamID))
                             {
                                 paramValues.Add(vp.ParamID, data.Asset.Params[vp.ParamID]);
                                 found = true;
@@ -1293,7 +1329,7 @@
 
         private void AgentCachedTextureResponseHandler(Packet packet, Simulator simulator)
         {
-            Logger.DebugLog("AgentCachedTextureResponseHandler()", Client);
+            Logger.Log("AgentCachedTextureResponseHandler()", Client);
             
             AgentCachedTextureResponsePacket response = (AgentCachedTextureResponsePacket)packet;
 
@@ -1307,12 +1343,12 @@
                 {
                     //UUID hash=new UUID();
                     // For each missing element we need to bake our own texture
-                    Logger.DebugLog("Cache response, index: " + block.TextureIndex + ", ID: " +
+                    Logger.Log("Cache response, index: " + block.TextureIndex + ", ID: " +
                         block.TextureID.ToString(), Client);
 
                     // FIXME: Use this. Right now we treat baked images on other sims as if they were missing
                     string host = Utils.BytesToString(block.HostName);
-                    if (host.Length > 0) Logger.DebugLog("Cached bake exists on foreign host " + host, Client);
+                    if (host.Length > 0) Logger.Log("Cached bake exists on foreign host " + host, Client);
 
                     BakeType bakeType = (BakeType)block.TextureIndex;
                     
@@ -1332,7 +1368,7 @@
                        
                         if (!PendingBakes.ContainsKey(bakeType))
                         {
-                            Logger.DebugLog("Initializing " + bakeType.ToString() + " bake with " + imageCount + " textures", Client);
+                            Logger.Log("Initializing " + bakeType.ToString() + " bake with " + imageCount + " textures", Client);
     
                             Dictionary<int, float> paramValues=MakeParamValues();
                             // Build a dictionary of appearance parameter indices and values from the wearables
@@ -1393,7 +1429,7 @@
                         {
                             kvp.Value.Asset = (AssetWearable)asset;
 
-                            Logger.DebugLog("Downloaded wearable asset " + kvp.Value.Asset.Name, Client);
+                            Logger.Log("Downloaded wearable asset " + kvp.Value.Asset.Name, Client);
 
                             if (!kvp.Value.Asset.Decode())
                             {
@@ -1407,7 +1443,7 @@
                                 {
                                     if (texture.Value != DEFAULT_AVATAR_TEXTURE) // this texture is not meant to be displayed
                                     {
-                                        Logger.DebugLog("Setting " + texture.Key + " to " + texture.Value, Client);
+                                        Logger.Log("Setting " + texture.Key + " to " + texture.Value, Client);
                                         AgentTextures[(int)texture.Key] = texture.Value;
                                     }
                                 }
@@ -1470,7 +1506,7 @@
                             {
                                 if (state == TextureRequestState.Finished)
                                 {
-                                    Logger.DebugLog("Finished downloading texture for " + index.ToString(), Client);
+                                    Logger.Log("Finished downloading texture for " + index.ToString(), Client);
                                     OpenJPEG.DecodeToImage(assetTexture.AssetData, out assetTexture.Image);
                                     baked = PendingBakes[type].AddTexture(index, assetTexture, false);
                                 }
@@ -1492,12 +1528,12 @@
                             {
                                 // This is a failsafe catch, as the upload completed callback should normally 
                                 // be triggering the event
-                                Logger.DebugLog("No pending downloads or uploads detected in OnImageReceived", Client);
+                                Logger.Log("No pending downloads or uploads detected in OnImageReceived", Client);
                                 CachedResponseEvent.Set();
                             }
                             else
                             {
-                                Logger.DebugLog("Pending uploads: " + PendingUploads.Count + ", pending downloads: " +
+                                Logger.Log("Pending uploads: " + PendingUploads.Count + ", pending downloads: " +
                                     ImageDownloads.Count, Client);
                             }
 
@@ -1522,10 +1558,19 @@
                     {
                         // Setup the TextureEntry with the new baked upload
                         TextureIndex index = PendingUploads[upload.AssetID];
-                        AgentTextures[(int)index] = upload.AssetID;
+                        int u = (int) index;
+                        if (u < 0)
+                        {
+                            Logger.Log("Invalid Index, AgentTextures " + index.ToString() + " set to " +
+                                upload.AssetID.ToString(), Client);
+                        }
+                        else
+                        {
+                            AgentTextures[u] = upload.AssetID;
 
-                        Logger.DebugLog("Upload complete, AgentTextures " + index.ToString() + " set to " + 
-                            upload.AssetID.ToString(), Client);
+                            Logger.Log("Upload complete, AgentTextures " + index.ToString() + " set to " +
+                                       upload.AssetID.ToString(), Client);
+                        }
                     }
                     else
                     {
@@ -1535,12 +1580,12 @@
 
                     PendingUploads.Remove(upload.AssetID);
 
-                    Logger.DebugLog("Pending uploads: " + PendingUploads.Count + ", pending downloads: " +
+                    Logger.Log("Pending uploads: " + PendingUploads.Count + ", pending downloads: " +
                         ImageDownloads.Count, Client);
 
                     if (PendingUploads.Count == 0 && ImageDownloads.Count == 0)
                     {
-                        Logger.DebugLog("All pending image downloads and uploads complete", Client);
+                        Logger.Log("All pending image downloads and uploads complete", Client);
 
                         CachedResponseEvent.Set();
                     }
@@ -1548,7 +1593,7 @@
                 else
                 {
                     // TEMP
-                    Logger.DebugLog("Upload " + upload.AssetID.ToString() + " was not found in PendingUploads", Client);
+                    Logger.Log("Upload " + upload.AssetID.ToString() + " was not found in PendingUploads", Client);
                 }
             }
         }
Index: OpenMetaverse/Assets/AssetTypes/AssetWearable.cs
===================================================================
--- OpenMetaverse/Assets/AssetTypes/AssetWearable.cs	(revision 2945)
+++ OpenMetaverse/Assets/AssetTypes/AssetWearable.cs	(working copy)
@@ -118,22 +118,29 @@
                         if (fields[0] == "parameters")
                         {
                             int count = Int32.Parse(fields[1]) + stri;
-                            for (; stri < count; )
+                            for (; stri < count;)
                             {
                                 stri++;
+                                if (stri >= lines.Length) return false;
                                 line = lines[stri].Trim();
                                 fields = line.Split(' ');
 
-                                int id = Int32.Parse(fields[0]);
-                                if (fields[1] == ",")
-                                    fields[1] = "0";
-                                else
-                                    fields[1] = fields[1].Replace(',', '.');
+                                int id;
+                                if (int.TryParse(fields[0], out id))
+                                {
+                                    if (fields.Length > 1)
+                                    {
+                                        if (fields[1] == ",")
+                                            fields[1] = "0";
+                                        else
+                                            fields[1] = fields[1].Replace(',', '.');
 
-                                float weight = float.Parse(fields[1], System.Globalization.NumberStyles.Float,
-                                    Utils.EnUsCulture.NumberFormat);
+                                        float weight = float.Parse(fields[1], System.Globalization.NumberStyles.Float,
+                                                                   Utils.EnUsCulture.NumberFormat);
 
-                                Params[id] = weight;
+                                        Params[id] = weight;
+                                    }
+                                }
                             }
                         }
                         else if (fields[0] == "textures")
Index: OpenMetaverse/AvatarManager.cs
===================================================================
--- OpenMetaverse/AvatarManager.cs	(revision 2945)
+++ OpenMetaverse/AvatarManager.cs	(working copy)
@@ -492,7 +492,7 @@
                 InternalDictionary<UUID, int> signaledAnims = new InternalDictionary<UUID, int>();
                 
                 for(int i=0; i < anims.AnimationList.Length; i++)
-                    signaledAnims.Add(anims.AnimationList[i].AnimID, anims.AnimationList[i].AnimSequenceID);
+                    signaledAnims.Dictionary.Add(anims.AnimationList[i].AnimID, anims.AnimationList[i].AnimSequenceID);
 
                 try { OnAvatarAnimation(anims.Sender.ID, signaledAnims); }
                 catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
Index: OpenMetaverse/BVHDecoder.cs
===================================================================
--- OpenMetaverse/BVHDecoder.cs	(revision 2945)
+++ OpenMetaverse/BVHDecoder.cs	(working copy)
@@ -343,14 +343,148 @@
             }
             return m_keys;
         }
+
+        public bool Equals(BinBVHAnimationReader other)
+        {
+            if (ReferenceEquals(null, other)) return false;
+            if (ReferenceEquals(this, other)) return true;
+            return other.Loop.Equals(Loop) && other.OutPoint == OutPoint && other.InPoint == InPoint && other.Length == Length && other.HandPose == HandPose && other.JointCount == JointCount && Equals(other.joints, joints) && other.EaseInTime == EaseInTime && other.EaseOutTime == EaseOutTime && other.Priority == Priority && other.unknown1 == unknown1 && other.unknown0 == unknown0 && other.positionkeys == positionkeys && other.rotationkeys == rotationkeys;
+        }
+
+        /// <summary>
+        /// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
+        /// </summary>
+        /// <returns>
+        /// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
+        /// </returns>
+        /// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>. 
+        ///                 </param><exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.
+        ///                 </exception><filterpriority>2</filterpriority>
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (ReferenceEquals(this, obj)) return true;
+            if (obj.GetType() != typeof (BinBVHAnimationReader)) return false;
+            return Equals((BinBVHAnimationReader) obj);
+        }
+
+        /// <summary>
+        /// Serves as a hash function for a particular type. 
+        /// </summary>
+        /// <returns>
+        /// A hash code for the current <see cref="T:System.Object"/>.
+        /// </returns>
+        /// <filterpriority>2</filterpriority>
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int result = Loop.GetHashCode();
+                result = (result*397) ^ OutPoint.GetHashCode();
+                result = (result*397) ^ InPoint.GetHashCode();
+                result = (result*397) ^ Length.GetHashCode();
+                result = (result*397) ^ HandPose.GetHashCode();
+                result = (result*397) ^ JointCount.GetHashCode();
+                result = (result*397) ^ (joints != null ? joints.GetHashCode() : 0);
+                result = (result*397) ^ EaseInTime.GetHashCode();
+                result = (result*397) ^ EaseOutTime.GetHashCode();
+                result = (result*397) ^ Priority;
+                result = (result*397) ^ unknown1.GetHashCode();
+                result = (result*397) ^ unknown0.GetHashCode();
+                result = (result*397) ^ positionkeys;
+                result = (result*397) ^ rotationkeys;
+                return result;
+            }
+        }
+
+        public static bool Equals(binBVHJoint[] arr1, binBVHJoint[] arr2)
+        {
+            if (arr1.Length == arr2.Length)
+            {
+                for (int i = 0; i < arr1.Length; i++)
+                    if (!arr1[i].Equals(arr2[i]))
+                        return false;
+                /* not same*/
+                return true;
+            }
+            return false;
+        }
+
     }
 
+
     /// <summary>
     /// A Joint and it's associated meta data and keyframes
     /// </summary>
     public struct binBVHJoint
     {
+        public static bool Equals(binBVHJointKey[] arr1, binBVHJointKey[] arr2)
+        {
+            if (arr1.Length == arr2.Length)
+            {
+                for (int i = 0; i < arr1.Length; i++)
+                    if (!Equals(arr1[i], arr2[i]))
+                        return false;
+                /* not same*/
+                return true;
+            }
+            return false;
+        }
+        public static bool Equals(binBVHJointKey arr1, binBVHJointKey arr2)
+        {
+            return (arr1.time == arr2.time && arr1.key_element == arr2.key_element);
+        }
+
+        public bool Equals(binBVHJoint other)
+        {
+            return other.Priority == Priority && Equals(other.rotationkeys, rotationkeys) && Equals(other.Name, Name) && Equals(other.positionkeys, positionkeys);
+        }
+
         /// <summary>
+        /// Indicates whether this instance and a specified object are equal.
+        /// </summary>
+        /// <returns>
+        /// true if <paramref name="obj"/> and this instance are the same type and represent the same value; otherwise, false.
+        /// </returns>
+        /// <param name="obj">Another object to compare to. 
+        ///                 </param><filterpriority>2</filterpriority>
+        public override bool Equals(object obj)
+        {
+            if (ReferenceEquals(null, obj)) return false;
+            if (obj.GetType() != typeof (binBVHJoint)) return false;
+            return Equals((binBVHJoint) obj);
+        }
+
+        /// <summary>
+        /// Returns the hash code for this instance.
+        /// </summary>
+        /// <returns>
+        /// A 32-bit signed integer that is the hash code for this instance.
+        /// </returns>
+        /// <filterpriority>2</filterpriority>
+        public override int GetHashCode()
+        {
+            unchecked
+            {
+                int result = Priority;
+                result = (result*397) ^ (rotationkeys != null ? rotationkeys.GetHashCode() : 0);
+                result = (result*397) ^ (Name != null ? Name.GetHashCode() : 0);
+                result = (result*397) ^ (positionkeys != null ? positionkeys.GetHashCode() : 0);
+                return result;
+            }
+        }
+
+        public static bool operator ==(binBVHJoint left, binBVHJoint right)
+        {
+            return left.Equals(right);
+        }
+
+        public static bool operator !=(binBVHJoint left, binBVHJoint right)
+        {
+            return !left.Equals(right);
+        }
+
+        /// <summary>
         /// Name of the Joint.  Matches the avatar_skeleton.xml in client distros
         /// </summary>
         public string Name;
Index: OpenMetaverse/EventDictionary.cs
===================================================================
--- OpenMetaverse/EventDictionary.cs	(revision 2945)
+++ OpenMetaverse/EventDictionary.cs	(working copy)
@@ -34,11 +34,14 @@
 
 namespace OpenMetaverse
 {
+    public delegate bool SkipEventCallback(PacketType type, Simulator sim);
     /// <summary>
     /// Registers, unregisters, and fires events generated by incoming packets
     /// </summary>
     public class PacketEventDictionary
     {
+        public event SkipEventCallback SkipEvent;
+
         /// <summary>
         /// Object that is passed to worker threads in the ThreadPool for
         /// firing packet callbacks
@@ -112,6 +115,7 @@
         {
             NetworkManager.PacketCallback callback;
 
+            if (SkipEvent != null && SkipEvent(packetType, simulator)) return;
             // Default handler first, if one exists
             if (_EventTable.TryGetValue(PacketType.Default, out callback))
             {
@@ -135,7 +139,7 @@
             
             if (packetType != PacketType.Default && packetType != PacketType.PacketAck)
             {
-                Logger.DebugLog("No handler registered for packet event " + packetType, Client);
+                Logger.Log("No handler registered for packet event " + packetType, Client);
             }
         }
 
@@ -147,6 +151,7 @@
         /// <param name="simulator">Simulator this packet was received from</param>
         internal void BeginRaiseEvent(PacketType packetType, Packet packet, Simulator simulator)
         {
+            if (SkipEvent != null && SkipEvent(packetType, simulator)) return;
             NetworkManager.PacketCallback callback;
             PacketCallbackWrapper wrapper;
 
@@ -177,7 +182,7 @@
 
             if (packetType != PacketType.Default && packetType != PacketType.PacketAck)
             {
-                Logger.DebugLog("No handler registered for packet event " + packetType, Client);
+                Logger.Log("No handler registered for packet event " + packetType, Client);
             }
         }
 
Index: OpenMetaverse/GroupManager.cs
===================================================================
--- OpenMetaverse/GroupManager.cs	(revision 2945)
+++ OpenMetaverse/GroupManager.cs	(working copy)
@@ -488,35 +488,37 @@
         /// </summary>
         /// <param name="requestID"><seealso cref="UUID"/> returned by RequestGroupMembers</param>
         /// <param name="groupID"><seealso cref="UUID"/> of the group</param>
+        /// <param name="memberCount">Total number of members in the group</param>
         /// <param name="members">A dictionary containing the members of a group
         /// where key is member <seealso cref="UUID"/> and value is <seealso cref="GroupMember"/> struct</param>
-        public delegate void GroupMembersCallback(UUID requestID, UUID groupID, Dictionary<UUID, GroupMember> members);
+        public delegate void GroupMembersCallback(UUID requestID, UUID groupID, int memberCount, Dictionary<UUID, GroupMember> members);
 
         /// <summary>
         /// Callback for retrieving group roles
         /// </summary>
         /// <param name="requestID"><seealso cref="UUID"/> of the request returned from RequestGroupRoles</param>
         /// <param name="groupID"><seealso cref="UUID"/> of the group</param>
+        /// <param name="roleCount">Total number of roles defined in the group</param>
         /// <param name="roles">A dictionary containing role <seealso cref="UUID"/>s as the key
         /// and <seealso cref="GroupRole"/> structs as values</param>
-        public delegate void GroupRolesCallback(UUID requestID, UUID groupID, Dictionary<UUID, GroupRole> roles);
+        public delegate void GroupRolesCallback(UUID requestID, UUID groupID, int roleCount, Dictionary<UUID, GroupRole> roles);
 
         /// <summary>
         /// Callback for a pairing of roles to members
         /// </summary>
         /// <param name="requestID"><seealso cref="UUID"/> of the request returned from RequestGroupRolesMembers</param>
         /// <param name="groupID"><seealso cref="UUID"/> of the group</param>
+        /// <param name="totalPairs">Total number of role/member mappings</param>
         /// <param name="rolesMembers">List containing role/member pairs</param>
-        public delegate void GroupRolesMembersCallback(UUID requestID, UUID groupID, List<KeyValuePair<UUID, UUID>> rolesMembers);
+        public delegate void GroupRolesMembersCallback(UUID requestID, UUID groupID, uint totalPairs, List<KeyValuePair<UUID, UUID>> rolesMembers);
 
         /// <summary>
         /// Callback for the title list of a group
         /// </summary>
-        /// <param name="requestID"><seealso cref="UUID"/> of the request returned from RequestGroupTitles</param>
         /// <param name="groupID">Group <seealso cref="UUID"/></param>
         /// <param name="titles">A dictionary containing the titles of a group
         /// where the Key is the role <seealso cref="UUID"/>, and the values are the title details</param>
-        public delegate void GroupTitlesCallback(UUID requestID, UUID groupID, Dictionary<UUID, GroupTitle> titles);
+        public delegate void GroupTitlesCallback(UUID groupID, Dictionary<UUID, GroupTitle> titles);
 
         /// <summary>
         /// Callback fired when group account summary information is received
@@ -1207,7 +1209,7 @@
                     group.Contribution = msg.GroupDataBlock[i].Contribution;
                     group.AcceptNotices = msg.GroupDataBlock[i].AcceptNotices;
                     group.Powers = msg.GroupDataBlock[i].GroupPowers;
-                    group.ListInProfile = msg.NewGroupDataBlock[i].ListInProfile;
+                   // group.ListInProfile = msg.NewGroupDataBlock[i].ListInProfile;
 
                     currentGroups.Add(group.ID, group);
 
@@ -1280,7 +1282,7 @@
                     groupTitleCache[block.RoleID] = groupTitle;
                 }
 
-                try { OnGroupTitles(titles.AgentData.RequestID, titles.AgentData.GroupID, groupTitleCache); }
+                try { OnGroupTitles(titles.AgentData.GroupID, groupTitleCache); }
                 catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
             }
         }
@@ -1326,9 +1328,9 @@
                 }
             }
 
-            if (OnGroupMembers != null && groupMemberCache != null && groupMemberCache.Count >= members.GroupData.MemberCount)
+            if (OnGroupMembers != null && groupMemberCache != null)
             {
-                try { OnGroupMembers(members.GroupData.RequestID, members.GroupData.GroupID, groupMemberCache); }
+                try { OnGroupMembers(members.GroupData.RequestID, members.GroupData.GroupID, members.GroupData.MemberCount, groupMemberCache); }
                 catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
             }
         }
@@ -1376,9 +1378,9 @@
                 }
             }
 
-            if (OnGroupRoles != null && groupRoleCache != null && groupRoleCache.Count >= roles.GroupData.RoleCount)
+            if (OnGroupRoles != null && groupRoleCache != null)
             {
-                try { OnGroupRoles(roles.GroupData.RequestID, roles.GroupData.GroupID, groupRoleCache); }
+                try { OnGroupRoles(roles.GroupData.RequestID, roles.GroupData.GroupID, roles.GroupData.RoleCount, groupRoleCache); }
                 catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
             }
         }
@@ -1425,9 +1427,9 @@
                 Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e);
             }
 
-            if (OnGroupRolesMembers != null && groupRoleMemberCache != null && groupRoleMemberCache.Count >= members.AgentData.TotalPairs)
+            if (OnGroupRolesMembers != null && groupRoleMemberCache != null)
             {
-                try { OnGroupRolesMembers(members.AgentData.RequestID, members.AgentData.GroupID, groupRoleMemberCache); }
+                try { OnGroupRolesMembers(members.AgentData.RequestID, members.AgentData.GroupID, members.AgentData.TotalPairs, groupRoleMemberCache); }
                 catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
             }
         }
Index: OpenMetaverse/Imaging/BakeLayer.cs
===================================================================
--- OpenMetaverse/Imaging/BakeLayer.cs	(revision 2945)
+++ OpenMetaverse/Imaging/BakeLayer.cs	(working copy)
@@ -125,7 +125,8 @@
                     }
                 }
 
-                _textures.Add(index, texture);
+                //_textures.Add(index, texture);
+                _textures[index] = texture;
                 Logger.DebugLog(String.Format("Added texture {0} (ID: {1}) to bake {2}", index, texture.AssetID, _bakeType), _client);
             }
 
Index: OpenMetaverse/InternalDictionary.cs
===================================================================
--- OpenMetaverse/InternalDictionary.cs	(revision 2945)
+++ OpenMetaverse/InternalDictionary.cs	(working copy)
@@ -26,6 +26,8 @@
 
 using System;
 using System.Collections.Generic;
+using System.Reflection;
+using System.Threading;
 
 namespace OpenMetaverse
 {
@@ -43,7 +45,7 @@
         /// <summary>Internal dictionary that this class wraps around. Do not
         /// modify or enumerate the contents of this dictionary without locking
         /// on this member</summary>
-        internal Dictionary<TKey, TValue> Dictionary;
+        public Dictionary<TKey, TValue> Dictionary;
 
         /// <summary>
         /// Gets the number of Key/Value pairs contained in the <seealso cref="T:InternalDictionary"/>
@@ -125,6 +127,7 @@
         /// </example>
         public bool TryGetValue(TKey key, out TValue value)
         {
+            ConfirmOuterModifierIsLocking();
             lock (Dictionary)
             {
                 return Dictionary.TryGetValue(key, out value);
@@ -274,6 +277,7 @@
         /// <returns><see langword="true"/> if found, <see langword="false"/> otherwise</returns>
         public bool ContainsKey(TKey key)
         {
+            ConfirmOuterModifierIsLocking();
             return Dictionary.ContainsKey(key);
         }
 
@@ -282,6 +286,7 @@
         /// <returns><see langword="true"/> if found, <see langword="false"/> otherwise</returns>
         public bool ContainsValue(TValue value)
         {
+            ConfirmOuterModifierIsLocking();
             return Dictionary.ContainsValue(value);
         }
 
@@ -293,6 +298,7 @@
         /// <param name="value">The value</param>
         internal void Add(TKey key, TValue value)
         {
+            ConfirmOuterModifierIsLocking();
             lock (Dictionary)
                 Dictionary.Add(key, value);
         }
@@ -304,6 +310,7 @@
         /// <returns><see langword="true"/> if successful, <see langword="false"/> otherwise</returns>
         internal bool Remove(TKey key)
         {
+            ConfirmOuterModifierIsLocking();
             lock (Dictionary)
                 return Dictionary.Remove(key);
         }
@@ -317,14 +324,44 @@
         {
             get
             {
+                ConfirmOuterModifierIsLocking();
                 lock (Dictionary)
                     return Dictionary[key];
             }
             internal set
             {
+                ConfirmOuterModifierIsLocking();
                 lock (Dictionary)
                     Dictionary[key] = value;
             }
         }
+        private void ConfirmOuterModifierIsLocking()
+        {
+            System.Diagnostics.StackTrace st = new System.Diagnostics.StackTrace(2);
+            System.Diagnostics.StackFrame sf = st.GetFrame(0);
+            MethodBase mb = sf.GetMethod();
+            if (!mb.DeclaringType.Namespace.StartsWith("OpenMetaverse")) return;
+
+            bool badGuy = false;
+            Thread t = new Thread(() =>
+                                      {
+                                          if (!Monitor.TryEnter(Dictionary))
+                                          {
+                                              //all is good!
+                                          }
+                                          else
+                                          {
+                                              Monitor.Exit(Dictionary);
+                                              //throw badGuy;
+                                              badGuy = true;
+                                          }
+                                      });
+            t.Start();
+            t.Join();
+            if (!badGuy) return;
+            throw new Exception(string.Format("{0}.{1} forgot to lock!", mb.DeclaringType.FullName, mb.Name));
+        }
+
+
     }
 }
Index: OpenMetaverse/Logger.cs
===================================================================
--- OpenMetaverse/Logger.cs	(revision 2945)
+++ OpenMetaverse/Logger.cs	(working copy)
@@ -82,6 +82,10 @@
             Log(message, level, null, null);
         }
 
+        public static void Log(object message, GridClient client)
+        {
+            Log(message, Helpers.LogLevel.Info,  client);
+        }
         /// <summary>
         /// Send a log message to the logging engine
         /// </summary>
@@ -183,5 +187,10 @@
                 LogInstance.Debug(message);
             }
         }
+
+        public static void Log(string message)
+        {
+            Log(message, Helpers.LogLevel.Info);
+        }
     }
 }
Index: OpenMetaverse/Login.cs
===================================================================
--- OpenMetaverse/Login.cs	(revision 2945)
+++ OpenMetaverse/Login.cs	(working copy)
@@ -1083,7 +1083,7 @@
             InternalStatusCode = status;
             InternalLoginMessage = message;
 
-            Logger.DebugLog("Login status: " + status.ToString() + ": " + message, Client);
+            Logger.Log("Login status: " + status.ToString() + ": " + message, Client);
 
             // If we reached a login resolution trigger the event
             if (status == LoginStatus.Success || status == LoginStatus.Failed)
Index: OpenMetaverse/Messages/LindenMessages.cs
===================================================================
--- OpenMetaverse/Messages/LindenMessages.cs	(revision 2945)
+++ OpenMetaverse/Messages/LindenMessages.cs	(working copy)
@@ -1167,7 +1167,7 @@
             AgentID = agentMap["AgentID"].AsUUID();
 
             OSDArray groupArray = (OSDArray)map["GroupData"];
-            OSDArray newGroupArray = (OSDArray)map["NewGroupData"];
+            //OSDArray newGroupArray = (OSDArray)map["NewGroupData"];
 
             GroupDataBlock = new GroupData[groupArray.Count];
 
@@ -1187,15 +1187,15 @@
                 GroupDataBlock[i] = groupData;
             }
 
-            NewGroupDataBlock = new NewGroupData[newGroupArray.Count];
+            //NewGroupDataBlock = new NewGroupData[newGroupArray.Count];
 
-            for (int i = 0; i < newGroupArray.Count; i++)
-            {
-                OSDMap newGroupMap = (OSDMap)newGroupArray[i];
-                NewGroupData newGroupData = new NewGroupData();
-                newGroupData.ListInProfile = newGroupMap["ListInProfile"].AsBoolean();
-                NewGroupDataBlock[i] = newGroupData;
-            }
+            //for (int i = 0; i < newGroupArray.Count; i++)
+            //{
+            //    OSDMap newGroupMap = (OSDMap)newGroupArray[i];
+            //    NewGroupData newGroupData = new NewGroupData();
+            //    newGroupData.ListInProfile = newGroupMap["ListInProfile"].AsBoolean();
+            //    NewGroupDataBlock[i] = newGroupData;
+            //}
         }
     }
 
Index: OpenMetaverse/NetworkManager.cs
===================================================================
--- OpenMetaverse/NetworkManager.cs	(revision 2945)
+++ OpenMetaverse/NetworkManager.cs	(working copy)
@@ -64,6 +64,8 @@
             ClientInitiated,
             /// <summary>The server notified us that it is disconnecting</summary>
             ServerInitiated,
+            /// <summary>The server notified us that it is disconnecting</summary>
+            TeleportInitiated,
             /// <summary>Either a socket was closed or network traffic timed out</summary>
             NetworkTimeout,
             /// <summary>The last active simulator shut down</summary>
@@ -267,7 +269,7 @@
         /// <summary>Handlers for incoming capability events</summary>
         internal CapsEventDictionary CapsEvents;
         /// <summary>Handlers for incoming packets</summary>
-        internal PacketEventDictionary PacketEvents;
+        public PacketEventDictionary PacketEvents;
         /// <summary>Incoming packets that are awaiting handling</summary>
         internal BlockingQueue<IncomingPacket> PacketInbox = new BlockingQueue<IncomingPacket>(Settings.PACKET_INBOX_SIZE);
         /// <summary>Outgoing packets that are awaiting handling</summary>
@@ -292,6 +294,7 @@
 
             // Register internal CAPS callbacks
             RegisterEventCallback("EnableSimulator", new Caps.EventQueueCallback(EnableSimulatorHandler));
+            RegisterEventCallback("DisableSimulator", new Caps.EventQueueCallback(DisableSimulatorCapsHandler));
 
             // Register the internal callbacks
             RegisterCallback(PacketType.RegionHandshake, new PacketCallback(RegionHandshakeHandler));
@@ -414,7 +417,7 @@
             if (simulator == null)
             {
                 // We're not tracking this sim, create a new Simulator object
-                simulator = new Simulator(Client, endPoint, handle);
+                simulator = Simulator.Create(Client, endPoint, handle);
 
                 // Immediately add this simulator to the list of current sims. It will be removed if the
                 // connection fails
@@ -482,9 +485,14 @@
                 }
                 else
                 {
+                    //if (OnSimDisconnected != null)
+                    //{
+                    //    try { OnSimDisconnected(simulator,DisconnectType.NetworkTimeout); }
+                    //    catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
+                    //}
                     // Connection failed, remove this simulator from our list and destroy it
-                    lock (Simulators) Simulators.Remove(simulator);
-                    return null;
+                    // lock (Simulators) Simulators.Remove(simulator);
+                    return simulator;
                 }
             }
             else if (setDefault)
@@ -564,22 +572,23 @@
         /// </summary>
         /// <param name="sim"></param>
         /// <param name="sendCloseCircuit"></param>
-        public void DisconnectSim(Simulator sim, bool sendCloseCircuit)
+        public void DisconnectSim(Simulator sim, bool sendCloseCircuit,DisconnectType disconnectType)
         {
             if (sim != null)
             {
-                sim.Disconnect(sendCloseCircuit);
+                sim.Disconnect(sendCloseCircuit, disconnectType);
 
                 // Fire the SimDisconnected event if a handler is registered
                 if (OnSimDisconnected != null)
                 {
-                    try { OnSimDisconnected(sim, DisconnectType.NetworkTimeout); }
+                    try { OnSimDisconnected(sim, disconnectType); }
                     catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
                 }
 
-                lock (Simulators) Simulators.Remove(sim);
+                //if (disconnectType == DisconnectType.ClientInitiated)
+                    lock (Simulators) Simulators.Remove(sim);
 
-                if (Simulators.Count == 0) Shutdown(DisconnectType.SimShutdown);
+                if (Simulators.Count == 0) Shutdown(disconnectType/* | DisconnectType.SimShutdown*/);
             }
             else
             {
@@ -623,7 +632,7 @@
             if (CurrentSim != null)
             {
                 // Kill the connection to the curent simulator
-                CurrentSim.Disconnect(sendCloseCircuit);
+                CurrentSim.Disconnect(sendCloseCircuit,type);
 
                 // Fire the SimDisconnected event if a handler is registered
                 if (OnSimDisconnected != null)
@@ -780,6 +789,7 @@
                 Timer timer = DisconnectTimer;
                 if (timer != null)
                     timer.Dispose();
+				timer = null;
                 connected = false;
             }
             else if (CurrentSim.DisconnectCandidate)
@@ -1034,11 +1044,18 @@
             }
         }
 
+        private void DisableSimulatorCapsHandler(string capsKey, IMessage message, Simulator simulator)
+        {
+            if (!Client.Settings.MULTIPLE_SIMS) return;
+            Logger.Log("Received a CAPS Based DisableSimulator packet from " + simulator + ", shutting it down", Client);
+            DisconnectSim(simulator, false, DisconnectType.ServerInitiated);
+        }
+
         private void DisableSimulatorHandler(Packet packet, Simulator simulator)
         {
             Logger.DebugLog("Received a DisableSimulator packet from " + simulator + ", shutting it down", Client);
 
-            DisconnectSim(simulator, false);
+            DisconnectSim(simulator, false, DisconnectType.ServerInitiated);
         }
 
         private void KickUserHandler(Packet packet, Simulator simulator)
Index: OpenMetaverse/ObjectManager.cs
===================================================================
--- OpenMetaverse/ObjectManager.cs	(revision 2945)
+++ OpenMetaverse/ObjectManager.cs	(working copy)
@@ -2863,6 +2863,10 @@
         protected void InterpolationTimer_Elapsed(object obj)
         {
             int elapsed = 0;
+            if (!Client.Settings.USE_INTERPOLATION_TIMER)
+            {         
+                return;
+            }
 
             if (Client.Network.Connected)
             {
Index: OpenMetaverse/ParcelManager.cs
===================================================================
--- OpenMetaverse/ParcelManager.cs	(revision 2945)
+++ OpenMetaverse/ParcelManager.cs	(working copy)
@@ -411,6 +411,73 @@
 
     #endregion Structs
 
+    /// <summary>
+    /// Parcel Media Command used in ParcelMediaCommandMessage
+    /// </summary>
+    public enum ParcelMediaCommand: uint
+    {
+        /// <summary>
+        /// 0  -  stop the media stream and go back to the first frame 
+        /// </summary>
+        Stop = 0,
+        /// <summary>
+        /// 1  -  pause the media stream (stop playing but stay on current frame) 
+        /// </summary>
+        Pause,
+        /// <summary>
+        /// 2  -  start the current media stream playing and stop when the end is reached
+        /// </summary>
+        Play,
+        /// <summary>
+        /// 3  -  start the current media stream playing, 
+        /// loop to the beginning when the end is reached and continue to play
+        /// </summary>
+        Loop,
+        /// <summary>
+        /// 4 - [key texture]  specifies the texture to replace with video 
+        /// Note: If passing the key of a texture, it must be explicitly typecast as a key, 
+        /// not just passed within double quotes.
+        /// </summary>
+        Texture,
+        /// <summary>
+        /// 5 - [string url]  specifies the movie URL (254 characters)
+        /// </summary>
+        URL,
+        /// <summary>
+        /// 6 - [float time]  specifies the time index at which to begin playing
+        /// </summary>
+        Time,
+        /// <summary>
+        /// 7 - [key agent]  specifies a single agent to apply the media command to
+        /// </summary>
+        Agent,
+        /// <summary>
+        /// 8  -  unloads the stream. While the stop command sets the texture to the first frame of the movie, 
+        /// unload resets it to the real texture that the movie was replacing.
+        /// </summary>
+        Unload,
+        /// <summary>
+        /// 9 - [integer enable]  
+        /// turns on/off the auto align feature, similar to the auto align checkbox in the parcel media properties 
+        /// (NOT to be confused with the "align" function in the textures view of the editor!) Takes TRUE or FALSE as parameter.
+        /// </summary>
+        AutoAlign,
+        /// <summary>
+        /// 10 - [string]  Allows a Web page or image to be placed on a prim (1.19.1 RC0 and later only). 
+        /// Use "text/html" for HTML.  
+        /// </summary>
+        Type,
+        /// <summary>
+        /// 11 - [integer x, integer y]  Resizes a Web page to fit on x, y pixels (1.19.1 RC0 and later only). 
+        /// Note: this might still not be working  
+        /// </summary>
+        Size,
+        /// <summary>
+        /// 12 - [string]  Sets a description for the media being displayed (1.19.1 RC0 and later only).  
+        /// </summary>
+        Desc
+    }
+
     #region Parcel Class
 
     /// <summary>
@@ -839,6 +906,16 @@
         /// <param name="media">A struct containing updated media information</param>
         public delegate void ParcelMediaUpdateReplyCallback(Simulator simulator, ParcelMedia media);
 
+        /// <summary>
+        /// Fired when a ParcelMediaCommandMessage packet is received, this occurs when the media on the parcel sends a specialized event
+        /// </summary>
+        /// <param name="simulator">A reference to the simulator object</param>
+        /// <param name="sequence">The sequence the parcel command belongs to</param>
+        /// <param name="flags">Updated parcel information</param>
+        /// <param name="command">The command executed on the Parcel</param>
+        /// <param name="time">The time operand for some parcel commands</param>
+        public delegate void ParcelMediaCommandMessageCallback(Simulator simulator, uint sequence, ParcelFlags flags, ParcelMediaCommand command, float time);
+
         #endregion Delegates
 
         #region Events
@@ -867,6 +944,10 @@
         /// <summary>Fired when the Agent receives a <seealso cref="Packets.ParcelMediaUpdatePacket"/> which
         /// occurs when the parcel media information is changed for the current parcel the Agent is over</summary>
         public event ParcelMediaUpdateReplyCallback OnParcelMediaUpdate;
+        /// <summary>Fired when the Agent receives a <seealso cref="Packets.ParcelMediaCommandMessage"/> which
+        /// occurs when the parcel media has a specialized event like starting and looping command on the media is raised
+        ///  for the current parcel the Agent is over</summary>
+        public event ParcelMediaCommandMessageCallback OnParcelMediaCommandMessage;
 
         #endregion Events
 
@@ -891,6 +972,7 @@
             Client.Network.RegisterCallback(PacketType.ParcelAccessListReply, new NetworkManager.PacketCallback(ParcelAccessListReplyHandler));
             Client.Network.RegisterCallback(PacketType.ForceObjectSelect, new NetworkManager.PacketCallback(SelectParcelObjectsReplyHandler));
             Client.Network.RegisterCallback(PacketType.ParcelMediaUpdate, new NetworkManager.PacketCallback(ParcelMediaUpdateHandler));
+            Client.Network.RegisterCallback(PacketType.ParcelMediaCommandMessage, new NetworkManager.PacketCallback(ParcelMediaCommandMessageHandler));
             Client.Network.RegisterCallback(PacketType.ParcelOverlay, new NetworkManager.PacketCallback(ParcelOverlayHandler));
         }
 
@@ -1792,6 +1874,17 @@
             }
         }
 
+        private void ParcelMediaCommandMessageHandler(Packet packet, Simulator simulator)
+        {
+            if (OnParcelMediaCommandMessage != null)
+            {
+                ParcelMediaCommandMessagePacket pmc = (ParcelMediaCommandMessagePacket)packet;
+                ParcelMediaCommandMessagePacket.CommandBlockBlock block = pmc.CommandBlock;
+                try { OnParcelMediaCommandMessage(simulator, pmc.Header.Sequence, (ParcelFlags)block.Flags, (ParcelMediaCommand)block.Command, block.Time); }
+                catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, Client, e); }
+            }
+        }
+
         private void ParcelOverlayHandler(Packet packet, Simulator simulator)
         {
             const int OVERLAY_COUNT = 4;
Index: OpenMetaverse/Simulator.cs
===================================================================
--- OpenMetaverse/Simulator.cs	(revision 2945)
+++ OpenMetaverse/Simulator.cs	(working copy)
@@ -448,18 +448,46 @@
         /// <param name="client">Reference to the GridClient object</param>
         /// <param name="address">IPEndPoint of the simulator</param>
         /// <param name="handle">handle of the simulator</param>
-        public Simulator(GridClient client, IPEndPoint address, ulong handle)
+        private Simulator(GridClient client, IPEndPoint address, ulong handle)
             : base(address)
         {
             Client = client;
 
             Handle = handle;
+            ReInit();
+        }
+
+        private void ReInit()
+        {            
             Network = Client.Network;
             PacketArchive = new IncomingPacketIDCollection(Settings.PACKET_ARCHIVE_SIZE);
             InBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE);
             OutBytes = new Queue<long>(Client.Settings.STATS_QUEUE_SIZE);
         }
 
+
+        readonly static Dictionary<GridClient, Dictionary<ulong, Simulator>> savedSims = new Dictionary<GridClient, Dictionary<ulong, Simulator>>();
+        public static Simulator Create(GridClient client, IPEndPoint point, ulong handle)
+        {
+            Dictionary<ulong, Simulator> dict;
+            lock (savedSims) if (!savedSims.TryGetValue(client, out dict))
+            {
+                dict = new Dictionary<ulong, Simulator>();
+                savedSims.Add(client, dict);
+            }
+            Simulator sim;
+            lock (dict) if (!dict.TryGetValue(handle, out sim))
+            {
+                sim = new Simulator(client, point, handle); 
+                dict.Add(handle,sim);
+            } else
+            {
+                sim.ReInit();
+            }           
+            return sim;
+
+        }   
+
         /// <summary>
         /// Called when this Simulator object is being destroyed
         /// </summary>
@@ -529,7 +557,7 @@
                 if (Client.Settings.SEND_AGENT_UPDATES)
                     Client.Self.Movement.SendUpdate(true, this);
 
-                if (!ConnectedEvent.WaitOne(Client.Settings.SIMULATOR_TIMEOUT, false))
+                if (!ConnectedEvent.WaitOne(Client.Settings.LOGIN_TIMEOUT, false))
                 {
                     Logger.Log("Giving up on waiting for RegionHandshake for " + this.ToString(),
                         Helpers.LogLevel.Warning, Client);
@@ -571,22 +599,36 @@
         /// Disconnect from this simulator
         /// </summary>
         public void Disconnect(bool sendCloseCircuit)
+        {          
+            Disconnect(sendCloseCircuit,NetworkManager.DisconnectType.ClientInitiated);   
+        }
+        public void Disconnect(bool sendCloseCircuit, NetworkManager.DisconnectType disconnectType)
         {
+            //lets wait until the server makes a desision
+            if (disconnectType == NetworkManager.DisconnectType.TeleportInitiated
+                || disconnectType == NetworkManager.DisconnectType.NetworkTimeout) return;
             if (connected)
             {
                 connected = false;
 
+                if (disconnectType != NetworkManager.DisconnectType.ServerInitiated)
+                {
+
                 // Destroy the timers
                 if (AckTimer != null) AckTimer.Dispose();
+                AckTimer = null;
                 if (StatsTimer != null) StatsTimer.Dispose();
+                StatsTimer = null;
                 if (PingTimer != null) PingTimer.Dispose();
+                PingTimer = null;
 
                 // Kill the current CAPS system
-                if (Caps != null)
+                if (Caps != null )
                 {
                     Caps.Disconnect(true);
                     Caps = null;
                 }
+                }
 
                 if (sendCloseCircuit)
                 {
Index: OpenMetaverse/TexturePipeline.cs
===================================================================
--- OpenMetaverse/TexturePipeline.cs	(revision 2945)
+++ OpenMetaverse/TexturePipeline.cs	(working copy)
@@ -130,13 +130,13 @@
         /// <summary>An array of worker slots which shows the availablity status of the slot</summary>
         private readonly int[] threadpoolSlots;
         /// <summary>The primary thread which manages the requests.</summary>
-        private readonly Thread downloadMaster;
+        private Thread downloadMaster;
         /// <summary>true if the TexturePipeline is currently running</summary>
         bool _Running;
         /// <summary>A synchronization object used by the primary thread</summary>
-        private object lockerObject = new object();
+        readonly private object lockerObject = new object();
         /// <summary>A refresh timer used to increase the priority of stalled requests</summary>
-        private readonly System.Timers.Timer RefreshDownloadsTimer =
+        private System.Timers.Timer RefreshDownloadsTimer =
             new System.Timers.Timer(Settings.PIPELINE_REFRESH_INTERVAL);
 
         /// <summary>Current number of pending and in-process transfers</summary>
@@ -168,12 +168,6 @@
             client.Network.OnConnected += delegate { Startup(); };
             client.Network.OnDisconnected += delegate { Shutdown(); };
 
-            // Instantiate master thread that manages the request pool
-            downloadMaster = new Thread(DownloadThread);
-            downloadMaster.Name = "TexturePipeline";
-            downloadMaster.IsBackground = true;
-
-            RefreshDownloadsTimer.Elapsed += RefreshDownloadsTimer_Elapsed;
         }
 
         /// <summary>
@@ -186,6 +180,21 @@
 
             _Running = true;
 
+            if (downloadMaster==null)
+            {
+                // Instantiate master thread that manages the request pool
+                downloadMaster = new Thread(DownloadThread);
+                downloadMaster.Name = "TexturePipeline";
+                downloadMaster.IsBackground = true;
+            }
+            if (RefreshDownloadsTimer==null)
+            {
+                RefreshDownloadsTimer =
+                    new System.Timers.Timer(Settings.PIPELINE_REFRESH_INTERVAL);
+                RefreshDownloadsTimer.Elapsed += RefreshDownloadsTimer_Elapsed;
+            }
+
+
             _Client.Network.RegisterCallback(PacketType.ImageData, ImageDataHandler);
             _Client.Network.RegisterCallback(PacketType.ImagePacket, ImagePacketHandler);
             _Client.Network.RegisterCallback(PacketType.ImageNotInDatabase, ImageNotInDatabaseHandler);
@@ -205,6 +214,8 @@
                         TotalTime, NetworkTime, Math.Round(TotalBytes / NetworkTime.TotalSeconds / 60, 2), TotalBytes), Helpers.LogLevel.Debug);
 #endif
             RefreshDownloadsTimer.Stop();
+            RefreshDownloadsTimer = null;
+            downloadMaster = null;
 
             _Client.Network.UnregisterCallback(PacketType.ImageNotInDatabase, ImageNotInDatabaseHandler);
             _Client.Network.UnregisterCallback(PacketType.ImageData, ImageDataHandler);
@@ -657,7 +668,10 @@
                                        task.Transfer.ID, Helpers.LogLevel.Warning, _Client);
 
                             _Transfers.Remove(task.Transfer.ID);
-                            resetEvents[task.RequestSlot].Set(); // free up request slot
+                            if (task.RequestSlot >= 0) resetEvents[task.RequestSlot].Set(); // free up request slot
+                            else
+                                Logger.Log("Negative slot in download for " +
+                                           task.Transfer.ID, Helpers.LogLevel.Warning, _Client);
 
                             foreach (TextureDownloadCallback callback in task.Callbacks)
                                 callback(TextureRequestState.Timeout, new AssetTexture(task.RequestID, task.Transfer.AssetData));
Index: OpenMetaverseTypes/DoubleDictionary.cs
===================================================================
--- OpenMetaverseTypes/DoubleDictionary.cs	(revision 2945)
+++ OpenMetaverseTypes/DoubleDictionary.cs	(working copy)
@@ -28,11 +28,11 @@
 using System.Threading;
 using System.Collections.Generic;
 
-#if VISUAL_STUDIO
+//#if VISUAL_STUDIO
 using ReaderWriterLockImpl = System.Threading.ReaderWriterLockSlim;
-#else
-using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
-#endif
+//#else
+//using ReaderWriterLockImpl = OpenMetaverse.ReaderWriterLockSlim;
+//#endif
 
 namespace OpenMetaverse
 {