private bool DoConnectionlessHandshake() { string command; byte [] data; this.connState = ConnectionState.Connecting; WriteConnectionlessPacket("getchallenge", null, 0, 0); if (ReadConnectionlessPacket(out command, out data)) { if (command == "challengeResponse") { this.challenge = Convert.ToInt32(Encoding.Default.GetString(data)); MemoryStream ms = new MemoryStream(); ms.Position = 2; Q3HuffmanStream huff = new Q3HuffmanStream(ms, System.IO.Compression.CompressionMode.Compress); string connStr = string.Format(@"\challenge\{0}\qport\{1}\protocol\{2}{3}", this.challenge, this.qport, PROTOCOL_VERSION, userInfo); huff.WriteString(connStr); huff.Flush(); ms.Position = 0; ms.Write(ExBitConverter.GetBytes(( short )connStr.Length, false), 0, 2); this.connState = ConnectionState.Challenging; WriteConnectionlessPacket("connect ", ms.GetBuffer(), 0, ( int )ms.Length); if (ReadConnectionlessPacket(out command, out data)) { if (command == "connectResponse") { this.connState = ConnectionState.Connected; return(true); } } } } return(false); }
/* * During normal gameplay, a client packet will contain something like: * * 4 sequence number * 2 qport * 4 serverid * 4 acknowledged sequence number * 4 serverCommandSequence * <optional reliable commands> * 1 ClientCommands.Move or ClientCommands.MoveNoDelta * 1 command count * <count * usercmds> */ private void WritePacket() { // 'sequence number' and 'qport' fields will be written by underlying // Q3NetworkStream to provide these values without compressing and cyphering q3HuffCStream.WriteInt32(this.serverId); // serverid q3HuffCStream.WriteInt32(this.incomingSequence); // acknowledged sequence number q3HuffCStream.WriteInt32(this.incomingCommandSequence); // serverCommandSequence reliableCommandsEvent.WaitOne(); //<optional reliable commands> for (int i = reliableAcknowledge + 1; i <= reliableSequence; i++) { q3HuffCStream.WriteByte(( byte )ClientCommandType.ClientCommand); q3HuffCStream.WriteInt32(i); q3HuffCStream.WriteString(outgoingReliableCommands [i & (MAX_RELIABLE_COMMANDS - 1)]); } reliableCommandsEvent.Set(); // we want to send all the usercmds that were generated in the last // few packet, so even if a couple packets are dropped in a row, // all the cmds will make it to the server if (this.packetDup < 0) { this.packetDup = 0; } else if (this.packetDup > 5) { this.packetDup = 5; } int oldPacketNum = (this.outgoingSequence - 1 - packetDup) & PACKET_MASK; int count = this.cmdNumber - this.outPackets [oldPacketNum].cmdNumber; if (count > MAX_PACKET_USERCMDS) { count = MAX_PACKET_USERCMDS; } UserCommand oldcmd = new UserCommand(); if (count >= 1 && this.newSnapshots) { // begin a client move command if (/*cl_nodelta->integer ||*/ !snap.valid || /*|| clc.demowaiting*/ this.incomingSequence != this.snap.messageNum) { q3HuffCStream.WriteByte(( byte )ClientCommandType.MoveNoDelta); } else { q3HuffCStream.WriteByte(( byte )ClientCommandType.Move); } // write the command count q3HuffCStream.WriteByte(( byte )count); // use the checksum feed in the key int key = this.checksumFeed; // also use the message acknowledge key ^= this.incomingSequence; // also use the last acknowledged server command in the key key ^= this.HashKey(this.incomingReliableCommands [this.incomingCommandSequence & (MAX_RELIABLE_COMMANDS - 1)], 32); // write all the commands, including the predicted command for (int i = 0; i < count; i++) { int j = (this.cmdNumber - count + i + 1) & CMD_MASK; WriteDeltaUsercmdKey(key, oldcmd, ref this.cmds [j]); oldcmd = this.cmds [j]; } this.newSnapshots = false; } int packetNum = this.outgoingSequence & PACKET_MASK; this.outPackets[packetNum].realtime = DateTime.Now.Millisecond; this.outPackets[packetNum].serverTime = oldcmd.serverTime; this.outPackets[packetNum].cmdNumber = this.cmdNumber; //clc.lastPacketSentTime = cls.realtime; q3HuffCStream.WriteByte(( byte )ClientCommandType.EOF); q3HuffCStream.Flush(); }