/// <summary> /// Serializes the data stored in the packet class into a byte array ready for sending. /// </summary> public override void Serialize() { //Packet ID Write((UInt16)((TypeID + streamID) << 8)); //Look through all our infos int lastRID = -1; foreach (Client.ReliableInfo info in reliables) { //Make sure it's in sequence if (lastRID != -1 && lastRID != UInt16.MaxValue && info.rid != lastRID + 1) { //An out of sync packet! throw new ArgumentException("Reliable boxing error! Packets in reliable queue were out of order, dropping."); } //Make sure the packet is serialized PacketBase packet = info.packet; lastRID = info.rid; packet.MakeSerialized(_client, _handler); //Insert the packet size byte[] packetData = packet.Data; Write((byte)packetData.Length); //Insert the data itself Write(packetData); } }
/// <summary> /// Serializes the data stored in the packet class into a byte array ready for sending. /// </summary> public override void Serialize() { //Packet ID Write((UInt16)((TypeID + streamID) << 8)); //Insert our number Write(Flip(rNumber)); //Make sure our packet is serialized packet.MakeSerialized(_client, _handler); //Write our packet contents Write(packet.Data); }
/// <summary> /// Sends a packet using the client socket /// </summary> internal void internalSend(PacketBase packet) { //First, allow the packet to serialize packet.MakeSerialized(this, _handler); //Do we need to apply the CRC32? if (!_CRC_S2C.bActive) { _handler.sendPacket(packet, packet.Data, _ipe); } else { //Perform a CRC check and add it to a new buffer byte[] packetData = packet.Data; byte[] newPacket = new byte[packetData.Length + _CRCLength]; Array.Copy(packetData, newPacket, packetData.Length); uint checksum = _CRC_S2C.ComputeChecksum(packetData, 0, packetData.Length); //Insert a CRC of the appropriate length switch (_CRCLength) { case 1: newPacket[packetData.Length] = (byte)(checksum & 0xFF); break; case 2: newPacket[packetData.Length + 1] = (byte)(checksum & 0xFF); newPacket[packetData.Length + 0] = (byte)((checksum >> 8) & 0xFF); break; case 3: newPacket[packetData.Length + 2] = (byte)(checksum & 0xFF); newPacket[packetData.Length + 1] = (byte)((checksum >> 8) & 0xFF); newPacket[packetData.Length + 0] = (byte)((checksum >> 16) & 0xFF); break; case 4: newPacket[packetData.Length + 3] = (byte)(checksum & 0xFF); newPacket[packetData.Length + 2] = (byte)((checksum >> 8) & 0xFF); newPacket[packetData.Length + 1] = (byte)((checksum >> 16) & 0xFF); newPacket[packetData.Length + 0] = (byte)((checksum >> 24) & 0xFF); break; } _handler.sendPacket(packet, newPacket, _ipe); } //Update our statistics _packetsSent++; _bytesSent += packet._size; }
/// <summary> /// Sends a reliable packet to the client /// </summary> public void sendReliable(PacketBase packet, Action completionCallback, int streamID) { //Sync up! using (DdMonitor.Lock(_sync)) { //Get the relevant stream Client.StreamState stream = _streams[streamID]; //Make sure the packet is serialized packet.MakeSerialized(this, _handler); //Is the (packet and reliable header) too large to be sent as one? if (4 + packet._size + _CRCLength > _C2S_UDPSize) { //Add the stream packet to the reliable queue so we know //when to start streaming it. DataStream ds = new DataStream(); ReliableInfo ri = new ReliableInfo(); ds.amountSent = 0; ds.buffer = packet.Data; if (completionCallback != null) { ds.Completed += completionCallback; } ri.dataStream = ds; //Put it in the reliable queue stream.reliableQueue.Enqueue(ri); } else { //Jam it in the reliable queue to be parsed ReliableInfo ri = new ReliableInfo(); ri.packet = packet; ri.rid = -1; if (completionCallback != null) { ri.Completed += completionCallback; } //Put it in the reliable queue stream.reliableQueue.Enqueue(ri); } } }
/// <summary> /// Sends queued packets, grouping them where necessary /// </summary> public void sendQueuedPackets() { //Are we over threshold? if (_bytesWritten > _rateThreshold) { return; } //If it's just one packet, there's no need int queueCount = _packetQueue.Count; if (queueCount == 0) { return; } else if (queueCount == 1) { PacketBase packet = _packetQueue.Dequeue(); internalSend(packet); _bytesWritten += packet._size; return; } //Go through the list, creating boxed packets as we go List <PacketBase> boxes = new List <PacketBase>(); BoxPacket box = new BoxPacket(); int currentSize = 2 + _CRCLength; //Header+footer size of a box packet //Send as many packets as we can! while (queueCount > 0 && _bytesWritten < _rateThreshold) { //Get our next packet PacketBase packet = _packetQueue.Dequeue(); _bytesWritten += packet._size; queueCount--; //Do not group data packets if (packet is DataPacket) { boxes.Add(packet); continue; } //Make sure the packet is serialized before we go comparing size packet.MakeSerialized(this, _handler); //If the packet exceeds the max limit, send it on it's own if (2 + 1 + packet.Length > byte.MaxValue) { //WARNING: This may disrupt the reliable flow? boxes.Add(packet); continue; } //Do we have space to add this packet? if (currentSize + packet.Length + 1 > udpMaxSize) { //There's not enough room. Check if our previous packet is on it's //own and actually warrants a box packet. if (box.packets.Count == 1) { boxes.Add(box.packets[0]); } else { boxes.Add(box); } //Create our new box box = new BoxPacket(); currentSize = 2 + _CRCLength; } //Add the packet to the box list box.packets.Add(packet); currentSize += packet.Length + 1; } //If the last box has more than one packet, keep it if (box.packets.Count > 1) { boxes.Add(box); } else if (box.packets.Count == 1) { //If it's only one packet, we don't need the box boxes.Add(box.packets[0]); } //Send all our packets foreach (PacketBase packet in boxes) { internalSend(packet); } }