ACR_ServerCommunicator.GameWorldManager.SynchronizeOnlineCharacters C# (CSharp) Method

SynchronizeOnlineCharacters() private method

This method synchronizes the online character list with the central database. Character join or part events are generated, as is appropriate.
private SynchronizeOnlineCharacters ( ) : void
return void
        private void SynchronizeOnlineCharacters()
        {
            IALFADatabase Database = DatabaseLinkQueryThread;

            //
            // Query the current player list and synchronize with our internal
            // state.
            //
            // There are several steps here:
            //
            // 1) Mark all online characters as "not visited".
            // 2) Retrieve the character list from the database.  For each
            //    character that wasn't already marked as online, or which has
            //    changed servers, update the state and fire the character join
            //    event.  Also, flag any character that is in the list from the
            //    database as "visited".
            // 3) Sweep the online character list for characters that are still
            //    flagged as "not visited".  These characters are those that
            //    have gone offline in the interim time and which need to have
            //    the character part event fired.
            //

            //
            // First - query the database.  This query returns a list of all
            // online characters from all servers that have checked in in the
            // past ten minutes.  We treat any server that has not checked in
            // within at least that long as having no online players.
            //

            List<SynchronizeOnlineCharactersRow> Rowset = new List<SynchronizeOnlineCharactersRow>();

            Database.ACR_SQLQuery(
                "SELECT " +
                    "`characters`.`ID` AS character_id, " +
                    "`characters`.`Location` as character_location, " +
                    "`players`.`IsDM` AS character_is_dm, " +
                    "`servers`.`ID` AS character_server_id " +
                "FROM `characters` " +
                "INNER JOIN `players` ON `players`.`ID` = `characters`.`PlayerID` " +
                "INNER JOIN `servers` ON `servers`.`ID` = `characters`.`ServerID` " +
                "INNER JOIN `pwdata` ON `pwdata`.`Name` = `servers`.`Name` " +
                "WHERE `characters`.`IsOnline` = 1 " +
                "AND pwdata.`Key` = 'ACR_TIME_SERVERTIME' " +
                "AND pwdata.`Last` >= DATE_SUB(CURRENT_TIMESTAMP, INTERVAL 10 MINUTE) "
                );

            //
            // Clear visited.
            //
            // N.B.  The Visited flag is only managed on the query thread or
            //       prior to list insertion during initial character creation.
            //
            //       Thus, while we must lock to protect the integrity of the
            //       list, there's no need to worry about another thread
            //       altering the Visited state after we drop the lock.
            //

            lock (this)
            {
                foreach (GameCharacter Character in OnlineCharacters)
                {
                    Character.Visited = false;
                }
            }

            //
            // Read each database row.
            //

            while (Database.ACR_SQLFetch())
            {
                SynchronizeOnlineCharactersRow Row;

                Row.CharacterId = Convert.ToInt32(Database.ACR_SQLGetData(0));
                Row.LocationString = Database.ACR_SQLGetData(1);
                Row.IsDM = ConvertToBoolean(Database.ACR_SQLGetData(2));
                Row.ServerId = Convert.ToInt32(Database.ACR_SQLGetData(3));

                Rowset.Add(Row);
            }

            lock (this)
            {
                //
                // Update entries.
                //

                foreach (SynchronizeOnlineCharactersRow Row in Rowset)
                {
                    int CharacterId = Row.CharacterId;
                    string LocationString = Row.LocationString;
                    bool IsDM = Row.IsDM;
                    int ServerId = Row.ServerId;

                    GameCharacter Character = ReferenceCharacterById(CharacterId, Database, IsDM);
                    GameServer Server = ReferenceServerById(ServerId, Database);

                    //
                    // Update the DM state of the character.
                    //

                    Character.Visited = true;
                    Character.Player.IsDM = IsDM;
                    Character.LocationString = LocationString;

                    if (Character.Server == Server)
                        continue;

                    //
                    // The character changed servers or came online from not
                    // being online, send the appropriate part and join events.
                    //

                    if (Character.Server != null && Character.Online)
                    {
                        OnCharacterPart(Character);
                        Character.Server.Characters.Remove(Character);
                        Character.Server = null;
                        OnlineCharacterList.Remove(Character);
                        Character.Online = false;
                    }

                    //
                    // If the user's server is still marked as offline, mark it
                    // as online now.  It has to have checked in for it to have
                    // been returned in the query as it is.
                    //

                    if (!Server.Online)
                    {
                        Server.Online = true;
                        Server.DatabaseOnline = true;
                        OnServerJoin(Server);
                    }

                    Character.Server = Server;

                    try
                    {
                        Character.Server.Characters.Add(Character);

                        try
                        {
                            OnlineCharacterList.Add(Character);
                        }
                        catch
                        {
                            Character.Server.Characters.Remove(Character);
                            throw;
                        }
                    }
                    catch
                    {
                        Character.Server = null;
                        Character.Online = false;
                        throw;
                    }

                    Character.Online = true;
                    OnCharacterJoin(Character);
                }

                //
                // Sweep offline characters.
                //

                var NowOfflineCharacters = (from C in OnlineCharacters
                                            where C.Visited == false
                                            select C);

                List<GameCharacter> ObjectsToRemove = new List<GameCharacter>(NowOfflineCharacters);

                foreach (GameCharacter Character in ObjectsToRemove)
                {
                    OnCharacterPart(Character);

                    if (Character.Server != null)
                        Character.Server.Characters.Remove(Character);

                    Character.Online = false;
                    OnlineCharacterList.Remove(Character);
                }
            }
        }