예제 #1
0
        /// <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);
        }
예제 #2
0
 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);
 }
예제 #3
0
 // 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);
     }
 }
예제 #4
0
        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);
        }
예제 #5
0
 /// <summary>Returns a NetBios name if client is on local net or an IP address if remote.</summary>
 internal string GetClientAddress(Client client, string networkAddr)
 {
     IPAddress serverIp = IPAddress.Parse(networkAddr);
     if (Utility.IsIpInNetwork(serverIp, client.IPEndPoint.Address, IPAddress.Parse("255.255.255.0")))   // TODO: pick up local net mask from config or something
         return Dns.GetHostEntry(client.IPEndPoint.Address).HostName;
     else
         return client.IPEndPoint.Address.ToString();
 }
예제 #6
0
 internal void SendLootRequestErrorPacket(Client client, byte response)
 {
     MoneyOnCorpse moc = new MoneyOnCorpse() { Response = response };
     EQApplicationPacket<MoneyOnCorpse> mocPack = new EQApplicationPacket<MoneyOnCorpse>(AppOpCode.MoneyOnCorpse, moc);
     client.SendApplicationPacket(mocPack);
 }
예제 #7
0
        /// <summary>Be careful, the _clients collection is locked when this fires.</summary>
        internal override void ClientDisconnected(Client client)
        {
            if (client.ZonePlayer != null)  // Could be null if we got kicked before the player obj was init
                client.ZonePlayer.Dispose();

            _log.DebugFormat("Detected a client disconnect. Total clients now connected: {0}", _clients.Count);

            if (_clients.Count == 0)    // TODO: modify for static and instanced zones
            {
                _shutdownTimer.Change(DYNAMIC_SHUTDOWN_TIMEOUT, Timeout.Infinite);  // if it's the last client to leave start the dynamic unload countdown
                _log.InfoFormat("Shutdown timer started.  Zone will unload in {0} ms", DYNAMIC_SHUTDOWN_TIMEOUT);
            }
        }
예제 #8
0
        // 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();
            }
        }
예제 #9
0
        // Do any basic processing common to all packets
        private void PreProcessRecvPacket(BasePacket packet)
        {
            Client client;
            _clientListLock.EnterReadLock();
            _clients.TryGetValue(packet.ClientIPE.ToString(), out client);
            _clientListLock.ExitReadLock();

            ProtocolOpCode opCode = (ProtocolOpCode)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.RawPacketData, 0));

            if (client != null)
            {
                // Found an existing client
                if (client.ConnectionState == ConnectionState.Closed)
                    return;     // ignore packets for closed connections
            }
            else
            {
                if (opCode != ProtocolOpCode.SessionRequest)
                    return;     // no client and not a session request - so ignore it
                else
                    client = new Client(packet.ClientIPE);
            }

            // CRC
            bool hasCrc = false;
            if (opCode != ProtocolOpCode.SessionRequest && opCode != ProtocolOpCode.SessionResponse && opCode != ProtocolOpCode.OutOfSession)
            {
                hasCrc = true;
                ushort sentCRC = (ushort)IPAddress.NetworkToHostOrder((short)BitConverter.ToUInt16(packet.RawPacketData, packet.RawPacketData.Length - 2));
                if (sentCRC != (ushort)CRC.ComputeChecksum(packet.RawPacketData, packet.RawPacketData.Length - 2, client.Key))
                {
                    _log.Error("Packet failed checksum.  Client key: " + client.Key);
                    return;
                }

                PreProcessInPacket(ref packet);   // Let the app level server get a crack at the packet
            }

            ProcessRecvPacket(new RawEQPacket(packet, hasCrc), client);
        }
예제 #10
0
        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));
        }
예제 #11
0
 internal static void SendItemPacket(Client client, InventoryItem invItem, ItemPacketType packetType)
 {
     SendItemPacket(client, invItem, invItem.SlotID, packetType);
 }
예제 #12
0
        /// <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);
        }
예제 #13
0
        internal void UpdateWorldWho(Client client)
        {
            try
            {
                //string clientAddr = GetClientAddress(client, WorldServer.ServerConfig.i

                WorldSvc.UpdateWho(client.IPEndPoint.Address.ToString(), client.ZonePlayer.ID, client.ZonePlayer.Name, client.ZonePlayer.IsGM,
                    client.ZonePlayer.IsGM, this.Zone.ZoneID, (byte)client.ZonePlayer.Race, (byte)client.ZonePlayer.Class, (byte)client.ZonePlayer.Level,
                    client.ZonePlayer.Anonymous == 1, (byte)client.ZonePlayer.GuildId, client.ZonePlayer.IsLFG);
            }
            catch (CommunicationException ce)    // Specific fault handlers go before the CommunicationException handler
            {
                _log.Error("Attempt to update world's who list errored out.", ce);
                _worldSvcClientChannel.Abort();
            }
            catch (TimeoutException te)
            {
                _log.Error("Attempt to update world's who list timed out.", te);
                _worldSvcClientChannel.Abort();
            }
            catch (Exception)
            {
                _worldSvcClientChannel.Abort();
                throw;
            }
        }
예제 #14
0
        internal void SendStancePacket(SpawnAppearanceType appearType, Mob mob, short stanceValue, bool wholeZone, bool ignoreSelf, Client target)
        {
            SpawnAppearance sa = new SpawnAppearance((ushort)mob.ID, (ushort)appearType, (uint)stanceValue);
            EQApplicationPacket<SpawnAppearance> saPack = new EQApplicationPacket<SpawnAppearance>(AppOpCode.SpawnAppearance, sa);

            if (wholeZone)
                this.QueuePacketToClients(mob, saPack, ignoreSelf);
            else if (target != null)
                QueuePacketToClient(target, saPack, false, ZoneConnectionState.Connected);
            else if (mob is ZonePlayer)
                QueuePacketToClient(((ZonePlayer)mob).Client, saPack, false, ZoneConnectionState.Connected);
        }
예제 #15
0
        /// <summary>Called when the client is allowed to zone.  Handles all which must happen when a client zones out.</summary>
        internal void ZoneClient(ZoneChange zc, Zone targetZone, float destX, float destY, float destZ, float destH, byte ignoreRestrictions, Client client)
        {
            this.SendLogoutPackets(client);

            _mobMgr.RemoveFromAllHateLists(client.ZonePlayer);

            // TODO: clear aggro for pet, if present

            _log.DebugFormat("{0} is ATTEMPTING to zone to {1} ({2}) {3}x {4}y {5}z", client.ZonePlayer.Name, targetZone.ShortName, targetZone.ZoneID,
                destX, destY, destZ);

            ZoneChange zcOut = new ZoneChange();
            if (targetZone.ZoneID == this.Zone.ZoneID)
            {
                // Zoning to same zone (maybe a bind point, etc.)
                zcOut.ZoneID = this.Zone.ZoneID;
                zcOut.Success = (int)ZoneError.Success;

                client.ZonePlayer.X = destX;
                client.ZonePlayer.Y = destY;
                client.ZonePlayer.Z = destZ;
                client.ZonePlayer.Heading = destH;

                _log.InfoFormat("{0} is zoning to same zone {1}x {2}y {3}z (no error)", client.ZonePlayer.Name, destX, destY, destZ);
                AddClientAuth(client.IPEndPoint.Address.ToString(), true);   // add to expected clients list
            }
            else
            {
                // Send a ZTZ to World
                ZoneToZone ztz = new ZoneToZone();
                ztz.CharName = client.ZonePlayer.Name;
                ztz.CharId = client.ZonePlayer.ID;
                ztz.ClientIp = client.IPEndPoint.Address.ToString();
                ztz.CurrentZoneId = this.Zone.ZoneID;
                ztz.RequestedZoneId = targetZone.ZoneID;
                ztz.AccountStatus = client.ZonePlayer.AccountStatus;
                ztz.IgnoreRestrictions = ignoreRestrictions;
                int ztzResult = WorldSvc.ZoneToZone(ztz);

                if (ztzResult > 0)
                {
                    // problems
                    zcOut.Success = (int)ZoneError.NotReady;
                    client.ZonePlayer.ZoneId = this.Zone.ZoneID;    // client isn't zoning after all, so set the id back to this zone

                    _log.InfoFormat("{0} is zoning to same zone {1}x {2}y {3}z due to error code {4} when asking world to zone",
                        client.ZonePlayer.Name, destX, destY, destZ, ztzResult);

                    client.ZonePlayer.MsgMgr.SendSpecialMessage(MessageType.Default, string.Format("There was a problem zoning.  Code {0}.", ztzResult));
                }
                else
                {
                    zcOut.Init();
                    Buffer.BlockCopy(Encoding.ASCII.GetBytes(client.ZonePlayer.Name), 0, zcOut.CharName, 0, client.ZonePlayer.Name.Length);
                    zcOut.ZoneID = targetZone.ZoneID;
                    zcOut.Success = (int)ZoneError.Success;

                    client.ZonePlayer.X = destX;
                    client.ZonePlayer.Y = destY;
                    client.ZonePlayer.Z = destZ;
                    client.ZonePlayer.Heading = destH;
                    client.ZonePlayer.ZoneId = targetZone.ZoneID;

                    _log.InfoFormat("{0} is zoning to {1} ({2}) {3}x {4}y {5}z", client.ZonePlayer.Name, targetZone.ShortName, targetZone.ZoneID,
                        destX, destY, destZ);

                    // TODO: for ignoreRestrictions of 3, get safe coords for target zone
                }
            }

            client.ZonePlayer.ZoneMode = ZoneMode.Unsolicited;  // reset the zoneMode
            client.ZonePlayer.Save();   // this forced save ensures the correct zone info is available to world when zoning the client

            EQApplicationPacket<ZoneChange> zcPack = new EQApplicationPacket<ZoneChange>(AppOpCode.ZoneChange, zcOut);
            client.SendApplicationPacket(zcPack);
        }
예제 #16
0
 /// <summary>Implemented by derived class to set the session response's compression and/or encoding.</summary>
 internal virtual void PreSendSessionResponse(Client client)
 {
     client.SendSessionResponse(SessionFormat.Normal);
 }
예제 #17
0
 /// <summary>Implemented by derived class to be notified of a client disconnecting from the server.</summary>
 internal virtual void ClientDisconnected(Client client)
 {
 }
예제 #18
0
 /// <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.");
 }
예제 #19
0
 internal override void PreSendSessionResponse(Client client)
 {
     client.SendSessionResponse(SessionFormat.Compressed);
     //client.SendSessionResponse(SessionFormat.Normal);
 }
예제 #20
0
        // 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;
            }
        }
예제 #21
0
        private void SendZoneCancel(ZoneChange zc, Client client)
        {
            // send client right back to where they were - TODO: could this be improved?
            Buffer.BlockCopy(Encoding.ASCII.GetBytes(client.ZonePlayer.Name), 0, zc.CharName, 0, client.ZonePlayer.Name.Length);
            zc.ZoneID = (ushort)this.Zone.ZoneID;
            zc.Success = 1;
            EQApplicationPacket<ZoneChange> zcPack = new EQApplicationPacket<ZoneChange>(AppOpCode.ZoneChange, zc);
            client.SendApplicationPacket(zcPack);

            client.ZonePlayer.ZoneMode = ZoneMode.Unsolicited;
        }
예제 #22
0
        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;
            }
        }
예제 #23
0
        private void SendZoneError(ZoneChange zc, ZoneError errCode, Client client)
        {
            _log.InfoFormat("Zone {0} is not available for {1} because it wasn't found, insufficient flags, insufficient level or locked zone", zc.ZoneID, client.ZonePlayer.Name);

            ZoneChange zcOut = new ZoneChange(client.ZonePlayer.Name);
            zcOut.ZoneID = zc.ZoneID;
            zcOut.Success = (int)errCode;
            EQApplicationPacket<ZoneChange> zcPack = new EQApplicationPacket<ZoneChange>(AppOpCode.ZoneChange, zcOut);
            client.SendApplicationPacket(zcPack);
        }
예제 #24
0
        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);
        }
예제 #25
0
 internal void SendEndLootComplete(Client client)
 {
     EQRawApplicationPacket lcPack = new EQRawApplicationPacket(AppOpCode.LootComplete, client.IPEndPoint, null);
     QueuePacketToClient(client, lcPack, true, ZoneConnectionState.All);
 }
예제 #26
0
        public ZonePlayer(short entityId, Data.Character toon, ushort zoneId, Client client)
            : base(entityId, toon.Name, toon.Surname, toon.X, toon.Y, toon.Z, toon.Heading.Value)
        {
            this.Client = client;
            _acctId = toon.AccountID;
            _charId = toon.CharacterID;
            _acctStatus = toon.Account.Status;
            _connState = ZoneConnectionState.Connecting;

            // TODO: change storage to the cached profile

            _pp.ZoneId = (ushort)zoneId;
            this.Class = toon.Class.Value;
            this.Level = toon.CharLevel;
            _pp.XP = toon.XP;   // Bypass property setter to avoid packet sending
            _pp.Points = toon.PracticePoints.Value;

            _pp.STR = (uint)toon.STR.Value;
            _pp.STA = (uint)toon.STA.Value;
            _pp.DEX = (uint)toon.DEX.Value;
            _pp.AGI = (uint)toon.AGI.Value;
            _pp.INT = (uint)toon.INT.Value;
            _pp.WIS = (uint)toon.WIS.Value;
            _pp.CHA = (uint)toon.CHA.Value;

            this.Race = toon.Race.Value;
            _baseRace = toon.Race.Value;
            this.Gender = toon.Gender.Value;
            _baseGender = toon.Gender.Value;
            this.Deity = (uint)toon.Deity.Value;
            _hairColor = toon.HairColor.Value;
            _hairStyle = toon.HairStyle.Value;
            _beardColor = toon.BeardColor.Value;
            _beard = toon.Beard.Value;
            _eyeColor1 = toon.EyeColor1.Value;
            _eyeColor2 = toon.EyeColor2.Value;
            _luclinFace = toon.Face.Value;
            this.GMStatus = toon.GMStatus;
            this.Platinum = toon.Platinum;
            this.Gold = toon.Gold;
            this.Silver = toon.Silver;
            this.Copper = toon.Copper;

            _pp.Birthday = Utility.TimeTFromDateTime(toon.CreatedDate);
            _pp.LastLogin = _pp.Birthday;
            //_pp.TimePlayedMin = 0;
            _pp.HungerLevel = (uint)toon.HungerLevel.Value;
            _pp.ThirstLevel = (uint)toon.ThirstLevel.Value;
            _pp.Languages = Encoding.ASCII.GetBytes(toon.Languages);

            if (this.X == -1 && this.Y == -1 && this.Z == -1)  // -1 is what these were set to on char creation
            {
                // set to zone safe points
                this.X = toon.Zone.SafeX;
                this.Y = toon.Zone.SafeY;
                this.Z = toon.Zone.SafeZ;

                _log.Debug("Char coords set to safe points");
            }

            // TODO: factions

            // TODO: old emu has code for invalid Z position fix

            _invMgr = new InventoryManager(toon.InventoryItems, this);
            _invMgr.ItemChargeUsed += new EventHandler<ItemChargeUseEventArgs>(InvMgr_ItemChargeUsed);
            _invMgr.ItemMoved += new EventHandler<ItemMoveEventArgs>(InvMgr_ItemMoved);

            // TODO: guild stuff
            _pp.GuildRank = (byte)Guild.GuildRank.None;   // TODO: implement guild tables and fetch this live

            _size = Mob.GetSize((CharRaces)_race);

            // TODO: AAs

            // Spells
            foreach (ScribedSpell ss in toon.ScribedSpells)
                _pp.SpellBook[ss.SlotID] = ss.SpellID;

            foreach (MemorizedSpell ms in toon.MemorizedSpells) {
                _pp.MemSpells[ms.SlotID] = ms.SpellID;
                _memdSpells[ms.SlotID] = ms.Spell;
            }

            // TODO: buffs?
            for (int i = 0; i < Character.MAX_BUFF; i++)    // blank out the buffs spell id
                Buffer.BlockCopy(BitConverter.GetBytes((uint)Spell.BLANK_SPELL), 0, _pp.BuffsBlob, (20 * i) + 4, 4);
                //_pp.BuffsBlob[i] = 0xFF;

            // TODO: binds
            _pp.Binds[0].ZoneId = (uint)zoneId;
            _pp.Binds[0].X = this.X;
            _pp.Binds[0].Y = this.Y;
            _pp.Binds[0].Z = this.Z;
            _pp.Binds[0].Heading = this.Heading;

            _pp.Mana = 0u;  // TODO: Mana
            _pp.HP = (uint)toon.HP.Value;
            _curHP = toon.HP.Value; // Bypass property settors to avoid packet sending

            CalcStatModifiers();    // Calculate stats (ac, attack, hp, bonuses, etc.)

            if (_pp.HP <= 0) {
                _pp.HP = (uint)this.MaxHP;  // If they were dead, let's set things back to full
                _curHP = this.MaxHP;
            }

            _pp.Endurance = _maxEndurance;

            // TODO: group shit

            // TODO: once zone init is coded, do underworld checks

            // Skills
            for (int i = 0; i < toon.Skills.Length; i++)
                _pp.Skills[i] = (uint)toon.Skills[i];   // may want to turn the db representation into an nchar if skill levels get > 255

            // TODO: tribute
            _pp.TributeTimeRemaining = uint.MaxValue;

            InitPlayerProfile();

            // Init timers
            int autoSaveInterval = WorldServer.ServerConfig.AutosaveIntervalSec * 1000;
            _autoSaveTimer = new Timer(new TimerCallback(AutosaveTimerCallback), null, autoSaveInterval, autoSaveInterval);
            _ldTimer = new SimpleTimer(0);
            _deadTimer = new SimpleTimer(0);
            _hpUpdateTimer = new SimpleTimer(0);
            _campTimer = new SimpleTimer(0);

            _msgMgr = new MessagingManager(this);
        }
예제 #27
0
        // 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);
            }
        }