/// <summary>
        /// Fire the events registered for this event type asynchronously
        /// </summary>
        /// <param name="capsEvent">Capability name</param>
        /// <param name="body">Decoded event body</param>
        /// <param name="simulator">Reference to the simulator that
        /// generated this event</param>
        internal void BeginRaiseEvent(string capsEvent, StructuredData.LLSD body, Simulator simulator)
        {
            bool specialHandler = false;

            Caps.EventQueueCallback callback;

            // Default handler first, if one exists
            if (_EventTable.TryGetValue(String.Empty, out callback))
            {
                if (callback != null)
                {
                    CapsCallbackWrapper wrapper;
                    wrapper.Callback  = callback;
                    wrapper.CapsEvent = capsEvent;
                    wrapper.Body      = body;
                    wrapper.Simulator = simulator;
                    ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper);
                }
            }

            // Generic parser next, don't generic parse events we've manually registered for
            if (body.Type == StructuredData.LLSDType.Map && !_EventTable.ContainsKey(capsEvent))
            {
                StructuredData.LLSDMap map = (StructuredData.LLSDMap)body;
                Packet packet = Packet.BuildPacket(capsEvent, map);
                if (packet != null)
                {
                    NetworkManager.IncomingPacket incomingPacket;
                    incomingPacket.Simulator = simulator;
                    incomingPacket.Packet    = packet;

                    Logger.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler", Client);

                    Client.Network.PacketInbox.Enqueue(incomingPacket);
                    specialHandler = true;
                }
            }

            // Explicit handler next
            if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null)
            {
                CapsCallbackWrapper wrapper;
                wrapper.Callback  = callback;
                wrapper.CapsEvent = capsEvent;
                wrapper.Body      = body;
                wrapper.Simulator = simulator;
                ThreadPool.QueueUserWorkItem(_ThreadPoolCallback, wrapper);

                specialHandler = true;
            }

            if (!specialHandler)
            {
                Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client);
            }
        }
        /// <summary>
        /// Fire the events registered for this event type synchronously
        /// </summary>
        /// <param name="capsEvent">Capability name</param>
        /// <param name="body">Decoded event body</param>
        /// <param name="simulator">Reference to the simulator that
        /// generated this event</param>
        internal void RaiseEvent(string capsEvent, StructuredData.LLSD body, Simulator simulator)
        {
            bool specialHandler = false;

            Caps.EventQueueCallback callback;

            // Default handler first, if one exists
            if (_EventTable.TryGetValue(capsEvent, out callback))
            {
                if (callback != null)
                {
                    try { callback(capsEvent, body, simulator); }
                    catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); }
                }
            }

            // Generic parser next
            if (body.Type == StructuredData.LLSDType.Map)
            {
                StructuredData.LLSDMap map = (StructuredData.LLSDMap)body;
                Packet packet = Packet.BuildPacket(capsEvent, map);
                if (packet != null)
                {
                    NetworkManager.IncomingPacket incomingPacket;
                    incomingPacket.Simulator = simulator;
                    incomingPacket.Packet    = packet;

                    Logger.DebugLog("Serializing " + packet.Type.ToString() + " capability with generic handler", Client);

                    Client.Network.PacketInbox.Enqueue(incomingPacket);
                    specialHandler = true;
                }
            }

            // Explicit handler next
            if (_EventTable.TryGetValue(capsEvent, out callback) && callback != null)
            {
                try { callback(capsEvent, body, simulator); }
                catch (Exception ex) { Logger.Log("CAPS Event Handler: " + ex.ToString(), Helpers.LogLevel.Error, Client); }

                specialHandler = true;
            }

            if (!specialHandler)
            {
                Logger.Log("Unhandled CAPS event " + capsEvent, Helpers.LogLevel.Warning, Client);
            }
        }
        protected override void PacketReceived(UDPPacketBuffer buffer)
        {
            Packet packet = null;

            // Check if this packet came from the server we expected it to come from
            if (!ipEndPoint.Address.Equals(((IPEndPoint)buffer.RemoteEndPoint).Address))
            {
                Logger.Log("Received " + buffer.DataLength + " bytes of data from unrecognized source " +
                           ((IPEndPoint)buffer.RemoteEndPoint).ToString(), Helpers.LogLevel.Warning, Client);
                return;
            }

            // Update the disconnect flag so this sim doesn't time out
            DisconnectCandidate = false;

            #region Packet Decoding

            int packetEnd = buffer.DataLength - 1;
            packet = Packet.BuildPacket(buffer.Data, ref packetEnd, buffer.ZeroData);

            // Fail-safe check
            if (packet == null)
            {
                Logger.Log("Couldn't build a message from the incoming data", Helpers.LogLevel.Warning, Client);
                return;
            }

            Stats.RecvBytes += (ulong)buffer.DataLength;
            Stats.RecvPackets++;

            #endregion Packet Decoding

            #region Reliable Handling

            if (packet.Header.Reliable)
            {
                // Add this packet to the list of ACKs that need to be sent out
                lock (PendingAcks)
                {
                    uint sequence = (uint)packet.Header.Sequence;
                    if (!PendingAcks.ContainsKey(sequence))
                    {
                        PendingAcks[sequence] = sequence;
                    }
                }

                // Send out ACKs if we have a lot of them
                if (PendingAcks.Count >= Client.Settings.MAX_PENDING_ACKS)
                {
                    SendAcks();
                }

                if (packet.Header.Resent)
                {
                    ++Stats.ReceivedResends;
                }
            }

            #endregion Reliable Handling

            #region Inbox Insertion

            NetworkManager.IncomingPacket incomingPacket;
            incomingPacket.Simulator = this;
            incomingPacket.Packet    = packet;

            // TODO: Prioritize the queue
            Network.PacketInbox.Enqueue(incomingPacket);

            #endregion Inbox Insertion
        }