/// <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 }
/// <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; }
/// <summary>Send the app packet with ackReq = true.</summary> public void SendApplicationPacket(EQRawApplicationPacket appPacket) { SendApplicationPacket(appPacket, true); }