/// <summary> /// Client wanted to transfer to a city server. /// </summary> public static void HandleCityTokenRequest(NetworkClient Client, ProcessedPacket P) { string AccountName = P.ReadString(); string CityGUID = P.ReadString(); string CharGUID = P.ReadString(); if (AccountName == string.Empty || CityGUID == string.Empty || CharGUID == string.Empty) { return; } Guid Token = Guid.NewGuid(); CityInfo CServer = NetworkFacade.CServerListener.GetCityServer(CityGUID); using (var db = DataAccess.Get()) { Account Acc = db.Accounts.GetByUsername(AccountName); PacketStream CServerPacket = new PacketStream(0x01, 0); CServerPacket.WriteHeader(); ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 1 + 4 + (Client.RemoteIP.Length + 1) + 4 + (CharGUID.ToString().Length + 1) + (Token.ToString().Length + 1)); CServerPacket.WriteUInt16(PacketLength); CServerPacket.WriteByte(0); //CharacterCreate = false. CServerPacket.WriteInt32(Acc.AccountID); CServerPacket.WriteString(Client.RemoteIP); CServerPacket.WriteInt32(Client.RemotePort); CServerPacket.WriteString(CharGUID.ToString()); CServerPacket.WriteString(Token.ToString("")); CServer.Client.Send(CServerPacket.ToArray()); } }
/// <summary> /// Client wanted to retire a character. /// </summary> public static void HandleCharacterRetirement(NetworkClient Client, ProcessedPacket P) { PacketStream Packet; string AccountName = P.ReadString(); string GUID = P.ReadString(); if (AccountName == string.Empty || GUID == string.Empty) { return; } using (var db = DataAccess.Get()) { Account Acc = db.Accounts.GetByUsername(AccountName); IQueryable <Character> Query = db.Characters.GetForAccount(Acc.AccountID); //F**K, I hate LINQ. Guid CharGUID = new Guid(GUID); Character Char = Query.Where(x => x.GUID == CharGUID).SingleOrDefault(); if (Char != null) { db.Characters.RetireCharacter(Char); } else { return; } //This actually updates the record, not sure how. Acc.NumCharacters--; if (Char != null) { CityInfo CInfo = NetworkFacade.CServerListener.GetCityServer(Char.City); //Just in case... if (CInfo != null) { Packet = new PacketStream(0x02, 0); Packet.WriteHeader(); ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 4 + GUID.Length + 1); Packet.WriteUInt16(PacketLength); Packet.WriteInt32(Acc.AccountID); Packet.WriteString(GUID); CInfo.Client.Send(Packet.ToArray()); } } } Packet = new PacketStream((byte)PacketType.RETIRE_CHARACTER_STATUS, 0); Packet.WriteString(GUID); Client.SendEncrypted((byte)PacketType.RETIRE_CHARACTER_STATUS, Packet.ToArray()); }
/// <summary> /// A cityserver logged in! /// </summary> public static void HandleCityServerLogin(NetworkClient Client, ProcessedPacket P) { Logger.LogInfo("CityServer logged in!\r\n"); string Name = P.ReadString(); string Description = P.ReadString(); string IP = P.ReadString(); int Port = P.ReadInt32(); CityInfoStatus Status = (CityInfoStatus)P.ReadByte(); ulong Thumbnail = P.ReadUInt64(); string UUID = P.ReadString(); ulong Map = P.ReadUInt64(); CityInfo Info = new CityInfo(true); Info.Name = Name; Info.Description = Description; Info.IP = IP; Info.Port = Port; Info.Status = Status; Info.Thumbnail = Thumbnail; Info.UUID = UUID; Info.Map = Map; Info.Client = Client; Info.Online = true; NetworkFacade.CServerListener.CityServers.Add(Info); NetworkFacade.CServerListener.PotentialLogins.TryTake(out Client); NetworkClient[] Clients = new NetworkClient[NetworkFacade.ClientListener.Clients.Count]; NetworkFacade.ClientListener.Clients.CopyTo(Clients, 0); PacketStream ClientPacket = new PacketStream((byte)PacketType.NEW_CITY_SERVER, 0); ClientPacket.WriteString(Name); ClientPacket.WriteString(Description); ClientPacket.WriteString(IP); ClientPacket.WriteInt32(Port); ClientPacket.WriteByte((byte)Status); ClientPacket.WriteUInt64(Thumbnail); ClientPacket.WriteString(UUID); ClientPacket.WriteUInt64(Map); foreach (NetworkClient Receiver in Clients) { Receiver.SendEncrypted((byte)PacketType.NEW_CITY_SERVER, ClientPacket.ToArray()); } }
/// <summary> /// A cityserver requested a decryptionkey for a client! /// </summary> public static void HandleKeyFetch(NetworkClient Client, ProcessedPacket P) { string AccountName = P.ReadString(); byte[] EncKey = new byte[1]; foreach (NetworkClient Cl in NetworkFacade.CServerListener.Clients) { if (Cl.ClientEncryptor.Username == AccountName) { EncKey = Cl.ClientEncryptor.GetDecryptionArgsContainer().ARC4DecryptArgs.EncryptionKey; //TODO: Figure out what to do about CurrentlyActiveSim... //if (Cl.CurrentlyActiveSim.CreatedThisSession) { //TODO: Update the DB to reflect the city that // this sim resides in. //Database.UpdateCityForCharacter(Cl.CurrentlyActiveSim.Name, Client.ServerInfo.Name); } } } PacketStream OutPacket = new PacketStream(0x01, 0x00); OutPacket.WriteByte((byte)0x01); OutPacket.WriteByte((byte)(EncKey.Length + 2)); OutPacket.WriteByte((byte)EncKey.Length); OutPacket.Write(EncKey, 0, EncKey.Length); Client.Send(OutPacket.ToArray()); //For now, assume client has already disconnected and doesn't need to be disconnected manually. NetworkFacade.CServerListener.TransferringClients.Remove(Client); }
public static void HandlePlayerOnlineResponse(NetworkClient Client, ProcessedPacket P) { byte Result = (byte)P.ReadByte(); string Token = P.ReadString(); //NOTE: Might have to find another way to identify a client, since two people // can be on the same account from the same IP. string RemoteIP = P.ReadString(); int RemotePort = P.ReadInt32(); PacketStream Packet; NetworkClient FoundClient; switch (Result) { case 0x01: Packet = new PacketStream((byte)PacketType.REQUEST_CITY_TOKEN, 0); Packet.WriteString(Token); FoundClient = NetworkFacade.ClientListener.GetClient(RemoteIP, RemotePort); if (FoundClient != null) { FoundClient.SendEncrypted((byte)PacketType.REQUEST_CITY_TOKEN, Packet.ToArray()); } break; case 0x02: //Write player was already online packet! Packet = new PacketStream((byte)PacketType.PLAYER_ALREADY_ONLINE, 0); Packet.WriteByte(0x00); //Dummy FoundClient = NetworkFacade.ClientListener.GetClient(RemoteIP, RemotePort); if (FoundClient != null) { FoundClient.SendEncrypted((byte)PacketType.PLAYER_ALREADY_ONLINE, Packet.ToArray()); } break; } }
/// <summary> /// A cityserver logged in! /// </summary> public static void HandleCityServerLogin(NetworkClient Client, ProcessedPacket P) { CityServerClient CityClient = (CityServerClient)Client; Logger.LogInfo("CityServer logged in!\r\n"); string Name = P.ReadString(); string Description = P.ReadString(); string IP = P.ReadString(); int Port = P.ReadInt32(); CityInfoStatus Status = (CityInfoStatus)P.ReadByte(); ulong Thumbnail = P.ReadUInt64(); string UUID = P.ReadString(); ulong Map = P.ReadUInt64(); CityInfo Info = new CityInfo(Name, Description, Thumbnail, UUID, Map, IP, Port); Info.Status = Status; CityClient.ServerInfo = Info; //Client instance changed, so update it... NetworkFacade.CServerListener.UpdateClient(CityClient); }
/// <summary> /// Client sent a response to our challenge, as well as account name and password. /// </summary> public static void HandleChallengeResponse(NetworkClient Client, ProcessedPacket P) { PacketStream OutPacket; if (P.BufferLength <= 1) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteByte(0x03); //Bad challenge response. Client.Send(OutPacket.ToArray()); Logger.LogInfo("Bad challenge response - sent SLoginFailResponse!\r\n"); return; //How does this even happen?! } int Length = P.ReadByte(); byte[] CResponse; if (P.BufferLength >= Length) { CResponse = P.ReadBytes(Length); } else { return; } AESDecryptionArgs DecryptionArgs = Client.ClientEncryptor.GetDecryptionArgsContainer().AESDecryptArgs; if (DecryptionArgs.Challenge.SequenceEqual(CResponse)) { string AccountName = SanitizeAccount(P.ReadString()); Length = P.ReadByte(); byte[] PasswordHash; if (P.BufferLength >= Length) { PasswordHash = P.ReadBytes(Length); } else { return; } // Check whether the accountname is empty or is/contains "username" if (AccountName == string.Empty || AccountName.ToLower().Equals("username") || AccountName.ToLower().Contains("username")) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x01); Client.Send(OutPacket.ToArray()); Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } using (var db = DataAccess.Get()) { var account = db.Accounts.GetByUsername(AccountName); if (!GlobalSettings.Default.CreateAccountsOnLogin) { Logger.LogInfo("Done reading LoginRequest, checking account...\r\n"); if (account == null) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x01); Client.Send(OutPacket.ToArray()); Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } } else { if (account == null) { try { if (!AccountName.ToLower().Equals("username") || !AccountName.ToLower().Contains("username")) { db.Accounts.Create(new Account { AccountName = AccountName.ToLower(), Password = Convert.ToBase64String(PasswordHash) }); } } catch (Exception) { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x01); Client.Send(OutPacket.ToArray()); Logger.LogInfo(@"Bad accountname (""" + AccountName + @""") - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } account = db.Accounts.GetByUsername(AccountName); } } if (account.IsCorrectPassword(AccountName, PasswordHash)) { OutPacket = new PacketStream((byte)PacketType.LOGIN_SUCCESS, 0); OutPacket.WriteByte(0x01); Client.ClientEncryptor.Username = AccountName; Client.SendEncrypted((byte)PacketType.LOGIN_SUCCESS, OutPacket.ToArray()); Logger.LogInfo("Sent SLoginSuccessResponse!\r\n"); return; } else { OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x02); Client.Send(OutPacket.ToArray()); Logger.LogInfo("Bad password - sent SLoginFailResponse!\r\n"); Client.Disconnect(); return; } } } OutPacket = new PacketStream((byte)PacketType.LOGIN_FAILURE, 0); OutPacket.WriteHeader(); OutPacket.WriteUInt16((ushort)(PacketHeaders.UNENCRYPTED + 1)); OutPacket.WriteByte(0x03); //Bad challenge response. Client.Send(OutPacket.ToArray()); Logger.LogInfo("Bad challenge response - sent SLoginFailResponse!\r\n"); return; }
/// <summary> /// Client created a character! /// </summary> public static void HandleCharacterCreate(NetworkClient Client, ProcessedPacket P) { Logger.LogInfo("Received CharacterCreate!"); string AccountName = SanitizeAccount(P.ReadString()); //Need to be variable length, because the success packet contains a token. PacketStream CCStatusPacket = new PacketStream((byte)PacketType.CHARACTER_CREATION_STATUS, 0); using (var db = DataAccess.Get()) { Account Acc = db.Accounts.GetByUsername(AccountName); if (Acc.NumCharacters >= 3) { CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.ExceededCharacterLimit); Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray()); return; } //TODO: Send GUID to client... var Char = new Character(); string LastCached = P.ReadString(); if (LastCached == string.Empty) { //TODO: Proper error... CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted); Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray()); return; } Char.LastCached = ProtoHelpers.ParseDateTime(LastCached); Char.Name = P.ReadString(); Char.Sex = P.ReadString(); Char.Description = P.ReadString(); Char.GUID = Guid.NewGuid(); Char.HeadOutfitID = (long)P.ReadUInt64(); Char.BodyOutfitID = (long)P.ReadUInt64(); Char.AccountID = Acc.AccountID; Char.AppearanceType = P.ReadByte(); Char.CityName = P.ReadString(); Char.CityThumb = (long)P.ReadUInt64(); Char.City = P.ReadString(); Char.CityMap = (long)P.ReadUInt64(); Char.CityIp = P.ReadString(); Char.CityPort = P.ReadInt32(); Char.Money = NetworkFacade.INITIAL_MONEY; //These are going into DB, so be nazi. Sieg heil! if (Char.Name == string.Empty || Char.Sex == string.Empty || Char.Description == string.Empty) { CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted); Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray()); return; } var status = db.Characters.CreateCharacter(Char); switch (status) { case LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted: CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameAlreadyExisted); Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray()); break; case LoginDataModel.Entities.CharacterCreationStatus.NameTooLong: CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.NameTooLong); Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray()); break; case LoginDataModel.Entities.CharacterCreationStatus.Success: Guid Token = Guid.NewGuid(); //This actually updates the record, not sure how. Acc.NumCharacters++; //THIS NEEDS TO HAPPEN FIRST FOR CITY SERVER AUTHENTICATION TO WORK! CityInfo CServer = NetworkFacade.CServerListener.GetCityServer(Char.City); //Just in case... if (CServer != null) { PacketStream CServerPacket = new PacketStream(0x01, 0); CServerPacket.WriteHeader(); ushort PacketLength = (ushort)(PacketHeaders.UNENCRYPTED + 1 + 4 + (Client.RemoteIP.Length + 1) + 4 + (Char.GUID.ToString().Length + 1) + (Token.ToString().Length + 1)); CServerPacket.WriteUInt16(PacketLength); CServerPacket.WriteByte(1); //CharacterCreate = true CServerPacket.WriteInt32(Acc.AccountID); CServerPacket.WriteString(Client.RemoteIP); CServerPacket.WriteInt32(Client.RemotePort); CServerPacket.WriteString(Char.GUID.ToString()); CServerPacket.WriteString(Token.ToString("")); CServer.Client.Send(CServerPacket.ToArray()); } CCStatusPacket.WriteByte((int)LoginDataModel.Entities.CharacterCreationStatus.Success); CCStatusPacket.WriteString(Char.GUID.ToString()); CCStatusPacket.WriteString(Token.ToString()); Client.SendEncrypted(CCStatusPacket.PacketID, CCStatusPacket.ToArray()); break; } } }
/// <summary> /// Client requested information about its characters. /// </summary> public static void HandleCharacterInfoRequest(NetworkClient Client, ProcessedPacket P) { Logger.LogInfo("Received CharacterInfoRequest!"); string DateTimeStr = P.ReadString(); DateTime Timestamp; if (DateTimeStr != string.Empty) { Timestamp = DateTime.Parse(DateTimeStr); } else { //Unix epoch Timestamp = new DateTime(1970, 1, 1, 0, 0, 1); } Character[] Characters = new Character[] { }; using (var db = DataAccess.Get()) { var account = db.Accounts.GetByUsername(Client.ClientEncryptor.Username); Characters = db.Characters.GetForAccount((int)account.AccountID).ToArray(); } int NumChars = 0, NewChars = 0; if (Characters != null) { PacketStream Packet = new PacketStream((byte)PacketType.CHARACTER_LIST, 0); MemoryStream PacketData = new MemoryStream(); BinaryWriter PacketWriter = new BinaryWriter(PacketData); NumChars = Characters.Length; foreach (Character avatar in Characters) { //Zero means same, less than zero means T1 is earlier than T2, more than zero means T1 is later. if (DateTime.Compare(Timestamp, avatar.LastCached) < 0) { NewChars++; PacketWriter.Write((int)avatar.CharacterID); PacketWriter.Write(avatar.GUID.ToString()); PacketWriter.Write(avatar.LastCached.ToString("yyyy.MM.dd hh:mm:ss", CultureInfo.InvariantCulture)); PacketWriter.Write(avatar.Name); PacketWriter.Write(avatar.Sex); PacketWriter.Write(avatar.Description); PacketWriter.Write((ulong)avatar.HeadOutfitID); PacketWriter.Write((ulong)avatar.BodyOutfitID); PacketWriter.Write((byte)avatar.AppearanceType); PacketWriter.Write((string)avatar.CityName); PacketWriter.Write((ulong)avatar.CityThumb); PacketWriter.Write((string)avatar.City); PacketWriter.Write((ulong)avatar.CityMap); PacketWriter.Write((string)avatar.CityIp); PacketWriter.Write((int)avatar.CityPort); PacketWriter.Write((int)avatar.Money); } } //NOTE: If Characters != null, but no chars were new, NumChars will be however many characters, // and NewChars will be 0. Packet.WriteByte((byte)NumChars); Packet.WriteByte((byte)NewChars); Packet.Write(PacketData.ToArray(), 0, (int)PacketData.Length); PacketWriter.Close(); Client.SendEncrypted((byte)PacketType.CHARACTER_LIST, Packet.ToArray()); } else //No characters existed for the account. { PacketStream Packet = new PacketStream(0x05, 0); Packet.WriteByte((byte)NumChars); //0 characters. Packet.WriteByte((byte)NewChars); //0 new characters. Client.SendEncrypted((byte)PacketType.CHARACTER_LIST, Packet.ToArray()); } }