/// <summary> /// Invoked when we recieve a world state from the superpeers controlling our zone. /// </summary> /// <param name="state">World state recieved.</param> internal void RecievedWorldState(SuperPeerWorldStatePacket state) { if (m_currentZone == null) { return; } // Check packet comes from a superpeer simulating our current zone. int lowest_id = 0; foreach (ZoneSuperPeer p in m_currentZone.SuperPeers) { if (p.ID < lowest_id || lowest_id == 0) { lowest_id = p.ID; } } // If it dosen't then ignore it, as its probably a left over from a superpeer we are // currently unregistering from. if (lowest_id != state.SuperPeerID) { return; } // Check for jumps. /* if (m_worldState != null) { foreach (SuperPeerWorldStatePlayerInfo newInfo in state.Peers) { foreach (SuperPeerWorldStatePlayerInfo oldInfo in m_worldState.Peers) { if (newInfo.ClientID == oldInfo.ClientID) { float dx = Math.Abs(newInfo.Account.PeristentState.X - oldInfo.Account.PeristentState.X); float dy = Math.Abs(newInfo.Account.PeristentState.Y - oldInfo.Account.PeristentState.Y); if (dx > 26.0f || dy > 26.0f) { System.Console.WriteLine("WUT!"); } } } } } */ m_worldState = state; foreach (SuperPeerWorldStatePlayerInfo peer in state.Peers) { if (peer.ClientID == m_clientID) { m_account = peer.Account; } } }
/// <summary> /// Processes a packet that has been recieved from the arbitrator. /// </summary> /// <param name="peer">The client or peer we recieved the packet from.</param> /// <param name="packet">Packet that we recieved.</param> private void ProcessArbitratorIncomingPacket(Connection peer, Packet packet) { // ----------------------------------------------------------------- // We've been sent an updated version of the zone grid. // ----------------------------------------------------------------- if (packet is ZoneGridPacket) { ZoneGridPacket specificPacket = packet as ZoneGridPacket; m_zoneGrid.FromPacket(specificPacket); // Invoke events for all super peers who have gained control of zones. foreach (ZoneSuperPeer p in m_zoneGrid.GainedSuperPeers) { Zone zone = m_zoneGrid.GetZoneByID(p.ZoneID); SuperPeerGainedControl(zone, p); } // Invoke events for all super peers who have lost control of zones. foreach (ZoneSuperPeer p in m_zoneGrid.LostSuperPeers) { Zone zone = m_zoneGrid.GetZoneByID(p.ZoneID); SuperPeerLostControl(zone, p); } Logger.Info("Recieved updated zone grid from arbitrator.", LoggerVerboseLevel.High); } // ----------------------------------------------------------------- // We've been sent our persistent state information. // ----------------------------------------------------------------- else if (packet is UserAccountStatePacket) { UserAccountStatePacket specificPacket = packet as UserAccountStatePacket; m_account = specificPacket.Account; m_clientID = specificPacket.ClientID; if (m_threadNameSet == false) { System.Threading.Thread.CurrentThread.Name = "Client #" + m_clientID; m_threadNameSet = true; } Logger.Info("Recieved updated account information from arbitrator.", LoggerVerboseLevel.High); } // ----------------------------------------------------------------- // Information sent to one of our super peers about a client? // ----------------------------------------------------------------- else if ((packet as SuperPeerClientPacket) != null) { SuperPeerClientPacket specificPacket = packet as SuperPeerClientPacket; bool found = false; foreach (Connection connection in m_listenConnection.Peers) { if (connection.MetaData != null) { GameClientPeer p = ((GameClientPeer)connection.MetaData); foreach (SuperPeerToClientConnection conn in p.SuperPeerConnections) // ERROR IS HERE: SuperPeerConnections is filled with inactive ones that are recieving the packets too :( { if (conn.SuperPeer.ID == specificPacket.SuperPeerID && conn.ClientID == specificPacket.ClientID) { conn.RecievedArbitratorPacket(specificPacket); found = true; } } } } if (found == false) { throw new InvalidOperationException("Failed to find super peer to direct arbitrator packet to."); } } // ----------------------------------------------------------------- // Information sent to one of our super peers? // ----------------------------------------------------------------- else if ((packet as SuperPeerPacket) != null) { SuperPeerPacket specificPacket = packet as SuperPeerPacket; SuperPeer superpeer = FindSuperPeerByID(specificPacket.SuperPeerID); if (superpeer != null) { superpeer.ArbitratorRecievedPacket(m_arbitratorConnection, specificPacket); } else { throw new InvalidOperationException("Failed to find super peer to direct arbitrator packet to."); } } }
/// <summary> /// Processes a packet that has been recieved from a client. /// </summary> /// <param name="packet">Packet that we recieved.</param> private void ProcessIncomingPacket(Packet packet) { // ----------------------------------------------------------------- // Client is attempting to login. // ----------------------------------------------------------------- if (packet is LoginPacket) { LoginPacket specificPacket = packet as LoginPacket; LoginResultPacket reply = new LoginResultPacket(); reply.Result = LoginResult.Success; // Already logged into an account? if (m_account != null) { reply.Result = LoginResult.AlreadyLoggedIn; } else { UserAccount account = UserAccount.LoadByUsername(m_arbitrator.DatabaseConnection, specificPacket.Username); // Account not found? if (account == null) { reply.Result = LoginResult.AccountNotFound; } // Password invalid? else if (account.Password != specificPacket.Password) { reply.Result = LoginResult.PasswordInvalid; } // Account already in us? else { DBResults results = m_arbitrator.DatabaseConnection.Query(@"SELECT id FROM {0} WHERE account_id={1}", Settings.DB_TABLE_ACTIVE_CLIENTS, account.ID); // Account already in us? if (results.RowsAffected > 0) { reply.Result = LoginResult.AccountInUse; } // Success! Mark client as logged in. else { m_arbitrator.DatabaseConnection.Query(@"UPDATE {0} SET account_id={1} WHERE id={2}", Settings.DB_TABLE_ACTIVE_CLIENTS, account.ID, m_clientDatabaseID); m_account = account; } } } m_connection.SendPacket(reply, specificPacket); } // ----------------------------------------------------------------- // Client is attempting to create an account. // ----------------------------------------------------------------- else if (packet is CreateAccountPacket) { CreateAccountPacket specificPacket = packet as CreateAccountPacket; CreateAccountResultPacket reply = new CreateAccountResultPacket(); reply.Result = CreateAccountResult.Success; // Email already exists :( if (UserAccount.LoadByEmail(m_arbitrator.DatabaseConnection, specificPacket.Email) != null) { reply.Result = CreateAccountResult.EmailAlreadyExists; } else { // Username already exists :(. if (UserAccount.LoadByUsername(m_arbitrator.DatabaseConnection, specificPacket.Username) != null) { reply.Result = CreateAccountResult.UsernameAlreadyExists; } // Create account! else { UserAccount.CreateAccount(m_arbitrator.Settings, m_arbitrator.DatabaseConnection, specificPacket.Username, specificPacket.Password, specificPacket.Email); } } m_connection.SendPacket(reply, specificPacket); } // ----------------------------------------------------------------- // Client is attempting to register as listening and ready to be // a superpeer. // ----------------------------------------------------------------- else if (packet is RegisterAsListeningPacket) { RegisterAsListeningPacket specificPacket = packet as RegisterAsListeningPacket; RegisterAsListeningResultPacket reply = new RegisterAsListeningResultPacket(); if (m_listening == true) { reply.Result = RegisterAsListeningResult.AlreadyListening; } else if (m_account == null) { reply.Result = RegisterAsListeningResult.NotLoggedIn; } else { m_listenPort = specificPacket.Port; m_listening = true; reply.Result = RegisterAsListeningResult.Success; // Update the client registration to include listening information. RegisterClient(); // Send the peer a world grid. SendUpdatedWorldGrid(); // Send account information to them. UserAccountStatePacket p = new UserAccountStatePacket(); p.Account = m_account.Clone(); p.Account.Email = ""; p.Account.Password = ""; p.ClientID = (int)m_clientDatabaseID; m_connection.SendPacket(p); } m_connection.SendPacket(reply, specificPacket); } // ----------------------------------------------------------------- // Client has changed zone. // ----------------------------------------------------------------- else if (packet is ChangeZonePacket) { ChangeZonePacket specificPacket = packet as ChangeZonePacket; Logger.Info("Client moved into zone #{0} from zone #{1}.", LoggerVerboseLevel.High, specificPacket.ZoneID, m_zoneID); // Update and save zone information to database. m_zoneID = specificPacket.ZoneID; RegisterClient(); } // ----------------------------------------------------------------- // SuperPeer wants account information for a given client. // ----------------------------------------------------------------- else if (packet is SuperPeerRetrieveAccountPacket) { SuperPeerRetrieveAccountPacket specificPacket = packet as SuperPeerRetrieveAccountPacket; // TODO: Check client has authority to retrieve account information for given player. // (eg. its a superpeer in an area the client is). Flag as cheating if not. Logger.Info("Client #{0} wants to retrieve account information for player #{1}.", LoggerVerboseLevel.High, m_clientDatabaseID, specificPacket.ClientID); // Load clients information from the database. DBResults client_info = m_arbitrator.DatabaseConnection.Query(@"SELECT `account_id` FROM {0} WHERE id={1}", Settings.DB_TABLE_ACTIVE_CLIENTS, specificPacket.ClientID); // TODO: Add error checking for when client-id is not valid. SuperPeerRetrieveAccountReplyPacket reply = new SuperPeerRetrieveAccountReplyPacket(); reply.SuperPeerID = specificPacket.SuperPeerID; reply.ClientID = specificPacket.ClientID; if (client_info.RowsAffected > 0) { reply.Account = UserAccount.LoadByID(m_arbitrator.DatabaseConnection, (int)client_info[0]["account_id"]); } else { reply.Account = new UserAccount(); reply.Account.Username = "******"; } reply.Account.Email = ""; reply.Account.Password = ""; m_connection.SendPacket(reply); } // ----------------------------------------------------------------- // SuperPeer wants to store account information for a given client. // ----------------------------------------------------------------- else if (packet is SuperPeerStoreAccountPacket) { SuperPeerStoreAccountPacket specificPacket = packet as SuperPeerStoreAccountPacket; // TODO: Check client has authority to store account information for given player. // (eg. its a superpeer in an area the client is). Flag as cheating if not. Logger.Info("Client #{0} wants to store account information for player #{1} in zone #{2}.", LoggerVerboseLevel.High, m_clientDatabaseID, specificPacket.ClientID, specificPacket.ZoneID); StoreAccountRequest request = new StoreAccountRequest(); request.SuperPeerID = specificPacket.SuperPeerID; request.ClientID = specificPacket.ClientID; request.ZoneID = specificPacket.ZoneID; request.RecievedFrom = this; request.Account = specificPacket.Account; request.RecieveTime = Environment.TickCount; request.Reason = specificPacket.Reason; m_arbitrator.StoreAccountRequestRecieved(request); } // ----------------------------------------------------------------- // Client wants to gracefully disconnect. // ----------------------------------------------------------------- else if (packet is GracefulDisconnectPacket) { UnRegisterClient(); GracefulDisconnectReplyPacket reply = new GracefulDisconnectReplyPacket(); m_connection.SendPacket(reply, packet); } }
/// <summary> /// Finishes the process of unregistering a peer. /// </summary> private void FinishUnregister() { if (m_unregistered == true) { throw new InvalidOperationException("Recieved invalid finish-unregister request, already unregistered."); } m_unregistered = true; m_registering = false; m_registered = false; m_unregistering = false; m_isActive = false; m_account = null; SuperPeerUnregisterReplyPacket reply = new SuperPeerUnregisterReplyPacket(); reply.SuperPeerID = m_superpeer.ID; m_connection.SendPacket(reply); }
/// <summary> /// Finishes the process of registering a peer. /// </summary> private void FinishRegister(UserAccount account) { if (m_registered == true || m_registering == false || m_unregistered == true || m_unregistering == true) { return; } m_unregistered = false; m_registering = false; m_registered = true; m_unregistering = false; m_isActive = true; m_account = account; // Send a success reply! SuperPeerRegisterReplyPacket reply = new SuperPeerRegisterReplyPacket(); reply.SuperPeerID = m_superpeer.ID; m_connection.SendPacket(reply); // And register this peer with the superpeer. m_superpeer.PeerRegistered(this); }
/// <summary> /// Loads a user account that has the given username from the database. /// </summary> /// <param name="database">Database to load username from.</param> /// <param name="username">Username of account to load.</param> /// <returns>Account loaded, or null if one dosen't exist.</returns> public static UserAccount LoadByUsername(DBConnection database, string username) { DBResults results = database.Query(@"SELECT id, username, password, email, last_login_timestamp, persistent_state FROM {0} WHERE LOWER(`username`)='{1}'", Settings.DB_TABLE_ACCOUNTS, StringHelper.Escape(username.ToLower())); if (results.RowsAffected > 0) { DBRow row = results[0]; UserAccount account = new UserAccount(); account.m_id = (int)row["id"]; account.m_username = row["username"].ToString(); account.m_password = row["password"].ToString(); account.m_email = row["email"].ToString(); account.m_last_login_timestamp = row["last_login_timestamp"] == null ? 0 : (int)row["last_login_timestamp"]; account.m_persistent_state = new UserAccountPersistentState((byte[])row["persistent_state"]); return account; } else { return null; } }
/// <summary> /// Create a user account with the given information. /// </summary> /// <param name="settings">Settings used to initialize this account.</param> /// <param name="database">Database to load username from.</param> /// <param name="username">Username of account to load.</param> /// <returns>Account loaded, or null if one dosen't exist.</returns> public static UserAccount CreateAccount(Settings settings, DBConnection database, string username, string password, string email) { DBResults results = database.Query(@"SELECT id FROM {0} WHERE LOWER(`username`)='{1}'", Settings.DB_TABLE_ACCOUNTS, StringHelper.Escape(username.ToLower())); if (results.RowsAffected <= 0) { UserAccount account = new UserAccount(); account.m_id = (int)results.LastInsertID; account.m_username = username; account.m_password = password; account.m_email = email; account.m_last_login_timestamp = 0; account.m_persistent_state = new UserAccountPersistentState(); account.LoadDefaults(settings); account.Serialize(database); return account; } else { return null; } }