/// <summary> /// This function handles turning a bundle of messages (representing all messages accrued in a timeslice), /// into 1 or more packets, combining multiple messages into one packet or spliting large message across /// several packets as needed. /// </summary> /// <param name="bundle"></param> private void SendBundle(NetworkBundle bundle, GameMessageGroup group) { packetLog.DebugFormat("[{0}] Sending Bundle", session.LoggingIdentifier); bool writeOptionalHeaders = true; List <MessageFragment> fragments = new List <MessageFragment>(); // Pull all messages out and create MessageFragment objects while (bundle.HasMoreMessages) { var message = bundle.Dequeue(); var fragment = new MessageFragment(message, ConnectionData.FragmentSequence++); fragments.Add(fragment); } packetLog.DebugFormat("[{0}] Bundle Fragment Count: {1}", session.LoggingIdentifier, fragments.Count); // Loop through while we have fragements while (fragments.Count > 0 || writeOptionalHeaders) { ServerPacket packet = new ServerPacket(); PacketHeader packetHeader = packet.Header; if (fragments.Count > 0) { packetHeader.Flags |= PacketHeaderFlags.BlobFragments; } if (bundle.EncryptedChecksum) { packetHeader.Flags |= PacketHeaderFlags.EncryptedChecksum; } int availableSpace = ServerPacket.MaxPacketSize; // Pull first message and see if it is a large one var firstMessage = fragments.FirstOrDefault(); if (firstMessage != null) { // If a large message send only this one, filling the whole packet if (firstMessage.DataRemaining >= availableSpace) { packetLog.DebugFormat("[{0}] Sending large fragment", session.LoggingIdentifier); ServerPacketFragment spf = firstMessage.GetNextFragment(); packet.Fragments.Add(spf); availableSpace -= spf.Length; if (firstMessage.DataRemaining <= 0) { fragments.Remove(firstMessage); } } // Otherwise we'll write any optional headers and process any small messages that will fit else { if (writeOptionalHeaders) { writeOptionalHeaders = false; WriteOptionalHeaders(bundle, packet); if (packet.Data != null) { availableSpace -= (int)packet.Data.Length; } } // Create a list to remove completed messages after iterator List <MessageFragment> removeList = new List <MessageFragment>(); foreach (MessageFragment fragment in fragments) { bool fragmentSkipped = false; // Is this a large fragment and does it have a tail that needs sending? if (!fragment.TailSent && availableSpace >= fragment.TailSize) { packetLog.DebugFormat("[{0}] Sending tail fragment", session.LoggingIdentifier); ServerPacketFragment spf = fragment.GetTailFragment(); packet.Fragments.Add(spf); availableSpace -= spf.Length; } // Otherwise will this message fit in the remaining space? else if (availableSpace >= fragment.NextSize) { packetLog.DebugFormat("[{0}] Sending small message", session.LoggingIdentifier); ServerPacketFragment spf = fragment.GetNextFragment(); packet.Fragments.Add(spf); availableSpace -= spf.Length; } else { fragmentSkipped = true; } // If message is out of data, set to remove it if (fragment.DataRemaining <= 0) { removeList.Add(fragment); } // UIQueue messages must go out in order. Otherwise, you might see an NPC's tells in an order that doesn't match their defined emotes. if (fragmentSkipped && group == GameMessageGroup.UIQueue) { break; } } // Remove all completed messages fragments.RemoveAll(x => removeList.Contains(x)); } } // If no messages, write optional headers else { packetLog.DebugFormat("[{0}] No messages, just sending optional headers", session.LoggingIdentifier); if (writeOptionalHeaders) { writeOptionalHeaders = false; WriteOptionalHeaders(bundle, packet); if (packet.Data != null) { availableSpace -= (int)packet.Data.Length; } } } EnqueueSend(packet); } }
public PacketHeaderOptional(BinaryReader payload, PacketHeader header) { Header = header; Size = (uint)payload.BaseStream.Position; BinaryWriter writer = new BinaryWriter(headerBytes); if (header.HasFlag(PacketHeaderFlags.ServerSwitch)) // 0x100 { writer.Write(payload.ReadBytes(8)); } if (header.HasFlag(PacketHeaderFlags.RequestRetransmit)) // 0x1000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 4) { IsValid = false; return; } uint retransmitCount = payload.ReadUInt32(); writer.Write(retransmitCount); RetransmitData = new List <uint>(); for (uint i = 0u; i < retransmitCount; i++) { if (payload.BaseStream.Length < payload.BaseStream.Position + 4) { IsValid = false; return; } uint sequence = payload.ReadUInt32(); writer.Write(sequence); RetransmitData.Add(sequence); } } if (header.HasFlag(PacketHeaderFlags.RejectRetransmit)) // 0x2000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 4) { IsValid = false; return; } uint count = payload.ReadUInt32(); writer.Write(count); for (int i = 0; i < count; i++) { if (payload.BaseStream.Length < payload.BaseStream.Position + 4) { IsValid = false; return; } writer.Write(payload.ReadBytes(4)); } } if (header.HasFlag(PacketHeaderFlags.AckSequence)) // 0x4000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 4) { IsValid = false; return; } AckSequence = payload.ReadUInt32(); writer.Write(AckSequence); } if (header.HasFlag(PacketHeaderFlags.LoginRequest)) // 0x10000 { long position = payload.BaseStream.Position; long length = payload.BaseStream.Length - position; if (length < 1) { IsValid = false; return; } byte[] loginBytes = new byte[length]; payload.BaseStream.Read(loginBytes, (int)position, (int)length); writer.Write(loginBytes); payload.BaseStream.Position = position; } if (header.HasFlag(PacketHeaderFlags.WorldLoginRequest)) // 0x20000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 8) { IsValid = false; return; } long position = payload.BaseStream.Position; writer.Write(payload.ReadBytes(8)); payload.BaseStream.Position = position; } if (header.HasFlag(PacketHeaderFlags.ConnectResponse)) // 0x80000 { long position = payload.BaseStream.Position; if (payload.BaseStream.Length < payload.BaseStream.Position + 8) { IsValid = false; return; } writer.Write(payload.ReadBytes(8)); payload.BaseStream.Position = position; } if (header.HasFlag(PacketHeaderFlags.CICMDCommand)) // 0x400000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 8) { IsValid = false; return; } writer.Write(payload.ReadBytes(8)); } if (header.HasFlag(PacketHeaderFlags.TimeSync)) // 0x1000000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 8) { IsValid = false; return; } TimeSynch = payload.ReadDouble(); writer.Write(TimeSynch); } if (header.HasFlag(PacketHeaderFlags.EchoRequest)) // 0x2000000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 4) { IsValid = false; return; } EchoRequestClientTime = payload.ReadSingle(); writer.Write(EchoRequestClientTime); } if (header.HasFlag(PacketHeaderFlags.Flow)) // 0x8000000 { if (payload.BaseStream.Length < payload.BaseStream.Position + 6) { IsValid = false; return; } FlowBytes = payload.ReadUInt32(); FlowInterval = payload.ReadUInt16(); writer.Write(FlowBytes); writer.Write(FlowInterval); } Size = (uint)payload.BaseStream.Position - Size; }
public ServerPacket() { Header = new PacketHeader(); Data = new MemoryStream(); BodyWriter = new BinaryWriter(Data); }
public PacketHeaderOptional(BinaryReader payload, PacketHeader header) { Size = (uint)payload.BaseStream.Position; BinaryWriter writer = new BinaryWriter(headerBytes); if (header.HasFlag(PacketHeaderFlags.ServerSwitch)) // 0x100 { writer.Write(payload.ReadBytes(8)); } if (header.HasFlag(PacketHeaderFlags.RequestRetransmit)) // 0x1000 { uint retransmitCount = payload.ReadUInt32(); writer.Write(retransmitCount); for (uint i = 0u; i < retransmitCount; i++) { uint sequence = payload.ReadUInt32(); writer.Write(sequence); RetransmitData.Add(sequence); } } if (header.HasFlag(PacketHeaderFlags.RejectRetransmit)) // 0x2000 { uint count = payload.ReadUInt32(); writer.Write(count); for (int i = 0; i < count; i++) { writer.Write(payload.ReadBytes(4)); } } if (header.HasFlag(PacketHeaderFlags.AckSequence)) // 0x4000 { Sequence = payload.ReadUInt32(); writer.Write(Sequence); } if (header.HasFlag(PacketHeaderFlags.LoginRequest)) // 0x10000 { var position = payload.BaseStream.Position; var length = payload.BaseStream.Length - position; byte[] loginBytes = new byte[length]; payload.BaseStream.Read(loginBytes, (int)position, (int)length); writer.Write(loginBytes); payload.BaseStream.Position = position; } if (header.HasFlag(PacketHeaderFlags.WorldLoginRequest)) // 0x20000 { var position = payload.BaseStream.Position; writer.Write(payload.ReadBytes(8)); payload.BaseStream.Position = position; } if (header.HasFlag(PacketHeaderFlags.ConnectResponse)) // 0x80000 { var position = payload.BaseStream.Position; writer.Write(payload.ReadBytes(8)); payload.BaseStream.Position = position; } if (header.HasFlag(PacketHeaderFlags.CICMDCommand)) // 0x400000 { writer.Write(payload.ReadBytes(8)); } if (header.HasFlag(PacketHeaderFlags.TimeSynch)) // 0x1000000 { TimeSynch = payload.ReadDouble(); writer.Write(TimeSynch); } if (header.HasFlag(PacketHeaderFlags.EchoRequest)) // 0x2000000 { EchoRequestClientTime = payload.ReadSingle(); writer.Write(EchoRequestClientTime); } if (header.HasFlag(PacketHeaderFlags.Flow)) // 0x8000000 { writer.Write(payload.ReadBytes(6)); } Size = (uint)payload.BaseStream.Position - Size; }