public static async Task UpdateChannelTopicAsync(ulong RaceId) { DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); EntrantsSummary entrantsSummary = database.GetEntrantsSummary(race.RaceId); database.Dispose(); SocketTextChannel raceChannel = (SocketTextChannel)client.GetChannel(race.TextChannelId); string newTopic = "**" + race.Status + "** | " + race.Description; if (race.Status == "Entry Open") { newTopic += " | Entered: " + (entrantsSummary.NotReady + entrantsSummary.Ready) + " | Ready: " + entrantsSummary.Ready; } else { newTopic += " | Racing: " + (entrantsSummary.Ready + entrantsSummary.Done + entrantsSummary.Forfeited + entrantsSummary.Disqalified) + " | Done: " + entrantsSummary.Done + " | Forfeited: " + entrantsSummary.Forfeited; } await raceChannel.ModifyAsync(x => { x.Topic = newTopic; }); }
public static async Task MarkEntrantDoneAsync(RaceItem Race, ulong UserId) { //Get the required information from Discord var raceServer = client.GetGuild(Globals.GuildId); var entrant = raceServer.GetUser(UserId); var raceChannel = raceServer.GetTextChannel(Race.TextChannelId); //Attempt to update the database. If the update function returns null, then the user isn't entered in the race DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); EntrantItem entrantInformation = database.MarkEntrantFinished(Race.RaceId, UserId, Race.StartTime); database.Dispose(); //if we get a result back from MarkEntrantFinished, let the racer know their place and finish time if (entrantInformation == null) { return; } var raceRole = raceServer.GetRole(Race.RoleId); await entrant.RemoveRoleAsync(raceRole); await raceChannel.SendMessageAsync(entrant.Mention + ", you finished in **" + AddOrdinal(entrantInformation.Place) + "** place with a time of **" + entrantInformation.FinishedTime + "**"); await AttemptRaceFinishAsync(Race); }
public static async Task MarkEntrantNotDoneAsync(RaceItem Race, ulong UserId) { //Get the required information from Discord var raceServer = client.GetGuild(Globals.GuildId); var entrant = raceServer.GetUser(UserId); var raceChannel = raceServer.GetTextChannel(Race.TextChannelId); //Attempt to update the database. If the update function returns null, then the user isn't entered in the race DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); if (database.MarkEntrantNotFinished(Race.RaceId, UserId)) { return; } var raceRole = raceServer.GetRole(Race.RoleId); await entrant.AddRoleAsync(raceRole); await raceChannel.SendMessageAsync(entrant.Mention + ", I marked you as not done. Keep racing!"); if (Race.Status == "Recently Completed") { database.UpdateRace(Race.RaceId, Status: "In Progress"); RemoveTimer(_completedRaceTimerList, Race.RaceId); _ = UpdateRacesChannelAsync(); } _ = UpdateChannelTopicAsync(Race.RaceId); database.Dispose(); }
public static async Task AddEntrantAsync(RaceItem Race, ulong UserId) { //get the required information from Discord var raceServer = client.GetGuild(Globals.GuildId); var entrant = raceServer.GetUser(UserId); var raceChannel = raceServer.GetTextChannel(Race.TextChannelId); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); //attempt to join the race. if the command returns true, then the user is probably already joined if (!database.JoinRace(Race.RaceId, UserId)) { //get the race role from Discord var raceRole = raceServer.GetRole(Race.RoleId); //assign the correct race role to the user await entrant.AddRoleAsync(raceRole); await raceChannel.SendMessageAsync(entrant.Mention + ", you are entered in the race. Type '.ready' when you are ready to start."); //Update the race channel topic to reflect the correct number of people joined. _ = UpdateChannelTopicAsync(Race.RaceId); } database.Dispose(); }
public Task CommandNotDone() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } //we need to get the race information from the database ulong RaceId = GetRaceId(Context.Channel.Name); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); EntrantItem entrant = database.GetEntrantInformation(RaceId, Context.User.Id); database.Dispose(); //don't continue with this command if the entrant isn't marked done. if (entrant.Status != "Done") { return(Task.CompletedTask); } if (race.Status != "In Progress" && race.Status != "Recently Completed") { return(Task.CompletedTask); } return(Task.Factory.StartNew(() => RaceManager.MarkEntrantNotDoneAsync(race, Context.User.Id))); }
public static async Task <bool> AttemptRaceFinishAsync(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); //we sometimes may need to know if the race is actually finishing bool raceIsFinishing = false; //Racers are stored as "Ready" until they finish, forfeit, or are disqualified if (entrantsSummary.Ready == 0) { await raceChannel.SendMessageAsync("Everyone is finished! GGs all around! This channel will be deleted in 10 minutes."); database.UpdateRace(Race.RaceId, Status: "Recently Completed"); var newTimer = new CountdownTimer(); newTimer.Interval = 600000; newTimer.race = Race; newTimer.AutoReset = false; newTimer.Elapsed += DeleteFinishedRaceAsync; newTimer.Enabled = true; newTimer.Start(); _completedRaceTimerList.Add(newTimer); raceIsFinishing = true; _ = UpdateRacesChannelAsync(); } _ = UpdateChannelTopicAsync(Race.RaceId); database.Dispose(); return(raceIsFinishing); }
public static async Task DeleteRaceAsync(RaceItem Race, string Status) { //Don't use this command if the status is anything other than "Aborted" or "Complete" if (Status != "Aborted" && Status != "Complete") { return; } //Update the database with the appropriate status DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); database.UpdateRace(Race.RaceId, Status: Status); database.Dispose(); //Get the channels and role from Discord var guild = client.GetGuild(Globals.GuildId); var textChannel = guild.GetChannel(Race.TextChannelId); var voiceChannel = guild.GetChannel(Race.VoiceChannelId); var raceRole = guild.GetRole(Race.RoleId); //Delete the channels and role from the Discord server await textChannel.DeleteAsync(); await voiceChannel.DeleteAsync(); await raceRole.DeleteAsync(); //check for and remove any force start timers that may be waiting to fire RemoveTimer(_forceStartTimerList, Race.RaceId); }
public Task CommandJoinRace() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } //get the RaceId by removing "race-" from the channel name we're in ulong RaceId = GetRaceId(Context.Channel.Name); //get the race information from the database DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); database.Dispose(); //Verify that the race is still open to entry if (race.Status != "Entry Open") { return(Task.CompletedTask); } return(Task.Factory.StartNew(() => RaceManager.AddEntrantAsync(race, Context.User.Id))); }
public Task CommandTime() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } //we need the race information from the database ulong RaceId = GetRaceId(Context.Channel.Name); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); database.Dispose(); //Verify that the race is still open to entry if (race.Status != "In Progress") { return(Task.CompletedTask); } return(Task.Factory.StartNew(() => RaceManager.ShowTimeAsync(race))); }
public Task CommandQuit() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } //we need to get the race information from the database ulong RaceId = GetRaceId(Context.Channel.Name); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); database.Dispose(); //depending on the race status, choose the correct way to handle the withdrawal (either remove outright or mark as forfeited. if (race.Status == "Entry Open" || race.Status == "Countdown") { return(Task.Factory.StartNew(() => RaceManager.RemoveEntrantAsync(race, Context.User.Id))); } else if (race.Status == "In Progress") { return(Task.Factory.StartNew(() => RaceManager.ForfeitEntrantAsync(race, Context.User.Id))); } return(Task.CompletedTask); }
public static async Task BeginForceStartAsync(RaceItem Race) { var raceServer = client.GetGuild(Globals.GuildId); var raceRole = raceServer.GetRole(Race.RoleId); var raceChannel = raceServer.GetTextChannel(Race.TextChannelId); //Set the race status to "Countdown" so no new entrants can join DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); database.UpdateRace(Race.RaceId, Status: "Countdown"); database.Dispose(); //We're going to set a timer to give the remaining entrants time to ready up await raceChannel.SendMessageAsync(raceRole.Mention + ", a moderator is force starting this race. Entrants who are not ready within 30 seconds will be kicked from the race."); var newTimer = new CountdownTimer(); newTimer.Interval = 30000; newTimer.race = Race; newTimer.AutoReset = false; newTimer.Elapsed += ForceStartRaceAsync; newTimer.Enabled = true; newTimer.Start(); _forceStartTimerList.Add(newTimer); _ = UpdateChannelTopicAsync(Race.RaceId); _ = UpdateRacesChannelAsync(); }
private static async void DeleteFinishedRaceAsync(Object source, ElapsedEventArgs e) { RaceItem race = ((CountdownTimer)source).race; await DeleteRaceAsync(race, "Complete"); await UpdateRacesChannelAsync(); }
public Task CommandCancel() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } ulong RaceId = GetRaceId(Context.Channel.Name); //get the race information from the database DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); database.Dispose(); //we need to check to see if the user has permission to cancel this race var user = Context.Guild.GetUser(Context.User.Id); List <SocketRole> userRoles = user.Roles.ToList(); bool userHasPermission = false; //check to see if the user is a moderator first. foreach (SocketRole item in userRoles) { if (item.Name.ToLower() == "moderator") { userHasPermission = true; break; } } //if the user is not a moderator and they are the owner of the race, they can still cancel it if it's open for entry. if (!userHasPermission && race.Owner == Context.User.Id) { if (race.Status == "Entry Open") { userHasPermission = true; } } //If the user isn't allowed to use this command, return if (!userHasPermission) { return(Task.CompletedTask); } //users can only cancel "Entry Open" or "In Progress" races if (race.Status == "Entry Open" || race.Status == "In Progress") { return(Task.Factory.StartNew( () => { _ = RaceManager.DeleteRaceAsync(race, "Aborted"); _ = RaceManager.UpdateRacesChannelAsync(); })); } return(Task.CompletedTask); }
public Task CommandSetDescription([Remainder][Summary("Description for the race channel")] string description) { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } ulong RaceId = GetRaceId(Context.Channel.Name); //get the race information from the database DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); //we need to check to see if the user has permission to cancel this race var user = Context.Guild.GetUser(Context.User.Id); List <SocketRole> userRoles = user.Roles.ToList(); bool userHasPermission = false; //check to see if the user is a moderator first. foreach (SocketRole item in userRoles) { if (item.Name.ToLower() == "moderator") { userHasPermission = true; break; } } //if the user is not a moderator and they are the owner of the race, they can still set the description it if it's open for entry. if (!userHasPermission && race.Owner == Context.User.Id) { if (race.Status == "Entry Open") { userHasPermission = true; } } //If the user isn't allowed to use this command, return if (!userHasPermission) { database.Dispose(); return(Task.CompletedTask); } //Clean the description, then set the new description. return(Task.Factory.StartNew( () => { string cleanedDescription = CleanDescription(description); database.UpdateRace(race.RaceId, Description: cleanedDescription); database.Dispose(); _ = RaceManager.UpdateChannelTopicAsync(race.RaceId); _ = ReplyAsync("Race description changed successfully."); })); }
public static async Task ShowTimeAsync(RaceItem Race) { var raceServer = client.GetGuild(Globals.GuildId); var raceChannel = raceServer.GetTextChannel(Race.TextChannelId); //calculate how much time has passed since the race start time and now TimeSpan elapsedTime = Race.StartTime - DateTime.Now; //Reply with elapsed time await raceChannel.SendMessageAsync("Elapsed time: **" + elapsedTime.ToString(@"hh\:mm\:ss") + "**"); }
public Task CommandRefresh() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } //This is a moderator only command var user = Context.Guild.GetUser(Context.User.Id); List <SocketRole> userRoles = user.Roles.ToList(); bool userHasPermission = false; foreach (SocketRole item in userRoles) { if (item.Name.ToLower() == "moderator") { userHasPermission = true; break; } } //return if the user doesn't have permission to use the command if (!userHasPermission) { return(Task.CompletedTask); } return(Task.Factory.StartNew( () => { ulong RaceId = GetRaceId(Context.Channel.Name); //get the race information from the database DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); database.Dispose(); _ = RaceManager.UpdateChannelTopicAsync(RaceId); if (race.Status == "Entry Open") { _ = RaceManager.AttemptRaceStartAsync(race); } else if (race.Status == "In Progress") { _ = RaceManager.AttemptRaceFinishAsync(race); } })); }
public static async Task SetEntrantStatusAsync(RaceItem Race, ulong UserId, string Status) { var raceServer = client.GetGuild(Globals.GuildId); var entrant = raceServer.GetUser(UserId); var raceChannel = raceServer.GetTextChannel(Race.TextChannelId); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); //Attempt to update the database. If the update function returns true, then the user isn't entered in the race if (!database.UpdateEntry(Race.RaceId, UserId, Status)) { await raceChannel.SendMessageAsync(entrant.Username + " is **" + Status + "**"); await AttemptRaceStartAsync(Race); } database.Dispose(); }
public Task CommandForceStart() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } //This is a moderator-only command var user = Context.Guild.GetUser(Context.User.Id); List <SocketRole> userRoles = user.Roles.ToList(); bool userHasPermission = false; //check to see if the user is a moderator first. foreach (SocketRole item in userRoles) { if (item.Name.ToLower() == "moderator") { userHasPermission = true; break; } } //If the user isn't allowed to use this command, let them know and return if (!userHasPermission) { return(Task.CompletedTask); } //get the race information from the database ulong RaceId = GetRaceId(Context.Channel.Name); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); database.Dispose(); //We can only force start races that have the Entry Open status if (race.Status != "Entry Open") { return(Task.CompletedTask); } return(Task.Factory.StartNew(() => RaceManager.BeginForceStartAsync(race))); }
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); }
/* * GetRaceInformation(): Returns the race information for [RaceId] */ public RaceItem GetRaceInformation(ulong RaceId) { MySqlCommand cmd; MySqlDataReader dataReader; //for reading the results of the query try { cmd = _connection.CreateCommand(); cmd.CommandText = "SELECT * from races WHERE ID = @RaceId"; cmd.Parameters.AddWithValue("@RaceId", RaceId); dataReader = cmd.ExecuteReader(); } catch (Exception e) { Console.WriteLine("Exception thrown: " + e.Message); throw; } //we should never read in more than one result, so we don't have to mess with a loop for dataReader.Read() dataReader.Read(); DateTime convertedDateTime; if (dataReader["StartTime"] == DBNull.Value) { convertedDateTime = DateTime.MinValue; } else { convertedDateTime = Convert.ToDateTime(dataReader["StartTime"]); } RaceItem Race = new RaceItem( RaceId, (ulong)dataReader["TextChannelId"], (ulong)dataReader["VoiceChannelId"], (ulong)dataReader["RoleId"], (ulong)dataReader["Owner"], (string)dataReader["Description"], (string)dataReader["Status"], convertedDateTime); dataReader.Close(); dataReader.Dispose(); return(Race); }
public static async Task ForfeitEntrantAsync(RaceItem Race, ulong UserId) { //get required info from Discord var guild = client.GetGuild(Globals.GuildId); var raceChannel = guild.GetTextChannel(Race.TextChannelId); var raceRole = guild.GetRole(Race.RoleId); var entrant = guild.GetUser(UserId); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); //Get the get the entrant's status. EntrantItem entrantStatus = database.GetEntrantInformation(Race.RaceId, UserId); //if no result was returned, the user isn't entered if (entrantStatus == null) { database.Dispose(); return; } //We can't forfeit a player who isn't still racing. if (entrantStatus.Status != "Ready") { database.Dispose(); return; } //attempt to forfeit the racer if (!database.UpdateEntry(Race.RaceId, UserId, "Forfeited")) { await entrant.RemoveRoleAsync(raceRole); await raceChannel.SendMessageAsync(entrant.Mention + ", you have forfeited from the race."); await AttemptRaceFinishAsync(Race); } //UpdateEntry shouldn't return true since we've already checked to see if the racer is entered, but if it does, we need to let the racer know. else { await raceChannel.SendMessageAsync(entrant.Mention + ", something went wrong when I tried to remove you. Please let a moderator know."); } database.Dispose(); }
private static async void ForceStartRaceAsync(Object source, ElapsedEventArgs e) { RaceItem race = ((CountdownTimer)source).race; var raceChannel = (SocketTextChannel)client.GetChannel(race.TextChannelId); var guild = client.GetGuild(Globals.GuildId); var raceRole = guild.GetRole(race.RoleId); //get the list of players who are not ready DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); List <EntrantItem> playersToRemove = database.GetEntrantList(race.RaceId, "Not Ready"); int kickedPlayers = 0; foreach (EntrantItem entrant in playersToRemove) { var discordEntrant = guild.GetUser(entrant.UserId); if (!database.DeleteEntrant(race.RaceId, entrant.UserId)) { kickedPlayers++; await discordEntrant.RemoveRoleAsync(raceRole); await discordEntrant.SendMessageAsync("You were kicked from **Race " + race.RaceId + ": " + race.Description + "** because you did not make yourself ready in a timely manner."); } } //Attempt to force start the race. If the race doesn't start, let everyone know and set //the race status back to "Entry Open" bool raceIsStarting = await AttemptRaceStartAsync(race); if (!raceIsStarting) { await raceChannel.SendMessageAsync("I could not force start this race because there aren't enough participants who are ready."); database.UpdateRace(race.RaceId, Status: "Entry Open"); await UpdateChannelTopicAsync(race.RaceId); } database.Dispose(); //remove the timer from our list of force start timers _forceStartTimerList.Remove((CountdownTimer)source); }
public static async Task RemoveEntrantAsync(RaceItem Race, ulong UserId) { //get required info from Discord var guild = client.GetGuild(Globals.GuildId); var raceChannel = guild.GetTextChannel(Race.TextChannelId); var raceRole = guild.GetRole(Race.RoleId); var entrant = guild.GetUser(UserId); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); //attempt to delete the entrant from the race. If DeleteEntrant returns true, they aren't entered in the race if (!database.DeleteEntrant(Race.RaceId, UserId)) { await entrant.RemoveRoleAsync(raceRole); await raceChannel.SendMessageAsync(entrant.Mention + ", you have been removed from the race."); await AttemptRaceStartAsync(Race); } database.Dispose(); }
public Task CommandReady() { //We can't process this message if it's not in a race channel, so we need to make sure it's coming from one SocketTextChannel messageChannel = (SocketTextChannel)Context.Client.GetChannel(Context.Channel.Id); if (!(messageChannel.CategoryId == Globals.RacesCategoryId)) { return(Task.CompletedTask); } //This command is only available when the race is open for entry, so we need to get the race information from the database ulong RaceId = GetRaceId(Context.Channel.Name); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); RaceItem race = database.GetRaceInformation(RaceId); database.Dispose(); if (race.Status != "Entry Open" && race.Status != "Countdown") { return(Task.CompletedTask); } return(Task.Factory.StartNew(() => RaceManager.SetEntrantStatusAsync(race, Context.User.Id, "Ready"))); }
private static async void CountdownRaceAsync(Object source, ElapsedEventArgs e) { RaceItem race = ((CountdownTimer)source).race; var raceChannel = (SocketTextChannel)client.GetChannel(race.TextChannelId); await raceChannel.SendMessageAsync("**3**"); Thread.Sleep(1000); await raceChannel.SendMessageAsync("**2**"); Thread.Sleep(1000); await raceChannel.SendMessageAsync("**1**"); Thread.Sleep(1000); await raceChannel.SendMessageAsync("**GO!**"); string startTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); DatabaseHandler database = new DatabaseHandler(Globals.MySqlConnectionString); database.UpdateRace(race.RaceId, Status: "In Progress", StartTime: startTime); database.Dispose(); await UpdateRacesChannelAsync(); await UpdateChannelTopicAsync(race.RaceId); }