/// <summary>Sends the complete inventory to the client.  Used during login.</summary>
        internal void SendInventoryBulk(Client client, Character toon)
        {
            // First let's see if we need to clear any norent items
            bool noRentExpired = DateTime.Now.Subtract(toon.LastSeenDate ?? DateTime.MinValue).TotalSeconds >= Item.NORENT_EXPIRATION;
            if (noRentExpired)
                client.ZonePlayer.InvMgr.ClearNoRent();

            StringBuilder serItems = new StringBuilder();

            // Old emu checks for validity of an item for the slot here, not sure if that's necessary... validation is when placing in a slot
            foreach (InventoryItem invItem in client.ZonePlayer.InvMgr.PersonalSlotItems()) {
                //_log.DebugFormat("During bulk inv send, found {0} in personal inv items at slot {1} ====> {2}", invItem.Item.Name, invItem.SlotID, invItem.Serialize());
                serItems = serItems.Append(invItem.Serialize() + '\0');
            }

            foreach (InventoryItem invItem in client.ZonePlayer.InvMgr.BankSlotItems()) {
                //_log.DebugFormat("During bulk inv send, found {0} in bank items at slot {1}.", invItem.Item.Name, invItem.SlotID);
                serItems = serItems.Append(invItem.Serialize() + '\0');
            }

            foreach (InventoryItem invItem in client.ZonePlayer.InvMgr.SharedBankSlotItems()) {
                //_log.DebugFormat("During bulk inv send, found {0} in shared bank items at slot {1}.", invItem.Item.Name, invItem.SlotID);
                serItems = serItems.Append(invItem.Serialize() + '\0');
            }

            //_log.DebugFormat("Serialized Inventory Dump: {0}", serItems.ToString());
            EQRawApplicationPacket invPack = new EQRawApplicationPacket(AppOpCode.CharInventory, client.IPEndPoint, Encoding.ASCII.GetBytes(serItems.ToString()));
            client.SendApplicationPacket(invPack);
        }
 internal static void SendItemPacket(Client client, InventoryItem invItem, int slotId, ItemPacketType packetType)
 {
     invItem.SlotID = slotId;
     _log.DebugFormat("Sending item packet for {0}", invItem);
     //_log.DebugFormat("Serialized inv item: {0}", invItem.Serialize());
     ItemPacket item = new ItemPacket(packetType, invItem.Serialize());
     AppOpCode opCode = packetType == ItemPacketType.ViewLink ? AppOpCode.ItemLinkResponse : AppOpCode.ItemPacket;
     //_log.DebugFormat("Serialized Item packet: {0}", BitConverter.ToString(item.Serialize()));
     EQRawApplicationPacket itemPack = new EQRawApplicationPacket(opCode, client.IPEndPoint, item.Serialize());
     client.SendApplicationPacket(itemPack);
 }
 // Handles application packets specific to the login server
 internal override void ApplicationPacketReceived(EQRawApplicationPacket packet, Client client)
 {
     try
     {
         ProcessApplicationPacket(packet, client);
     }
     catch (Exception ex)
     {
         _log.Error("Error processing an application packet", ex);
     }
 }
        internal void SendLogoutPackets(Client client)
        {
            CancelTrade ct = new CancelTrade();
            ct.FromID = (uint)client.ZonePlayer.ID;
            ct.Action = 7;  // TODO: figure out wtf 7 is and constant-ize it (looks like a group action of "update")
            EQApplicationPacket<CancelTrade> ctPack = new EQApplicationPacket<CancelTrade>(AppOpCode.CancelTrade, ct);
            client.SendApplicationPacket(ctPack);

            EQRawApplicationPacket plrPack = new EQRawApplicationPacket(AppOpCode.PreLogoutReply, client.IPEndPoint, null);
            client.SendApplicationPacket(plrPack);
        }
        /// <summary>Sends a formatted message.</summary>
        /// <param name="msgTxt">Separate multiple messages by null terminators.</param>
        internal void SendMessageID(uint type, MessageStrings msgStr, byte[] msgTxt)
        {
            // TODO: add message filtering once filters are in

            if (type == (uint)MessageType.Emote)
                type = 4;

            FormattedMessageBytes fmb = new FormattedMessageBytes() { StringId = (uint)msgStr, MsgType = type, MsgBytes = msgTxt };
            EQRawApplicationPacket fmPack = new EQRawApplicationPacket(AppOpCode.FormattedMessage, _zp.Client.IPEndPoint, fmb.Serialize());
            _zp.Client.SendApplicationPacket(fmPack, true);
        }
        // Process the different protocol packet types
        private void ProcessRecvPacket(RawEQPacket packet, Client client)
        {
            if (packet.RawOpCode > 0x00ff)      // Check for application level packet
            {
                //_log.Debug("OPCode above 0x00ff.");
                packet.RawOpCode = (ushort)IPAddress.NetworkToHostOrder((short)packet.RawOpCode);   // orig code says opcode byte order is backwards in this case
                ApplicationPacketReceived(new EQRawApplicationPacket(packet), client);  // Handled by specialized server type
                return;
            }

            int subPacketLen = 0, processed = 0;

            switch (packet.OpCode)
            {
                case ProtocolOpCode.None:
                    _log.Error("Protocol OpCode found not set during packet processing... please fix.");
                    break;
                case ProtocolOpCode.SessionRequest:
                    // Check for existing client - may be getting blitzed w/ session requests
                    if (client.SessionId != 0 && client.ConnectionState == ConnectionState.Established)
                    {
                        _log.Warn("Recv a sessionRequest for an existing open client.");
                        break;
                    }

                    bool add = (client.SessionId == 0);   // handles case of existing clients that aren't connected (no need to re-add)

                    EQPacket<SessionRequest> sessReqPacket = new EQPacket<SessionRequest>(packet);
                    lock (client.syncRoot)
                    {
                        client.SessionId = (UInt32)IPAddress.NetworkToHostOrder((int)sessReqPacket.PacketStruct.SessionId);
                        client.MaxLength = (UInt32)IPAddress.NetworkToHostOrder((int)sessReqPacket.PacketStruct.MaxLength);
                        client.Key = 0x11223344;
                        client.ConnectionState = ConnectionState.Established;
                        //_log.Debug(string.Format("Received Session Request: session {0} maxlength {1}", client.SessionId, client.MaxLength));
                        PreSendSessionResponse(client);
                    }

                    if (add)
                    {
                        _clientListLock.EnterWriteLock();
                        try
                        {
                            _clients.Add(client.IPEndPoint.ToString(), client);
                            _log.InfoFormat("New client connecting from {0}", client.IPEndPoint.ToString());
                        }
                        finally
                        {
                            _clientListLock.ExitWriteLock();
                        }
                    }

                    break;
                case ProtocolOpCode.SessionResponse:
                    _log.Warn("Received unhandled SessionResponse OPCode");
                    break;
                case ProtocolOpCode.Combined:

                    while (processed < packet.GetPayload().Length)
                    {
                        subPacketLen = Buffer.GetByte(packet.GetPayload(), processed);
                        //_log.Debug("Extracting combined packet of length " + subPacketLen);
                        byte[] embBytes = new byte[subPacketLen];
                        Buffer.BlockCopy(packet.GetPayload(), processed + 1, embBytes, 0, subPacketLen);
                        RawEQPacket embPacket = new RawEQPacket(client.IPEndPoint, embBytes);
                        ProcessRecvPacket(embPacket, client);
                        processed += subPacketLen + 1;
                    }
                    break;
                case ProtocolOpCode.SessionDisconnect:
                    lock (client.syncRoot)
                    {
                        switch (client.ConnectionState)
                        {
                            case ConnectionState.Established:
                                _log.Debug("Received client initiated disconnect");
                                lock (client.syncRoot)
                                    client.ConnectionState = ConnectionState.Closed;
                                    //client.SendDisconnect(ConnectionState.Closed);
                                break;
                            case ConnectionState.Closing:
                                _log.Debug("Received disconnect during a pending close");
                                lock (client.syncRoot)
                                    client.SendDisconnect(ConnectionState.Closed);
                                break;
                            case ConnectionState.Closed:
                            case ConnectionState.Disconnecting:     // This is never sent back... handling a different way
                                _log.Debug("Received expected disconnect");
                                lock (client.syncRoot)
                                    client.ConnectionState = ConnectionState.Closed;
                                break;
                        }
                    }
                    break;
                case ProtocolOpCode.KeepAlive:
                    lock (client.syncRoot)
                        client.NonSequencedQueue.Enqueue(new RawEQPacket(client.IPEndPoint, packet.RawPacketData));

                    _log.Debug("Received and replied to a KeepAlive");
                    break;
                case ProtocolOpCode.SessionStatRequest:
                    EQPacket<SessionStats> statsPacket = new EQPacket<SessionStats>(packet);
                    //_log.DebugFormat("Received Stats: {0} packets recv, {1} packets sent, Deltas: local {2}, ({3} <- {4} -> {5}) remote {6}",
                    //    RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.PacketsRecieved), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.PacketsRecieved), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.LastLocalDelta),
                    //    RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.LowDelta), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.AverageDelta),
                    //    RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.HighDelta), RawEQPacket.NetToHostOrder(statsPacket.PacketStruct.LastRemoteDelta));

                    lock (client.syncRoot)
                        client.SendSessionStats(statsPacket);
                    break;
                case ProtocolOpCode.SessionStatResponse:
                    _log.Debug("Received SessionStatResponse OPCode, ignoring");
                    break;
                case ProtocolOpCode.Packet:
                    ushort seqNum = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 0));   // get seq num
                    //_log.Debug(string.Format("Received Data Packet: session {0} sequence {1}", client.SessionId, seqNum));

                    // TODO: figure out the locking strategy here
                    // determine the packet sequence
                    if (seqNum > client.NextInSeq)
                    {
                        _log.DebugFormat("Recv future data packet - expected {0} but got {1}", client.NextInSeq, seqNum);
                        lock (client.syncRoot)
                        {
                            client.DataPackets.Remove(seqNum);
                            client.DataPackets.Add(seqNum, packet);     // shove into the deferred packet list
                        }
                    }
                    else if (seqNum < client.NextInSeq)
                    {
                        //_log.DebugFormat("Recv duplicate data packet - expected {0} but got {1}", client.NextInSeq, seqNum);
                        client.SendOutOfOrderAck(seqNum);
                    }
                    else
                    {
                        // Received packet w/ expected seq
                        lock (client.syncRoot)
                        {
                            client.DataPackets.Remove(seqNum);  // Remove if it was previously queued as a future packet
                            client.SetNextAckToSend(seqNum);    // sequenced packets must be ack'd
                        }

                        // check for embedded OP_AppCombined (0x19)
                        ProtocolOpCode embOp = (ProtocolOpCode)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 2));
                        if (embOp == ProtocolOpCode.AppCombined)
                        {
                            //_log.Debug("Found and extracted an embedded packet in a data packet");
                            byte[] embBytes = new byte[packet.GetPayload().Length - 4]; // snip the data packet sequence num & AppCombined OpCode
                            Buffer.BlockCopy(packet.GetPayload(), 4, embBytes, 0, packet.GetPayload().Length - 4);
                            RawEQPacket embPacket = new RawEQPacket(ProtocolOpCode.AppCombined, embBytes, client.IPEndPoint);
                            ProcessRecvPacket(embPacket, client);
                        }
                        else
                        {
                            // Needs to be handled by specialized server, let's get us an app packet going
                            byte[] appBytes = new byte[packet.GetPayload().Length - 2]; // snip the data packet sequence num
                            Buffer.BlockCopy(packet.GetPayload(), 2, appBytes, 0, packet.GetPayload().Length - 2);
                            ApplicationPacketReceived(new EQRawApplicationPacket(client.IPEndPoint, appBytes), client);
                        }
                    }
                    break;
                case ProtocolOpCode.Fragment:
                    ushort fragSeqNum = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 0));

                    if (fragSeqNum > client.NextInSeq)
                    {
                        _log.DebugFormat("Recv future fragment - expected {0} but got {1}", client.NextInSeq, fragSeqNum);
                        lock (client.syncRoot)
                            client.DataPackets.Add(fragSeqNum, packet);     // shove into the deferred data packet list
                    }
                    else if (fragSeqNum < client.NextInSeq)
                    {
                        //_log.DebugFormat("Recv duplicate data fragment - expected {0} but got {1}", client.NextInSeq, fragSeqNum);
                        client.SendOutOfOrderAck(fragSeqNum);
                    }
                    else
                    {
                        // Received packet w/ expected seq
                        BasePacket bigPacket = null;
                        lock (client.syncRoot)
                        {
                            client.DataPackets.Remove(fragSeqNum);  // Remove if it was previously queued as a future packet
                            client.SetNextAckToSend(fragSeqNum);

                            if (client.OversizedBuffer != null)
                            {
                                // copy this round's fragment into the oversized buffer
                                Buffer.BlockCopy(packet.GetPayload(), 2, client.OversizedBuffer, client.OversizedOffset, packet.GetPayload().Length - 2);
                                client.OversizedOffset += packet.GetPayload().Length - 2;
                                //_log.DebugFormat("Recv fragment - seq {0} now at {1}", fragSeqNum, client.OversizedBuffer.Length / client.OversizedOffset);

                                if (client.OversizedOffset == client.OversizedBuffer.Length)
                                {
                                    // I totally don't get this first comparison (shouldn't we be looking in the oversized buffer), but ok...
                                    if (Buffer.GetByte(packet.GetPayload(), 2) == 0x00 && Buffer.GetByte(packet.GetPayload(), 3) == 0x19)
                                        bigPacket = new RawEQPacket(packet.ClientIPE, client.OversizedBuffer);
                                    else
                                        bigPacket = new EQRawApplicationPacket(client.IPEndPoint, client.OversizedBuffer);

                                    client.OversizedBuffer = null;
                                    client.OversizedOffset = 0;
                                    //_log.Debug("Completed combined oversized packet.");
                                }
                            }
                            else
                            {
                                uint oversizedLen = (uint)IPAddress.NetworkToHostOrder((int)BitConverter.ToUInt32(packet.GetPayload(), 2));
                                client.OversizedBuffer = new byte[oversizedLen];    // initialize the oversized packet buffer
                                Buffer.BlockCopy(packet.GetPayload(), 6, client.OversizedBuffer, 0, packet.GetPayload().Length - 6);
                                client.OversizedOffset = packet.GetPayload().Length - 6;
                                //_log.DebugFormat("Recv initial fragment packet - total size: {0} fragment len: {1}", oversizedLen, packet.GetPayload().Length - 6);
                            }
                        }

                        if (bigPacket is RawEQPacket)
                            ProcessRecvPacket(bigPacket as RawEQPacket, client);
                        else if(bigPacket is EQRawApplicationPacket)
                            ApplicationPacketReceived(bigPacket as EQRawApplicationPacket, client);
                    }
                    break;
                case ProtocolOpCode.OutOfOrderAck:
                    _log.Debug("Received OutOfOrderAck OPCode");
                    break;
                case ProtocolOpCode.Ack:
                    ushort ackSeqNum = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), 0));   // get seq num
                    lock (client.syncRoot)
                        client.AckPackets(ackSeqNum);
                    break;
                case ProtocolOpCode.AppCombined:
                    //_log.Debug("Processing App Combined packet: " + BitConverter.ToString(packet.RawPacketData));
                    processed = 0;
                    EQRawApplicationPacket appPacket = null;

                    while (processed < packet.GetPayload().Length)
                    {
                        appPacket = null;
                        subPacketLen = Buffer.GetByte(packet.GetPayload(), processed);

                        if (subPacketLen != 0xff)
                        {
                            //_log.Debug("Extracting App Combined packet of length " + subPacketLen);
                            byte[] appBytes = new byte[subPacketLen];
                            Buffer.BlockCopy(packet.GetPayload(), processed + 1, appBytes, 0, subPacketLen);
                            appPacket = new EQRawApplicationPacket(client.IPEndPoint, appBytes);
                            processed += (subPacketLen + 1);
                        }
                        else
                        {
                            subPacketLen = IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.GetPayload(), processed + 1));
                            //_log.Debug("Extracting App Combined packet of length " + subPacketLen);
                            byte[] appBytes = new byte[subPacketLen];
                            Buffer.BlockCopy(packet.GetPayload(), processed + 3, appBytes, 0, subPacketLen);
                            appPacket = new EQRawApplicationPacket(client.IPEndPoint, appBytes);
                            processed += (subPacketLen + 3);
                        }

                        ApplicationPacketReceived(appPacket, client);
                    }
                    break;
                case ProtocolOpCode.OutOfSession:
                    _log.Debug("Received OutOfSession OPCode, ignoring");
                    break;
                default:
                    _log.Warn("Received Unknown Protocol OPCode: " + (ushort)packet.OpCode);
                    break;
            }
        }
 /// <summary>Implemented by derived class to perform handle application level packets.</summary>
 internal virtual void ApplicationPacketReceived(EQRawApplicationPacket packet, Client client)
 {
     throw new NotImplementedException("Must override ApplicationPacketReceived virtual method in the specialized server class.");
 }
        // Handles application packets specific to the zone server
        internal override void ApplicationPacketReceived(EQRawApplicationPacket packet, Client client)
        {
            try
            {
                if (packet.OpCode == AppOpCode.AppAck)
                {
                    //_log.Debug("Recv AppAck... ignoring.");
                    return;
                }

                if (client.ZonePlayer == null)
                {
                    // Assume this is a zone entry, if not we have issues
                    if (packet.OpCode == AppOpCode.ZoneEntry)
                        HandleZoneEntry(packet, client);
                    else
                        _log.Error("Expected ZoneEntry OpCdode... what's up with that?");
                }
                else
                {
                    switch (client.ZonePlayer.ConnectionState)
                    {
                        case ZoneConnectionState.Connecting:
                            if (_connectingOpCodeHandlers.ContainsKey(packet.OpCode))
                                _connectingOpCodeHandlers[packet.OpCode](packet, client);
                            else
                                _log.Warn("Received Unexpected Connecting Application OPCode: " + packet.OpCode);
                            break;
                        case ZoneConnectionState.Connected:
                            if (_connectedOpCodeHandlers.ContainsKey(packet.OpCode))
                                _connectedOpCodeHandlers[packet.OpCode](packet, client);
                            else
                                _log.Warn("Received Unexpected Connected Application OPCode: " + packet.OpCode);
                            break;
                        case ZoneConnectionState.LinkDead:
                        case ZoneConnectionState.Kicked:
                        case ZoneConnectionState.Disconnected:
                            break;
                        case ZoneConnectionState.ClientError:
                        case ZoneConnectionState.All:
                            _log.WarnFormat("Unhandled client connection state {0} when recv OPCode {1}", client.ZonePlayer.ConnectionState, packet.OpCode);
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                _log.Error("Error processing an application packet", ex);
            }
        }
        private void ProcessApplicationPacket(EQRawApplicationPacket packet, Client client)
        {
            switch (packet.OpCode)
            {
                case AppOpCode.None:
                    _log.Error("Application OpCode found not set during packet processing... please fix.");
                    break;
                case AppOpCode.SessionReady:
                    //_log.Debug("Received SessionReady OPCode");

                    // Send a chat message - why? I have no idea
                    EQRawApplicationPacket chatPacket = new EQRawApplicationPacket(AppOpCode.ChatMessage, packet.ClientIPE, CHAT_MSG);
                    lock (client.syncRoot)
                        client.SendApplicationPacket(chatPacket);
                    break;
                case AppOpCode.Login:
                    //_log.Debug("Received Login OPCode");

                    // Authenticate - either with IPAddress or netbios name (if local)
                    string hostName = null;
                    if (Utility.IsIpInNetwork(IPAddress.Parse(_worldServer.IPAddress), client.IPEndPoint.Address, IPAddress.Parse("255.255.255.0")))
                        hostName = Dns.GetHostEntry(client.IPEndPoint.Address).HostName;
                    else
                        hostName = client.IPEndPoint.Address.ToString();

                    LoginAccount logAcct = null;
                    using (EmuDataContext dbCtx = new EmuDataContext())
                    {
                        logAcct = dbCtx.LoginAccounts.SingleOrDefault(la => la.IPAddress == hostName);
                    }

                    if (logAcct == null)
                    {
                        _log.InfoFormat("Client ({0}) attempted login but no matching Login Account was found.", hostName);
                        client.Close();
                        return;
                    }

                    _log.InfoFormat("Client ({0}) login successful.", hostName);
                    // TODO: set last login date?

                    // Send a login accepted
                    EQRawApplicationPacket laPacket = new EQRawApplicationPacket(AppOpCode.LoginAccepted, packet.ClientIPE, LOGIN_ACCEPTED_MSG);
                    lock (client.syncRoot)
                        client.SendApplicationPacket(laPacket);
                    break;
                case AppOpCode.ServerListRequest:
                    //_log.Debug("Received ServerListRequest OPCode");
                    SendServerList(client);
                    break;
                case AppOpCode.PlayEverquestRequest:
                    //_log.Debug("Received PlayEverquestRequest OPCode");

                    // TODO: check for locked and admin level

                    // TODO: check for max players and admin level

                    SendPlayResponse(client);
                    break;
                case AppOpCode.EnterChat:
                case AppOpCode.ChatMessage:
                case AppOpCode.Poll:
                default:
                    _log.Warn("Received Unexpected Application OPCode: " + packet.OpCode);
                    break;
            }
        }
        internal void QueuePacketToClient(Client client, EQRawApplicationPacket appPacket, bool ackReq, ZoneConnectionState reqConnState)
        {
            // TODO: when messaging filters are in, add support here

            // See if the packet should be deferred for later sending when the client is "connected"
            if (reqConnState == ZoneConnectionState.All || client.ZonePlayer.ConnectionState == reqConnState)
                client.SendApplicationPacket(appPacket);
            else
                client.ZonePlayer.AddDeferredPacket(new DeferredPacket(appPacket, true));
        }
        /// <summary>Sends packets of spawn information to a single client, max of 100 spawns at a time.</summary>
        private void SendSpawnsBulk(Client client)
        {
            int perPack = _mobMgr.MobCount < 100 ? _mobMgr.MobCount : 100;    // Top out each bulk send at 100
            int totalToSend = _mobMgr.MobCount;
            //_log.DebugFormat("detecting initially that we're going to need to send {0} total spawn", totalMobs);

            int i = 0, t = 0;
            int size = Marshal.SizeOf(typeof(Internals.Packets.Spawn));
            byte[] spawnsBytes = new byte[perPack * size];
            EQRawApplicationPacket spawnsPack;

            foreach (Mob mob in _mobMgr.AllMobs)    // Piss on locking it for this early operation
            {
                if (mob.IsInZone())
                {
                    if (mob is ZonePlayer && ((ZonePlayer)mob).IsGMHidden)
                    {
                        totalToSend--;
                        continue;
                    }

                    if (i == perPack)
                    {
                        // Send packet
                        spawnsPack = new EQRawApplicationPacket(AppOpCode.ZoneSpawns, client.IPEndPoint, spawnsBytes);
                        client.SendApplicationPacket(spawnsPack);

                        perPack = (totalToSend - t) < 100 ? totalToSend - t : 100;
                        spawnsBytes = new byte[perPack * size];
                        //_log.DebugFormat("created spawn array for {0} spawn.  t at {1}", perPack, t);
                        i = 0;
                    }

                    // append spawn bytes
                    Internals.Packets.Spawn s = mob.GetSpawn();
                    byte[] spawnBytes = Utility.SerializeStruct<Internals.Packets.Spawn>(s);
                    Buffer.BlockCopy(spawnBytes, 0, spawnsBytes, i * size, size);
                    i++;
                    t++;    // bump num of total spawns sent
                }
                else
                    totalToSend--;
            }

            if (i != 0) // Don't send anything if there is nothing to send
            {
                Array.Resize(ref spawnsBytes, i * size);   // Make sure we don't send empty spawns (might have had omissions)

                // Send packet
                spawnsPack = new EQRawApplicationPacket(AppOpCode.ZoneSpawns, client.IPEndPoint, spawnsBytes);
                //_log.DebugFormat("Sending Bulk Spawns Dump: {0}", BitConverter.ToString(spawnsBytes));
                client.SendApplicationPacket(spawnsPack);
            }

            //_log.DebugFormat("sent {0} total spawn", t);
        }
        private void SendServerList(Client client)
        {
            // Send the list of servers
            byte[] prefIpBuf = Encoding.ASCII.GetBytes(_worldServer.IPAddress);
            byte[] prefServerBuf = Encoding.ASCII.GetBytes(_worldServer.LongName);
            int offSet = 20;
            byte[] slBuffer = new byte[512];

            // clearly hackish, but it gets the job done
            Buffer.BlockCopy(SERVER_LIST_BEG_MSG, 0, slBuffer, 0, 16);
            Buffer.SetByte(slBuffer, 16, 0x01);     // server count (we're starting at 1)
            Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00 }, 0, slBuffer, 17, 3);
            Buffer.BlockCopy(prefIpBuf, 0, slBuffer, 20, prefIpBuf.Length);     // begin preferred server info
            offSet += prefIpBuf.Length;
            slBuffer[offSet] = 0x00;
            slBuffer[offSet + 1] = _worldServer.ServerType;   // 0x09=preferred,0x01=regular?,0x11=legends?
            offSet += 2;
            Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00 }, 0, slBuffer, offSet, 7);  // sever index
            offSet += 7;
            Buffer.BlockCopy(prefServerBuf, 0, slBuffer, offSet, prefServerBuf.Length);
            offSet += prefServerBuf.Length;
            Buffer.BlockCopy(new byte[] { 0x00, 0x45, 0x4e, 0x00, 0x55, 0x53, 0x00 }, 0, slBuffer, offSet, 7);
            offSet += 7;
            Buffer.SetByte(slBuffer, offSet, _worldServer.Status);    // status: 0x00=open, 0xfe=locked
            offSet++;
            Buffer.BlockCopy(new byte[] { 0x00, 0x00 }, 0, slBuffer, offSet, 2);
            offSet += 2;
            Buffer.BlockCopy(BitConverter.GetBytes((short)_clientCount), 0, slBuffer, offSet, 2);
            offSet += 2;
            Buffer.BlockCopy(new byte[] { 0x00, 0x00, 0x00 }, 0, slBuffer, offSet, 3);
            offSet += 3;
            Array.Resize<byte>(ref slBuffer, offSet);

            EQRawApplicationPacket slPacket = new EQRawApplicationPacket(AppOpCode.ServerListResponse, client.IPEndPoint, slBuffer);
            lock (client.syncRoot)
                client.SendApplicationPacket(slPacket);
        }
 internal void QueuePacketToNearbyClients(Mob sender, EQRawApplicationPacket packet, float distance, bool skipSender, bool ackReq)
 {
     QueuePacketToNearbyClients(sender, packet, distance, skipSender, true, null);
 }
        internal void QueuePacketToNearbyClients(Mob sender, EQRawApplicationPacket packet, float distance, bool skipSender, bool ackReq, int[] skipIDs)
        {
            if (distance <= 0)
                distance = 600;

            float range = distance * distance;

            foreach (Client client in this.GetConnectedClients()) {
                if (client.ZonePlayer == null
                    || (client.ZonePlayer == sender && skipSender)
                    || (skipIDs != null && skipIDs.Contains(client.ZonePlayer.ID)))
                    continue;   // Don't send to a client before its zonePlayer is set or to self if skip set or if client is on the skip list

                // TODO: when messaging filters are in, add support here
                if (client.ZonePlayer.ConnectionState == ZoneConnectionState.Connected && sender.DistanceNoRoot(client.ZonePlayer) <= range)
                    QueuePacketToClient(client, packet, ackReq, ZoneConnectionState.Connected);
                //else
                //    _log.DebugFormat("{0} is too far from {1}, not sending {2}", client.ZonePlayer.Name, sender.Name, packet.OpCode);
            }
        }
 internal void QueuePacketToClientsByTarget(Mob sender, EQRawApplicationPacket packet, bool skipSender, bool ackReq)
 {
     foreach (Client client in this.GetConnectedClients()) {
         if (!skipSender || client.ZonePlayer != sender) {
             // Not skipping the sender or the client isn't the sender anyways
             if (client.ZonePlayer.TargetMob != null && client.ZonePlayer.TargetMob == sender) {
                 // this client has the sender targeted, so send the packet to them
                 QueuePacketToClient(client, packet, ackReq, ZoneConnectionState.Connected);
                 //_log.DebugFormat("Sent {0} by target to {1}.", packet.OpCode, client.ZonePlayer.Name);
             }
         }
     }
 }
        internal void QueuePacketToClients(Mob sender, EQRawApplicationPacket packet, ZoneConnectionState reqConnState, bool skipSender, bool ackReq)
        {
            foreach (Client client in this.GetConnectedClients())
            {
                if (client.ZonePlayer == null || (client.ZonePlayer == sender && skipSender))
                    continue;   // Don't send to a client before its zonePlayer is set or to self if skip set

                QueuePacketToClient(client, packet, ackReq, reqConnState);
            }
        }
 /// <summary>Sends the provided packet to all clients that meet the specified zone connection state.</summary>
 internal void QueuePacketToClients(Mob sender, EQRawApplicationPacket packet, ZoneConnectionState reqConnState, bool skipSender)
 {
     QueuePacketToClients(sender, packet, reqConnState, skipSender, true);
 }
        internal void SendSpecialMessage(MessageType mt, string message)
        {
            // TODO: add message filtering once filters are in

            SpecialMessage msg = new SpecialMessage((uint)mt, message);
            EQRawApplicationPacket msgPack = new EQRawApplicationPacket(AppOpCode.SpecialMesg, _zp.Client.IPEndPoint, msg.Serialize());
            _zp.Client.SendApplicationPacket(msgPack, true);
        }
        /// <summary>Sends a communication message (tell, say, etc.) to the player.  Since we are sending this player the message, it is the listener.</summary>
        /// <param name="fromName">An optionally blank speaker's name.</param>
        /// <param name="toName">An optionally blank target's name.</param>
        /// <remarks>Messages should already be scrubbed for validity (GM messages intended only for GMs, etc.)</remarks>
        internal void SendChannelMessage(string fromName, string toName, MessageChannel chan, Language lang, int langSkill, string message)
        {
            ChannelMessage cm = new ChannelMessage();
            cm.ChannelId = (int)chan;
            cm.Message = message;
            cm.SpeakerName = string.IsNullOrEmpty(fromName) ? "ZServer" : fromName;     // Why 'ZServer'?

            // Looks like even though we know who the message is intended for, the target field can be blank
            if (!string.IsNullOrEmpty(toName))
                cm.TargetName = toName;
            else if (chan == MessageChannel.Tell)
                cm.TargetName = this.Name;

            int listenerSkill;
            if ((int)lang < Character.MAX_LANGUAGE) {   // Is the language being spoken within the allowable range
                listenerSkill = this.PlayerProfile.Languages[(int)lang];
                cm.LanguageId = (int)lang;
                if (chan == MessageChannel.Group && listenerSkill < 100) {  // group messages in unmastered languages, check for skill up
                    if ((this.PlayerProfile.Languages[(int)lang] <= langSkill) && fromName != this.Name)
                        CheckForSkillUp(lang, langSkill);
                }
            }
            else {
                // Not in allowable range, assume common tongue
                listenerSkill = this.PlayerProfile.Languages[(int)Language.CommonTongue];
                cm.LanguageId = (int)Language.CommonTongue;
            }

            // Set effective language skill = lower of sender and receiver skills
            int effSkill = Math.Min(langSkill, listenerSkill);
            effSkill = Math.Min(effSkill, 100); // Cap at 100
            cm.LanguageSkill = effSkill;

            EQRawApplicationPacket cmPack = new EQRawApplicationPacket(AppOpCode.ZonePlayerToBind, this.Client.IPEndPoint, cm.Serialize());
            this.Client.SendApplicationPacket(cmPack);
        }
        void Mob_SpellCastInterrupted(object sender, InterruptCastEventArgs ice)
        {
            ZonePlayer zp = sender as ZonePlayer;   // a player trigger this event?
            if (zp != null) {
                // Send the client a packet
                InterruptCast ic = new InterruptCast() { SpawnId = (uint)zp.ID, MessageId =  (uint)ice.Message};
                EQRawApplicationPacket icPacket = new EQRawApplicationPacket(AppOpCode.InterruptCast, zp.Client.IPEndPoint, ic.Serialize());
                _zoneSvr.QueuePacketToClient(zp.Client, icPacket, true, ZoneConnectionState.All);

                zp.SendSpellBarEnable(ice.SpellId);
            }

            // Now notify people in the area

            // First determine the message they should be sent
            MessageStrings othersMsg = MessageStrings.INTERRUPT_SPELL_OTHER;
            switch (ice.Message) {
                case MessageStrings.SPELL_FIZZLE:
                    othersMsg = MessageStrings.SPELL_FIZZLE_OTHER;
                    break;
                case MessageStrings.MISS_NOTE:
                    othersMsg = MessageStrings.MISSED_NOTE_OTHER;
                    break;
                case MessageStrings.SONG_ENDS_ABRUPTLY:
                    othersMsg = MessageStrings.SONG_ENDS_ABRUPTLY_OTHER;
                    break;
                case MessageStrings.SONG_ENDS:
                    othersMsg = MessageStrings.SONG_ENDS_OTHER;
                    break;
            }

            Mob m = sender as Mob;
            InterruptCast icb = new InterruptCast() { MessageId = (uint)othersMsg, SpawnId = (uint)m.ID, Message = m.DisplayName };
            EQRawApplicationPacket icbPacket = new EQRawApplicationPacket(AppOpCode.InterruptCast, null, icb.Serialize());
            _zoneSvr.QueuePacketToNearbyClients(m, icbPacket, 200.0f, true, true);  // TODO: pass in PC or NPC spell for the queue call to filter on when filters are in
        }
Exemple #21
0
        /// <summary>Sends an application packet as one or more raw packets.</summary>
        public void SendApplicationPacket(EQRawApplicationPacket appPacket, bool ackReq)
        {
            //_log.Debug("Sending " + appPacket.OpCode.ToString() + " application packet");

            if (appPacket.ClientIPE == null)
                appPacket.ClientIPE = this.IPEndPoint;

            if (ackReq)     // ack required = seq queue, no ack req = non-seq
            {
                // If the app packet can fit in one raw packet then send an OP_Packet packet, otherwise frament and send multiple OP_Fragment packets
                if (appPacket.GetPayload().Length > _maxLen - 8)    // proto-op(2), seq(2), app-op(2)... data ...crc(2)
                {
                    int chunksize, used;
                    byte[] tmpBuffer;
                    //_log.DebugFormat("Making oversized packet for a length of {0}", appPacket.GetPayload().Length);

                    // Build the raw bytes
                    int len = appPacket.RawPacketData.Length;
                    //uint lenNO = RawEQPacket.HostToNetOrder(len);
                    int lenNO = IPAddress.HostToNetworkOrder(appPacket.RawPacketData.Length);
                    tmpBuffer = new byte[_maxLen - 6];  // the fragment opCode, seq# and crc get thrown on later
                    used = (int)_maxLen - 10;           // track how many bytes we've copied, allowing 10 for opCode, seq#, length and crc
                    Buffer.BlockCopy(BitConverter.GetBytes(lenNO), 0, tmpBuffer, 0, 4);     // first packet gets the total length
                    Buffer.BlockCopy(appPacket.RawPacketData, 0, tmpBuffer, 4, used);
                    //_log.DebugFormat("First fragment: used {0}/{1} - Put size {2} in the packet", used, appPacket.RawPacketData.Length, len);
                    SendSequencedPacket(new BasePacket(appPacket.ClientIPE, tmpBuffer), ProtocolOpCode.Fragment);

                    while (used < appPacket.RawPacketData.Length)
                    {
                        chunksize = (int)Math.Min(appPacket.RawPacketData.Length - used, _maxLen - 6);
                        tmpBuffer = new byte[chunksize];
                        Buffer.BlockCopy(appPacket.RawPacketData, used, tmpBuffer, 0, chunksize);
                        used += chunksize;
                        //_log.DebugFormat("Next fragment: used {0}/{1}, len: {2}", used, appPacket.RawPacketData.Length, chunksize);
                        SendSequencedPacket(new BasePacket(appPacket.ClientIPE, tmpBuffer), ProtocolOpCode.Fragment);
                    }
                }
                else
                    SendSequencedPacket(appPacket, ProtocolOpCode.Packet);
            }
            else
                _nonSeqQueue.Enqueue(new RawEQPacket(ProtocolOpCode.Packet, appPacket.RawPacketData, appPacket.ClientIPE));
        }
        // Only one server could've been selected, so just roll with that.  TODO: Need to implement more code if we have more than one server
        private void SendPlayResponse(Client client)
        {
            bool worldUp = false;

            // Tell world there will be a client coming its way
            try
            {
                bool isLocalNet = Utility.IsIpInNetwork(IPAddress.Parse(_worldServer.IPAddress), client.IPEndPoint.Address, IPAddress.Parse("255.255.255.0"));
                WorldSvcClient.ExpectNewClient(client.IPEndPoint.Address.ToString(), isLocalNet);   // always authenticate by IP
                worldUp = true;
            }
            catch (CommunicationException ce)    // Specific fault handlers go before the CommunicationException handler
            {
                //_log.Error("Attempt to tell world to expect a new client encountered a Communication Exception.", ce);
                _log.Error("Attempt to tell world to expect a new client encountered a Communication Exception... World probably not up or has an issue with the WorldService ServiceHost.");
            }
            catch (TimeoutException te)
            {
                _log.Error("Attempt to tell world to expect a new client has timed out.", te);
            }
            catch (Exception e)
            {
                _log.Error("Attempt to tell world to expect a new client has errored out.", e);
            }

            if (worldUp)
            {
                // Give the client the ok
                Buffer.SetByte(PLAY_EQ_RESP_MSG, 16, 0x01);     // sets the index of the server to go to (evidently one based)
                EQRawApplicationPacket perPacket = new EQRawApplicationPacket(AppOpCode.PlayEverquestResponse, client.IPEndPoint, PLAY_EQ_RESP_MSG);
                lock (client.syncRoot)
                    client.SendApplicationPacket(perPacket);

                Interlocked.Increment(ref _clientCount);    // bump the client count
            }
            else
            {
                _worldSvcClientChannel.Abort();
                client.Close();
            }
        }
        internal void MovePlayer(ZonePlayer zp, uint zoneId, uint instanceId, float x, float y, float z, float heading, ZoneMode zm)
        {
            if (zoneId == this.Zone.ZoneID) {   // TODO: also test if the instance id is equal to this zone's
                if (zp.IsAIControlled) {
                    // TODO: quick move the pc
                    return;
                }

                // TODO: if they have a pet, quick move the pet to the new spot as well
            }

            zp.ZoneMode = zm;

            switch (zm) {
                case ZoneMode.EvacToSafeCoords:
                case ZoneMode.ZoneToSafeCoords:
                    // TODO: start cheat timer?
                    zp.ZoneSummonX = x;
                    zp.ZoneSummonY = y;
                    zp.ZoneSummonZ = z;
                    zp.Heading = heading;
                    break;
                case ZoneMode.GMSummon:
                    zp.MsgMgr.SendSpecialMessage(MessageType.Default, "You have been summoned by a GM!");
                    zp.ZoneSummonX = x;
                    zp.ZoneSummonY = y;
                    zp.ZoneSummonZ = z;
                    zp.Heading = heading;
                    zp.ZoneSummonID = (ushort)zoneId;
                    break;
                case ZoneMode.Solicited:
                    zp.ZoneSummonX = x;
                    zp.ZoneSummonY = y;
                    zp.ZoneSummonZ = z;
                    zp.Heading = heading;
                    zp.ZoneSummonID = (ushort)zoneId;
                    break;
                case ZoneMode.ZoneToBindPoint:
                    zp.ZoneId = (ushort)zoneId;
                    zp.X = x;
                    zp.Y = y;
                    zp.Z = z;
                    zp.Heading = heading;
                    _log.InfoFormat("Player {0} has died and will be zoned to bind point in zone {1} at LOC x={2}, y={3}, z={4}", zp.Name,
                        zoneId, x, y, z);

                    ZonePlayerToBind zptb = new ZonePlayerToBind(zoneId, x, y, z, heading, "Bind Location");
                    EQRawApplicationPacket zptbPack = new EQRawApplicationPacket(AppOpCode.ZonePlayerToBind, zp.Client.IPEndPoint, zptb.Serialize());
                    QueuePacketToClient(zp.Client, zptbPack, true, ZoneConnectionState.All);
                    return;
                case ZoneMode.Unsolicited:
                    throw new NotSupportedException("This type of player moving not supported yet.  Implement it!");
                    //break;
                case ZoneMode.GateToBindPoint:
                    throw new NotSupportedException("This type of player moving not supported yet.  Implement it!");
                    //break;
                case ZoneMode.SummonPC:
                    zp.MsgMgr.SendSpecialMessage(MessageType.Default, "You have been summoned!");
                    throw new NotSupportedException("This type of player moving not supported yet.  Implement it!");
                    //break;
            }

            // Handle Packet sending wasn't handled yet if we've gotten this far, so handle it now
            if (zm == ZoneMode.Solicited || zm == ZoneMode.ZoneToSafeCoords) {
                RequestClientZoneChange rczc = new RequestClientZoneChange()
                {
                    ZoneId = (ushort)zoneId,
                    X = x,
                    Y = y,
                    Z = z,
                    Heading = heading,
                    InstanceId = (ushort)instanceId,
                    Type = 0x01     // Might be meaningless... noted as an "observed value"
                };

                EQApplicationPacket<RequestClientZoneChange> rczcPack = new EQApplicationPacket<RequestClientZoneChange>(AppOpCode.RequestClientZoneChange, rczc);
                QueuePacketToClient(zp.Client, rczcPack, true, ZoneConnectionState.Connected);
            }
        }
 internal void SendDespawnPacket(Mob despawner)
 {
     EQRawApplicationPacket dsPack = new EQRawApplicationPacket(AppOpCode.DeleteSpawn, null, BitConverter.GetBytes(despawner.ID));
     QueuePacketToClients(despawner, dsPack, true);
 }
 internal void SendEndLootComplete(Client client)
 {
     EQRawApplicationPacket lcPack = new EQRawApplicationPacket(AppOpCode.LootComplete, client.IPEndPoint, null);
     QueuePacketToClient(client, lcPack, true, ZoneConnectionState.All);
 }
 public DeferredPacket(EQRawApplicationPacket appPacket, bool ackReq)
 {
     _appPacket = appPacket;
     _ackReq = ackReq;
 }
Exemple #27
0
 /// <summary>Send the app packet with ackReq = true.</summary>
 public void SendApplicationPacket(EQRawApplicationPacket appPacket)
 {
     SendApplicationPacket(appPacket, true);
 }