Merge pull request #965 from Kwoth/dev

Small updates
This commit is contained in:
Master Kwoth 2017-01-12 01:59:39 +01:00 committed by GitHub
commit 250de2c058
16 changed files with 65 additions and 118 deletions

View File

@ -45,6 +45,10 @@ Command and aliases | Description | Usage
`.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer` `.iam` | Adds a role to you that you choose. Role must be on a list of self-assignable roles. | `.iam Gamer`
`.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer` `.iamnot` `.iamn` | Removes a role to you that you choose. Role must be on a list of self-assignable roles. | `.iamn Gamer`
`.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode` `.slowmode` | Toggles slowmode. Disable by specifying no parameters. To enable, specify a number of messages each user can send, and an interval in seconds. For example 1 message every 5 seconds. **Requires ManageMessages server permission.** | `.slowmode 1 5` or `.slowmode`
`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick`
`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban`
`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore`
`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist`
`.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl` `.rotateplaying` `.ropl` | Toggles rotation of playing status of the dynamic strings you previously specified. **Bot Owner only.** | `.ropl`
`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued% **Bot Owner only.** | `.adpl` `.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: %servers%, %users%, %playing%, %queued% **Bot Owner only.** | `.adpl`
`.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl` `.listplaying` `.lipl` | Lists all playing statuses with their corresponding number. **Bot Owner only.** | `.lipl`
@ -57,22 +61,13 @@ Command and aliases | Description | Usage
`.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone` `.voicemute` | Prevents a mentioned user from speaking in voice channels. **Requires MuteMembers server permission.** | `.voicemute @Someone`
`.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy` `.voiceunmute` | Gives a previously voice-muted user a permission to speak. **Requires MuteMembers server permission.** | `.voiceunmute @Someguy`
`.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata` `.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata`
`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1`
`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2`
`.repeat` | Repeat a message every X minutes in the current channel. **Requires ManageMessages server permission.** | `.repeat 5 Hello there`
`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist`
`.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable` `.logserver` | Enables or Disables ALL log events. If enabled, all log events will log to this channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logserver enable` or `.logserver disable`
`.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore` `.logignore` | Toggles whether the .logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Requires Administrator server permission.** **Bot Owner only.** | `.logignore`
`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents` `.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents`
`.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned` `.log` | Toggles logging event. Disables it if it's active anywhere on the server. Enables if it's not active. Use `.logevents` to see a list of all events you can subscribe to. **Requires Administrator server permission.** **Bot Owner only.** | `.log userpresence` or `.log userbanned`
`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs` `.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs`
`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall` `.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json **Bot Owner only.** | `.fwtoall`
`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner only.** | `.scsc`
`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere`
`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc`
`.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable `.autoassignrole` `.aar` | Automaticaly assigns a specified role to every user who joins the server. **Requires ManageRoles server permission.** | `.aar` to disable, `.aar Role Name` to enable
`.antiraid` | Sets an anti-raid protection on the server. First argument is number of people which will trigger the protection. Second one is a time interval in which that number of people needs to join in order to trigger the protection, and third argument is punishment for those people (Kick, Ban, Mute) **Requires Administrator server permission.** | `.antiraid 5 20 Kick`
`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. **Requires Administrator server permission.** | `.antispam 3 Mute` or `.antispam 4 Kick` or `.antispam 6 Ban`
`.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms` `.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms`
`.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd` `.delmsgoncmd` | Toggles the automatic deletion of user's successful command message to prevent chat flood. **Requires Administrator server permission.** | `.delmsgoncmd`
`.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest` `.setrole` `.sr` | Sets a role for a given user. **Requires ManageRoles server permission.** | `.sr @User Guest`
@ -93,7 +88,6 @@ Command and aliases | Description | Usage
`.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic` `.settopic` `.st` | Sets a topic on the current channel. **Requires ManageChannels server permission.** | `.st My new topic`
`.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName` `.setchanlname` `.schn` | Changes the name of the current channel. **Requires ManageChannels server permission.** | `.schn NewName`
`.prune` `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X` `.prune` `.clr` | `.prune` removes all nadeko's messages in the last 100 messages.`.prune X` removes last X messages from the channel (up to 100)`.prune @Someone` removes all Someone's messages in the last 100 messages.`.prune @Someone X` removes last X 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150`
`.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName` `.mentionrole` `.menro` | Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. **Requires MentionEveryone server permission.** | `.menro RoleName`
`.donators` | List of lovely people who donated to keep this project alive. | `.donators` `.donators` | List of lovely people who donated to keep this project alive. | `.donators`
`.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount` `.donadd` | Add a donator to the database. **Bot Owner only.** | `.donadd Donate Amount`
@ -365,9 +359,16 @@ Command and aliases | Description | Usage
`..` | Adds a new quote with the specified name and message. | `.. sayhi Hi` `..` | Adds a new quote with the specified name and message. | `.. sayhi Hi`
`.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc` `.deletequote` `.delq` | Deletes a random quote with the specified keyword. You have to either be server Administrator or the creator of the quote to delete it. | `.delq abc`
`.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek` `.delallq` `.daq` | Deletes all quotes on a specified keyword. **Requires Administrator server permission.** | `.delallq kek`
`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1`
`.repeatremove` `.reprm` | Removes a repeating message on a specified index. Use `.repeatlist` to see indexes. **Requires ManageMessages server permission.** | `.reprm 2`
`.repeat` | Repeat a message every X minutes in the current channel. You can have up to 5 repeating messages on the server in total. **Requires ManageMessages server permission.** | `.repeat 5 Hello there`
`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist`
`.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server` `.serverinfo` `.sinfo` | Shows info about the server the bot is on. If no channel is supplied, it defaults to current one. | `.sinfo Some Server`
`.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel` `.channelinfo` `.cinfo` | Shows info about the channel. If no channel is supplied, it defaults to current one. | `.cinfo #some-channel`
`.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser` `.userinfo` `.uinfo` | Shows info about the user. If no user is supplied, it defaults a user running the command. | `.uinfo @SomeUser`
`.scsc` | Starts an instance of cross server channel. You will get a token as a DM that other people will use to tune in to the same instance. **Bot Owner only.** | `.scsc`
`.jcsc` | Joins current channel to an instance of cross server channel using the token. **Requires ManageServer server permission.** | `.jcsc TokenHere`
`.lcsc` | Leaves Cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc`
`.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1` `.calculate` `.calc` | Evaluate a mathematical expression. | `.calc 1+1`
`.calcops` | Shows all available operations in .calc command | `.calcops` `.calcops` | Shows all available operations in .calc command | `.calcops`
`.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole` `.rotaterolecolor` `.rrc` | Rotates a roles color on an interval with a list of supplied colors. First argument is interval in seconds (Minimum 60). Second argument is a role, followed by a space-separated list of colors in hex. Provide a rolename with a 0 interval to disable. **Bot Owner only.** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole`
@ -384,4 +385,5 @@ Command and aliases | Description | Usage
`.stats` | Shows some basic stats for Nadeko. | `.stats` `.stats` | Shows some basic stats for Nadeko. | `.stats`
`.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis` `.showemojis` `.se` | Shows a name and a link to every SPECIAL emoji in the message. | `.se A message full of SPECIAL emojis`
`.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3` `.listservers` | Lists servers the bot is on with some basic info. 15 per page. **Bot Owner only.** | `.listservers 3`
`.savechat` | Saves a number of messages to a text file and sends it to you. **Bot Owner only.** | `.savechat 150`
`.activity` | Checks for spammers. **Bot Owner only.** | `.activity` `.activity` | Checks for spammers. **Bot Owner only.** | `.activity`

View File

@ -48,9 +48,6 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
GOTO :end GOTO :end
:backupinstall :backupinstall
TITLE Backing up old files TITLE Backing up old files
ECHO.
ECHO Make sure to close any files such as NadekoBot.db before PRESSing ANY KEY TO CONTINUE to prevent data loss
PAUSE >nul 2>&1
::Recursively copies all files and folders from NadekoBot to NadekoBot_Old ::Recursively copies all files and folders from NadekoBot to NadekoBot_Old
ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)

View File

@ -48,9 +48,6 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
GOTO :end GOTO :end
:backupinstall :backupinstall
TITLE Backing up old files TITLE Backing up old files
ECHO.
ECHO Make sure to close any files such as NadekoBot.db before PRESSing ANY KEY TO CONTINUE to prevent data loss
PAUSE >nul 2>&1
::Recursively copies all files and folders from NadekoBot to NadekoBot_Old ::Recursively copies all files and folders from NadekoBot to NadekoBot_Old
ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1 ROBOCOPY "%root%NadekoBot" "%root%NadekoBot_Old" /MIR >nul 2>&1
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror) IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)

View File

@ -27,12 +27,8 @@ namespace NadekoBot.Modules.Administration
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
using (var uow = DbHandler.UnitOfWork()) RotatingStatusMessages = NadekoBot.BotConfig.RotatingStatusMessages;
{ RotatingStatuses = NadekoBot.BotConfig.RotatingStatuses;
var conf = uow.BotConfig.GetOrCreate();
RotatingStatusMessages = conf.RotatingStatusMessages;
RotatingStatuses = conf.RotatingStatuses;
}
var t = Task.Run(async () => var t = Task.Run(async () =>
{ {

View File

@ -77,7 +77,7 @@ namespace NadekoBot.Modules.Gambling
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
animals = new ConcurrentQueue<string>(uow.BotConfig.GetOrCreate().RaceAnimals.Select(ra => ra.Icon).Shuffle()); animals = new ConcurrentQueue<string>(NadekoBot.BotConfig.RaceAnimals.Select(ra => ra.Icon).Shuffle());
} }
@ -248,7 +248,7 @@ namespace NadekoBot.Modules.Gambling
if (amount > 0) if (amount > 0)
if (!await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)u, "BetRace", amount, false).ConfigureAwait(false)) if (!await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)u, "BetRace", amount, false).ConfigureAwait(false))
{ {
try { await raceChannel.SendErrorAsync($"{u.Mention} You don't have enough {Gambling.CurrencyName}s.").ConfigureAwait(false); } catch { } try { await raceChannel.SendErrorAsync($"{u.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); } catch { }
return; return;
} }
participants.Add(p); participants.Add(p);

View File

@ -55,14 +55,14 @@ namespace NadekoBot.Modules.Gambling
if (amount < 3) if (amount < 3)
{ {
await Context.Channel.SendErrorAsync($"You can't bet less than 3{Gambling.CurrencySign}.") await Context.Channel.SendErrorAsync($"You can't bet less than 3{CurrencySign}.")
.ConfigureAwait(false); .ConfigureAwait(false);
return; return;
} }
var removed = await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betflip Gamble", amount, false).ConfigureAwait(false); var removed = await CurrencyHandler.RemoveCurrencyAsync(Context.User, "Betflip Gamble", amount, false).ConfigureAwait(false);
if (!removed) if (!removed)
{ {
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {Gambling.CurrencyPluralName}.").ConfigureAwait(false); await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false);
return; return;
} }
//heads = true //heads = true
@ -85,7 +85,7 @@ namespace NadekoBot.Modules.Gambling
if (isHeads == result) if (isHeads == result)
{ {
var toWin = (int)Math.Round(amount * 1.8); var toWin = (int)Math.Round(amount * 1.8);
str = $"{Context.User.Mention}`You guessed it!` You won {toWin}{Gambling.CurrencySign}"; str = $"{Context.User.Mention}`You guessed it!` You won {toWin}{CurrencySign}";
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false);
} }
else else

View File

@ -20,14 +20,9 @@ namespace NadekoBot.Modules.Gambling
static Gambling() static Gambling()
{ {
using (var uow = DbHandler.UnitOfWork()) CurrencyName = NadekoBot.BotConfig.CurrencyName;
{ CurrencyPluralName = NadekoBot.BotConfig.CurrencyPluralName;
var conf = uow.BotConfig.GetOrCreate(); CurrencySign = NadekoBot.BotConfig.CurrencySign;
CurrencyName = conf.CurrencyName;
CurrencySign = conf.CurrencySign;
CurrencyPluralName = conf.CurrencyPluralName;
}
} }
public static long GetCurrency(ulong id) public static long GetCurrency(ulong id)
@ -75,11 +70,11 @@ namespace NadekoBot.Modules.Gambling
var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, true).ConfigureAwait(false); var success = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Gift to {receiver.Username} ({receiver.Id}).", amount, true).ConfigureAwait(false);
if (!success) if (!success)
{ {
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {Gambling.CurrencyPluralName}.").ConfigureAwait(false); await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}.").ConfigureAwait(false);
return; return;
} }
await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync(receiver, $"Gift from {Context.User.Username} ({Context.User.Id}).", amount, true).ConfigureAwait(false);
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to {receiver.Mention}!").ConfigureAwait(false); await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully sent {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to {receiver.Mention}!").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -99,7 +94,7 @@ namespace NadekoBot.Modules.Gambling
await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync(usrId, $"Awarded by bot owner. ({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false);
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false); await Context.Channel.SendConfirmAsync($"{Context.User.Mention} awarded {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} to <@{usrId}>!").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -117,7 +112,7 @@ namespace NadekoBot.Modules.Gambling
amount))) amount)))
.ConfigureAwait(false); .ConfigureAwait(false);
await Context.Channel.SendConfirmAsync($"Awarded `{amount}` {Gambling.CurrencyPluralName} to `{users.Count}` users from `{role.Name}` role.") await Context.Channel.SendConfirmAsync($"Awarded `{amount}` {CurrencyPluralName} to `{users.Count}` users from `{role.Name}` role.")
.ConfigureAwait(false); .ConfigureAwait(false);
} }
@ -131,9 +126,9 @@ namespace NadekoBot.Modules.Gambling
return; return;
if (await CurrencyHandler.RemoveCurrencyAsync(user, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount, true).ConfigureAwait(false)) if (await CurrencyHandler.RemoveCurrencyAsync(user, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount, true).ConfigureAwait(false))
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from {user}!").ConfigureAwait(false); await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user}!").ConfigureAwait(false);
else else
await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from {user} because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false); await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from {user} because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false);
} }
@ -145,9 +140,9 @@ namespace NadekoBot.Modules.Gambling
return; return;
if (await CurrencyHandler.RemoveCurrencyAsync(usrId, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false)) if (await CurrencyHandler.RemoveCurrencyAsync(usrId, $"Taken by bot owner.({Context.User.Username}/{Context.User.Id})", amount).ConfigureAwait(false))
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from <@{usrId}>!").ConfigureAwait(false); await Context.Channel.SendConfirmAsync($"{Context.User.Mention} successfully took {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from <@{usrId}>!").ConfigureAwait(false);
else else
await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? Gambling.CurrencyName : Gambling.CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {Gambling.CurrencyPluralName}!").ConfigureAwait(false); await Context.Channel.SendErrorAsync($"{Context.User.Mention} was unable to take {amount} {(amount == 1 ? CurrencyName : CurrencyPluralName)} from `{usrId}` because the user doesn't have that much {CurrencyPluralName}!").ConfigureAwait(false);
} }
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
@ -164,7 +159,7 @@ namespace NadekoBot.Modules.Gambling
if (userFlowers < amount) if (userFlowers < amount)
{ {
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {Gambling.CurrencyPluralName}. You only have {userFlowers}{Gambling.CurrencySign}.").ConfigureAwait(false); await Context.Channel.SendErrorAsync($"{Context.User.Mention} You don't have enough {CurrencyPluralName}. You only have {userFlowers}{CurrencySign}.").ConfigureAwait(false);
return; return;
} }
@ -178,17 +173,17 @@ namespace NadekoBot.Modules.Gambling
} }
else if (rng < 91) else if (rng < 91)
{ {
str += $"Congratulations! You won {amount * 2}{Gambling.CurrencySign} for rolling above 66"; str += $"Congratulations! You won {amount * 2}{CurrencySign} for rolling above 66";
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 2, false).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 2, false).ConfigureAwait(false);
} }
else if (rng < 100) else if (rng < 100)
{ {
str += $"Congratulations! You won {amount * 3}{Gambling.CurrencySign} for rolling above 90."; str += $"Congratulations! You won {amount * 3}{CurrencySign} for rolling above 90.";
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 3, false).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 3, false).ConfigureAwait(false);
} }
else else
{ {
str += $"👑 Congratulations! You won {amount * 10}{Gambling.CurrencySign} for rolling **100**. 👑"; str += $"👑 Congratulations! You won {amount * 10}{CurrencySign} for rolling **100**. 👑";
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 10, false).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync(Context.User, "Betroll Gamble", amount * 10, false).ConfigureAwait(false);
} }

View File

@ -38,32 +38,17 @@ namespace NadekoBot.Modules.Games
private static ConcurrentHashSet<ulong> usersRecentlyPicked { get; } = new ConcurrentHashSet<ulong>(); private static ConcurrentHashSet<ulong> usersRecentlyPicked { get; } = new ConcurrentHashSet<ulong>();
private static float chance { get; }
private static int cooldown { get; }
private static Logger _log { get; } private static Logger _log { get; }
static PlantPickCommands() static PlantPickCommands()
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
var sw = Stopwatch.StartNew();
#if !GLOBAL_NADEKO #if !GLOBAL_NADEKO
NadekoBot.Client.MessageReceived += PotentialFlowerGeneration; NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
#endif #endif
using (var uow = DbHandler.UnitOfWork())
{
var conf = uow.BotConfig.GetOrCreate();
var x =
generationChannels = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs generationChannels = new ConcurrentHashSet<ulong>(NadekoBot.AllGuildConfigs
.SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId))); .SelectMany(c => c.GenerateCurrencyChannelIds.Select(obj => obj.ChannelId)));
chance = conf.CurrencyGenerationChance;
cooldown = conf.CurrencyGenerationCooldown;
}
sw.Stop();
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
} }
private static async void PotentialFlowerGeneration(SocketMessage imsg) private static async void PotentialFlowerGeneration(SocketMessage imsg)
@ -84,10 +69,10 @@ namespace NadekoBot.Modules.Games
var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue); var lastGeneration = lastGenerations.GetOrAdd(channel.Id, DateTime.MinValue);
var rng = new NadekoRandom(); var rng = new NadekoRandom();
if (DateTime.Now - TimeSpan.FromSeconds(cooldown) < lastGeneration) //recently generated in this channel, don't generate again if (DateTime.Now - TimeSpan.FromSeconds(NadekoBot.BotConfig.CurrencyGenerationCooldown) < lastGeneration) //recently generated in this channel, don't generate again
return; return;
var num = rng.Next(1, 101) + chance * 100; var num = rng.Next(1, 101) + NadekoBot.BotConfig.CurrencyGenerationChance * 100;
if (num > 100) if (num > 100)
{ {
@ -96,7 +81,7 @@ namespace NadekoBot.Modules.Games
var sent = await channel.SendFileAsync( var sent = await channel.SendFileAsync(
File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate), File.Open(GetRandomCurrencyImagePath(), FileMode.OpenOrCreate),
"RandomFlower.jpg", "RandomFlower.jpg",
$"❗ A random { Gambling.Gambling.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`") $"❗ A random { NadekoBot.BotConfig.CurrencyName } appeared! Pick it up by typing `{NadekoBot.ModulePrefixes[typeof(Games).Name]}pick`")
.ConfigureAwait(false); .ConfigureAwait(false);
plantedFlowers.AddOrUpdate(channel.Id, new List<IUserMessage>() { sent }, (id, old) => { old.Add(sent); return old; }); plantedFlowers.AddOrUpdate(channel.Id, new List<IUserMessage>() { sent }, (id, old) => { old.Add(sent); return old; });
@ -129,8 +114,8 @@ namespace NadekoBot.Modules.Games
await Task.WhenAll(msgs.Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false); await Task.WhenAll(msgs.Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {Gambling.Gambling.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false); await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.CurrencyPluralName}", msgs.Count, false).ConfigureAwait(false);
var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{Gambling.Gambling.CurrencySign}!").ConfigureAwait(false); var msg = await channel.SendConfirmAsync($"**{Context.User}** picked {msgs.Count}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false);
msg.DeleteAfter(10); msg.DeleteAfter(10);
} }
finally finally
@ -146,21 +131,21 @@ namespace NadekoBot.Modules.Games
[RequireContext(ContextType.Guild)] [RequireContext(ContextType.Guild)]
public async Task Plant() public async Task Plant()
{ {
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {Gambling.Gambling.CurrencyName}", 1, false).ConfigureAwait(false); var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", 1, false).ConfigureAwait(false);
if (!removed) if (!removed)
{ {
await Context.Channel.SendErrorAsync($"You don't have any {Gambling.Gambling.CurrencyPluralName}.").ConfigureAwait(false); await Context.Channel.SendErrorAsync($"You don't have any {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false);
return; return;
} }
var file = GetRandomCurrencyImagePath(); var file = GetRandomCurrencyImagePath();
IUserMessage msg; IUserMessage msg;
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(Gambling.Gambling.CurrencyName[0]); var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(vowelFirst ? "an" : "a")} {Gambling.Gambling.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick"; var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.BotConfig.CurrencyName}. Pick it using {NadekoBot.ModulePrefixes[typeof(Games).Name]}pick";
if (file == null) if (file == null)
{ {
msg = await Context.Channel.SendConfirmAsync(Gambling.Gambling.CurrencySign).ConfigureAwait(false); msg = await Context.Channel.SendConfirmAsync(NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
} }
else else
{ {

View File

@ -13,14 +13,7 @@ namespace NadekoBot.Modules.Games
[NadekoModule("Games", ">")] [NadekoModule("Games", ">")]
public partial class Games : DiscordModule public partial class Games : DiscordModule
{ {
private IEnumerable<string> _8BallResponses { private static IEnumerable<string> _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text);
get {
using (var uow = DbHandler.UnitOfWork())
{
return uow.BotConfig.GetOrCreate().EightBallResponses.Select(ebr => ebr.Text);
}
}
}
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]

View File

@ -15,26 +15,10 @@ namespace NadekoBot.Modules.Help
[NadekoModule("Help", "-")] [NadekoModule("Help", "-")]
public partial class Help : DiscordModule public partial class Help : DiscordModule
{ {
private static string helpString { get; } private static string helpString { get; } = NadekoBot.BotConfig.HelpString;
public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]); public static string HelpString => String.Format(helpString, NadekoBot.Credentials.ClientId, NadekoBot.ModulePrefixes[typeof(Help).Name]);
public static string DMHelpString { get; } public static string DMHelpString { get; } = NadekoBot.BotConfig.DMHelpString;
static Help()
{
//todo don't cache this, just query db when someone wants -h
using (var uow = DbHandler.UnitOfWork())
{
var config = uow.BotConfig.GetOrCreate();
helpString = config.HelpString;
DMHelpString = config.DMHelpString;
}
}
public Help() : base()
{
}
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
public async Task Modules() public async Task Modules()

View File

@ -12,7 +12,6 @@ using System;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.IO; using System.IO;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using static NadekoBot.Modules.Gambling.Gambling;
namespace NadekoBot.Modules.Pokemon namespace NadekoBot.Modules.Pokemon
{ {
@ -254,7 +253,7 @@ namespace NadekoBot.Modules.Pokemon
{ {
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false)) if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"Poke-Heal {target}", amount, true).ConfigureAwait(false))
{ {
try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {CurrencyName}s.").ConfigureAwait(false); } catch { } try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { }
return; return;
} }
} }
@ -267,15 +266,15 @@ namespace NadekoBot.Modules.Pokemon
Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2); Stats[targetUser.Id].Hp = (targetStats.MaxHp / 2);
if (target == "yourself") if (target == "yourself")
{ {
await Context.Channel.SendMessageAsync($"You revived yourself with one {CurrencySign}").ConfigureAwait(false); await Context.Channel.SendMessageAsync($"You revived yourself with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
} }
else else
{ {
await Context.Channel.SendMessageAsync($"{user.Mention} revived {targetUser.Mention} with one {CurrencySign}").ConfigureAwait(false); await Context.Channel.SendMessageAsync($"{user.Mention} revived {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
} }
return; return;
} }
await Context.Channel.SendMessageAsync($"{user.Mention} healed {targetUser.Mention} with one {CurrencySign}").ConfigureAwait(false); await Context.Channel.SendMessageAsync($"{user.Mention} healed {targetUser.Mention} with one {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
return; return;
} }
else else
@ -329,7 +328,7 @@ namespace NadekoBot.Modules.Pokemon
{ {
if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user.Mention} change type to {typeTargeted}", amount, true).ConfigureAwait(false)) if (!await CurrencyHandler.RemoveCurrencyAsync(user, $"{user.Mention} change type to {typeTargeted}", amount, true).ConfigureAwait(false))
{ {
try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {CurrencyName}s.").ConfigureAwait(false); } catch { } try { await Context.Channel.SendMessageAsync($"{user.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyName}s.").ConfigureAwait(false); } catch { }
return; return;
} }
} }
@ -362,7 +361,7 @@ namespace NadekoBot.Modules.Pokemon
} }
//Now for the response //Now for the response
await Context.Channel.SendMessageAsync($"Set type of {user.Mention} to {typeTargeted}{targetType.Icon} for a {CurrencySign}").ConfigureAwait(false); await Context.Channel.SendMessageAsync($"Set type of {user.Mention} to {typeTargeted}{targetType.Icon} for a {NadekoBot.BotConfig.CurrencySign}").ConfigureAwait(false);
} }
} }

View File

@ -40,9 +40,8 @@ namespace NadekoBot.Modules.Utility
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
reminders = uow.Reminders.GetAll().ToList(); reminders = uow.Reminders.GetAll().ToList();
RemindMessageFormat = uow.BotConfig.GetOrCreate().RemindMessageFormat;
} }
RemindMessageFormat = NadekoBot.BotConfig.RemindMessageFormat;
foreach (var r in reminders) foreach (var r in reminders)
{ {

View File

@ -281,7 +281,7 @@ namespace NadekoBot.Modules.Utility
.AddField(efb => efb.WithName(Format.Bold("Commands Ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Commands Ran")).WithValue(stats.CommandsRan.ToString()).WithIsInline(true))
.AddField(efb => efb.WithName(Format.Bold("Messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Messages")).WithValue($"{stats.MessageCounter} ({stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
.AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Memory")).WithValue($"{stats.Heap} MB").WithIsInline(true))
.AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(stats.OwnerIds).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Owner ID(s)")).WithValue(string.Join("\n", NadekoBot.Credentials.OwnerIds)).WithIsInline(true))
.AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Uptime")).WithValue(stats.GetUptimeString("\n")).WithIsInline(true))
.AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildsCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true)) .AddField(efb => efb.WithName(Format.Bold("Presence")).WithValue($"{NadekoBot.Client.GetGuildsCount()} Servers\n{stats.TextChannels} Text Channels\n{stats.VoiceChannels} Voice Channels").WithIsInline(true))
#if !GLOBAL_NADEKO #if !GLOBAL_NADEKO

View File

@ -38,6 +38,7 @@ namespace NadekoBot
public static bool Ready { get; private set; } public static bool Ready { get; private set; }
public static IEnumerable<GuildConfig> AllGuildConfigs { get; } public static IEnumerable<GuildConfig> AllGuildConfigs { get; }
public static BotConfig BotConfig { get; }
static NadekoBot() static NadekoBot()
{ {
@ -47,6 +48,7 @@ namespace NadekoBot
using (var uow = DbHandler.UnitOfWork()) using (var uow = DbHandler.UnitOfWork())
{ {
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(); AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs();
BotConfig = uow.BotConfig.GetOrCreate();
} }
} }
@ -98,10 +100,9 @@ namespace NadekoBot
_log.Info("Connected"); _log.Info("Connected");
//load commands and prefixes //load commands and prefixes
using (var uow = DbHandler.UnitOfWork())
{ ModulePrefixes = new ConcurrentDictionary<string, string>(NadekoBot.BotConfig.ModulePrefixes.OrderByDescending(mp => mp.Prefix.Length).ToDictionary(m => m.ModuleName, m => m.Prefix));
ModulePrefixes = new ConcurrentDictionary<string, string>(uow.BotConfig.GetOrCreate().ModulePrefixes.OrderByDescending(mp => mp.Prefix.Length).ToDictionary(m => m.ModuleName, m => m.Prefix));
}
// start handling messages received in commandhandler // start handling messages received in commandhandler
await CommandHandler.StartHandling().ConfigureAwait(false); await CommandHandler.StartHandling().ConfigureAwait(false);

View File

@ -14,7 +14,7 @@ namespace NadekoBot.Services
var success = await RemoveCurrencyAsync(author.Id, reason, amount); var success = await RemoveCurrencyAsync(author.Id, reason, amount);
if (success && sendMessage) if (success && sendMessage)
try { await author.SendErrorAsync($"`You lost:` {amount} {Gambling.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } try { await author.SendErrorAsync($"`You lost:` {amount} {NadekoBot.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { }
return success; return success;
} }
@ -47,7 +47,7 @@ namespace NadekoBot.Services
await AddCurrencyAsync(author.Id, reason, amount); await AddCurrencyAsync(author.Id, reason, amount);
if (sendMessage) if (sendMessage)
try { await author.SendConfirmAsync($"`You received:` {amount} {Gambling.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { } try { await author.SendConfirmAsync($"`You received:` {amount} {NadekoBot.BotConfig.CurrencySign}\n`Reason:` {reason}").ConfigureAwait(false); } catch { }
} }
public static async Task AddCurrencyAsync(ulong receiverId, string reason, long amount) public static async Task AddCurrencyAsync(ulong receiverId, string reason, long amount)

View File

@ -27,7 +27,6 @@ namespace NadekoBot.Services.Impl
public int TextChannels => _textChannels; public int TextChannels => _textChannels;
private int _voiceChannels = 0; private int _voiceChannels = 0;
public int VoiceChannels => _voiceChannels; public int VoiceChannels => _voiceChannels;
public string OwnerIds => string.Join(", ", NadekoBot.Credentials.OwnerIds);
Timer carbonitexTimer { get; } Timer carbonitexTimer { get; }
@ -111,7 +110,7 @@ namespace NadekoBot.Services.Impl
Author: [{Author}] | Library: [{Library}] Author: [{Author}] | Library: [{Library}]
Bot Version: [{BotVersion}] Bot Version: [{BotVersion}]
Bot ID: {curUser.Id} Bot ID: {curUser.Id}
Owner ID(s): {OwnerIds} Owner ID(s): {string.Join(", ", NadekoBot.Credentials.OwnerIds)}
Uptime: {GetUptimeString()} Uptime: {GetUptimeString()}
Servers: {client.GetGuildsCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels} Servers: {client.GetGuildsCount()} | TextChannels: {TextChannels} | VoiceChannels: {VoiceChannels}
Commands Ran this session: {CommandsRan} Commands Ran this session: {CommandsRan}