private static void ProcessRdpReport(Session MySession, List <byte> MyPacket, bool UnreliableReport) { //Eventually incorporate UnreliableReport to cycle through unreliables and update accordingly //Read client bundle here. Accept client bundle as is because packets could be lost or dropped, client bundle# should not be "tracked" //considerations could be to track it for possible drop/lost rates MySession.clientBundleNumber = (ushort)(MyPacket[1] << 8 | MyPacket[0]); ushort LastRecvBundleNumber = (ushort)(MyPacket[3] << 8 | MyPacket[2]); ushort LastRecvMessageNumber = (ushort)(MyPacket[5] << 8 | MyPacket[4]); //Check our list of reliable messages to remove for (int i = 0; i < MySession.MyMessageList.Count(); i++) { //If our message stored is less then client ack, need to remove it! if (MySession.MyMessageList[i - i].ThisMessagenumber <= LastRecvMessageNumber) { MySession.MyMessageList.RemoveAt(0); } //Need to keep remaining messages, move on else { break; } } MyPacket.RemoveRange(0, 6); ///Only one that really matters, should tie into our packet resender stuff if (MySession.serverMessageNumber >= LastRecvMessageNumber) { ///This should be removing messages from resend mechanics. ///Update our last known message ack'd by client MySession.clientRecvMessageNumber = LastRecvMessageNumber; } ///Triggers creating master session if (((MySession.clientEndpoint + 1) == (MySession.sessionIDBase & 0x0000FFFF)) && MySession.SessionAck && MySession.serverSelect == false) { ///Key point here for character select is (MySession.clientEndpoint + 1 == MySession.sessionIDBase) ///SessionIDBase is 1 more then clientEndPoint ///Assume it's Create Master session? Session NewMasterSession = new Session(MySession.clientEndpoint, MySession.MyIPEndPoint, MySession.AccountID); SessionManager.AddMasterSession(NewMasterSession); } ///Trigger Server Select with this? else if ((MySession.clientEndpoint == (MySession.sessionIDBase & 0x0000FFFF)) && MySession.SessionAck && MySession.serverSelect == false) { MySession.serverSelect = true; } ///Triggers Character select else if (MySession.CharacterSelect && (MySession.clientEndpoint != MySession.sessionIDBase)) { MySession.CharacterSelect = false; List <Character> MyCharacterList = new List <Character>(); Logger.Info("Generating Character Select"); MyCharacterList = SQLOperations.AccountCharacters(MySession); //Assign to our session MySession.CharacterData = MyCharacterList; ProcessOpcode.CreateCharacterList(MyCharacterList, MySession); } else if (MySession.Dumpstarted) { //Let client know more data is coming if (MySession.MyDumpData.Count() > 500) { List <byte> ThisChunk = MySession.MyDumpData.GetRange(0, 500); MySession.MyDumpData.RemoveRange(0, 500); ///Handles packing message into outgoing packet RdpCommOut.PackMessage(MySession, ThisChunk, MessageOpcodeTypes.MultiShortReliableMessage); } //End of dump else { List <byte> ThisChunk = MySession.MyDumpData.GetRange(0, MySession.MyDumpData.Count()); MySession.MyDumpData.Clear(); ///Handles packing message into outgoing packet RdpCommOut.PackMessage(MySession, ThisChunk, MessageOpcodeTypes.ShortReliableMessage); //turn dump off MySession.Dumpstarted = false; //Gather remaining data to send in dump //ignore list ProcessOpcode.IgnoreList(MySession); //Randommessage //RandomFriend //characterSpeed ProcessOpcode.ActorSpeed(MySession); //Some opcode } } else { Logger.Err($"Client received server message {LastRecvMessageNumber}, expected {MySession.serverMessageNumber}"); } }
///Big switch statement to process Opcodes. private static void OpcodeChecker(Session MySession, ushort Opcode, List <byte> myPacket, int MessageLength) { switch (Opcode) { ///Game Disc Version case GameOpcode.DiscVersion: Logger.Info("Processing Game Disc Version"); ProcessGameDisc(MySession, myPacket); break; case GameOpcode.Authenticate: Logger.Info("Server Select Authentication"); ProcessAuthenticate(MySession, myPacket, false); break; case GameOpcode.Authenticate2: Logger.Info("Character Select Authentication"); ProcessAuthenticate(MySession, myPacket, true); break; case GameOpcode.DelCharacter: Logger.Info("Character Deletion Request"); ProcessDelChar(MySession, myPacket); break; case GameOpcode.CreateCharacter: Logger.Info("Create Character Request"); ProcessCreateChar(MySession, myPacket); break; case GameOpcode.SELECTED_CHAR: //Checking sent data to verify no changes to character ProcessCharacterChanges(MySession, myPacket); Logger.Info("Character Selected, starting memory dump"); //Start new session Session thisSession = new Session(MySession.clientEndpoint, MySession.MyIPEndPoint, MySession.remoteMaster, MySession.AccountID, MySession.sessionIDUp, MySession.MyCharacter); SessionManager.AddMasterSession(thisSession); ProcessMemoryDump(thisSession); break; case GameOpcode.DisconnectClient: //Client is disconnecting from the game world //Add logic here to save character data, position etc //Drop the session SessionManager.DropSession(MySession); break; default: Logger.Err($"Unable to identify Opcode: {Opcode}"); //Remove unknwon opcodes here //Eventually add logic to send unknwon opcodes to client via chat byte[] MyOpcodeMessage = new byte[MessageLength + 1]; myPacket.CopyTo(0, MyOpcodeMessage, 0, MessageLength); //Log opcode message and contents Logger.Info(MyOpcodeMessage); ClientOpcodeUnknown(MySession, Opcode); if (MessageLength > 0) { myPacket.RemoveRange(0, MessageLength); } break; } }