public static async Task <bool> AttemptRaceStartAsync(RaceItem Race) { DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); EntrantsSummary entrantsSummary = database.GetEntrantsSummary(Race.RaceId); var raceServer = client.GetGuild(Globals.GuildId); var raceRole = raceServer.GetRole(Race.RoleId); var raceChannel = raceServer.GetTextChannel(Race.TextChannelId); //sometimes we need to know if we're actually starting the race. bool raceIsStarting = false; //See if the number of ready entrants + disqualified entrants equals the total number of entrants //It is possible (but rare) for an entrant to be marked disqualified before a race starts //Excessive DQs may result in a penalty at some point, so it's important to record them if (entrantsSummary.Ready + entrantsSummary.Disqalified == entrantsSummary.TotalEntrants) { //we don't want a situation where there is only one racer who is ready, but the race starts //because of DQed entrants. if (entrantsSummary.Ready > 1) { //All of the entrants are ready, and we have enough entrants, so we can start the race await raceChannel.SendMessageAsync(raceRole.Mention + " Everyone is ready! Race will start in 10 seconds."); database.UpdateRace(Race.RaceId, Status: "Countdown"); var newTimer = new CountdownTimer(); newTimer.Interval = 7000; newTimer.race = Race; newTimer.AutoReset = false; newTimer.Elapsed += CountdownRaceAsync; newTimer.Enabled = true; newTimer.Start(); //check for and remove any force start timers that may be waiting to fire RemoveTimer(_forceStartTimerList, Race.RaceId); _ = UpdateRacesChannelAsync(); raceIsStarting = true; } } _ = UpdateChannelTopicAsync(Race.RaceId); database.Dispose(); return(raceIsStarting); }