/// <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>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(); }
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); }
/// <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); } }
// 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(); } }
// 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); }
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)); }
internal static void SendItemPacket(Client client, InventoryItem invItem, ItemPacketType packetType) { SendItemPacket(client, invItem, invItem.SlotID, packetType); }
/// <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); }
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; } }
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); }
/// <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); }
/// <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); }
/// <summary>Implemented by derived class to be notified of a client disconnecting from the server.</summary> internal virtual void ClientDisconnected(Client client) { }
/// <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."); }
internal override void PreSendSessionResponse(Client client) { client.SendSessionResponse(SessionFormat.Compressed); //client.SendSessionResponse(SessionFormat.Normal); }
// 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; } }
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; }
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; } }
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); }
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 SendEndLootComplete(Client client) { EQRawApplicationPacket lcPack = new EQRawApplicationPacket(AppOpCode.LootComplete, client.IPEndPoint, null); QueuePacketToClient(client, lcPack, true, ZoneConnectionState.All); }
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); }
// 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); } }