commit
1c55e3b5b2
16
README.md
16
README.md
@ -1,14 +1,12 @@
|
|||||||
![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true)
|
![img](https://ci.appveyor.com/api/projects/status/gmu6b3ltc80hr3k9?svg=true)
|
||||||
[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot)
|
[![Discord](https://discordapp.com/api/guilds/117523346618318850/widget.png)](https://discord.gg/nadekobot)
|
||||||
[![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest)
|
[![Documentation Status](https://readthedocs.org/projects/nadekobot/badge/?version=latest)](http://nadekobot.readthedocs.io/en/latest/?badge=latest)
|
||||||
# NadekoBot
|
[![nadeko0](https://cdn.discordapp.com/attachments/266240393639755778/281920716809699328/part1.png)](http://nadekobot.xyz)
|
||||||
[![nadeko1](https://cdn.discordapp.com/attachments/155726317222887425/252095170676391936/A1.jpg)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
|
[![nadeko1](https://cdn.discordapp.com/attachments/266240393639755778/281920134967328768/part2.png)](https://discordapp.com/oauth2/authorize?client_id=170254782546575360&scope=bot&permissions=66186303)
|
||||||
[![nadeko2](https://cdn.discordapp.com/attachments/155726317222887425/252095207514832896/A2.jpg)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/)
|
[![nadeko2](https://cdn.discordapp.com/attachments/266240393639755778/281920161311883264/part3.png)](http://nadekobot.readthedocs.io/en/latest/Commands%20List/)
|
||||||
|
|
||||||
##For Update, Help and Guidlines
|
|
||||||
|
|
||||||
`Follow me on twitter for updates. | Join my Discord server if you need help. | Read the Docs for hosting guides.`
|
|
||||||
|
|
||||||
[![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) [![discord](https://cdn.discordapp.com/attachments/155726317222887425/252192415673221122/discord_banner.JPG)](https://discord.gg/nadekobot) [![Wiki](https://cdn.discordapp.com/attachments/155726317222887425/252192472849973250/read_the_docs_banner.JPG)](http://nadekobot.readthedocs.io/en/latest/)
|
|
||||||
|
|
||||||
|
## For Updates, Help and Guidelines
|
||||||
|
|
||||||
|
| [![twitter](https://cdn.discordapp.com/attachments/155726317222887425/252192520094613504/twiter_banner.JPG)](https://twitter.com/TheNadekoBot) | [![discord](https://cdn.discordapp.com/attachments/266240393639755778/281920766490968064/discord.png)](https://discord.gg/nadekobot) | [![Wiki](https://cdn.discordapp.com/attachments/266240393639755778/281920793330581506/datcord.png)](http://nadekobot.readthedocs.io/en/latest/)
|
||||||
|
| --- | --- | --- |
|
||||||
|
| **Follow me on Twitter.** | **Join my Discord server for help.** | **Read the Docs for self-hosting.** |
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: <https://www.paypal.me/Kwoth>
|
You can support the project on patreon: <https://patreon.com/nadekobot> or paypal: <https://paypal.me/Kwoth>
|
||||||
|
|
||||||
##Table Of Contents
|
##Table of contents
|
||||||
- [Help](#help)
|
- [Help](#help)
|
||||||
- [Administration](#administration)
|
- [Administration](#administration)
|
||||||
- [ClashOfClans](#clashofclans)
|
- [ClashOfClans](#clashofclans)
|
||||||
@ -16,19 +16,18 @@ You can support the project on patreon: <https://patreon.com/nadekobot> or paypa
|
|||||||
|
|
||||||
|
|
||||||
### Administration
|
### Administration
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`.resetperms` | Resets BOT's permissions module on this server to the default value. **Requires Administrator server permission.** | `.resetperms`
|
`.resetperms` | Resets the 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`
|
`.resetglobalperms` | Resets global permissions set by bot owner. **Bot owner only** | `.resetglobalperms`
|
||||||
|
`.delmsgoncmd` | Toggles the automatic deletion of the 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`
|
||||||
`.removerole` `.rr` | Removes a role from a given user. **Requires ManageRoles server permission.** | `.rr @User Admin`
|
`.removerole` `.rr` | Removes a role from a given user. **Requires ManageRoles server permission.** | `.rr @User Admin`
|
||||||
`.renamerole` `.renr` | Renames a role. Roles you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole`
|
`.renamerole` `.renr` | Renames a role. The role you are renaming must be lower than bot's highest role. **Requires ManageRoles server permission.** | `.renr "First role" SecondRole`
|
||||||
`.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User`
|
`.removeallroles` `.rar` | Removes all roles from a mentioned user. **Requires ManageRoles server permission.** | `.rar @User`
|
||||||
`.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role`
|
`.createrole` `.cr` | Creates a role with a given name. **Requires ManageRoles server permission.** | `.cr Awesome Role`
|
||||||
|
`.rolehoist` `.rh` | Toggles if this role is displayed in the sidebar or not **Requires ManageRoles server permission.** | `.rh Guests true` or `.rh "Space Wizards" true
|
||||||
`.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55`
|
`.rolecolor` `.rc` | Set a role's color to the hex or 0-255 rgb color value provided. **Requires ManageRoles server permission.** | `.rc Admin 255 200 100` or `.rc Admin ffba55`
|
||||||
`.ban` `.b` | Bans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.b "@some Guy" Your behaviour is toxic.`
|
|
||||||
`.softban` `.sb` | Bans and then unbans a user by ID or name with an optional message. **Requires KickMembers server permission.** **Requires ManageMessages server permission.** | `.sb "@some Guy" Your behaviour is toxic.`
|
|
||||||
`.kick` `.k` | Kicks a mentioned user. **Requires KickMembers server permission.** | `.k "@some Guy" Your behaviour is toxic.`
|
|
||||||
`.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"`
|
`.deafen` `.deaf` | Deafens mentioned user or users. **Requires DeafenMembers server permission.** | `.deaf "@Someguy"` or `.deaf "@Someguy" "@Someguy"`
|
||||||
`.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"`
|
`.undeafen` `.undef` | Undeafens mentioned user or users. **Requires DeafenMembers server permission.** | `.undef "@Someguy"` or `.undef "@Someguy" "@Someguy"`
|
||||||
`.delvoichanl` `.dvch` | Deletes a voice channel with a given name. **Requires ManageChannels server permission.** | `.dvch VoiceChannelName`
|
`.delvoichanl` `.dvch` | Deletes a voice channel with a given name. **Requires ManageChannels server permission.** | `.dvch VoiceChannelName`
|
||||||
@ -37,70 +36,92 @@ Command and aliases | Description | Usage
|
|||||||
`.creatxtchanl` `.ctch` | Creates a new text channel with a given name. **Requires ManageChannels server permission.** | `.ctch TextChannelName`
|
`.creatxtchanl` `.ctch` | Creates a new text channel with a given name. **Requires ManageChannels server permission.** | `.ctch TextChannelName`
|
||||||
`.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` number of 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` number of 'Someone's' messages in the channel. | `.prune` or `.prune 5` or `.prune @Someone` or `.prune @Someone X`
|
||||||
`.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 MentionEveryone server permission.** | `.menro RoleName`
|
||||||
`.donators` | List of lovely people who donated to keep this project alive. | `.donators`
|
`.donators` | List of the 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`
|
||||||
`.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
|
||||||
`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot Owner only.** | `.fwmsgs`
|
`.gvc` | Toggles game voice channel feature in the voice channel you're currently in. Users who join the game voice channel will get automatically redirected to the voice channel with the name of their current game, if it exists. Can't move users to channels that the bot has no connect permission for. One per server. **Requires Administrator server permission.** | `.gvc`
|
||||||
`.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`
|
`.languageset` `.langset` | Sets this server's response language. If bot's response strings have been translated to that language, bot will use that language in this server. Reset by using `default` as the locale name. Provide no arguments to see currently set language. | `.langset de-DE ` or `.langset default`
|
||||||
`.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`
|
`.langsetdefault` `.langsetd` | Sets the bot's default response language. All servers which use a default locale will use this one. Setting to `default` will use the host's current culture. Provide no arguments to see currently set language. | `.langsetd en-US` or `.langsetd default`
|
||||||
`.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`
|
`.languageslist` `.langli` | List of languages for which translation (or part of it) exist atm. | `.langli`
|
||||||
`.logevents` | Shows a list of all events you can subscribe to with `.log` **Requires Administrator server permission.** **Bot Owner only.** | `.logevents`
|
`.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`
|
||||||
`.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`
|
`.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`
|
||||||
`.migratedata` | Migrate data from old bot configuration **Bot Owner only.** | `.migratedata`
|
`.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 is active anywhere on the server. Enables if it isn't 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`
|
||||||
|
`.migratedata` | Migrate data from old bot configuration **Bot owner only** | `.migratedata`
|
||||||
`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced`
|
`.setmuterole` | Sets a name of the role which will be assigned to people who should be muted. Default is nadeko-mute. **Requires ManageRoles server permission.** | `.setmuterole Silenced`
|
||||||
`.mute` | Mutes a mentioned user both from speaking and chatting. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone`
|
`.mute` | Mutes a mentioned user both from speaking and chatting. You can also specify time in minutes (up to 1440) for how long the user should be muted. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.mute @Someone` or `.mute 30 @Someone`
|
||||||
`.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone`
|
`.unmute` | Unmutes a mentioned user previously muted with `.mute` command. **Requires ManageRoles server permission.** **Requires MuteMembers server permission.** | `.unmute @Someone`
|
||||||
`.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone`
|
`.chatmute` | Prevents a mentioned user from chatting in text channels. **Requires ManageRoles server permission.** | `.chatmute @Someone`
|
||||||
`.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone`
|
`.chatunmute` | Removes a mute role previously set on a mentioned user with `.chatmute` which prevented him from chatting in text channels. **Requires ManageRoles server permission.** | `.chatunmute @Someone`
|
||||||
`.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`
|
||||||
`.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%, %time%,%shardid%,%shardcount%, %shardguilds% **Bot Owner only.** | `.adpl`
|
`.addplaying` `.adpl` | Adds a specified string to the list of playing strings to rotate. Supported placeholders: `%servers%`, `%users%`, `%playing%`, `%queued%`, `%time%`, `%shardid%`, `%shardcount%`, `%shardguilds%`. **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`
|
||||||
`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot Owner only.** | `.rmpl`
|
`.removeplaying` `.rmpl` `.repl` | Removes a playing string on a given number. **Bot owner only** | `.rmpl`
|
||||||
`.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`
|
`.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`
|
`.antispam` | Stops people from repeating same message X times in a row. You can specify to either mute, kick or ban the offenders. Max message count is 10. **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`
|
`.antispamignore` | Toggles whether antispam ignores current channel. Antispam must be enabled. | `.antispamignore`
|
||||||
`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist`
|
`.antilist` `.antilst` | Shows currently enabled protection features. | `.antilist`
|
||||||
`.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`
|
||||||
`.adsarm` | Toggles the automatic deletion of confirmations for .iam and .iamn commands. **Requires ManageMessages server permission.** | `.adsarm`
|
`.slowmodewl` | Ignores a role or a user from the slowmode feature. **Requires ManageMessages server permission.** | `.slowmodewl SomeRole` or `.slowmodewl AdminDude`
|
||||||
|
`.adsarm` | Toggles the automatic deletion of confirmations for `.iam` and `.iamn` commands. **Requires ManageMessages server permission.** | `.adsarm`
|
||||||
`.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer`
|
`.asar` | Adds a role to the list of self-assignable roles. **Requires ManageRoles server permission.** | `.asar Gamer`
|
||||||
`.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar`
|
`.rsar` | Removes a specified role from the list of self-assignable roles. **Requires ManageRoles server permission.** | `.rsar`
|
||||||
`.lsar` | Lists all self-assignable roles. | `.lsar`
|
`.lsar` | Lists all self-assignable roles. | `.lsar`
|
||||||
`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar`
|
`.togglexclsar` `.tesar` | Toggles whether the self-assigned roles are exclusive. (So that any person can have only one of the self assignable roles) **Requires ManageRoles server permission.** | `.tesar`
|
||||||
`.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`
|
||||||
`.leave` | Makes Nadeko leave the server. Either name or id required. **Bot Owner only.** | `.leave 123123123331`
|
`.scadd` | Adds a command to the list of commands which will be executed automatically in the current channel, in the order they were added in, by the bot when it startups up. **Bot owner only** | `.scadd .stats`
|
||||||
`.die` | Shuts the bot down. **Bot Owner only.** | `.die`
|
`.sclist` | Lists all startup commands in the order they will be executed in. **Bot owner only** | `.sclist`
|
||||||
`.setname` `.newnm` | Gives the bot a new name. **Bot Owner only.** | `.newnm BotName`
|
`.wait` | Used only as a startup command. Waits a certain number of miliseconds before continuing the execution of the following startup commands. **Bot owner only** | `.wait 3000`
|
||||||
`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot Owner only.** | `.setstatus Idle`
|
`.scrm` | Removes a startup command with the provided command text. **Bot owner only** | `.scrm .stats`
|
||||||
`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner only.** | `.setav http://i.imgur.com/xTG3a1I.jpg`
|
`.scclr` | Removes all startup commands. **Bot owner only** | `.scclr`
|
||||||
`.setgame` | Sets the bots game. **Bot Owner only.** | `.setgame with snakes`
|
`.fwmsgs` | Toggles forwarding of non-command messages sent to bot's DM to the bot owners **Bot owner only** | `.fwmsgs`
|
||||||
`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot Owner only.** | `.setstream TWITCHLINK Hello`
|
`.fwtoall` | Toggles whether messages will be forwarded to all bot owners or only to the first one specified in the credentials.json file **Bot owner only** | `.fwtoall`
|
||||||
`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prepend channel id with `c:` and user id with `u:`. **Bot Owner only.** | `.send serverid|c:channelid message` or `.send serverid|u:userid message`
|
`.connectshard` | Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. **Bot owner only** | `.connectshard 2`
|
||||||
`.announce` | Sends a message to all servers' general channel bot is connected to. **Bot Owner only.** | `.announce Useless spam`
|
`.leave` | Makes Nadeko leave the server. Either server name or server ID is required. **Bot owner only** | `.leave 123123123331`
|
||||||
`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot Owner only.** | `.reloadimages`
|
`.die` | Shuts the bot down. **Bot owner only** | `.die`
|
||||||
`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30`
|
`.setname` `.newnm` | Gives the bot a new name. **Bot owner only** | `.newnm BotName`
|
||||||
|
`.setstatus` | Sets the bot's status. (Online/Idle/Dnd/Invisible) **Bot owner only** | `.setstatus Idle`
|
||||||
|
`.setavatar` `.setav` | Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot owner only** | `.setav http://i.imgur.com/xTG3a1I.jpg`
|
||||||
|
`.setgame` | Sets the bots game. **Bot owner only** | `.setgame with snakes`
|
||||||
|
`.setstream` | Sets the bots stream. First argument is the twitch link, second argument is stream name. **Bot owner only** | `.setstream TWITCHLINK Hello`
|
||||||
|
`.send` | Sends a message to someone on a different server through the bot. Separate server and channel/user ids with `|` and prefix the channel id with `c:` and the user id with `u:`. **Bot owner only** | `.send serverid|c:channelid message` or `.send serverid|u:userid message`
|
||||||
|
`.announce` | Sends a message to all servers' default channel that bot is connected to. **Bot owner only** | `.announce Useless spam`
|
||||||
|
`.reloadimages` | Reloads images bot is using. Safe to use even when bot is being used heavily. **Bot owner only** | `.reloadimages`
|
||||||
|
`.greetdel` `.grdel` | Sets the time it takes (in seconds) for greet messages to be auto-deleted. Set it to 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.greetdel 0` or `.greetdel 30`
|
||||||
`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet`
|
`.greet` | Toggles anouncements on the current channel when someone joins the server. **Requires ManageServer server permission.** | `.greet`
|
||||||
`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.`
|
`.greetmsg` | Sets a new join announcement message which will be shown in the server's channel. Type `%user%` if you want to mention the new member. Using it with no message will show the current greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetmsg Welcome, %user%.`
|
||||||
`.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm`
|
`.greetdm` | Toggles whether the greet messages will be sent in a DM (This is separate from greet - you can have both, any or neither enabled). **Requires ManageServer server permission.** | `.greetdm`
|
||||||
`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type %user% if you want to mention the new member. Using it with no message will show the current DM greet message. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`.
|
`.greetdmmsg` | Sets a new join announcement message which will be sent to the user who joined. Type `%user%` if you want to mention the new member. Using it with no message will show the current DM greet message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.greetdmmsg Welcome to the server, %user%`.
|
||||||
`.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye`
|
`.bye` | Toggles anouncements on the current channel when someone leaves the server. **Requires ManageServer server permission.** | `.bye`
|
||||||
`.byemsg` | Sets a new leave announcement message. Type %user% if you want to show the name the user who left. Type %id% to show id. Using this command with no message will show the current bye message. **Requires ManageServer server permission.** | `.byemsg %user% has left.`
|
`.byemsg` | Sets a new leave announcement message. Type `%user%` if you want to show the name the user who left. Type `%id%` to show id. Using this command with no message will show the current bye message. You can use embed json from <http://nadekobot.xyz/embedbuilder/> instead of a regular text, if you want the message to be embedded. **Requires ManageServer server permission.** | `.byemsg %user% has left.`
|
||||||
`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set 0 to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30`
|
`.byedel` | Sets the time it takes (in seconds) for bye messages to be auto-deleted. Set it to `0` to disable automatic deletion. **Requires ManageServer server permission.** | `.byedel 0` or `.byedel 30`
|
||||||
`.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see.If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t`
|
`.warn` | Warns a user. **Requires BanMembers server permission.** | `.warn @b1nzy Very rude person`
|
||||||
|
`.warnlog` | See a list of warnings of a certain user. **Requires BanMembers server permission.** | `.warnlog @b1nzy`
|
||||||
|
`.warnclear` `.warnc` | Clears all warnings from a certain user. **Requires BanMembers server permission.** | `.warnclear @PoorDude`
|
||||||
|
`.warnpunish` `.warnp` | Sets a punishment for a certain number of warnings. Provide no punishment to remove. **Requires BanMembers server permission.** | `.warnpunish 5 Ban` or `.warnpunish 3`
|
||||||
|
`.warnpunishlist` `.warnpl` | Lists punishments for warnings. | `.warnpunishlist`
|
||||||
|
`.ban` `.b` | Bans a user by ID or name with an optional message. **Requires BanMembers server permission.** | `.b "@some Guy" Your behaviour is toxic.`
|
||||||
|
`.unban` | Unbans a user with the provided user#discrim or id. **Requires BanMembers server permission.** | `.unban kwoth#1234` or `.unban 123123123`
|
||||||
|
`.softban` `.sb` | Bans and then unbans a user by ID or name with an optional message. **Requires KickMembers server permission.** **Requires ManageMessages server permission.** | `.sb "@some Guy" Your behaviour is toxic.`
|
||||||
|
`.kick` `.k` | Kicks a mentioned user. **Requires KickMembers server permission.** | `.k "@some Guy" Your behaviour is toxic.`
|
||||||
|
`.vcrole` | Sets or resets a role which will be given to users who join the voice channel you're in when you run this command. Provide no role name to disable. You must be in a voice channel to run this command. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.vcrole SomeRole` or `.vcrole`
|
||||||
|
`.vcrolelist` | Shows a list of currently set voice channel roles. | `.vcrolelist`
|
||||||
|
`.voice+text` `.v+t` | Creates a text channel for each voice channel only users in that voice channel can see. If you are server owner, keep in mind you will see them all the time regardless. **Requires ManageRoles server permission.** **Requires ManageChannels server permission.** | `.v+t`
|
||||||
`.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t`
|
`.cleanvplust` `.cv+t` | Deletes all text channels ending in `-voice` for which voicechannels are not found. Use at your own risk. **Requires ManageChannels server permission.** **Requires ManageRoles server permission.** | `.cleanv+t`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### ClashOfClans
|
### ClashOfClans
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`,createwar` `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | `,cw 15 The Enemy Clan`
|
`,createwar` `,cw` | Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. **Requires ManageMessages server permission.** | `,cw 15 The Enemy Clan`
|
||||||
`,startwar` `,sw` | Starts a war with a given number. | `,sw 15`
|
`,startwar` `,sw` | Starts a war with a given number. | `,sw 15`
|
||||||
`,listwar` `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `,lw [war_number] or ,lw`
|
`,listwar` `,lw` | Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `,lw [war_number]` or `,lw`
|
||||||
`,claim` `,call` `,c` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | `,call [war_number] [base_number] [optional_other_name]`
|
`,claim` `,call` `,c` | Claims a certain base from a certain war. You can supply a name in the third optional argument to claim in someone else's place. | `,call [war_number] [base_number] [optional_other_name]`
|
||||||
`,claimfinish1` `,cf1` | Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf1 1` or `,cf1 1 5`
|
`,claimfinish1` `,cf1` | Finish your claim with 1 star if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf1 1` or `,cf1 1 5`
|
||||||
`,claimfinish2` `,cf2` | Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf2 1` or `,cf2 1 5`
|
`,claimfinish2` `,cf2` | Finish your claim with 2 stars if you destroyed a base. First argument is the war number, optional second argument is a base number if you want to finish for someone else. | `,cf2 1` or `,cf2 1 5`
|
||||||
@ -108,61 +129,69 @@ Command and aliases | Description | Usage
|
|||||||
`,endwar` `,ew` | Ends the war with a given index. | `,ew [war_number]`
|
`,endwar` `,ew` | Ends the war with a given index. | `,ew [war_number]`
|
||||||
`,unclaim` `,ucall` `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `,uc [war_number] [optional_other_name]`
|
`,unclaim` `,ucall` `,uc` | Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `,uc [war_number] [optional_other_name]`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### CustomReactions
|
### CustomReactions
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`.addcustreact` `.acr` | Add a custom reaction with a trigger and a response. Running this command in server requires Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> | `.acr "hello" Hi there %user%`
|
`.addcustreact` `.acr` | Add a custom reaction with a trigger and a response. Running this command in server requires the Administration permission. Running this command in DM is Bot Owner only and adds a new global custom reaction. Guide here: <http://nadekobot.readthedocs.io/en/latest/Custom%20Reactions/> | `.acr "hello" Hi there %user%`
|
||||||
`.listcustreact` `.lcr` | Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. | `.lcr 1` or `.lcr all`
|
`.listcustreact` `.lcr` | Lists global or server custom reactions (20 commands per page). Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. Specifying `all` argument instead of the number will DM you a text file with a list of all custom reactions. | `.lcr 1` or `.lcr all`
|
||||||
`.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1`
|
`.listcustreactg` `.lcrg` | Lists global or server custom reactions (20 commands per page) grouped by trigger, and show a number of responses for each. Running the command in DM will list global custom reactions, while running it in server will list that server's custom reactions. | `.lcrg 1`
|
||||||
`.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1`
|
`.showcustreact` `.scr` | Shows a custom reaction's response on a given ID. | `.scr 1`
|
||||||
`.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration priviledges and removes server custom reaction. | `.dcr 5`
|
`.delcustreact` `.dcr` | Deletes a custom reaction on a specific index. If ran in DM, it is bot owner only and deletes a global custom reaction. If ran in a server, it requires Administration privileges and removes server custom reaction. | `.dcr 5`
|
||||||
`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot Owner only.** | `.crstatsclear` or `.crstatsclear rng`
|
`.crdm` | Toggles whether the response message of the custom reaction will be sent as a direct message. | `.crdm 44`
|
||||||
|
`.crad` | Toggles whether the message triggering the custom reaction will be automatically deleted. | `.crad 59`
|
||||||
|
`.crstatsclear` | Resets the counters on `.crstats`. You can specify a trigger to clear stats only for that trigger. **Bot owner only** | `.crstatsclear` or `.crstatsclear rng`
|
||||||
`.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3`
|
`.crstats` | Shows a list of custom reactions and the number of times they have been executed. Paginated with 10 per page. Use `.crstatsclear` to reset the counters. | `.crstats` or `.crstats 3`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Gambling
|
### Gambling
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName`
|
`$raffle` | Prints a name and ID of a random user from the online list from the (optional) role. | `$raffle` or `$raffle RoleName`
|
||||||
`$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy`
|
`$cash` `$$$` | Check how much currency a person has. (Defaults to yourself) | `$$$` or `$$$ @SomeGuy`
|
||||||
`$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
|
`$give` | Give someone a certain amount of currency. | `$give 1 "@SomeGuy"`
|
||||||
`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot Owner only.** | `$award 100 @person` or `$award 5 Role Of Gamblers`
|
`$award` | Awards someone a certain amount of currency. You can also specify a role name to award currency to all users in a role. **Bot owner only** | `$award 100 @person` or `$award 5 Role Of Gamblers`
|
||||||
`$take` | Takes a certain amount of currency from someone. **Bot Owner only.** | `$take 1 "@someguy"`
|
`$take` | Takes a certain amount of currency from someone. **Bot owner only** | `$take 1 "@someguy"`
|
||||||
`$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x3 and 100 x10. | `$br 5`
|
`$betroll` `$br` | Bets a certain amount of currency and rolls a dice. Rolling over 66 yields x2 of your currency, over 90 - x4 and 100 x10. | `$br 5`
|
||||||
`$leaderboard` `$lb` | Displays bot currency leaderboard. | `$lb`
|
`$leaderboard` `$lb` | Displays the bot's currency leaderboard. | `$lb`
|
||||||
`$race` | Starts a new animal race. | `$race`
|
`$race` | Starts a new animal race. | `$race`
|
||||||
`$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
|
`$joinrace` `$jr` | Joins a new race. You can specify an amount of currency for betting (optional). You will get YourBet*(participants-1) back if you win. | `$jr` or `$jr 5`
|
||||||
`$startevent` | Starts one of the events seen on public nadeko. **Bot Owner only.** | `$startevent flowerreaction`
|
`$startevent` | Starts one of the events seen on public nadeko. **Bot owner only** | `$startevent flowerreaction`
|
||||||
`$roll` | Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. Y can be a letter 'F' if you want to roll fate dice instead of dnd. | `$roll` or `$roll 7` or `$roll 3d5` or `$roll 5dF`
|
`$roll` | Rolls 0-100. If you supply a number `X` it rolls up to 30 normal dice. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. `Y` can be a letter 'F' if you want to roll fate dice instead of dnd. | `$roll` or `$roll 7` or `$roll 3d5` or `$roll 5dF`
|
||||||
`$rolluo` | Rolls X normal dice (up to 30) unordered. If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5`
|
`$rolluo` | Rolls `X` normal dice (up to 30) unordered. If you split 2 numbers with letter `d` (`xdy`) it will roll `X` dice from 1 to `y`. | `$rolluo` or `$rolluo 7` or `$rolluo 3d5`
|
||||||
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
|
`$nroll` | Rolls in a given range. | `$nroll 5` (rolls 0-5) or `$nroll 5-15`
|
||||||
`$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5`
|
`$draw` | Draws a card from the deck.If you supply number X, she draws up to 5 cards from the deck. | `$draw` or `$draw 5`
|
||||||
`$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh`
|
`$shuffle` `$sh` | Reshuffles all cards back into the deck. | `$sh`
|
||||||
`$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`
|
`$flip` | Flips coin(s) - heads or tails, and shows an image. | `$flip` or `$flip 3`
|
||||||
`$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t`
|
`$betflip` `$bf` | Bet to guess will the result be heads or tails. Guessing awards you 1.95x the currency you've bet (rounded up). Multiplier can be changed by the bot owner. | `$bf 5 heads` or `$bf 3 t`
|
||||||
`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot Owner only.** | `$slotstats`
|
`$shop` | Lists this server's administrators' shop. Paginated. | `$shop` or `$shop 2`
|
||||||
`$slottest` | Tests to see how much slots payout for X number of plays. **Bot Owner only.** | `$slottest 1000`
|
`$buy` | Buys an item from the shop on a given index. If buying items, make sure that the bot can DM you. | `$buy 2`
|
||||||
`$slot` | Play Nadeko slots. Max bet is 999. 3 seconds cooldown per user. | `$slot 5`
|
`$shopadd` | Adds an item to the shop by specifying type price and name. Available types are role and list. **Requires Administrator server permission.** | `$shopadd role 1000 Rich`
|
||||||
`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend atleast 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama`
|
`$shoplistadd` | Adds an item to the list of items for sale in the shop entry given the index. You usually want to run this command in the secret channel, so that the unique items are not leaked. **Requires Administrator server permission.** | `$shoplistadd 1 Uni-que-Steam-Key`
|
||||||
|
`$shoprem` `$shoprm` | Removes an item from the shop by its color. **Requires Administrator server permission.** | `$shoprm 1`
|
||||||
|
`$slotstats` | Shows the total stats of the slot command for this bot's session. **Bot owner only** | `$slotstats`
|
||||||
|
`$slottest` | Tests to see how much slots payout for X number of plays. **Bot owner only** | `$slottest 1000`
|
||||||
|
`$slot` | Play Nadeko slots. Max bet is 9999. 1.5 second cooldown per user. | `$slot 5`
|
||||||
|
`$claimwaifu` `$claim` | Claim a waifu for yourself by spending currency. You must spend at least 10% more than her current value unless she set `$affinity` towards you. | `$claim 50 @Himesama`
|
||||||
`$divorce` | Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. | `$divorce @CheatingSloot`
|
`$divorce` | Releases your claim on a specific waifu. You will get some of the money you've spent back unless that waifu has an affinity towards you. 6 hours cooldown. | `$divorce @CheatingSloot`
|
||||||
`$affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `$claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `$affinity @MyHusband` or `$affinity`
|
`$affinity` | Sets your affinity towards someone you want to be claimed by. Setting affinity will reduce their `$claim` on you by 20%. You can leave second argument empty to clear your affinity. 30 minutes cooldown. | `$affinity @MyHusband` or `$affinity`
|
||||||
`$waifus` `$waifulb` | Shows top 9 waifus. | `$waifus`
|
`$waifus` `$waifulb` | Shows top 9 waifus. | `$waifus`
|
||||||
`$waifuinfo` `$waifustats` | Shows waifu stats for a target person. Defaults to you if no user is provided. | `$waifuinfo @MyCrush` or `$waifuinfo`
|
`$waifuinfo` `$waifustats` | Shows waifu stats for a target person. Defaults to you if no user is provided. | `$waifuinfo @MyCrush` or `$waifuinfo`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Games
|
### Games
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more`
|
`>choose` | Chooses a thing from a list of things | `>choose Get up;Sleep;Sleep more`
|
||||||
`>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something`
|
`>8ball` | Ask the 8ball a yes/no question. | `>8ball should I do something`
|
||||||
`>rps` | Play a game of rocket paperclip scissors with Nadeko. | `>rps scissors`
|
`>rps` | Play a game of Rocket-Paperclip-Scissors with Nadeko. | `>rps scissors`
|
||||||
|
`>rategirl` | Use the universal hot-crazy wife zone matrix to determine the girl's worth. It is everything young men need to know about women. At any moment in time, any woman you have previously located on this chart can vanish from that location and appear anywhere else on the chart. | `>rategirl @SomeGurl`
|
||||||
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
|
`>linux` | Prints a customizable Linux interjection | `>linux Spyware Windows`
|
||||||
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello`
|
`>leet` | Converts a text to leetspeak with 6 (1-6) severity levels | `>leet 3 Hello`
|
||||||
`>acrophobia` `>acro` | Starts an Acrophobia game. Second argment is optional round length in seconds. (default is 60) | `>acro` or `>acro 30`
|
`>acrophobia` `>acro` | Starts an Acrophobia game. Second argument is optional round length in seconds. (default is 60) | `>acro` or `>acro 30`
|
||||||
`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot`
|
`>cleverbot` | Toggles cleverbot session. When enabled, the bot will reply to messages starting with bot mention in the server. Custom reactions starting with %mention% won't work if cleverbot is enabled. **Requires ManageMessages server permission.** | `>cleverbot`
|
||||||
`>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist`
|
`>hangmanlist` | Shows a list of hangman term types. | `> hangmanlist`
|
||||||
`>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies`
|
`>hangman` | Starts a game of hangman in the channel. Use `>hangmanlist` to see a list of available term types. Defaults to 'all'. | `>hangman` or `>hangman movies`
|
||||||
@ -175,89 +204,90 @@ Command and aliases | Description | Usage
|
|||||||
`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend`
|
`>pollend` | Stops active poll on this server and prints the results in this channel. **Requires ManageMessages server permission.** | `>pollend`
|
||||||
`>typestart` | Starts a typing contest. | `>typestart`
|
`>typestart` | Starts a typing contest. | `>typestart`
|
||||||
`>typestop` | Stops a typing contest on the current channel. | `>typestop`
|
`>typestop` | Stops a typing contest on the current channel. | `>typestop`
|
||||||
`>typeadd` | Adds a new article to the typing contest. **Bot Owner only.** | `>typeadd wordswords`
|
`>typeadd` | Adds a new article to the typing contest. **Bot owner only** | `>typeadd wordswords`
|
||||||
`>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3`
|
`>typelist` | Lists added typing articles with their IDs. 15 per page. | `>typelist` or `>typelist 3`
|
||||||
`>typedel` | Deletes a typing article given the ID. **Bot Owner only.** | `>typedel 3`
|
`>typedel` | Deletes a typing article given the ID. **Bot owner only** | `>typedel 3`
|
||||||
`>trivia` `>t` | Starts a game of trivia. You can add nohint to prevent hints.First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint`
|
`>tictactoe` `>ttt` | Starts a game of tic tac toe. Another user must run the command in the same channel in order to accept the challenge. Use numbers 1-9 to play. 15 seconds per move. | >ttt
|
||||||
|
`>trivia` `>t` | Starts a game of trivia. You can add `nohint` to prevent hints. First player to get to 10 points wins by default. You can specify a different number. 30 seconds per question. | `>t` or `>t 5 nohint`
|
||||||
`>tl` | Shows a current trivia leaderboard. | `>tl`
|
`>tl` | Shows a current trivia leaderboard. | `>tl`
|
||||||
`>tq` | Quits current trivia after current question. | `>tq`
|
`>tq` | Quits current trivia after current question. | `>tq`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Help
|
### Help
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`-modules` `-mdls` | Lists all bot modules. | `-modules`
|
`-modules` `-mdls` | Lists all bot modules. | `-modules`
|
||||||
`-commands` `-cmds` | List all of the bot's commands from a certain module. You can either specify full, or only first few letters of the module name. | `-commands Administration` or `-cmds Admin`
|
`-commands` `-cmds` | List all of the bot's commands from a certain module. You can either specify the full name or only the first few letters of the module name. | `-commands Administration` or `-cmds Admin`
|
||||||
`-help` `-h` | Either shows a help for a single command, or DMs you help link if no arguments are specified. | `-h !!q` or `-h`
|
`-help` `-h` | Either shows a help for a single command, or DMs you help link if no arguments are specified. | `-h -cmds` or `-h`
|
||||||
`-hgit` | Generates the commandlist.md file. **Bot Owner only.** | `-hgit`
|
`-hgit` | Generates the commandlist.md file. **Bot owner only** | `-hgit`
|
||||||
`-readme` `-guide` | Sends a readme and a guide links to the channel. | `-readme` or `-guide`
|
`-readme` `-guide` | Sends a readme and a guide links to the channel. | `-readme` or `-guide`
|
||||||
`-donate` | Instructions for helping the project financially. | `-donate`
|
`-donate` | Instructions for helping the project financially. | `-donate`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Music
|
### Music
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`!!next` `!!n` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if !!rcs or !!rpl is enabled. | `!!n` or `!!n 5`
|
`!!next` `!!n` | Goes to the next song in the queue. You have to be in the same voice channel as the bot. You can skip multiple songs, but in that case songs will not be requeued if !!rcs or !!rpl is enabled. | `!!n` or `!!n 5`
|
||||||
`!!stop` `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!!s`
|
`!!stop` `!!s` | Stops the music and clears the playlist. Stays in the channel. | `!!s`
|
||||||
`!!destroy` `!!d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!!d`
|
`!!destroy` `!!d` | Completely stops the music and unbinds the bot from the channel. (may cause weird behaviour) | `!!d`
|
||||||
`!!pause` `!!p` | Pauses or Unpauses the song. | `!!p`
|
`!!pause` `!!p` | Pauses or Unpauses the song. | `!!p`
|
||||||
`!!fairplay` `!!fp` | Toggles fairplay. While enabled, music player will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. | `!!fp`
|
`!!fairplay` `!!fp` | Toggles fairplay. While enabled, the bot will prioritize songs from users who didn't have their song recently played instead of the song's position in the queue. | `!!fp`
|
||||||
`!!queue` `!!q` `!!yq` | Queue a song using keywords or a link. Bot will join your voice channel.**You must be in a voice channel**. | `!!q Dream Of Venice`
|
`!!queue` `!!q` `!!yq` | Queue a song using keywords or a link. Bot will join your voice channel. **You must be in a voice channel**. | `!!q Dream Of Venice`
|
||||||
`!!soundcloudqueue` `!!sq` | Queue a soundcloud song using keywords. Bot will join your voice channel.**You must be in a voice channel**. | `!!sq Dream Of Venice`
|
`!!soundcloudqueue` `!!sq` | Queue a soundcloud song using keywords. Bot will join your voice channel. **You must be in a voice channel**. | `!!sq Dream Of Venice`
|
||||||
`!!listqueue` `!!lq` | Lists 15 currently queued songs per page. Default page is 1. | `!!lq` or `!!lq 2`
|
`!!listqueue` `!!lq` | Lists 15 currently queued songs per page. Default page is 1. | `!!lq` or `!!lq 2`
|
||||||
`!!nowplaying` `!!np` | Shows the song currently playing. | `!!np`
|
`!!nowplaying` `!!np` | Shows the song that the bot is currently playing. | `!!np`
|
||||||
`!!volume` `!!vol` | Sets the music volume 0-100% | `!!vol 50`
|
`!!volume` `!!vol` | Sets the music playback volume (0-100%) | `!!vol 50`
|
||||||
`!!defvol` `!!dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!!dv 80`
|
`!!defvol` `!!dv` | Sets the default music volume when music playback is started (0-100). Persists through restarts. | `!!dv 80`
|
||||||
`!!shuffle` `!!sh` | Shuffles the current playlist. | `!!sh`
|
`!!shuffle` `!!sh` | Shuffles the current playlist. | `!!sh`
|
||||||
`!!playlist` `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!!pl playlist link or name`
|
`!!playlist` `!!pl` | Queues up to 500 songs from a youtube playlist specified by a link, or keywords. | `!!pl playlist link or name`
|
||||||
`!!soundcloudpl` `!!scpl` | Queue a soundcloud playlist using a link. | `!!scpl soundcloudseturl`
|
`!!soundcloudpl` `!!scpl` | Queue a Soundcloud playlist using a link. | `!!scpl soundcloudseturl`
|
||||||
`!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot Owner only.** | `!!lopl C:/music/classical`
|
`!!localplaylst` `!!lopl` | Queues all songs from a directory. **Bot owner only** | `!!lopl C:/music/classical`
|
||||||
`!!radio` `!!ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: <https://streamable.com/al54>) | `!!ra radio link here`
|
`!!radio` `!!ra` | Queues a radio stream from a link. It can be a direct mp3 radio stream, .m3u, .pls .asx or .xspf (Usage Video: <https://streamable.com/al54>) | `!!ra radio link here`
|
||||||
`!!local` `!!lo` | Queues a local file by specifying a full path. **Bot Owner only.** | `!!lo C:/music/mysong.mp3`
|
`!!local` `!!lo` | Queues a local file by specifying a full path. **Bot owner only** | `!!lo C:/music/mysong.mp3`
|
||||||
`!!remove` `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!!rm 5`
|
`!!remove` `!!rm` | Remove a song by its # in the queue, or 'all' to remove whole queue. | `!!rm 5`
|
||||||
`!!movesong` `!!ms` | Moves a song from one position to another. | `!!ms 5>3`
|
`!!movesong` `!!ms` | Moves a song from one position to another. | `!!ms 5>3`
|
||||||
`!!setmaxqueue` `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!!smq 50` or `!!smq`
|
`!!setmaxqueue` `!!smq` | Sets a maximum queue size. Supply 0 or no argument to have no limit. | `!!smq 50` or `!!smq`
|
||||||
`!!setmaxplaytime` `!!smp` | Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. | `!!smp 0` or `!!smp 270`
|
`!!setmaxplaytime` `!!smp` | Sets a maximum number of seconds (>14) a song can run before being skipped automatically. Set 0 to have no limit. | `!!smp 0` or `!!smp 270`
|
||||||
`!!reptcursong` `!!rcs` | Toggles repeat of current song. | `!!rcs`
|
`!!reptcursong` `!!rcs` | Toggles repeat of current song. | `!!rcs`
|
||||||
`!!rpeatplaylst` `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!!rpl`
|
`!!rpeatplaylst` `!!rpl` | Toggles repeat of all songs in the queue (every song that finishes is added to the end of the queue). | `!!rpl`
|
||||||
`!!save` | Saves a playlist under a certain name. Name must be no longer than 20 characters and mustn't contain dashes. | `!!save classical1`
|
`!!save` | Saves a playlist under a certain name. Playlist name must be no longer than 20 characters and must not contain dashes. | `!!save classical1`
|
||||||
`!!load` | Loads a saved playlist using it's ID. Use `!!pls` to list all saved playlists and !!save to save new ones. | `!!load 5`
|
`!!load` | Loads a saved playlist using its ID. Use `!!pls` to list all saved playlists and `!!save` to save new ones. | `!!load 5`
|
||||||
`!!playlists` `!!pls` | Lists all playlists. Paginated. 20 per page. Default page is 0. | `!!pls 1`
|
`!!playlists` `!!pls` | Lists all playlists. Paginated, 20 per page. Default page is 0. | `!!pls 1`
|
||||||
`!!deleteplaylist` `!!delpls` | Deletes a saved playlist. Only if you made it or if you are the bot owner. | `!!delpls animu-5`
|
`!!deleteplaylist` `!!delpls` | Deletes a saved playlist. Works only if you made it or if you are the bot owner. | `!!delpls animu-5`
|
||||||
`!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30`
|
`!!goto` | Goes to a specific time in seconds in a song. | `!!goto 30`
|
||||||
`!!autoplay` `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related youtube song. (Works only for youtube songs and when queue is empty) | `!!ap`
|
`!!autoplay` `!!ap` | Toggles autoplay - When the song is finished, automatically queue a related Youtube song. (Works only for Youtube songs and when queue is empty) | `!!ap`
|
||||||
`!!setmusicchannel` `!!smch` | Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. **Requires ManageMessages server permission.** | `!!smch`
|
`!!setmusicchannel` `!!smch` | Sets the current channel as the default music output channel. This will output playing, finished, paused and removed songs to that channel instead of the channel where the first song was queued in. **Requires ManageMessages server permission.** | `!!smch`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### NSFW
|
### NSFW
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`~hentai` | Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru or yandere) with a given tag. Tag is optional but preferred. Only 1 tag allowed. | `~hentai yuri`
|
`~hentai` | Shows a hentai image from a random website (gelbooru or danbooru or konachan or atfbooru or yandere) with a given tag. Tag is optional but preferred. Only 1 tag allowed. | `~hentai yuri`
|
||||||
`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. **Requires ManageMessages channel permission.** | `~autohentai 30 yuri|tail|long_hair` or `~autohentai`
|
`~autohentai` | Posts a hentai every X seconds with a random tag from the provided tags. Use `|` to separate tags. 20 seconds minimum. Provide no arguments to disable. **Requires ManageMessages channel permission.** | `~autohentai 30 yuri|tail|long_hair` or `~autohentai`
|
||||||
`~hentaibomb` | Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. | `~hentaibomb yuri`
|
`~hentaibomb` | Shows a total 5 images (from gelbooru, danbooru, konachan, yandere and atfbooru). Tag is optional but preferred. | `~hentaibomb yuri`
|
||||||
`~yandere` | Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~yandere tag1+tag2`
|
`~yandere` | Shows a random image from yandere with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~yandere tag1+tag2`
|
||||||
`~konachan` | Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. | `~konachan yuri`
|
`~konachan` | Shows a random hentai image from konachan with a given tag. Tag is optional but preferred. | `~konachan yuri`
|
||||||
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~rule34 yuri+kissing`
|
|
||||||
`~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. | `~e621 yuri kissing`
|
`~e621` | Shows a random hentai image from e621.net with a given tag. Tag is optional but preferred. Use spaces for multiple tags. | `~e621 yuri kissing`
|
||||||
|
`~rule34` | Shows a random image from rule34.xx with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~rule34 yuri+kissing`
|
||||||
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~danbooru yuri+kissing`
|
`~danbooru` | Shows a random hentai image from danbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~danbooru yuri+kissing`
|
||||||
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~gelbooru yuri+kissing`
|
`~gelbooru` | Shows a random hentai image from gelbooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~gelbooru yuri+kissing`
|
||||||
`~cp` | We all know where this will lead you to. | `~cp`
|
`~cp` | We all know where this will lead you to. | `~cp`
|
||||||
`~boobs` | Real adult content. | `~boobs`
|
`~boobs` | Real adult content. | `~boobs`
|
||||||
`~butts` `~ass` `~butt` | Real adult content. | `~butts` or `~ass`
|
`~butts` `~ass` `~butt` | Real adult content. | `~butts` or `~ass`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Permissions
|
### Permissions
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true`
|
`;verbose` `;v` | Sets whether to show when a command/module is blocked. | `;verbose true`
|
||||||
`;permrole` `;pr` | Sets a role which can change permissions. Or supply no parameters to find out the current one. Default one is 'Nadeko'. | `;pr role`
|
`;permrole` `;pr` | Sets a role which can change permissions. Supply no parameters to see the current one. Default is 'Nadeko'. | `;pr role`
|
||||||
`;listperms` `;lp` | Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. | `;lp` or `;lp 3`
|
`;listperms` `;lp` | Lists whole permission chain with their indexes. You can specify an optional page number if there are a lot of permissions. | `;lp` or `;lp 3`
|
||||||
`;removeperm` `;rp` | Removes a permission from a given position in Permissions list. | `;rp 1`
|
`;removeperm` `;rp` | Removes a permission from a given position in the Permissions list. | `;rp 1`
|
||||||
`;moveperm` `;mp` | Moves permission from one position to another in Permissions list. | `;mp 2 4`
|
`;moveperm` `;mp` | Moves permission from one position to another in the Permissions list. | `;mp 2 4`
|
||||||
`;srvrcmd` `;sc` | Sets a command's permission at the server level. | `;sc "command name" disable`
|
`;srvrcmd` `;sc` | Sets a command's permission at the server level. | `;sc "command name" disable`
|
||||||
`;srvrmdl` `;sm` | Sets a module's permission at the server level. | `;sm ModuleName enable`
|
`;srvrmdl` `;sm` | Sets a module's permission at the server level. | `;sm ModuleName enable`
|
||||||
`;usrcmd` `;uc` | Sets a command's permission at the user level. | `;uc "command name" enable SomeUsername`
|
`;usrcmd` `;uc` | Sets a command's permission at the user level. | `;uc "command name" enable SomeUsername`
|
||||||
@ -270,73 +300,74 @@ Command and aliases | Description | Usage
|
|||||||
`;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole`
|
`;allrolemdls` `;arm` | Enable or disable all modules for a specific role. | `;arm [enable/disable] MyRole`
|
||||||
`;allusrmdls` `;aum` | Enable or disable all modules for a specific user. | `;aum enable @someone`
|
`;allusrmdls` `;aum` | Enable or disable all modules for a specific user. | `;aum enable @someone`
|
||||||
`;allsrvrmdls` `;asm` | Enable or disable all modules for your server. | `;asm [enable/disable]`
|
`;allsrvrmdls` `;asm` | Enable or disable all modules for your server. | `;asm [enable/disable]`
|
||||||
`;ubl` | Either [add]s or [rem]oves a user specified by a mention or ID from a blacklist. **Bot Owner only.** | `;ubl add @SomeUser` or `;ubl rem 12312312313`
|
`;ubl` | Either [add]s or [rem]oves a user specified by a Mention or an ID from a blacklist. **Bot owner only** | `;ubl add @SomeUser` or `;ubl rem 12312312313`
|
||||||
`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot Owner only.** | `;cbl rem 12312312312`
|
`;cbl` | Either [add]s or [rem]oves a channel specified by an ID from a blacklist. **Bot owner only** | `;cbl rem 12312312312`
|
||||||
`;sbl` | Either [add]s or [rem]oves a server specified by a Name or ID from a blacklist. **Bot Owner only.** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer`
|
`;sbl` | Either [add]s or [rem]oves a server specified by a Name or an ID from a blacklist. **Bot owner only** | `;sbl add 12312321312` or `;sbl rem SomeTrashServer`
|
||||||
`;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set to 0 to remove the cooldown. | `;cmdcd "some cmd" 5`
|
`;cmdcooldown` `;cmdcd` | Sets a cooldown per user for a command. Set it to 0 to remove the cooldown. | `;cmdcd "some cmd" 5`
|
||||||
`;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds`
|
`;allcmdcooldowns` `;acmdcds` | Shows a list of all commands and their respective cooldowns. | `;acmdcds`
|
||||||
`;cmdcosts` | Shows a list of command costs. Paginated with 9 command per page. | `;cmdcosts` or `;cmdcosts 2`
|
`;srvrfilterinv` `;sfi` | Toggles automatic deletion of invites posted in the server. Does not affect the Bot Owner. | `;sfi`
|
||||||
`;srvrfilterinv` `;sfi` | Toggles automatic deleting of invites posted in the server. Does not affect Bot Owner. | `;sfi`
|
`;chnlfilterinv` `;cfi` | Toggles automatic deletion of invites posted in the channel. Does not negate the `;srvrfilterinv` enabled setting. Does not affect the Bot Owner. | `;cfi`
|
||||||
`;chnlfilterinv` `;cfi` | Toggles automatic deleting of invites posted in the channel. Does not negate the ;srvrfilterinv enabled setting. Does not affect Bot Owner. | `;cfi`
|
`;srvrfilterwords` `;sfw` | Toggles automatic deletion of messages containing filtered words on the server. Does not affect the Bot Owner. | `;sfw`
|
||||||
`;srvrfilterwords` `;sfw` | Toggles automatic deleting of messages containing forbidden words on the server. Does not affect Bot Owner. | `;sfw`
|
`;chnlfilterwords` `;cfw` | Toggles automatic deletion of messages containing filtered words on the channel. Does not negate the `;srvrfilterwords` enabled setting. Does not affect the Bot Owner. | `;cfw`
|
||||||
`;chnlfilterwords` `;cfw` | Toggles automatic deleting of messages containing banned words on the channel. Does not negate the ;srvrfilterwords enabled setting. Does not affect bot owner. | `;cfw`
|
|
||||||
`;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop`
|
`;fw` | Adds or removes (if it exists) a word from the list of filtered words. Use`;sfw` or `;cfw` to toggle filtering. | `;fw poop`
|
||||||
`;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw`
|
`;lstfilterwords` `;lfw` | Shows a list of filtered words. | `;lfw`
|
||||||
|
`;listglobalperms` `;lgp` | Lists global permissions set by the bot owner. **Bot owner only** | `;lgp`
|
||||||
|
`;globalmodule` `;gmod` | Enable or disable a module from use on all servers. **Bot owner only** | `;gmod nsfw disable`
|
||||||
|
`;globalcommand` `;gcmd` | Enables or disables a command from use on all servers. **Bot owner only** | `;gcmd `
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Pokemon
|
### Pokemon
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy`
|
`>attack` | Attacks a target with the given move. Use `>movelist` to see a list of moves your type can use. | `>attack "vine whip" @someguy`
|
||||||
`>movelist` `>ml` | Lists the moves you are able to use | `>ml`
|
`>movelist` `>ml` | Lists the moves you are able to use | `>ml`
|
||||||
`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower | `>heal @someone`
|
`>heal` | Heals someone. Revives those who fainted. Costs a NadekoFlower. | `>heal @someone`
|
||||||
`>type` | Get the poketype of the target. | `>type @someone`
|
`>type` | Get the poketype of the target. | `>type @someone`
|
||||||
`>settype` | Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. | `>settype fire` or `>settype`
|
`>settype` | Set your poketype. Costs a NadekoFlower. Provide no arguments to see a list of available types. | `>settype fire` or `>settype`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Searches
|
### Searches
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU`
|
`~weather` `~we` | Shows weather data for a specified city. You can also specify a country after a comma. | `~we Moscow, RU`
|
||||||
|
`~time` | Shows the current time and timezone in the specified location. | `~time London, UK`
|
||||||
`~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query`
|
`~youtube` `~yt` | Searches youtubes and shows the first result | `~yt query`
|
||||||
`~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman`
|
`~imdb` `~omdb` | Queries omdb for movies or series, show first result. | `~imdb Batman vs Superman`
|
||||||
`~randomcat` `~meow` | Shows a random cat image. | `~meow`
|
`~randomcat` `~meow` | Shows a random cat image. | `~meow`
|
||||||
`~randomdog` `~woof` | Shows a random dog image. | `~woof`
|
`~randomdog` `~woof` | Shows a random dog image. | `~woof`
|
||||||
`~image` `~img` | Pulls the first image found using a search parameter. Use ~rimg for different results. | `~img cute kitten`
|
`~image` `~img` | Pulls the first image found using a search parameter. Use `~rimg` for different results. | `~img cute kitten`
|
||||||
`~randomimage` `~rimg` | Pulls a random image using a search parameter. | `~rimg cute kitten`
|
`~randomimage` `~rimg` | Pulls a random image using a search parameter. | `~rimg cute kitten`
|
||||||
`~lmgtfy` | Google something for an idiot. | `~lmgtfy query`
|
`~lmgtfy` | Google something for an idiot. | `~lmgtfy query`
|
||||||
`~shorten` | Attempts to shorten an URL, if it fails, returns the input URL. | `~shorten https://google.com`
|
`~shorten` | Attempts to shorten an URL, if it fails, returns the input URL. | `~shorten https://google.com`
|
||||||
`~google` `~g` | Get a google search link for some terms. | `~google query`
|
`~google` `~g` | Get a Google search link for some terms. | `~google query`
|
||||||
`~magicthegathering` `~mtg` | Searches for a Magic The Gathering card. | `~magicthegathering about face` or `~mtg about face`
|
`~magicthegathering` `~mtg` | Searches for a Magic The Gathering card. | `~magicthegathering about face` or `~mtg about face`
|
||||||
`~hearthstone` `~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | `~hs Ysera`
|
`~hearthstone` `~hs` | Searches for a Hearthstone card and shows its image. Takes a while to complete. | `~hs Ysera`
|
||||||
`~yodify` `~yoda` | Translates your normal sentences into Yoda styled sentences! | ~yodify I was once an adventurer like you` or `~yoda my feelings hurt`
|
`~yodify` `~yoda` | Translates your normal sentences into Yoda styled sentences! | `~yoda my feelings hurt`
|
||||||
`~urbandict` `~ud` | Searches Urban Dictionary for a word. | `~ud Pineapple`
|
`~urbandict` `~ud` | Searches Urban Dictionary for a word. | `~ud Pineapple`
|
||||||
`~define` `~def` | Finds a definition of a word. | `~def heresy`
|
`~define` `~def` | Finds a definition of a word. | `~def heresy`
|
||||||
`~#` | Searches Tagdef.com for a hashtag. | `~# ff`
|
`~#` | Searches Tagdef.com for a hashtag. | `~# ff`
|
||||||
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> | `~catfact`
|
`~catfact` | Shows a random catfact from <http://catfacts-api.appspot.com/api/facts> | `~catfact`
|
||||||
`~revav` | Returns a google reverse image search for someone's avatar. | `~revav "@SomeGuy"`
|
`~revav` | Returns a Google reverse image search for someone's avatar. | `~revav "@SomeGuy"`
|
||||||
`~revimg` | Returns a google reverse image search for an image from a link. | `~revimg Image link`
|
`~revimg` | Returns a Google reverse image search for an image from a link. | `~revimg Image link`
|
||||||
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~safebooru yuri+kissing`
|
`~safebooru` | Shows a random image from safebooru with a given tag. Tag is optional but preferred. (multiple tags are appended with +) | `~safebooru yuri+kissing`
|
||||||
`~wikipedia` `~wiki` | Gives you back a wikipedia link | `~wiki query`
|
`~wikipedia` `~wiki` | Gives you back a wikipedia link | `~wiki query`
|
||||||
`~color` `~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00`
|
`~color` `~clr` | Shows you what color corresponds to that hex. | `~clr 00ff00`
|
||||||
`~videocall` | Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `~videocall "@SomeGuy"`
|
`~videocall` | Creates a private <http://www.appear.in> video call link for you and other mentioned people. The link is sent to mentioned people via a private message. | `~videocall "@SomeGuy"`
|
||||||
`~avatar` `~av` | Shows a mentioned person's avatar. | `~av "@SomeGuy"`
|
`~avatar` `~av` | Shows a mentioned person's avatar. | `~av "@SomeGuy"`
|
||||||
`~wikia` | Gives you back a wikia link | `~wikia mtg Vigilance` or `~wikia mlp Dashy`
|
`~wikia` | Gives you back a wikia link | `~wikia mtg Vigilance` or `~wikia mlp Dashy`
|
||||||
`~minecraftping` `~mcping` | Pings a minecraft server. | `~mcping 127.0.0.1:25565`
|
|
||||||
`~minecraftquery` `~mcq` | Finds information about a minecraft server. | `~mcq server:ip`
|
|
||||||
`~lolban` | Shows top banned champions ordered by ban rate. | `~lolban`
|
`~lolban` | Shows top banned champions ordered by ban rate. | `~lolban`
|
||||||
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist`
|
`~mal` | Shows basic info from a MyAnimeList profile. | `~mal straysocks`
|
||||||
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
|
|
||||||
`~mal` | Shows basic info from myanimelist profile. | `~mal straysocks`
|
|
||||||
`~anime` `~ani` `~aq` | Queries anilist for an anime and shows the first result. | `~ani aquarion evol`
|
`~anime` `~ani` `~aq` | Queries anilist for an anime and shows the first result. | `~ani aquarion evol`
|
||||||
`~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin`
|
`~manga` `~mang` `~mq` | Queries anilist for a manga and shows the first result. | `~mq Shingeki no kyojin`
|
||||||
`~yomama` `~ym` | Shows a random joke from <http://api.yomomma.info/> | `~ym`
|
`~yomama` `~ym` | Shows a random joke from <http://api.yomomma.info/> | `~ym`
|
||||||
`~randjoke` `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `~rj`
|
`~randjoke` `~rj` | Shows a random joke from <http://tambal.azurewebsites.net/joke/random> | `~rj`
|
||||||
`~chucknorris` `~cn` | Shows a random chucknorris joke from <http://tambal.azurewebsites.net/joke/random> | `~cn`
|
`~chucknorris` `~cn` | Shows a random Chuck Norris joke from <http://tambal.azurewebsites.net/joke/random> | `~cn`
|
||||||
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke`
|
`~wowjoke` | Get one of Kwoth's penultimate WoW jokes. | `~wowjoke`
|
||||||
`~magicitem` `~mi` | Shows a random magicitem from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `~mi`
|
`~magicitem` `~mi` | Shows a random magic item from <https://1d4chan.org/wiki/List_of_/tg/%27s_magic_items> | `~mi`
|
||||||
|
`~memelist` | Pulls a list of memes you can use with `~memegen` from http://memegen.link/templates/ | `~memelist`
|
||||||
|
`~memegen` | Generates a meme from memelist with top and bottom text. | `~memegen biw "gets iced coffee" "in the winter"`
|
||||||
`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko`
|
`~osu` | Shows osu stats for a player. | `~osu Name` or `~osu Name taiko`
|
||||||
`~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712`
|
`~osub` | Shows information about an osu beatmap. | `~osub https://osu.ppy.sh/s/127712`
|
||||||
`~osu5` | Displays a user's top 5 plays. | `~osu5 Name`
|
`~osu5` | Displays a user's top 5 plays. | `~osu5 Name`
|
||||||
@ -352,50 +383,59 @@ Command and aliases | Description | Usage
|
|||||||
`~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy`
|
`~removestream` `~rms` | Removes notifications of a certain streamer from a certain platform on this channel. **Requires ManageMessages server permission.** | `~rms Twitch SomeGuy` or `~rms Beam SomeOtherGuy`
|
||||||
`~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer`
|
`~checkstream` `~cs` | Checks if a user is online on a certain streaming platform. | `~cs twitch MyFavStreamer`
|
||||||
`~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello`
|
`~translate` `~trans` | Translates from>to text. From the given language to the destination language. | `~trans en>fr Hello`
|
||||||
`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot Owner only.** | `~at` or `~at del`
|
`~autotrans` `~at` | Starts automatic translation of all messages by users who set their `~atl` in this channel. You can set "del" argument to automatically delete all translated user messages. **Requires Administrator server permission.** **Bot owner only** | `~at` or `~at del`
|
||||||
`~autotranslang` `~atl` | `~atl en>fr` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value.
|
`~autotranslang` `~atl` | Sets your source and target language to be used with `~at`. Specify no arguments to remove previously set value. | `~atl en>fr`
|
||||||
`~translangs` | Lists the valid languages for translation. | `~translangs`
|
`~translangs` | Lists the valid languages for translation. | `~translangs`
|
||||||
`~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest`
|
`~xkcd` | Shows a XKCD comic. No arguments will retrieve random one. Number argument will retrieve a specific comic, and "latest" will get the latest one. | `~xkcd` or `~xkcd 1400` or `~xkcd latest`
|
||||||
|
|
||||||
###### [Back to TOC](#table-of-contents)
|
###### [Back to ToC](#table-of-contents)
|
||||||
|
|
||||||
### Utility
|
### Utility
|
||||||
Command and aliases | Description | Usage
|
Commands and aliases | Description | Usage
|
||||||
----------------|--------------|-------
|
----------------|--------------|-------
|
||||||
`.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. **Requires ManageRoles server permission.** **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. **Requires ManageRoles server permission.** **Bot owner only** | `.rrc 60 MyLsdRole #ff0000 #00ff00 #0000ff` or `.rrc 0 MyLsdRole`
|
||||||
`.togethertube` `.totube` | Creates a new room on <https://togethertube.com> and shows the link in the chat. | `.totube`
|
`.togethertube` `.totube` | Creates a new room on <https://togethertube.com> and shows the link in the chat. | `.totube`
|
||||||
`.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch`
|
`.whosplaying` `.whpl` | Shows a list of users who are playing the specified game. | `.whpl Overwatch`
|
||||||
`.inrole` | Lists every person from the provided role or roles (separated by a ',') on this server. If the list is too long for 1 message, you must have Manage Messages permission. | `.inrole Role`
|
`.inrole` | Lists every person from the specified role on this server. You can use role ID, role name. | `.inrole Some Role`
|
||||||
`.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms`
|
`.checkmyperms` | Checks your user-specific permissions on this channel. | `.checkmyperms`
|
||||||
`.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"`
|
`.userid` `.uid` | Shows user ID. | `.uid` or `.uid "@SomeGuy"`
|
||||||
`.channelid` `.cid` | Shows current channel ID. | `.cid`
|
`.channelid` `.cid` | Shows current channel ID. | `.cid`
|
||||||
`.serverid` `.sid` | Shows current server ID. | `.sid`
|
`.serverid` `.sid` | Shows current server ID. | `.sid`
|
||||||
`.roles` | List roles on this server or a roles of a specific user if specified. Paginated. 20 roles per page. | `.roles 2` or `.roles @Someone`
|
`.roles` | List roles on this server or a roles of a specific user if specified. Paginated, 20 roles per page. | `.roles 2` or `.roles @Someone`
|
||||||
`.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct`
|
`.channeltopic` `.ct` | Sends current channel's topic as a message. | `.ct`
|
||||||
`.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv`
|
`.createinvite` `.crinv` | Creates a new invite which has infinite max uses and never expires. **Requires CreateInstantInvite channel permission.** | `.crinv`
|
||||||
|
`.shardstats` | Stats for shards. Paginated with 25 shards per page. | `.shardstats` or `.shardstats 2`
|
||||||
|
`.shardid` | Shows which shard is a certain guild on, by guildid. | `.shardid 117523346618318850`
|
||||||
`.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`
|
`.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`
|
`.ping` | Ping the bot to see if there are latency issues. | `.ping`
|
||||||
|
`.activity` | Checks for spammers. **Bot owner only** | `.activity`
|
||||||
`.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 the `.calc` command | `.calcops`
|
||||||
`.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`
|
`.alias` `.cmdmap` | Create a custom alias for a certain Nadeko command. Provide no alias to remove the existing one. **Requires Administrator server permission.** | `.alias allin $bf 100 h` or `.alias "linux thingy" >loonix Spyware Windows`
|
||||||
|
`.aliaslist` `.cmdmaplist` `.aliases` | Shows the list of currently set aliases. Paginated. | `.aliaslist` or `.aliaslist 3`
|
||||||
|
`.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`
|
`.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`
|
`.lcsc` | Leaves a cross server channel instance from this channel. **Requires ManageServer server permission.** | `.lcsc`
|
||||||
`.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`
|
||||||
`.repeatinvoke` `.repinv` | Immediately shows the repeat message on a certain index and restarts its timer. **Requires ManageMessages server permission.** | `.repinv 1`
|
`.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`
|
`.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`
|
`.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`
|
`.repeatlist` `.replst` | Shows currently repeating messages and their indexes. **Requires ManageMessages server permission.** | `.repeatlist`
|
||||||
`.listquotes` `.liqu` | `.liqu` or `.liqu 3` | Lists all quotes on the server ordered alphabetically. 15 Per page.
|
`.parewrel` | Forces the update of the list of patrons who are eligible for the reward. **Bot owner only** | `.parewrel`
|
||||||
|
`.clparew` | Claim patreon rewards. If you're subscribed to bot owner's patreon you can use this command to claim your rewards - assuming bot owner did setup has their patreon key. | `.clparew`
|
||||||
|
`.listquotes` `.liqu` | Lists all quotes on the server ordered alphabetically. 15 Per page. | `.liqu` or `.liqu 3`
|
||||||
`...` | Shows a random quote with a specified name. | `... abc`
|
`...` | Shows a random quote with a specified name. | `... abc`
|
||||||
|
`.qsearch` | Shows a random quote for a keyword that contains any text specified in the search. | `.qsearch keyword text`
|
||||||
|
`.quoteid` `.qid` | Displays the quote with the specified ID number. Quote ID numbers can be found by typing `.liqu [num]` where `[num]` is a number of a page which contains 15 quotes. | `.qid 123456`
|
||||||
`..` | 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 quote with the specified ID. You have to be either server Administrator or the creator of the quote to delete it. | `.delq 123456`
|
||||||
`.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`
|
||||||
`.remind` | Sends a message to you or a channel after certain amount of time. First argument is me/here/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword)message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!`
|
`.remind` | Sends a message to you or a channel after certain amount of time. First argument is `me`/`here`/'channelname'. Second argument is time in a descending order (mo>w>d>h>m) example: 1w5d3h10m. Third argument is a (multiword) message. | `.remind me 1d5h Do something` or `.remind #general 1m Start now!`
|
||||||
`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are %user% - user who ran the command, %message% - Message specified in the remind, %target% - target channel of the remind. **Bot Owner only.** | `.remindtemplate %user%, do %message%!`
|
`.remindtemplate` | Sets message for when the remind is triggered. Available placeholders are `%user%` - user who ran the command, `%message%` - Message specified in the remind, `%target%` - target channel of the remind. **Bot owner only** | `.remindtemplate %user%, do %message%!`
|
||||||
`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist`
|
`.convertlist` | List of the convertible dimensions and currencies. | `.convertlist`
|
||||||
`.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000`
|
`.convert` | Convert quantities. Use `.convertlist` to see supported dimensions and currencies. | `.convert m km 1000`
|
||||||
|
@ -1,18 +1,18 @@
|
|||||||
##Setting up NadekoBot on Linux
|
## Setting up NadekoBot on Linux
|
||||||
|
|
||||||
####Setting up NadekoBot on Linux Digital Ocean Droplet
|
#### Setting up NadekoBot on Linux Digital Ocean Droplet
|
||||||
If you want Nadeko to play music for you 24/7 without having to hosting it on your PC and want to keep it cheap, reliable and convenient as possible, you can try Nadeko on Linux Digital Ocean Droplet using the link [DigitalOcean](http://m.do.co/c/46b4d3d44795/) (and using this link will be supporting Nadeko and will give you **$10 credit**)
|
If you want Nadeko to play music for you 24/7 without having to hosting it on your PC and want to keep it cheap, reliable and convenient as possible, you can try Nadeko on Linux Digital Ocean Droplet using the link [DigitalOcean](http://m.do.co/c/46b4d3d44795/) (and using this link will be supporting Nadeko and will give you **$10 credit**)
|
||||||
|
|
||||||
####Setting up NadekoBot
|
#### Setting up NadekoBot
|
||||||
Assuming you have followed the link above to setup an account and Droplet with 64bit OS in Digital Ocean and got the `IP address and root password (in email)` to login, its time to get started.
|
Assuming you have followed the link above to setup an account and Droplet with 64bit OS in Digital Ocean and got the `IP address and root password (in email)` to login, its time to get started.
|
||||||
|
|
||||||
**Go through this whole guide before setting up Nadeko**
|
**Go through this whole guide before setting up Nadeko**
|
||||||
|
|
||||||
####Prerequisites
|
#### Prerequisites
|
||||||
- Download [PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html)
|
- Download [PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html)
|
||||||
- Download [WinSCP](https://winscp.net/eng/download.php) *(optional)*
|
- Download [WinSCP](https://winscp.net/eng/download.php) *(optional)*
|
||||||
|
|
||||||
####Starting up
|
#### Starting up
|
||||||
|
|
||||||
- **Open PuTTY.exe** that you downloaded before, and paste or enter your `IP address` and then click **Open**.
|
- **Open PuTTY.exe** that you downloaded before, and paste or enter your `IP address` and then click **Open**.
|
||||||
If you entered your Droplets IP address correctly, it should show **login as:** in a newly opened window.
|
If you entered your Droplets IP address correctly, it should show **login as:** in a newly opened window.
|
||||||
@ -24,7 +24,7 @@ If you entered your Droplets IP address correctly, it should show **login as:**
|
|||||||
|
|
||||||
**NOTE:** Copy the commands, and just paste them using **mouse single right-click.**
|
**NOTE:** Copy the commands, and just paste them using **mouse single right-click.**
|
||||||
|
|
||||||
####Creating and Inviting bot
|
#### Creating and Inviting bot
|
||||||
|
|
||||||
- Read here how to [create a DiscordBot application](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#creating-discordbot-application)
|
- Read here how to [create a DiscordBot application](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#creating-discordbot-application)
|
||||||
- [Visual Invite Guide](http://discord.kongslien.net/guide.html) **(Note: Client ID is your Bot ID)**
|
- [Visual Invite Guide](http://discord.kongslien.net/guide.html) **(Note: Client ID is your Bot ID)**
|
||||||
@ -37,8 +37,8 @@ If you entered your Droplets IP address correctly, it should show **login as:**
|
|||||||
- Go to the newly created link and pick the server we created, and click `Authorize`
|
- Go to the newly created link and pick the server we created, and click `Authorize`
|
||||||
- The bot should have been added to your server.
|
- The bot should have been added to your server.
|
||||||
|
|
||||||
####Getting NadekoBot
|
#### Getting NadekoBot
|
||||||
#####Part I
|
##### Part I - Downloading the installer
|
||||||
Use the following command to get and run `linuxAIO.sh`
|
Use the following command to get and run `linuxAIO.sh`
|
||||||
(Remember **Do Not** rename the file **linuxAIO.sh**)
|
(Remember **Do Not** rename the file **linuxAIO.sh**)
|
||||||
|
|
||||||
@ -55,7 +55,8 @@ You should see these following options after using the above command:
|
|||||||
6. Set up credentials.json (if you have downloaded the bot already)
|
6. Set up credentials.json (if you have downloaded the bot already)
|
||||||
7. To exit
|
7. To exit
|
||||||
```
|
```
|
||||||
#####Part II (Optional)
|
##### Part II - Downloading Nadekobot prerequisites
|
||||||
|
|
||||||
**If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed and have Ubuntu, Debian or CentOS, Press `5` and `enter` key, then `y` when you see the following:
|
**If** you are running NadekoBot for the first time on your system and never had any *prerequisites* installed and have Ubuntu, Debian or CentOS, Press `5` and `enter` key, then `y` when you see the following:
|
||||||
```
|
```
|
||||||
Welcome to NadekoBot Auto Prerequisites Installer.
|
Welcome to NadekoBot Auto Prerequisites Installer.
|
||||||
@ -63,10 +64,11 @@ Would you like to continue?
|
|||||||
```
|
```
|
||||||
That will install all the prerequisites your system need to run NadekoBot.
|
That will install all the prerequisites your system need to run NadekoBot.
|
||||||
|
|
||||||
If you prefer to install them [manually](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#installing-manually-optional), click on the link. *(Optional)*
|
(Optional) **If** you want to install it manually, you can try finding it [here](https://github.com/Kwoth/NadekoBot-BashScript/blob/master/nadekoautoinstaller.sh)
|
||||||
|
|
||||||
Once *prerequisites* finish installing.
|
Once *prerequisites* finish installing,
|
||||||
#####Part III
|
|
||||||
|
##### Part III - Installing Nadeko
|
||||||
Choose either
|
Choose either
|
||||||
`1` to get the **most updated build of NadekoBot**
|
`1` to get the **most updated build of NadekoBot**
|
||||||
or
|
or
|
||||||
@ -76,8 +78,7 @@ and then press `enter` key.
|
|||||||
Once Installation is completed you should see the options again.
|
Once Installation is completed you should see the options again.
|
||||||
|
|
||||||
Next, check out:
|
Next, check out:
|
||||||
#####Part IV (Optional)
|
##### Part IV - Setting up credentials
|
||||||
If you prefer to skip this step and want to do it [manually](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-sftp) or already have the `credentials.json` file, click on the link. *(Optional)*
|
|
||||||
|
|
||||||
- [1. Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-credentialsjson)
|
- [1. Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#setting-up-credentialsjson)
|
||||||
- [2. To Get the Google API](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music)
|
- [2. To Get the Google API](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music)
|
||||||
@ -102,17 +103,17 @@ You will be asked to enter the required informations, just follow the on-screen
|
|||||||
|
|
||||||
(If you want to skip any optional infos, just press `enter` key without typing/pasting anything.)
|
(If you want to skip any optional infos, just press `enter` key without typing/pasting anything.)
|
||||||
Once done,
|
Once done,
|
||||||
#####Part V
|
##### Part V - Checking if Nadeko is working
|
||||||
You should see the options again.
|
You should see the options again.
|
||||||
Next, press `3` to **Run Nadeko (Normally)**
|
Next, press `3` to **Run Nadeko (Normally)**.
|
||||||
Check in your discord server if your new bot is working properly.
|
Check in your discord server if your new bot is working properly.
|
||||||
#####Part VI
|
##### Part VI - Running Nadeko on tmux
|
||||||
If your bot is working properly in your server, type `.die` to **shut down the bot**, then press `7` to **exit**.
|
If your bot is working properly in your server, type `.die` to **shut down the bot**, then press `7` to **exit**.
|
||||||
Next, [Run your bot again with **tmux**.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot)
|
Next, [Run your bot again with **tmux**.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot)
|
||||||
|
|
||||||
[Check this when you need to **restart** your **NadekoBot** anytime later along with tmux session.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko)
|
[Check this when you need to **restart** your **NadekoBot** anytime later along with tmux session.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#restarting-nadeko)
|
||||||
|
|
||||||
####Running NadekoBot
|
#### Running NadekoBot
|
||||||
|
|
||||||
**Create a new Session:**
|
**Create a new Session:**
|
||||||
|
|
||||||
@ -147,9 +148,9 @@ See how that happens:
|
|||||||
|
|
||||||
**Now check your Discord, the bot should be online**
|
**Now check your Discord, the bot should be online**
|
||||||
|
|
||||||
Next to **move the bot to background** and to do that, press **CTRL+B+D** (that will detach the nadeko session using TMUX) and you can finally close **PuTTY** if you want.
|
Next to **move the bot to background** and to do that, press **CTRL+B, release, D** (that will detach the nadeko session using TMUX) and you can finally close **PuTTY** if you want.
|
||||||
|
|
||||||
####Restarting Nadeko
|
#### Restarting Nadeko
|
||||||
|
|
||||||
**Restarting NadekoBot:**
|
**Restarting NadekoBot:**
|
||||||
|
|
||||||
@ -166,7 +167,7 @@ Open **PuTTY** and login as you have before, type `reboot` and hit Enter.
|
|||||||
- `tmux kill-session -t nadeko` (don't forget to replace "nadeko" to what ever you named your bot's session)
|
- `tmux kill-session -t nadeko` (don't forget to replace "nadeko" to what ever you named your bot's session)
|
||||||
- [Run the bot again.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot)
|
- [Run the bot again.](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot)
|
||||||
|
|
||||||
####Updating Nadeko
|
#### Updating Nadeko
|
||||||
|
|
||||||
- Connect to the terminal through **PuTTY**.
|
- Connect to the terminal through **PuTTY**.
|
||||||
- `tmux kill-session -t nadeko` (don't forget to replace **nadeko** in the command with the name of your bot's session)
|
- `tmux kill-session -t nadeko` (don't forget to replace **nadeko** in the command with the name of your bot's session)
|
||||||
@ -177,98 +178,21 @@ Open **PuTTY** and login as you have before, type `reboot` and hit Enter.
|
|||||||
- Choose either `3` or `4` to run the bot again with **normally** or **auto restart** respectively.
|
- Choose either `3` or `4` to run the bot again with **normally** or **auto restart** respectively.
|
||||||
- Done. You can close **PuTTY** now.
|
- Done. You can close **PuTTY** now.
|
||||||
|
|
||||||
####Installing Manually (Optional)
|
#### Setting up Music
|
||||||
|
|
||||||
#####Installing Git
|
To set up Nadeko for music and Google API Keys, follow [Setting up NadekoBot for Music](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music)
|
||||||
|
|
||||||
![img1](https://cdn.discordapp.com/attachments/251504306010849280/251504416019054592/git.gif)
|
Once done, go back to **PuTTY**
|
||||||
|
|
||||||
Ubuntu:
|
#### Some more Info
|
||||||
|
|
||||||
`sudo apt-get install git -y`
|
##### Info about tmux
|
||||||
|
|
||||||
CentOS:
|
- If you want to **see the sessions** after logging back again, type `tmux ls`, and that will give you the list of sessions running.
|
||||||
|
- If you want to **switch to/ see that session**, type `tmux a -t nadeko` (**nadeko** is the name of the session we created before so, replace **“nadeko”** with the session name you created.)
|
||||||
|
- If you want to **kill** NadekoBot **session**, type `tmux kill-session -t nadeko`
|
||||||
|
|
||||||
`yum -y install git`
|
#### Guide for Advance Users (Optional)
|
||||||
|
|
||||||
**NOTE:** If the command is not being initiated, hit **Enter**
|
|
||||||
|
|
||||||
#####Installing .NET Core SDK
|
|
||||||
|
|
||||||
![img2](https://cdn.discordapp.com/attachments/251504306010849280/251504746987388938/dotnet.gif)
|
|
||||||
|
|
||||||
Go to [this link](https://www.microsoft.com/net/core#ubuntu) (for Ubuntu) or to [this link](https://www.microsoft.com/net/core#linuxcentos) (for CentOS) provided by microsoft for instructions on how to get the most up to date version of the dotnet core sdk!
|
|
||||||
Make sure that you're on the correct page for your distribution of linux as the guides are different for the various distributions
|
|
||||||
|
|
||||||
We'll go over the steps here for Ubuntu 16.04 anyway (these will **only** work on Ubuntu 16.04), accurate as of 3/2/2017
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo sh -c 'echo "deb [arch=amd64] https://apt-mo.trafficmanager.net/repos/dotnet-release/ xenial main" > /etc/apt/sources.list.d/dotnetdev.list'
|
|
||||||
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 417A0893
|
|
||||||
sudo apt-get update && sudo apt-get install dotnet-dev-1.0.0-preview2.1-003177 -y
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOTE:** .NET CORE SDK only supports 64-bit Linux Operating Systems (Raspberry Pis are not supported because of this)
|
|
||||||
|
|
||||||
#####Installing Opus Voice Codec and libsodium
|
|
||||||
|
|
||||||
![img3](https://cdn.discordapp.com/attachments/251504306010849280/251505294654308353/libopus.gif)
|
|
||||||
|
|
||||||
Ubuntu:
|
|
||||||
|
|
||||||
`sudo apt-get install libopus0 opus-tools libopus-dev libsodium-dev -y`
|
|
||||||
|
|
||||||
CentOS:
|
|
||||||
|
|
||||||
`yum -y install opus opus-devel`
|
|
||||||
|
|
||||||
#####Installing FFMPEG
|
|
||||||
|
|
||||||
![img4](https://cdn.discordapp.com/attachments/251504306010849280/251505443111829505/ffmpeg.gif)
|
|
||||||
|
|
||||||
Ubuntu:
|
|
||||||
|
|
||||||
`apt-get install ffmpeg -y`
|
|
||||||
|
|
||||||
Centos:
|
|
||||||
|
|
||||||
```
|
|
||||||
yum -y install http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm epel-release
|
|
||||||
yum -y install ffmpeg
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOTE:** If you are running **UBUNTU 14.04**, you must run these first:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo add-apt-repository ppa:mc3man/trusty-media
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get dist-upgrade
|
|
||||||
```
|
|
||||||
|
|
||||||
**Before executing:** `sudo apt-get install ffmpeg`
|
|
||||||
|
|
||||||
|
|
||||||
**NOTE:** If you are running **Debian 8 Jessie**, please, follow these steps:
|
|
||||||
|
|
||||||
```
|
|
||||||
sudo apt-get update
|
|
||||||
echo "deb http://ftp.debian.org/debian jessie-backports main" | tee /etc/apt/sources.list.d/debian-backports.list
|
|
||||||
sudo apt-get update && sudo apt-get install ffmpeg -y
|
|
||||||
```
|
|
||||||
|
|
||||||
#####Installing TMUX
|
|
||||||
|
|
||||||
![img5](https://cdn.discordapp.com/attachments/251504306010849280/251505519758409728/tmux.gif)
|
|
||||||
|
|
||||||
Ubuntu:
|
|
||||||
|
|
||||||
`sudo apt-get install tmux -y`
|
|
||||||
|
|
||||||
Centos:
|
|
||||||
|
|
||||||
`yum -y install tmux`
|
|
||||||
|
|
||||||
####Guide for Advance Users (Optional)
|
|
||||||
|
|
||||||
**Skip this step if you are a Regular User or New to Linux.**
|
**Skip this step if you are a Regular User or New to Linux.**
|
||||||
|
|
||||||
@ -285,7 +209,7 @@ Centos:
|
|||||||
- It will then ask "File Name to Write" (rename), just hit `Enter` and Done.
|
- It will then ask "File Name to Write" (rename), just hit `Enter` and Done.
|
||||||
- You can now move to [Running NadekoBot](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot)
|
- You can now move to [Running NadekoBot](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#running-nadekobot)
|
||||||
|
|
||||||
####Setting up SFTP
|
#### Setting up SFTP
|
||||||
|
|
||||||
- Open **WinSCP**
|
- Open **WinSCP**
|
||||||
- Click on **New Site** (top-left corner).
|
- Click on **New Site** (top-left corner).
|
||||||
@ -298,7 +222,7 @@ Centos:
|
|||||||
- It should show you the NadekoBot folder which was created by git earlier on the right-hand side window.
|
- It should show you the NadekoBot folder which was created by git earlier on the right-hand side window.
|
||||||
- Open that folder, then open the `src` folder, followed by another `NadekoBot` folder and you should see `credentials.json` there.
|
- Open that folder, then open the `src` folder, followed by another `NadekoBot` folder and you should see `credentials.json` there.
|
||||||
|
|
||||||
####Setting up credentials.json
|
#### Setting up credentials.json
|
||||||
|
|
||||||
- Copy the `credentials.json` to desktop
|
- Copy the `credentials.json` to desktop
|
||||||
- EDIT it as it is guided here: [Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file)
|
- EDIT it as it is guided here: [Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file)
|
||||||
@ -306,39 +230,5 @@ Centos:
|
|||||||
- **If** you already have Nadeko 1.0 setup and have `credentials.json` and `NadekoBot.db`, you can just copy and paste the `credentials.json` to `NadekoBot/src/NadekoBot` and `NadekoBot.db` to `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data` using WinSCP.
|
- **If** you already have Nadeko 1.0 setup and have `credentials.json` and `NadekoBot.db`, you can just copy and paste the `credentials.json` to `NadekoBot/src/NadekoBot` and `NadekoBot.db` to `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data` using WinSCP.
|
||||||
- **If** you have Nadeko 0.9x follow the [Upgrading Guide](http://nadekobot.readthedocs.io/en/latest/guides/Upgrading%20Guide/)
|
- **If** you have Nadeko 0.9x follow the [Upgrading Guide](http://nadekobot.readthedocs.io/en/latest/guides/Upgrading%20Guide/)
|
||||||
|
|
||||||
####Setting up Music
|
|
||||||
|
|
||||||
To set up Nadeko for music and Google API Keys, follow [Setting up NadekoBot for Music](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music)
|
|
||||||
|
|
||||||
Once done, go back to **PuTTY**
|
|
||||||
|
|
||||||
####Some more Info
|
|
||||||
|
|
||||||
#####Info about tmux
|
|
||||||
|
|
||||||
- If you want to **see the sessions** after logging back again, type `tmux ls`, and that will give you the list of sessions running.
|
|
||||||
- If you want to **switch to/ see that session**, type `tmux a -t nadeko` (**nadeko** is the name of the session we created before so, replace **“nadeko”** with the session name you created.)
|
|
||||||
- If you want to **kill** NadekoBot **session**, type `tmux kill-session -t nadeko`
|
|
||||||
|
|
||||||
#####Alternative way to Install
|
|
||||||
|
|
||||||
If the [Nadeko installer](http://nadekobot.readthedocs.io/en/latest/guides/Linux%20Guide/#getting-nadekobot) shows any kind error, check if you have the `linuxAIO.sh` file and make sure its not renamed or if you want to manually install the bot. Use the following command(s):
|
|
||||||
|
|
||||||
![img6](https://cdn.discordapp.com/attachments/251504306010849280/251505587089571850/getting_nadeko.gif)
|
|
||||||
|
|
||||||
`cd ~ && curl -L https://github.com/Kwoth/NadekoBot-BashScript/raw/master/nadeko_installer.sh | sh`
|
|
||||||
|
|
||||||
**OR**
|
|
||||||
|
|
||||||
```
|
|
||||||
cd ~ && git clone -b dev --recursive --depth 1 https://github.com/Kwoth/NadekoBot.git
|
|
||||||
cd ~/NadekoBot/discord.net/src/Discord.Net && dotnet restore && cd ../Discord.Net.Commands && dotnet restore && cd ../../../src/NadekoBot/ && dotnet restore && dotnet build --configuration Release
|
|
||||||
```
|
|
||||||
|
|
||||||
If you are getting error using the above steps try:
|
|
||||||
|
|
||||||
```
|
|
||||||
cd ~/NadekoBot/discord.net && dotnet restore -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json && dotnet restore
|
|
||||||
cd ~/NadekoBot/src/NadekoBot/ && dotnet restore && dotnet build --configuration Release
|
|
||||||
```
|
|
||||||
[img7]: https://cdn.discordapp.com/attachments/251504306010849280/251505766370902016/setting_up_credentials.gif
|
[img7]: https://cdn.discordapp.com/attachments/251504306010849280/251505766370902016/setting_up_credentials.gif
|
||||||
|
@ -6,14 +6,15 @@
|
|||||||
- Soundcloud Account (if you want soundcloud support)
|
- Soundcloud Account (if you want soundcloud support)
|
||||||
- Text Editor (TextWrangler, or equivalent) or outside editor such as [Atom][Atom]
|
- Text Editor (TextWrangler, or equivalent) or outside editor such as [Atom][Atom]
|
||||||
|
|
||||||
####Installing Homebrew
|
#### Installing Homebrew
|
||||||
|
|
||||||
```/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"```
|
```/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"```
|
||||||
|
|
||||||
Run `brew update` to fetch the latest package data.
|
Run `brew update` to fetch the latest package data.
|
||||||
|
|
||||||
####Installing dependencies
|
#### Installing dependencies
|
||||||
```
|
```
|
||||||
|
brew install wget
|
||||||
brew install git
|
brew install git
|
||||||
brew install ffmpeg
|
brew install ffmpeg
|
||||||
brew update && brew upgrade ffmpeg
|
brew update && brew upgrade ffmpeg
|
||||||
@ -26,15 +27,15 @@ brew install libsodium
|
|||||||
brew install tmux
|
brew install tmux
|
||||||
```
|
```
|
||||||
|
|
||||||
####Installing .NET Core SDK
|
#### Installing .NET Core SDK
|
||||||
|
|
||||||
- `ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/`
|
- `ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/`
|
||||||
- `ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/`
|
- `ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/`
|
||||||
- Download the [.NET Core SDK](https://www.microsoft.com/net/core#macos), found [here.](https://go.microsoft.com/fwlink/?LinkID=835011)
|
- Download the [.NET Core SDK][.NET Core SDK]
|
||||||
- Open the `.pkg` file you downloaded and install it.
|
- Open the `.pkg` file you downloaded and install it.
|
||||||
- `ln -s /usr/local/share/dotnet/dotnet /usr/local/bin`
|
- `ln -s /usr/local/share/dotnet/dotnet /usr/local/bin`
|
||||||
|
|
||||||
####Check your `FFMPEG`
|
#### Check your `FFMPEG`
|
||||||
|
|
||||||
**In case your `FFMPEG` wasnt installed properly (Optional)**
|
**In case your `FFMPEG` wasnt installed properly (Optional)**
|
||||||
|
|
||||||
@ -45,7 +46,7 @@ brew install tmux
|
|||||||
- `brew doctor` (Check your Homebrew installation for common issues)
|
- `brew doctor` (Check your Homebrew installation for common issues)
|
||||||
- Then try `brew install ffmpeg` again.
|
- Then try `brew install ffmpeg` again.
|
||||||
|
|
||||||
####Installing xcode-select
|
#### Installing xcode-select
|
||||||
|
|
||||||
Xcode command line tools. You will do this in Terminal.app by running the following command line:
|
Xcode command line tools. You will do this in Terminal.app by running the following command line:
|
||||||
|
|
||||||
@ -53,7 +54,7 @@ Xcode command line tools. You will do this in Terminal.app by running the follow
|
|||||||
|
|
||||||
A dialog box will open asking if you want to install `xcode-select`. Select install and finish the installation.
|
A dialog box will open asking if you want to install `xcode-select`. Select install and finish the installation.
|
||||||
|
|
||||||
####Downloading and building Nadeko
|
#### Downloading and building Nadeko
|
||||||
|
|
||||||
Use the following command to get and run `linuxAIO.sh`:
|
Use the following command to get and run `linuxAIO.sh`:
|
||||||
(Remember **DO NOT** rename the file `linuxAIO.sh`)
|
(Remember **DO NOT** rename the file `linuxAIO.sh`)
|
||||||
@ -69,7 +70,7 @@ Choose either `1` or `2` then press `enter` key.
|
|||||||
Once Installation is completed you should see the options again.
|
Once Installation is completed you should see the options again.
|
||||||
Next, choose `5` to exit.
|
Next, choose `5` to exit.
|
||||||
|
|
||||||
####Creating and Inviting bot
|
#### Creating and Inviting bot
|
||||||
|
|
||||||
- Read here how to [create a DiscordBot application](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#creating-discordbot-application)
|
- Read here how to [create a DiscordBot application](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#creating-discordbot-application)
|
||||||
- [Visual Invite Guide](http://discord.kongslien.net/guide.html) *NOTE: Client ID is your Bot ID*
|
- [Visual Invite Guide](http://discord.kongslien.net/guide.html) *NOTE: Client ID is your Bot ID*
|
||||||
@ -79,17 +80,17 @@ Next, choose `5` to exit.
|
|||||||
- Go to the newly created link and pick the server we created, and click `Authorize`.
|
- Go to the newly created link and pick the server we created, and click `Authorize`.
|
||||||
- The bot should have been added to your server.
|
- The bot should have been added to your server.
|
||||||
|
|
||||||
####Setting up Credentials.json file
|
#### Setting up Credentials.json file
|
||||||
- Open up the `NadekoBot` folder, which should be in your home directory, then `NadekoBot` folder then `src` folder and then the additonal `NadekoBot` folder.
|
- Open up the `NadekoBot` folder, which should be in your home directory, then `NadekoBot` folder then `src` folder and then the additonal `NadekoBot` folder.
|
||||||
- EDIT it as it is guided here: [Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file)
|
- EDIT it as it is guided here: [Setting up credentials.json](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-credentialsjson-file)
|
||||||
- **If** you already have Nadeko 1.0 setup and have `credentials.json` and `NadekoBot.db`, you can just copy and paste the `credentials.json` to `NadekoBot/src/NadekoBot` and `NadekoBot.db` to `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data`.
|
- **If** you already have Nadeko 1.0 setup and have `credentials.json` and `NadekoBot.db`, you can just copy and paste the `credentials.json` to `NadekoBot/src/NadekoBot` and `NadekoBot.db` to `NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.0/data`.
|
||||||
- **If** you have Nadeko 0.9x follow the [Upgrading Guide](http://nadekobot.readthedocs.io/en/latest/guides/Upgrading%20Guide/)
|
- **If** you have Nadeko 0.9x follow the [Upgrading Guide](http://nadekobot.readthedocs.io/en/latest/guides/Upgrading%20Guide/)
|
||||||
|
|
||||||
####Setting NadekoBot Music
|
#### Setting NadekoBot Music
|
||||||
|
|
||||||
For Music Setup and API keys check [Setting up NadekoBot for Music](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music) and [JSON Explanations](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/).
|
For Music Setup and API keys check [Setting up NadekoBot for Music](http://nadekobot.readthedocs.io/en/latest/guides/Windows%20Guide/#setting-up-nadekobot-for-music) and [JSON Explanations](http://nadekobot.readthedocs.io/en/latest/JSON%20Explanations/).
|
||||||
|
|
||||||
####Running NadekoBot
|
#### Running NadekoBot
|
||||||
|
|
||||||
- Using tmux
|
- Using tmux
|
||||||
|
|
||||||
@ -123,7 +124,7 @@ Choose `4` To Run the bot with Auto Restart.
|
|||||||
Now time to move bot to background and to do that, press CTRL+B+D (this will detach the nadeko session using TMUX)
|
Now time to move bot to background and to do that, press CTRL+B+D (this will detach the nadeko session using TMUX)
|
||||||
If you used Screen press CTRL+A+D (this will detach the nadeko screen)
|
If you used Screen press CTRL+A+D (this will detach the nadeko screen)
|
||||||
|
|
||||||
####Updating Nadeko
|
#### Updating Nadeko
|
||||||
|
|
||||||
- Connect to the terminal.
|
- Connect to the terminal.
|
||||||
- `tmux kill-session -t nadeko` [(don't forget to replace **nadeko** in the command to what ever you named your bot's session)](http://nadekobot.readthedocs.io/en/latest/guides/OSX%20Guide/#some-more-info)
|
- `tmux kill-session -t nadeko` [(don't forget to replace **nadeko** in the command to what ever you named your bot's session)](http://nadekobot.readthedocs.io/en/latest/guides/OSX%20Guide/#some-more-info)
|
||||||
@ -134,7 +135,7 @@ If you used Screen press CTRL+A+D (this will detach the nadeko screen)
|
|||||||
- Choose either `3` or `4` to run the bot again with **normally** or **auto restart** respectively.
|
- Choose either `3` or `4` to run the bot again with **normally** or **auto restart** respectively.
|
||||||
- Done. You can close terminal now.
|
- Done. You can close terminal now.
|
||||||
|
|
||||||
####Some more Info
|
#### Some more Info
|
||||||
|
|
||||||
**TMUX**
|
**TMUX**
|
||||||
|
|
||||||
@ -148,7 +149,7 @@ If you used Screen press CTRL+A+D (this will detach the nadeko screen)
|
|||||||
- If you want to switch to/ see that screen, type `screen -r nadeko` (nadeko is the name of the screen we created before so, replace `nadeko` with the screen name you created.)
|
- If you want to switch to/ see that screen, type `screen -r nadeko` (nadeko is the name of the screen we created before so, replace `nadeko` with the screen name you created.)
|
||||||
- If you want to kill the NadekoBot screen, type `screen -X -S nadeko quit`
|
- If you want to kill the NadekoBot screen, type `screen -X -S nadeko quit`
|
||||||
|
|
||||||
####Alternative Method to Install Nadeko
|
#### Alternative Method to Install Nadeko
|
||||||
|
|
||||||
**METHOD I**
|
**METHOD I**
|
||||||
|
|
||||||
@ -166,6 +167,7 @@ If you used Screen press CTRL+A+D (this will detach the nadeko screen)
|
|||||||
- `dotnet build --configuration Release`
|
- `dotnet build --configuration Release`
|
||||||
|
|
||||||
[Homebrew]: http://brew.sh/
|
[Homebrew]: http://brew.sh/
|
||||||
|
[.NET Core SDK]: https://github.com/dotnet/core/blob/master/release-notes/download-archives/1.1-preview2.1-download.md
|
||||||
[DiscordApp]: https://discordapp.com/developers/applications/me
|
[DiscordApp]: https://discordapp.com/developers/applications/me
|
||||||
[Atom]: https://atom.io/
|
[Atom]: https://atom.io/
|
||||||
[Invite Guide]: http://discord.kongslien.net/guide.html
|
[Invite Guide]: http://discord.kongslien.net/guide.html
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
________________________________________________________________________________
|
________________________________________________________________________________
|
||||||
*Thanks to @Flatbread and Mirai for making this guide*
|
*Thanks to @Flatbread and @Mirai for making this guide*
|
||||||
________________________________________________________________________________
|
________________________________________________________________________________
|
||||||
|
|
||||||
## Setting Up NadekoBot on Windows
|
## Setting Up NadekoBot on Windows
|
||||||
@ -13,7 +13,7 @@ ________________________________________________________________________________
|
|||||||
- 6) [Notepad++][Notepad++]
|
- 6) [Notepad++][Notepad++]
|
||||||
- 7) Windows 8 or later
|
- 7) Windows 8 or later
|
||||||
|
|
||||||
####Guide
|
#### Guide
|
||||||
- Make sure you have installed both [Git][Git] and the [.NET Core SDK][.NET Core SDK].
|
- Make sure you have installed both [Git][Git] and the [.NET Core SDK][.NET Core SDK].
|
||||||
- Create a **new folder** anywhere you like and name it `Nadeko`.
|
- Create a **new folder** anywhere you like and name it `Nadeko`.
|
||||||
- Next, [Right-Click on this link](https://github.com/Kwoth/NadekoBotInstallerWin/raw/master/NadekoInstaller.bat) and select **Save link as** and save the file `NadekoInstaller.bat` inside the `Nadeko` folder that we created earlier. (Please **DO NOT** rename the file `NadekoInstaller.bat`.)
|
- Next, [Right-Click on this link](https://github.com/Kwoth/NadekoBotInstallerWin/raw/master/NadekoInstaller.bat) and select **Save link as** and save the file `NadekoInstaller.bat` inside the `Nadeko` folder that we created earlier. (Please **DO NOT** rename the file `NadekoInstaller.bat`.)
|
||||||
@ -24,8 +24,9 @@ ________________________________________________________________________________
|
|||||||
- Wait a while for the file to finish installing, it'll display it's progress in the command prompt.
|
- Wait a while for the file to finish installing, it'll display it's progress in the command prompt.
|
||||||
- You should now have a new folder named `NadekoBot` inside the `Nadeko` folder we previously created.
|
- You should now have a new folder named `NadekoBot` inside the `Nadeko` folder we previously created.
|
||||||
- Once Installation is completed, press any key to close the command prompt.
|
- Once Installation is completed, press any key to close the command prompt.
|
||||||
|
![img1](http://i.imgur.com/O1dY9eW.gif)
|
||||||
|
|
||||||
####Creating DiscordBot application
|
#### Creating DiscordBot application
|
||||||
- Go to [the Discord developer application page][DiscordApp].
|
- Go to [the Discord developer application page][DiscordApp].
|
||||||
- Log in with your Discord account.
|
- Log in with your Discord account.
|
||||||
- On the left side, press `New Application`.
|
- On the left side, press `New Application`.
|
||||||
@ -33,8 +34,9 @@ ________________________________________________________________________________
|
|||||||
- Create the application.
|
- Create the application.
|
||||||
- Click on `Create a Bot User` and confirm that you do want to add a bot to this app.
|
- Click on `Create a Bot User` and confirm that you do want to add a bot to this app.
|
||||||
- Keep this window open for now.
|
- Keep this window open for now.
|
||||||
|
![img2](http://i.imgur.com/x3jWudH.gif)
|
||||||
|
|
||||||
####Setting up credentials.json file
|
#### Setting up credentials.json file
|
||||||
- In our `NadekoBot` folder you should see a `src` folder, then *another* `NadekoBot` folder, in this final folder, you should see a `.json` file named `credentials.json`. (Note: If you do not see a `.json` after `credentials.json`, do not add the `.json`. You most likely have **"Hide file extensions"** enabled.)
|
- In our `NadekoBot` folder you should see a `src` folder, then *another* `NadekoBot` folder, in this final folder, you should see a `.json` file named `credentials.json`. (Note: If you do not see a `.json` after `credentials.json`, do not add the `.json`. You most likely have **"Hide file extensions"** enabled.)
|
||||||
- If you mess up the setup of `credentials.json`, rename `credentials_example.json` to `credentials.json`.
|
- If you mess up the setup of `credentials.json`, rename `credentials_example.json` to `credentials.json`.
|
||||||
- Open the file with [Notepad++][Notepad++].
|
- Open the file with [Notepad++][Notepad++].
|
||||||
@ -45,19 +47,21 @@ ________________________________________________________________________________
|
|||||||
- Again, copy the same `Client ID` and replace the `null` part of the `BotId` line with it.
|
- Again, copy the same `Client ID` and replace the `null` part of the `BotId` line with it.
|
||||||
- Go to a server on discord and attempt to mention yourself, but put a backslash at the start like shown below
|
- Go to a server on discord and attempt to mention yourself, but put a backslash at the start like shown below
|
||||||
- So the message `\@fearnlj01#3535` will appears as `<@145521851676884992>` after you send the message (to make it slightly easier, add the backslash after you type the mention out)
|
- So the message `\@fearnlj01#3535` will appears as `<@145521851676884992>` after you send the message (to make it slightly easier, add the backslash after you type the mention out)
|
||||||
- The message will appear as a mention if done correctly, copy the numbers from the message you sent (`145521851676884992`) and replace the `0` on the `OwnerIds` section with your user ID shown earlier.
|
- The message will appear as a mention if done correctly, copy the numbers from the message you sent (`145521851676884992`) and replace the ID (By default, the ID is `105635576866156544`) on the `OwnerIds` section with your user ID shown earlier.
|
||||||
- Save `credentials.json` (make sure you aren't saving it as `credentials.json.txt`)
|
- Save `credentials.json` (make sure you aren't saving it as `credentials.json.txt`)
|
||||||
- If done correctly, you are now the bot owner. You can add multiple owners by seperating each owner ID with a comma within the square brackets.
|
- If done correctly, you are now the bot owner. You can add multiple owners by seperating each owner ID with a comma within the square brackets.
|
||||||
|
![img3](http://i.imgur.com/QwKMnTG.gif)
|
||||||
|
|
||||||
####Inviting your bot to your server
|
#### Inviting your bot to your server
|
||||||
- [Invite Guide][Invite Guide]
|
- [Invite Guide][Invite Guide]
|
||||||
- Copy your `Client ID` from your [applications page][DiscordApp].
|
- Copy your `Client ID` from your [applications page][DiscordApp].
|
||||||
- Replace the `12345678` in this link `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with your `Client ID`.
|
- Replace the `12345678` in this link `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with your `Client ID`.
|
||||||
- The link should now look like this: `https://discordapp.com/oauth2/authorize?client_id=**YOUR_CLENT_ID_HERE**&scope=bot&permissions=66186303`.
|
- The link should now look like this: `https://discordapp.com/oauth2/authorize?client_id=**YOUR_CLENT_ID_HERE**&scope=bot&permissions=66186303`.
|
||||||
- Go to the newly created link and pick the server we created, and click `Authorize`.
|
- Go to the newly created link and pick the server we created, and click `Authorize`.
|
||||||
- The bot should have been added to your server.
|
- The bot should have been added to your server.
|
||||||
|
![img4](http://i.imgur.com/aFK7InR.gif)
|
||||||
|
|
||||||
####Starting the bot
|
#### Starting the bot
|
||||||
- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file as Administrator.
|
- Go to the `Nadeko` folder that we have created earlier, and run the `NadekoInstaller.bat` file as Administrator.
|
||||||
- From the options,
|
- From the options,
|
||||||
- Choose `3` to **run the bot normally**.
|
- Choose `3` to **run the bot normally**.
|
||||||
@ -65,7 +69,7 @@ ________________________________________________________________________________
|
|||||||
- Choose `4` to **run the bot with auto restart**.
|
- Choose `4` to **run the bot with auto restart**.
|
||||||
(with auto restart the bot will restart itself if it disconnects by the use of `.die` command. Useful if you want to have restart function for any reason.)
|
(with auto restart the bot will restart itself if it disconnects by the use of `.die` command. Useful if you want to have restart function for any reason.)
|
||||||
|
|
||||||
####Updating NadekoBot
|
#### Updating NadekoBot
|
||||||
- Make sure the bot is closed and is not running (Run `.die` in a connected server to ensure it's not running).
|
- Make sure the bot is closed and is not running (Run `.die` in a connected server to ensure it's not running).
|
||||||
- Once that's checked, go to the `Nadeko` folder.
|
- Once that's checked, go to the `Nadeko` folder.
|
||||||
- Run the `NadekoInstaller.bat` file.
|
- Run the `NadekoInstaller.bat` file.
|
||||||
@ -106,7 +110,8 @@ In order to have a functioning music module, you need to install ffmpeg and setu
|
|||||||
- Follow these steps on how to setup Google API keys:
|
- Follow these steps on how to setup Google API keys:
|
||||||
- Go to [Google Console][Google Console] and log in.
|
- Go to [Google Console][Google Console] and log in.
|
||||||
- Create a new project (name does not matter). Once the project is created, go into "Enable and manage APIs."
|
- Create a new project (name does not matter). Once the project is created, go into "Enable and manage APIs."
|
||||||
- Under the "Other Popular APIs" section, enable `URL Shortener API` and `Custom Search Api`. Under the `YouTube APIs` section, enable `YouTube Data API`.
|
- Under the "Other Popular APIs" section, enable `URL Shortener API` and `Custom Search API`. Under the `YouTube APIs` section, enable `YouTube Data API`.
|
||||||
|
- Under the "Google Maps APIs" section, enable `Google Maps Geocoding API` and `Google Maps Time Zone API`.
|
||||||
- On the left tab, access `Credentials`. Click `Create Credentials` button. Click on `API Key`. A new window will appear with your `Google API key`.
|
- On the left tab, access `Credentials`. Click `Create Credentials` button. Click on `API Key`. A new window will appear with your `Google API key`.
|
||||||
- Copy the key.
|
- Copy the key.
|
||||||
- Open up `credentials.json`.
|
- Open up `credentials.json`.
|
||||||
@ -120,7 +125,9 @@ In order to have a functioning music module, you need to install ffmpeg and setu
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
[.NET Core SDK]: https://www.microsoft.com/net/core#windowscmd
|
|
||||||
|
|
||||||
|
[.NET Core SDK]: https://github.com/dotnet/core/blob/master/release-notes/download-archives/1.1-preview2.1-download.md
|
||||||
[Git]: https://git-scm.com/download/win
|
[Git]: https://git-scm.com/download/win
|
||||||
[7zip]: http://www.7-zip.org/download.html
|
[7zip]: http://www.7-zip.org/download.html
|
||||||
[DiscordApp]: https://discordapp.com/developers/applications/me
|
[DiscordApp]: https://discordapp.com/developers/applications/me
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
{
|
{
|
||||||
"projects": [ "Discord.Net/src", "src" ]
|
"projects": [ "Discord.Net/src", "src" ],
|
||||||
|
"sdk": {
|
||||||
|
"version": "1.0.0-preview2-1-003177"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
@ECHO off
|
@ECHO off
|
||||||
TITLE Downloading Latest Build of NadekoBot...
|
TITLE Downloading Latest Build of NadekoBot...
|
||||||
::Setting convenient to read variables which don't delete the windows temp folder
|
::Setting convenient to read variables which don't delete the windows temp folder
|
||||||
SET root=%~dp0
|
SET "root=%~dp0"
|
||||||
CD /D %root%
|
CD /D "%root%"
|
||||||
SET rootdir=%cd%
|
SET "rootdir=%cd%"
|
||||||
SET build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\
|
SET "build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\"
|
||||||
SET build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\
|
SET "build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\"
|
||||||
SET build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\
|
SET "build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\"
|
||||||
SET build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\
|
SET "build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\"
|
||||||
SET build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\
|
SET "build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\"
|
||||||
SET installtemp=%root%NadekoInstall_Temp\
|
SET "installtemp=%root%NadekoInstall_Temp\"
|
||||||
::Deleting traces of last setup for the sake of clean folders, if by some miracle it still exists
|
::Deleting traces of last setup for the sake of clean folders, if by some miracle it still exists
|
||||||
IF EXIST %installtemp% ( RMDIR %installtemp% /S /Q >nul 2>&1)
|
IF EXIST "%installtemp%" ( RMDIR "%installtemp%" /S /Q >nul 2>&1)
|
||||||
|
timeout /t 5
|
||||||
::Checks that both git and dotnet are installed
|
::Checks that both git and dotnet are installed
|
||||||
dotnet --version >nul 2>&1 || GOTO :dotnet
|
dotnet --version >nul 2>&1 || GOTO :dotnet
|
||||||
git --version >nul 2>&1 || GOTO :git
|
git --version >nul 2>&1 || GOTO :git
|
||||||
::Creates the install directory to work in and get the current directory because spaces ruins everything otherwise
|
::Creates the install directory to work in and get the current directory because spaces ruins everything otherwise
|
||||||
:start
|
:start
|
||||||
MKDIR NadekoInstall_Temp
|
MKDIR "%root%NadekoInstall_Temp"
|
||||||
CD /D %installtemp%
|
CD /D "%installtemp%"
|
||||||
::Downloads the latest version of Nadeko
|
::Downloads the latest version of Nadeko
|
||||||
ECHO Downloading Nadeko...
|
ECHO Downloading Nadeko...
|
||||||
ECHO.
|
ECHO.
|
||||||
@ -28,28 +29,28 @@ TITLE Installing NadekoBot, please wait...
|
|||||||
ECHO.
|
ECHO.
|
||||||
ECHO Installing Discord.Net(1/4)...
|
ECHO Installing Discord.Net(1/4)...
|
||||||
::Building Nadeko
|
::Building Nadeko
|
||||||
CD /D %build1%
|
CD /D "%build1%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO Installing Discord.Net(2/4)...
|
ECHO Installing Discord.Net(2/4)...
|
||||||
CD /D %build2%
|
CD /D "%build2%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO Installing Discord.Net(3/4)...
|
ECHO Installing Discord.Net(3/4)...
|
||||||
CD /D %build3%
|
CD /D "%build3%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO Installing Discord.Net(4/4)...
|
ECHO Installing Discord.Net(4/4)...
|
||||||
CD /D %build4%
|
CD /D "%build4%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Discord.Net installation completed successfully...
|
ECHO Discord.Net installation completed successfully...
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Installing NadekoBot...
|
ECHO Installing NadekoBot...
|
||||||
CD /D %build5%
|
CD /D "%build5%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
dotnet build --configuration Release >nul 2>&1
|
dotnet build --configuration Release >nul 2>&1
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO NadekoBot installation completed successfully...
|
ECHO NadekoBot installation completed successfully...
|
||||||
::Attempts to backup old files if they currently exist in the same folder as the batch file
|
::Attempts to backup old files if they currently exist in the same folder as the batch file
|
||||||
IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) ELSE (GOTO :freshinstall)
|
||||||
:freshinstall
|
:freshinstall
|
||||||
::Moves the NadekoBot folder to keep things tidy
|
::Moves the NadekoBot folder to keep things tidy
|
||||||
ECHO.
|
ECHO.
|
||||||
@ -65,20 +66,23 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
|||||||
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)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Old files backed up to NadekoBot_Old
|
ECHO Old files backed up to NadekoBot_Old...
|
||||||
::Copies the credentials and database from the backed up data to the new folder
|
::Copies the credentials and database from the backed up data to the new folder
|
||||||
COPY "%root%NadekoBot_Old\src\NadekoBot\credentials.json" "%installtemp%NadekoBot\src\NadekoBot\credentials.json" >nul 2>&1
|
COPY "%root%NadekoBot_Old\src\NadekoBot\credentials.json" "%installtemp%NadekoBot\src\NadekoBot\credentials.json" >nul 2>&1
|
||||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO credentials.json copied to new folder
|
ECHO credentials.json copied...
|
||||||
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\bin" "%installtemp%NadekoBot\src\NadekoBot\bin" /E >nul 2>&1
|
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\bin" "%installtemp%NadekoBot\src\NadekoBot\bin" /E >nul 2>&1
|
||||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Old bin folder copied to new folder
|
ECHO bin folder copied...
|
||||||
|
RD /S /Q "%root%NadekoBot_Old\src\NadekoBot\data\musicdata"
|
||||||
|
ECHO.
|
||||||
|
ECHO music cache cleared...
|
||||||
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1
|
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1
|
||||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Old data folder copied to new folder
|
ECHO Old data folder copied...
|
||||||
::Moves the setup Nadeko folder
|
::Moves the setup Nadeko folder
|
||||||
RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1
|
RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1
|
||||||
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
||||||
@ -103,7 +107,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
|||||||
:giterror
|
:giterror
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Git clone failed, trying again
|
ECHO Git clone failed, trying again
|
||||||
RMDIR %installtemp% /S /Q >nul 2>&1
|
RMDIR "%installtemp%" /S /Q >nul 2>&1
|
||||||
GOTO :start
|
GOTO :start
|
||||||
:copyerror
|
:copyerror
|
||||||
::If at any point a copy error is encountered
|
::If at any point a copy error is encountered
|
||||||
@ -124,22 +128,39 @@ ECHO.
|
|||||||
ECHO Your System Architecture is 32bit...
|
ECHO Your System Architecture is 32bit...
|
||||||
timeout /t 5
|
timeout /t 5
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Downloading libsodium.dll and opus.dll...
|
ECHO Getting 32bit libsodium.dll and opus.dll...
|
||||||
|
IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" (GOTO copysodium) ELSE (GOTO downloadsodium)
|
||||||
|
:copysodium
|
||||||
|
del "%root%NadekoBot\src\NadekoBot\libsodium.dll"
|
||||||
|
copy "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" "%root%NadekoBot\src\NadekoBot\libsodium.dll"
|
||||||
|
ECHO libsodium.dll copied.
|
||||||
|
ECHO.
|
||||||
|
timeout /t 5
|
||||||
|
IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus)
|
||||||
|
:downloadsodium
|
||||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll"
|
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll"
|
||||||
bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%"
|
powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile '%FILENAME%'"
|
||||||
ECHO libsodium.dll downloaded.
|
ECHO libsodium.dll downloaded.
|
||||||
ECHO.
|
ECHO.
|
||||||
timeout /t 5
|
timeout /t 5
|
||||||
|
IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus)
|
||||||
|
:copyopus
|
||||||
|
del "%root%NadekoBot\src\NadekoBot\opus.dll"
|
||||||
|
copy "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" "%root%NadekoBot\src\NadekoBot\opus.dll"
|
||||||
|
ECHO opus.dll copied.
|
||||||
|
GOTO end
|
||||||
|
:downloadopus
|
||||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll"
|
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll"
|
||||||
bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%"
|
powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile '%FILENAME%'"
|
||||||
ECHO opus.dll downloaded.
|
ECHO opus.dll downloaded.
|
||||||
GOTO end
|
GOTO end
|
||||||
:end
|
:end
|
||||||
::Normal execution of end of script
|
::Normal execution of end of script
|
||||||
TITLE Installation complete!
|
TITLE NadekoBot Installation complete!
|
||||||
CD /D "%root%"
|
CD /D "%root%"
|
||||||
RMDIR /S /Q "%installtemp%" >nul 2>&1
|
RMDIR /S /Q "%installtemp%" >nul 2>&1
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Installation complete, press any key to close this window!
|
ECHO Installation complete!
|
||||||
|
ECHO.
|
||||||
timeout /t 5
|
timeout /t 5
|
||||||
del Latest.bat
|
del Latest.bat
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
@TITLE NadekoBot
|
@TITLE NadekoBot
|
||||||
|
|
||||||
|
|
||||||
SET root=%~dp0
|
SET "root=%~dp0"
|
||||||
CD /D %root%
|
CD /D "%root%"
|
||||||
|
|
||||||
CLS
|
CLS
|
||||||
ECHO Welcome to NadekoBot Auto Restart and Update!
|
ECHO Welcome to NadekoBot Auto Restart and Update!
|
||||||
@ -25,32 +25,28 @@ IF ERRORLEVEL 1 GOTO latestar
|
|||||||
:latestar
|
:latestar
|
||||||
ECHO Auto Restart and Update with Dev Build (latest)
|
ECHO Auto Restart and Update with Dev Build (latest)
|
||||||
ECHO Bot will auto update on every restart!
|
ECHO Bot will auto update on every restart!
|
||||||
timeout /t 3
|
CD /D "%~dp0NadekoBot\src\NadekoBot"
|
||||||
CD /D %~dp0NadekoBot\src\NadekoBot
|
|
||||||
dotnet run --configuration Release
|
dotnet run --configuration Release
|
||||||
ECHO Updating...
|
ECHO Updating...
|
||||||
timeout /t 3
|
|
||||||
SET "FILENAME=%~dp0\Latest.bat"
|
SET "FILENAME=%~dp0\Latest.bat"
|
||||||
bitsadmin.exe /transfer "Downloading Nadeko (Latest)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Latest.bat "%FILENAME%"
|
powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/scripts/Latest.bat -OutFile '%FILENAME%'"
|
||||||
ECHO NadekoBot Dev Build (latest) downloaded.
|
ECHO NadekoBot Dev Build (latest) downloaded.
|
||||||
SET root=%~dp0
|
SET "root=%~dp0"
|
||||||
CD /D %root%
|
CD /D "%root%"
|
||||||
CALL Latest.bat
|
CALL Latest.bat
|
||||||
GOTO latestar
|
GOTO latestar
|
||||||
|
|
||||||
:stablear
|
:stablear
|
||||||
ECHO Auto Restart and Update with Stable Build
|
ECHO Auto Restart and Update with Stable Build
|
||||||
ECHO Bot will auto update on every restart!
|
ECHO Bot will auto update on every restart!
|
||||||
timeout /t 3
|
CD /D "%~dp0NadekoBot\src\NadekoBot"
|
||||||
CD /D %~dp0NadekoBot\src\NadekoBot
|
|
||||||
dotnet run --configuration Release
|
dotnet run --configuration Release
|
||||||
ECHO Updating...
|
ECHO Updating...
|
||||||
timeout /t 3
|
|
||||||
SET "FILENAME=%~dp0\Stable.bat"
|
SET "FILENAME=%~dp0\Stable.bat"
|
||||||
bitsadmin.exe /transfer "Downloading Nadeko (Stable)" /priority high https://github.com/Kwoth/NadekoBot/raw/master/scripts/Stable.bat "%FILENAME%"
|
powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/scripts/Stable.bat -OutFile '%FILENAME%'"
|
||||||
ECHO NadekoBot Stable build downloaded.
|
ECHO NadekoBot Stable build downloaded.
|
||||||
SET root=%~dp0
|
SET "root=%~dp0"
|
||||||
CD /D %root%
|
CD /D "%root%"
|
||||||
CALL Stable.bat
|
CALL Stable.bat
|
||||||
GOTO stablear
|
GOTO stablear
|
||||||
|
|
||||||
@ -58,12 +54,12 @@ GOTO stablear
|
|||||||
ECHO Normal Auto Restart
|
ECHO Normal Auto Restart
|
||||||
ECHO Bot will not auto update on every restart!
|
ECHO Bot will not auto update on every restart!
|
||||||
timeout /t 3
|
timeout /t 3
|
||||||
CD /D %~dp0NadekoBot\src\NadekoBot
|
CD /D "%~dp0NadekoBot\src\NadekoBot"
|
||||||
dotnet run --configuration Release
|
dotnet run --configuration Release
|
||||||
goto autorun
|
goto autorun
|
||||||
|
|
||||||
:Exit
|
:Exit
|
||||||
SET root=%~dp0
|
SET "root=%~dp0"
|
||||||
CD /D %root%
|
CD /D "%root%"
|
||||||
del NadekoAutoRun.bat
|
del NadekoAutoRun.bat
|
||||||
CALL NadekoInstaller.bat
|
CALL NadekoInstaller.bat
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
@ECHO off
|
@ECHO off
|
||||||
@TITLE NadekoBot
|
@TITLE NadekoBot
|
||||||
CD /D %~dp0NadekoBot\src\NadekoBot
|
CD /D "%~dp0NadekoBot\src\NadekoBot"
|
||||||
dotnet run --configuration Release
|
dotnet run --configuration Release
|
||||||
ECHO NadekoBot has been succesfully stopped, press any key to close this window.
|
ECHO NadekoBot has been succesfully stopped, press any key to close this window.
|
||||||
TITLE NadekoBot - Stopped
|
TITLE NadekoBot - Stopped
|
||||||
CD /D %~dp0
|
CD /D "%~dp0"
|
||||||
PAUSE >nul 2>&1
|
PAUSE >nul 2>&1
|
||||||
del NadekoRunNormal.bat
|
del NadekoRunNormal.bat
|
||||||
|
@ -1,24 +1,25 @@
|
|||||||
@ECHO off
|
@ECHO off
|
||||||
TITLE Downloading Stable Build of NadekoBot...
|
TITLE Downloading Stable Build of NadekoBot...
|
||||||
::Setting convenient to read variables which don't delete the windows temp folder
|
::Setting convenient to read variables which don't delete the windows temp folder
|
||||||
SET root=%~dp0
|
SET "root=%~dp0"
|
||||||
CD /D %root%
|
CD /D "%root%"
|
||||||
SET rootdir=%cd%
|
SET "rootdir=%cd%"
|
||||||
SET build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\
|
SET "build1=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Core\"
|
||||||
SET build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\
|
SET "build2=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Rest\"
|
||||||
SET build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\
|
SET "build3=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.WebSocket\"
|
||||||
SET build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\
|
SET "build4=%root%NadekoInstall_Temp\NadekoBot\Discord.Net\src\Discord.Net.Commands\"
|
||||||
SET build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\
|
SET "build5=%root%NadekoInstall_Temp\NadekoBot\src\NadekoBot\"
|
||||||
SET installtemp=%root%NadekoInstall_Temp\
|
SET "installtemp=%root%NadekoInstall_Temp\"
|
||||||
::Deleting traces of last setup for the sake of clean folders, if by some miracle it still exists
|
::Deleting traces of last setup for the sake of clean folders, if by some miracle it still exists
|
||||||
IF EXIST %installtemp% ( RMDIR %installtemp% /S /Q >nul 2>&1)
|
IF EXIST "%installtemp%" ( RMDIR "%installtemp%" /S /Q >nul 2>&1)
|
||||||
|
timeout /t 5
|
||||||
::Checks that both git and dotnet are installed
|
::Checks that both git and dotnet are installed
|
||||||
dotnet --version >nul 2>&1 || GOTO :dotnet
|
dotnet --version >nul 2>&1 || GOTO :dotnet
|
||||||
git --version >nul 2>&1 || GOTO :git
|
git --version >nul 2>&1 || GOTO :git
|
||||||
::Creates the install directory to work in and get the current directory because spaces ruins everything otherwise
|
::Creates the install directory to work in and get the current directory because spaces ruins everything otherwise
|
||||||
:start
|
:start
|
||||||
MKDIR NadekoInstall_Temp
|
MKDIR "%root%NadekoInstall_Temp"
|
||||||
CD /D %installtemp%
|
CD /D "%installtemp%"
|
||||||
::Downloads the latest version of Nadeko
|
::Downloads the latest version of Nadeko
|
||||||
ECHO Downloading Nadeko...
|
ECHO Downloading Nadeko...
|
||||||
ECHO.
|
ECHO.
|
||||||
@ -28,28 +29,28 @@ TITLE Installing NadekoBot, please wait...
|
|||||||
ECHO.
|
ECHO.
|
||||||
ECHO Installing Discord.Net(1/4)...
|
ECHO Installing Discord.Net(1/4)...
|
||||||
::Building Nadeko
|
::Building Nadeko
|
||||||
CD /D %build1%
|
CD /D "%build1%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO Installing Discord.Net(2/4)...
|
ECHO Installing Discord.Net(2/4)...
|
||||||
CD /D %build2%
|
CD /D "%build2%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO Installing Discord.Net(3/4)...
|
ECHO Installing Discord.Net(3/4)...
|
||||||
CD /D %build3%
|
CD /D "%build3%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO Installing Discord.Net(4/4)...
|
ECHO Installing Discord.Net(4/4)...
|
||||||
CD /D %build4%
|
CD /D "%build4%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Discord.Net installation completed successfully...
|
ECHO Discord.Net installation completed successfully...
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Installing NadekoBot...
|
ECHO Installing NadekoBot...
|
||||||
CD /D %build5%
|
CD /D "%build5%"
|
||||||
dotnet restore >nul 2>&1
|
dotnet restore >nul 2>&1
|
||||||
dotnet build --configuration Release >nul 2>&1
|
dotnet build --configuration Release >nul 2>&1
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO NadekoBot installation completed successfully...
|
ECHO NadekoBot installation completed successfully...
|
||||||
::Attempts to backup old files if they currently exist in the same folder as the batch file
|
::Attempts to backup old files if they currently exist in the same folder as the batch file
|
||||||
IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
IF EXIST "%root%NadekoBot\" (GOTO :backupinstall) ELSE (GOTO :freshinstall)
|
||||||
:freshinstall
|
:freshinstall
|
||||||
::Moves the NadekoBot folder to keep things tidy
|
::Moves the NadekoBot folder to keep things tidy
|
||||||
ECHO.
|
ECHO.
|
||||||
@ -65,20 +66,23 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
|||||||
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)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Old files backed up to NadekoBot_Old
|
ECHO Old files backed up to NadekoBot_Old...
|
||||||
::Copies the credentials and database from the backed up data to the new folder
|
::Copies the credentials and database from the backed up data to the new folder
|
||||||
COPY "%root%NadekoBot_Old\src\NadekoBot\credentials.json" "%installtemp%NadekoBot\src\NadekoBot\credentials.json" >nul 2>&1
|
COPY "%root%NadekoBot_Old\src\NadekoBot\credentials.json" "%installtemp%NadekoBot\src\NadekoBot\credentials.json" >nul 2>&1
|
||||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO credentials.json copied to new folder
|
ECHO credentials.json copied...
|
||||||
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\bin" "%installtemp%NadekoBot\src\NadekoBot\bin" /E >nul 2>&1
|
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\bin" "%installtemp%NadekoBot\src\NadekoBot\bin" /E >nul 2>&1
|
||||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Old bin folder copied to new folder
|
ECHO bin folder copied...
|
||||||
|
RD /S /Q "%root%NadekoBot_Old\src\NadekoBot\data\musicdata"
|
||||||
|
ECHO.
|
||||||
|
ECHO music cache cleared...
|
||||||
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1
|
ROBOCOPY "%root%NadekoBot_Old\src\NadekoBot\data" "%installtemp%NadekoBot\src\NadekoBot\data" /E >nul 2>&1
|
||||||
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
IF %ERRORLEVEL% GEQ 8 (GOTO :copyerror)
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Old data folder copied to new folder
|
ECHO Old data folder copied...
|
||||||
::Moves the setup Nadeko folder
|
::Moves the setup Nadeko folder
|
||||||
RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1
|
RMDIR "%root%NadekoBot\" /S /Q >nul 2>&1
|
||||||
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
ROBOCOPY "%root%NadekoInstall_Temp" "%rootdir%" /E /MOVE >nul 2>&1
|
||||||
@ -103,7 +107,7 @@ IF EXIST "%root%NadekoBot\" (GOTO :backupinstall)
|
|||||||
:giterror
|
:giterror
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Git clone failed, trying again
|
ECHO Git clone failed, trying again
|
||||||
RMDIR %installtemp% /S /Q >nul 2>&1
|
RMDIR "%installtemp%" /S /Q >nul 2>&1
|
||||||
GOTO :start
|
GOTO :start
|
||||||
:copyerror
|
:copyerror
|
||||||
::If at any point a copy error is encountered
|
::If at any point a copy error is encountered
|
||||||
@ -124,22 +128,39 @@ ECHO.
|
|||||||
ECHO Your System Architecture is 32bit...
|
ECHO Your System Architecture is 32bit...
|
||||||
timeout /t 5
|
timeout /t 5
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Downloading libsodium.dll and opus.dll...
|
ECHO Getting 32bit libsodium.dll and opus.dll...
|
||||||
|
IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" (GOTO copysodium) ELSE (GOTO downloadsodium)
|
||||||
|
:copysodium
|
||||||
|
del "%root%NadekoBot\src\NadekoBot\libsodium.dll"
|
||||||
|
copy "%root%NadekoBot\src\NadekoBot\_libs\32\libsodium.dll" "%root%NadekoBot\src\NadekoBot\libsodium.dll"
|
||||||
|
ECHO libsodium.dll copied.
|
||||||
|
ECHO.
|
||||||
|
timeout /t 5
|
||||||
|
IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus)
|
||||||
|
:downloadsodium
|
||||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll"
|
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\libsodium.dll"
|
||||||
bitsadmin.exe /transfer "Downloading libsodium.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll "%FILENAME%"
|
powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/libsodium.dll -OutFile '%FILENAME%'"
|
||||||
ECHO libsodium.dll downloaded.
|
ECHO libsodium.dll downloaded.
|
||||||
ECHO.
|
ECHO.
|
||||||
timeout /t 5
|
timeout /t 5
|
||||||
|
IF EXIST "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" (GOTO copyopus) ELSE (GOTO downloadopus)
|
||||||
|
:copyopus
|
||||||
|
del "%root%NadekoBot\src\NadekoBot\opus.dll"
|
||||||
|
copy "%root%NadekoBot\src\NadekoBot\_libs\32\opus.dll" "%root%NadekoBot\src\NadekoBot\opus.dll"
|
||||||
|
ECHO opus.dll copied.
|
||||||
|
GOTO end
|
||||||
|
:downloadopus
|
||||||
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll"
|
SET "FILENAME=%~dp0\NadekoBot\src\NadekoBot\opus.dll"
|
||||||
bitsadmin.exe /transfer "Downloading opus.dll" /priority high https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll "%FILENAME%"
|
powershell -Command "Invoke-WebRequest https://github.com/Kwoth/NadekoBot/raw/dev/src/NadekoBot/_libs/32/opus.dll -OutFile '%FILENAME%'"
|
||||||
ECHO opus.dll downloaded.
|
ECHO opus.dll downloaded.
|
||||||
GOTO end
|
GOTO end
|
||||||
:end
|
:end
|
||||||
::Normal execution of end of script
|
::Normal execution of end of script
|
||||||
TITLE Installation complete!
|
TITLE NadekoBot Installation complete!
|
||||||
CD /D "%root%"
|
CD /D "%root%"
|
||||||
RMDIR /S /Q "%installtemp%" >nul 2>&1
|
RMDIR /S /Q "%installtemp%" >nul 2>&1
|
||||||
ECHO.
|
ECHO.
|
||||||
ECHO Installation complete, press any key to close this window!
|
ECHO Installation complete!
|
||||||
|
ECHO.
|
||||||
timeout /t 5
|
timeout /t 5
|
||||||
del Stable.bat
|
del Stable.bat
|
||||||
|
@ -6,6 +6,6 @@ namespace NadekoBot.Attributes
|
|||||||
public class OwnerOnlyAttribute : PreconditionAttribute
|
public class OwnerOnlyAttribute : PreconditionAttribute
|
||||||
{
|
{
|
||||||
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) =>
|
public override Task<PreconditionResult> CheckPermissions(ICommandContext context, CommandInfo executingCommand,IDependencyMap depMap) =>
|
||||||
Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")));
|
Task.FromResult((NadekoBot.Credentials.IsOwner(context.User) || NadekoBot.Client.CurrentUser.Id == context.User.Id ? PreconditionResult.FromSuccess() : PreconditionResult.FromError("Not owner")));
|
||||||
}
|
}
|
||||||
}
|
}
|
23
src/NadekoBot/DataStructures/AsyncLazy.cs
Normal file
23
src/NadekoBot/DataStructures/AsyncLazy.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
public class AsyncLazy<T> : Lazy<Task<T>>
|
||||||
|
{
|
||||||
|
public AsyncLazy(Func<T> valueFactory) :
|
||||||
|
base(() => Task.Factory.StartNew(valueFactory))
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public AsyncLazy(Func<Task<T>> taskFactory) :
|
||||||
|
base(() => Task.Factory.StartNew(taskFactory).Unwrap())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
128
src/NadekoBot/DataStructures/IndexedCollection.cs
Normal file
128
src/NadekoBot/DataStructures/IndexedCollection.cs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
public class IndexedCollection<T> : IList<T> where T : IIndexed
|
||||||
|
{
|
||||||
|
public List<T> Source { get; }
|
||||||
|
private readonly object _locker = new object();
|
||||||
|
|
||||||
|
public IndexedCollection(IEnumerable<T> source)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Source = source.OrderBy(x => x.Index).ToList();
|
||||||
|
for (var i = 0; i < Source.Count; i++)
|
||||||
|
{
|
||||||
|
if (Source[i].Index != i)
|
||||||
|
Source[i].Index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator List<T>(IndexedCollection<T> x) =>
|
||||||
|
x.Source;
|
||||||
|
|
||||||
|
public IEnumerator<T> GetEnumerator() =>
|
||||||
|
Source.GetEnumerator();
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() =>
|
||||||
|
Source.GetEnumerator();
|
||||||
|
|
||||||
|
public void Add(T item)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
item.Index = Source.Count;
|
||||||
|
Source.Add(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void Clear()
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Source.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(T item)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
return Source.Contains(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(T[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Source.CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Remove(T item)
|
||||||
|
{
|
||||||
|
bool removed;
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
if (removed = Source.Remove(item))
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Source.Count; i++)
|
||||||
|
{
|
||||||
|
// hm, no idea how ef works, so I don't want to set if it's not changed,
|
||||||
|
// maybe it will try to update db?
|
||||||
|
// But most likely it just compares old to new values, meh.
|
||||||
|
if (Source[i].Index != i)
|
||||||
|
Source[i].Index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => Source.Count;
|
||||||
|
public bool IsReadOnly => false;
|
||||||
|
public int IndexOf(T item) => item.Index;
|
||||||
|
|
||||||
|
public virtual void Insert(int index, T item)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Source.Insert(index, item);
|
||||||
|
for (int i = index; i < Source.Count; i++)
|
||||||
|
{
|
||||||
|
Source[i].Index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
Source.RemoveAt(index);
|
||||||
|
for (int i = index; i < Source.Count; i++)
|
||||||
|
{
|
||||||
|
Source[i].Index = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual T this[int index] {
|
||||||
|
get { return Source[index]; }
|
||||||
|
set {
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
value.Index = index;
|
||||||
|
Source[index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
75
src/NadekoBot/DataStructures/PermissionsCollection.cs
Normal file
75
src/NadekoBot/DataStructures/PermissionsCollection.cs
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
|
namespace NadekoBot.DataStructures
|
||||||
|
{
|
||||||
|
public class PermissionsCollection<T> : IndexedCollection<T> where T : IIndexed
|
||||||
|
{
|
||||||
|
private readonly object _localLocker = new object();
|
||||||
|
public PermissionsCollection(IEnumerable<T> source) : base(source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static implicit operator List<T>(PermissionsCollection<T> x) =>
|
||||||
|
x.Source;
|
||||||
|
|
||||||
|
public override void Clear()
|
||||||
|
{
|
||||||
|
lock (_localLocker)
|
||||||
|
{
|
||||||
|
var first = Source[0];
|
||||||
|
base.Clear();
|
||||||
|
Source[0] = first;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Remove(T item)
|
||||||
|
{
|
||||||
|
bool removed;
|
||||||
|
lock (_localLocker)
|
||||||
|
{
|
||||||
|
if(Source.IndexOf(item) == 0)
|
||||||
|
throw new ArgumentException("You can't remove first permsission (allow all)");
|
||||||
|
removed = base.Remove(item);
|
||||||
|
}
|
||||||
|
return removed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Insert(int index, T item)
|
||||||
|
{
|
||||||
|
lock (_localLocker)
|
||||||
|
{
|
||||||
|
if(index == 0) // can't insert on first place. Last item is always allow all.
|
||||||
|
throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
base.Insert(index, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void RemoveAt(int index)
|
||||||
|
{
|
||||||
|
lock (_localLocker)
|
||||||
|
{
|
||||||
|
if(index == 0) // you can't remove first permission (allow all)
|
||||||
|
throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
|
||||||
|
base.RemoveAt(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override T this[int index] {
|
||||||
|
get { return Source[index]; }
|
||||||
|
set {
|
||||||
|
lock (_localLocker)
|
||||||
|
{
|
||||||
|
if(index == 0) // can't set first element. It's always allow all
|
||||||
|
throw new IndexOutOfRangeException(nameof(index));
|
||||||
|
base[index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
1171
src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs
generated
Normal file
1171
src/NadekoBot/Migrations/20170222162505_dateadded.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
357
src/NadekoBot/Migrations/20170222162505_dateadded.cs
Normal file
357
src/NadekoBot/Migrations/20170222162505_dateadded.cs
Normal file
@ -0,0 +1,357 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class dateadded : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuUpdates",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuInfo",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PokeGame",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "SelfAssignableRoles",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Reminders",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "RaceAnimals",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Quotes",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlaylistSong",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlayingStatus",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Permission",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MutedUserId",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MusicPlaylists",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ModulePrefixes",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "LogSettings",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredVoicePresenceCHannels",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredLogChannels",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildRepeater",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GCChannelId",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FollowedStream",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilteredWord",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilterChannelId",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "EightBallResponses",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Donators",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "DiscordUser",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CustomReactions",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CurrencyTransactions",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Currency",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ConversionUnits",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandPrice",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandCooldown",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashOfClans",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashCallers",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BotConfig",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BlacklistItem",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamSetting",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamIgnore",
|
||||||
|
nullable: true);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<DateTime>(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiRaidSetting",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuUpdates");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "WaifuInfo");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PokeGame");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "SelfAssignableRoles");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Reminders");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "RaceAnimals");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Quotes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlaylistSong");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "PlayingStatus");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Permission");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MutedUserId");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "MusicPlaylists");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ModulePrefixes");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "LogSettings");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredVoicePresenceCHannels");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "IgnoredLogChannels");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildRepeater");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "GCChannelId");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FollowedStream");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilteredWord");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "FilterChannelId");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "EightBallResponses");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Donators");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "DiscordUser");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CustomReactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CurrencyTransactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "Currency");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ConversionUnits");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandPrice");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "CommandCooldown");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashOfClans");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "ClashCallers");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BotConfig");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "BlacklistItem");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamSetting");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiSpamIgnore");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DateAdded",
|
||||||
|
table: "AntiRaidSetting");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1206
src/NadekoBot/Migrations/20170308033058_permsv2.Designer.cs
generated
Normal file
1206
src/NadekoBot/Migrations/20170308033058_permsv2.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
49
src/NadekoBot/Migrations/20170308033058_permsv2.cs
Normal file
49
src/NadekoBot/Migrations/20170308033058_permsv2.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class permsv2 : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Permissionv2",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
Index = table.Column<int>(nullable: false),
|
||||||
|
PrimaryTarget = table.Column<int>(nullable: false),
|
||||||
|
PrimaryTargetId = table.Column<ulong>(nullable: false),
|
||||||
|
SecondaryTarget = table.Column<int>(nullable: false),
|
||||||
|
SecondaryTargetName = table.Column<string>(nullable: true),
|
||||||
|
State = table.Column<bool>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Permissionv2", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_Permissionv2_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_Permissionv2_GuildConfigId",
|
||||||
|
table: "Permissionv2",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Permissionv2");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1233
src/NadekoBot/Migrations/20170310210952_unmute-timers.Designer.cs
generated
Normal file
1233
src/NadekoBot/Migrations/20170310210952_unmute-timers.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
45
src/NadekoBot/Migrations/20170310210952_unmute-timers.cs
Normal file
45
src/NadekoBot/Migrations/20170310210952_unmute-timers.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class unmutetimers : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "UnmuteTimer",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
UnmuteAt = table.Column<DateTime>(nullable: false),
|
||||||
|
UserId = table.Column<ulong>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_UnmuteTimer", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_UnmuteTimer_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_UnmuteTimer_GuildConfigId",
|
||||||
|
table: "UnmuteTimer",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "UnmuteTimer");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1260
src/NadekoBot/Migrations/20170311054632_vcrole.Designer.cs
generated
Normal file
1260
src/NadekoBot/Migrations/20170311054632_vcrole.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
45
src/NadekoBot/Migrations/20170311054632_vcrole.cs
Normal file
45
src/NadekoBot/Migrations/20170311054632_vcrole.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class vcrole : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "VcRoleInfo",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
RoleId = table.Column<ulong>(nullable: false),
|
||||||
|
VoiceChannelId = table.Column<ulong>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_VcRoleInfo", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_VcRoleInfo_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_VcRoleInfo_GuildConfigId",
|
||||||
|
table: "VcRoleInfo",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "VcRoleInfo");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1264
src/NadekoBot/Migrations/20170318190018_crad-and-crdm.Designer.cs
generated
Normal file
1264
src/NadekoBot/Migrations/20170318190018_crad-and-crdm.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
35
src/NadekoBot/Migrations/20170318190018_crad-and-crdm.cs
Normal file
35
src/NadekoBot/Migrations/20170318190018_crad-and-crdm.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class cradandcrdm : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "AutoDeleteTrigger",
|
||||||
|
table: "CustomReactions",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "DmResponse",
|
||||||
|
table: "CustomReactions",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "AutoDeleteTrigger",
|
||||||
|
table: "CustomReactions");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "DmResponse",
|
||||||
|
table: "CustomReactions");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1291
src/NadekoBot/Migrations/20170320090138_command-aliasing.Designer.cs
generated
Normal file
1291
src/NadekoBot/Migrations/20170320090138_command-aliasing.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
45
src/NadekoBot/Migrations/20170320090138_command-aliasing.cs
Normal file
45
src/NadekoBot/Migrations/20170320090138_command-aliasing.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class commandaliasing : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "CommandAlias",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
Mapping = table.Column<string>(nullable: true),
|
||||||
|
Trigger = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_CommandAlias", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_CommandAlias_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_CommandAlias_GuildConfigId",
|
||||||
|
table: "CommandAlias",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "CommandAlias");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1346
src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs
generated
Normal file
1346
src/NadekoBot/Migrations/20170330000613_warning-commands.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
78
src/NadekoBot/Migrations/20170330000613_warning-commands.cs
Normal file
78
src/NadekoBot/Migrations/20170330000613_warning-commands.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class warningcommands : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<bool>(
|
||||||
|
name: "WarningsInitialized",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
nullable: false,
|
||||||
|
defaultValue: false);
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "Warnings",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
Forgiven = table.Column<bool>(nullable: false),
|
||||||
|
ForgivenBy = table.Column<string>(nullable: true),
|
||||||
|
GuildId = table.Column<ulong>(nullable: false),
|
||||||
|
Moderator = table.Column<string>(nullable: true),
|
||||||
|
Reason = table.Column<string>(nullable: true),
|
||||||
|
UserId = table.Column<ulong>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_Warnings", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "WarningPunishment",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
Count = table.Column<int>(nullable: false),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
Punishment = table.Column<int>(nullable: false),
|
||||||
|
Time = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_WarningPunishment", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_WarningPunishment_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_WarningPunishment_GuildConfigId",
|
||||||
|
table: "WarningPunishment",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "Warnings");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "WarningPunishment");
|
||||||
|
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "WarningsInitialized",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1385
src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs
generated
Normal file
1385
src/NadekoBot/Migrations/20170331093025_startup-commands.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
51
src/NadekoBot/Migrations/20170331093025_startup-commands.cs
Normal file
51
src/NadekoBot/Migrations/20170331093025_startup-commands.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class startupcommands : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "StartupCommand",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
BotConfigId = table.Column<int>(nullable: true),
|
||||||
|
ChannelId = table.Column<ulong>(nullable: false),
|
||||||
|
ChannelName = table.Column<string>(nullable: true),
|
||||||
|
CommandText = table.Column<string>(nullable: true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildId = table.Column<ulong>(nullable: true),
|
||||||
|
GuildName = table.Column<string>(nullable: true),
|
||||||
|
Index = table.Column<int>(nullable: false),
|
||||||
|
VoiceChannelId = table.Column<ulong>(nullable: true),
|
||||||
|
VoiceChannelName = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_StartupCommand", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_StartupCommand_BotConfig_BotConfigId",
|
||||||
|
column: x => x.BotConfigId,
|
||||||
|
principalTable: "BotConfig",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_StartupCommand_BotConfigId",
|
||||||
|
table: "StartupCommand",
|
||||||
|
column: "BotConfigId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "StartupCommand");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1435
src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs
generated
Normal file
1435
src/NadekoBot/Migrations/20170401161600_slowmode-whitelist.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,73 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class slowmodewhitelist : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SlowmodeIgnoredRole",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
RoleId = table.Column<ulong>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SlowmodeIgnoredRole", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SlowmodeIgnoredRole_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "SlowmodeIgnoredUser",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
UserId = table.Column<ulong>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_SlowmodeIgnoredUser", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_SlowmodeIgnoredUser_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SlowmodeIgnoredRole_GuildConfigId",
|
||||||
|
table: "SlowmodeIgnoredRole",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_SlowmodeIgnoredUser_GuildConfigId",
|
||||||
|
table: "SlowmodeIgnoredUser",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SlowmodeIgnoredRole");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "SlowmodeIgnoredUser");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1456
src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs
generated
Normal file
1456
src/NadekoBot/Migrations/20170401205753_patreon-rewards.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
40
src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs
Normal file
40
src/NadekoBot/Migrations/20170401205753_patreon-rewards.cs
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class patreonrewards : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "RewardedUsers",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
AmountRewardedThisMonth = table.Column<int>(nullable: false),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
LastReward = table.Column<DateTime>(nullable: false),
|
||||||
|
UserId = table.Column<ulong>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_RewardedUsers", x => x.Id);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_RewardedUsers_UserId",
|
||||||
|
table: "RewardedUsers",
|
||||||
|
column: "UserId",
|
||||||
|
unique: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "RewardedUsers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1518
src/NadekoBot/Migrations/20170405161814_flower-shop.Designer.cs
generated
Normal file
1518
src/NadekoBot/Migrations/20170405161814_flower-shop.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
79
src/NadekoBot/Migrations/20170405161814_flower-shop.cs
Normal file
79
src/NadekoBot/Migrations/20170405161814_flower-shop.cs
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class flowershop : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShopEntry",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
AuthorId = table.Column<ulong>(nullable: false),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
GuildConfigId = table.Column<int>(nullable: true),
|
||||||
|
Index = table.Column<int>(nullable: false),
|
||||||
|
Name = table.Column<string>(nullable: true),
|
||||||
|
Price = table.Column<int>(nullable: false),
|
||||||
|
RoleId = table.Column<ulong>(nullable: false),
|
||||||
|
RoleName = table.Column<string>(nullable: true),
|
||||||
|
Type = table.Column<int>(nullable: false)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShopEntry", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShopEntry_GuildConfigs_GuildConfigId",
|
||||||
|
column: x => x.GuildConfigId,
|
||||||
|
principalTable: "GuildConfigs",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "ShopEntryItem",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
ShopEntryId = table.Column<int>(nullable: true),
|
||||||
|
Text = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_ShopEntryItem", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_ShopEntryItem_ShopEntry_ShopEntryId",
|
||||||
|
column: x => x.ShopEntryId,
|
||||||
|
principalTable: "ShopEntry",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShopEntry_GuildConfigId",
|
||||||
|
table: "ShopEntry",
|
||||||
|
column: "GuildConfigId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_ShopEntryItem_ShopEntryId",
|
||||||
|
table: "ShopEntryItem",
|
||||||
|
column: "ShopEntryId");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShopEntryItem");
|
||||||
|
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "ShopEntry");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1520
src/NadekoBot/Migrations/20170408162851_game-voice-channel.Designer.cs
generated
Normal file
1520
src/NadekoBot/Migrations/20170408162851_game-voice-channel.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class gamevoicechannel : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.AddColumn<ulong>(
|
||||||
|
name: "GameVoiceChannel",
|
||||||
|
table: "GuildConfigs",
|
||||||
|
nullable: true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropColumn(
|
||||||
|
name: "GameVoiceChannel",
|
||||||
|
table: "GuildConfigs");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1553
src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.Designer.cs
generated
Normal file
1553
src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.Designer.cs
generated
Normal file
File diff suppressed because it is too large
Load Diff
56
src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.cs
Normal file
56
src/NadekoBot/Migrations/20170409193757_gmod-and-cmod.cs
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.EntityFrameworkCore.Migrations;
|
||||||
|
|
||||||
|
namespace NadekoBot.Migrations
|
||||||
|
{
|
||||||
|
public partial class gmodandcmod : Migration
|
||||||
|
{
|
||||||
|
protected override void Up(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.CreateTable(
|
||||||
|
name: "BlockedCmdOrMdl",
|
||||||
|
columns: table => new
|
||||||
|
{
|
||||||
|
Id = table.Column<int>(nullable: false)
|
||||||
|
.Annotation("Sqlite:Autoincrement", true),
|
||||||
|
BotConfigId = table.Column<int>(nullable: true),
|
||||||
|
BotConfigId1 = table.Column<int>(nullable: true),
|
||||||
|
DateAdded = table.Column<DateTime>(nullable: true),
|
||||||
|
Name = table.Column<string>(nullable: true)
|
||||||
|
},
|
||||||
|
constraints: table =>
|
||||||
|
{
|
||||||
|
table.PrimaryKey("PK_BlockedCmdOrMdl", x => x.Id);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_BlockedCmdOrMdl_BotConfig_BotConfigId",
|
||||||
|
column: x => x.BotConfigId,
|
||||||
|
principalTable: "BotConfig",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
table.ForeignKey(
|
||||||
|
name: "FK_BlockedCmdOrMdl_BotConfig_BotConfigId1",
|
||||||
|
column: x => x.BotConfigId1,
|
||||||
|
principalTable: "BotConfig",
|
||||||
|
principalColumn: "Id",
|
||||||
|
onDelete: ReferentialAction.Restrict);
|
||||||
|
});
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_BlockedCmdOrMdl_BotConfigId",
|
||||||
|
table: "BlockedCmdOrMdl",
|
||||||
|
column: "BotConfigId");
|
||||||
|
|
||||||
|
migrationBuilder.CreateIndex(
|
||||||
|
name: "IX_BlockedCmdOrMdl_BotConfigId1",
|
||||||
|
table: "BlockedCmdOrMdl",
|
||||||
|
column: "BotConfigId1");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Down(MigrationBuilder migrationBuilder)
|
||||||
|
{
|
||||||
|
migrationBuilder.DropTable(
|
||||||
|
name: "BlockedCmdOrMdl");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,6 +24,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("Action");
|
b.Property<int>("Action");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("GuildConfigId");
|
b.Property<int>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int>("Seconds");
|
b.Property<int>("Seconds");
|
||||||
@ -47,6 +49,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("AntiSpamSettingId");
|
b.HasIndex("AntiSpamSettingId");
|
||||||
@ -61,6 +65,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("Action");
|
b.Property<int>("Action");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("GuildConfigId");
|
b.Property<int>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int>("MessageThreshold");
|
b.Property<int>("MessageThreshold");
|
||||||
@ -80,6 +86,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("ItemId");
|
b.Property<ulong>("ItemId");
|
||||||
|
|
||||||
b.Property<int>("Type");
|
b.Property<int>("Type");
|
||||||
@ -91,6 +99,28 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("BlacklistItem");
|
b.ToTable("BlacklistItem");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlockedCmdOrMdl", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<int?>("BotConfigId1");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BotConfigId");
|
||||||
|
|
||||||
|
b.HasIndex("BotConfigId1");
|
||||||
|
|
||||||
|
b.ToTable("BlockedCmdOrMdl");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.BotConfig", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -120,6 +150,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("DMHelpString");
|
b.Property<string>("DMHelpString");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("ErrorColor");
|
b.Property<string>("ErrorColor");
|
||||||
|
|
||||||
b.Property<bool>("ForwardMessages");
|
b.Property<bool>("ForwardMessages");
|
||||||
@ -158,6 +190,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("ClashWarId");
|
b.Property<int>("ClashWarId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("SequenceNumber");
|
b.Property<int?>("SequenceNumber");
|
||||||
|
|
||||||
b.Property<int>("Stars");
|
b.Property<int>("Stars");
|
||||||
@ -178,6 +212,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("EnemyClan");
|
b.Property<string>("EnemyClan");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
@ -193,6 +229,26 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("ClashOfClans");
|
b.ToTable("ClashOfClans");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<string>("Mapping");
|
||||||
|
|
||||||
|
b.Property<string>("Trigger");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("CommandAlias");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -200,6 +256,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("CommandName");
|
b.Property<string>("CommandName");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int>("Seconds");
|
b.Property<int>("Seconds");
|
||||||
@ -220,6 +278,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("CommandName");
|
b.Property<string>("CommandName");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("Price");
|
b.Property<int>("Price");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -237,6 +297,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("InternalTrigger");
|
b.Property<string>("InternalTrigger");
|
||||||
|
|
||||||
b.Property<decimal>("Modifier");
|
b.Property<decimal>("Modifier");
|
||||||
@ -255,6 +317,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<long>("Amount");
|
b.Property<long>("Amount");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -272,6 +336,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<long>("Amount");
|
b.Property<long>("Amount");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Reason");
|
b.Property<string>("Reason");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -286,6 +352,12 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<bool>("AutoDeleteTrigger");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<bool>("DmResponse");
|
||||||
|
|
||||||
b.Property<ulong?>("GuildId");
|
b.Property<ulong?>("GuildId");
|
||||||
|
|
||||||
b.Property<bool>("IsRegex");
|
b.Property<bool>("IsRegex");
|
||||||
@ -308,6 +380,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<string>("AvatarId");
|
b.Property<string>("AvatarId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Discriminator");
|
b.Property<string>("Discriminator");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -328,6 +402,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int>("Amount");
|
b.Property<int>("Amount");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Name");
|
b.Property<string>("Name");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -347,6 +423,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Text");
|
b.Property<string>("Text");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -363,6 +441,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId1");
|
b.Property<int?>("GuildConfigId1");
|
||||||
@ -381,6 +461,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<string>("Word");
|
b.Property<string>("Word");
|
||||||
@ -399,6 +481,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
@ -421,6 +505,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -455,6 +541,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<bool>("CleverbotEnabled");
|
b.Property<bool>("CleverbotEnabled");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<float>("DefaultMusicVolume");
|
b.Property<float>("DefaultMusicVolume");
|
||||||
|
|
||||||
b.Property<bool>("DeleteMessageOnCommand");
|
b.Property<bool>("DeleteMessageOnCommand");
|
||||||
@ -467,6 +555,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<bool>("FilterWords");
|
b.Property<bool>("FilterWords");
|
||||||
|
|
||||||
|
b.Property<ulong?>("GameVoiceChannel");
|
||||||
|
|
||||||
b.Property<ulong>("GreetMessageChannelId");
|
b.Property<ulong>("GreetMessageChannelId");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
@ -493,6 +583,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<bool>("VoicePlusTextEnabled");
|
b.Property<bool>("VoicePlusTextEnabled");
|
||||||
|
|
||||||
|
b.Property<bool>("WarningsInitialized");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
|
|
||||||
b.HasIndex("GuildId")
|
b.HasIndex("GuildId")
|
||||||
@ -512,6 +604,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
@ -534,6 +628,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("LogSettingId");
|
b.Property<int?>("LogSettingId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -550,6 +646,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("LogSettingId");
|
b.Property<int?>("LogSettingId");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -578,6 +676,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong?>("ChannelUpdatedId");
|
b.Property<ulong?>("ChannelUpdatedId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<bool>("IsLogging");
|
b.Property<bool>("IsLogging");
|
||||||
|
|
||||||
b.Property<ulong?>("LogOtherId");
|
b.Property<ulong?>("LogOtherId");
|
||||||
@ -638,6 +738,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("ModuleName");
|
b.Property<string>("ModuleName");
|
||||||
|
|
||||||
b.Property<string>("Prefix");
|
b.Property<string>("Prefix");
|
||||||
@ -658,6 +760,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("AuthorId");
|
b.Property<ulong>("AuthorId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Name");
|
b.Property<string>("Name");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -670,6 +774,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("GuildConfigId");
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
@ -686,6 +792,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("NextId");
|
b.Property<int?>("NextId");
|
||||||
|
|
||||||
b.Property<int>("PrimaryTarget");
|
b.Property<int>("PrimaryTarget");
|
||||||
@ -706,6 +814,34 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("Permission");
|
b.ToTable("Permission");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<int>("Index");
|
||||||
|
|
||||||
|
b.Property<int>("PrimaryTarget");
|
||||||
|
|
||||||
|
b.Property<ulong>("PrimaryTargetId");
|
||||||
|
|
||||||
|
b.Property<int>("SecondaryTarget");
|
||||||
|
|
||||||
|
b.Property<string>("SecondaryTargetName");
|
||||||
|
|
||||||
|
b.Property<bool>("State");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("Permissionv2");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -713,6 +849,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Status");
|
b.Property<string>("Status");
|
||||||
|
|
||||||
b.HasKey("Id");
|
b.HasKey("Id");
|
||||||
@ -727,6 +865,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("MusicPlaylistId");
|
b.Property<int?>("MusicPlaylistId");
|
||||||
|
|
||||||
b.Property<string>("Provider");
|
b.Property<string>("Provider");
|
||||||
@ -756,6 +896,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<string>("AuthorName")
|
b.Property<string>("AuthorName")
|
||||||
.IsRequired();
|
.IsRequired();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
|
|
||||||
b.Property<string>("Keyword")
|
b.Property<string>("Keyword")
|
||||||
@ -776,6 +918,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("BotConfigId");
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<string>("Icon");
|
b.Property<string>("Icon");
|
||||||
|
|
||||||
b.Property<string>("Name");
|
b.Property<string>("Name");
|
||||||
@ -794,6 +938,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<ulong>("ChannelId");
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<bool>("IsPrivate");
|
b.Property<bool>("IsPrivate");
|
||||||
|
|
||||||
b.Property<string>("Message");
|
b.Property<string>("Message");
|
||||||
@ -809,11 +955,34 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("Reminders");
|
b.ToTable("Reminders");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.RewardedUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("AmountRewardedThisMonth");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<DateTime>("LastReward");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("UserId")
|
||||||
|
.IsUnique();
|
||||||
|
|
||||||
|
b.ToTable("RewardedUsers");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SelfAssignedRole", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("GuildId");
|
b.Property<ulong>("GuildId");
|
||||||
|
|
||||||
b.Property<ulong>("RoleId");
|
b.Property<ulong>("RoleId");
|
||||||
@ -826,11 +995,149 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("SelfAssignableRoles");
|
b.ToTable("SelfAssignableRoles");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<ulong>("AuthorId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<int>("Index");
|
||||||
|
|
||||||
|
b.Property<string>("Name");
|
||||||
|
|
||||||
|
b.Property<int>("Price");
|
||||||
|
|
||||||
|
b.Property<ulong>("RoleId");
|
||||||
|
|
||||||
|
b.Property<string>("RoleName");
|
||||||
|
|
||||||
|
b.Property<int>("Type");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("ShopEntry");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("ShopEntryId");
|
||||||
|
|
||||||
|
b.Property<string>("Text");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("ShopEntryId");
|
||||||
|
|
||||||
|
b.ToTable("ShopEntryItem");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<ulong>("RoleId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("SlowmodeIgnoredRole");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("SlowmodeIgnoredUser");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int?>("BotConfigId");
|
||||||
|
|
||||||
|
b.Property<ulong>("ChannelId");
|
||||||
|
|
||||||
|
b.Property<string>("ChannelName");
|
||||||
|
|
||||||
|
b.Property<string>("CommandText");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<ulong?>("GuildId");
|
||||||
|
|
||||||
|
b.Property<string>("GuildName");
|
||||||
|
|
||||||
|
b.Property<int>("Index");
|
||||||
|
|
||||||
|
b.Property<ulong?>("VoiceChannelId");
|
||||||
|
|
||||||
|
b.Property<string>("VoiceChannelName");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("BotConfigId");
|
||||||
|
|
||||||
|
b.ToTable("StartupCommand");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<DateTime>("UnmuteAt");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("UnmuteTimer");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.UserPokeTypes", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<ulong>("UserId");
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
b.Property<string>("type");
|
b.Property<string>("type");
|
||||||
@ -843,6 +1150,26 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("PokeGame");
|
b.ToTable("PokeGame");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<ulong>("RoleId");
|
||||||
|
|
||||||
|
b.Property<ulong>("VoiceChannelId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("VcRoleInfo");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
|
||||||
{
|
{
|
||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
@ -852,6 +1179,8 @@ namespace NadekoBot.Migrations
|
|||||||
|
|
||||||
b.Property<int?>("ClaimerId");
|
b.Property<int?>("ClaimerId");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int>("Price");
|
b.Property<int>("Price");
|
||||||
|
|
||||||
b.Property<int>("WaifuId");
|
b.Property<int>("WaifuId");
|
||||||
@ -873,6 +1202,8 @@ namespace NadekoBot.Migrations
|
|||||||
b.Property<int>("Id")
|
b.Property<int>("Id")
|
||||||
.ValueGeneratedOnAdd();
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
b.Property<int?>("NewId");
|
b.Property<int?>("NewId");
|
||||||
|
|
||||||
b.Property<int?>("OldId");
|
b.Property<int?>("OldId");
|
||||||
@ -892,6 +1223,52 @@ namespace NadekoBot.Migrations
|
|||||||
b.ToTable("WaifuUpdates");
|
b.ToTable("WaifuUpdates");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Warning", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<bool>("Forgiven");
|
||||||
|
|
||||||
|
b.Property<string>("ForgivenBy");
|
||||||
|
|
||||||
|
b.Property<ulong>("GuildId");
|
||||||
|
|
||||||
|
b.Property<string>("Moderator");
|
||||||
|
|
||||||
|
b.Property<string>("Reason");
|
||||||
|
|
||||||
|
b.Property<ulong>("UserId");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.ToTable("Warnings");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b =>
|
||||||
|
{
|
||||||
|
b.Property<int>("Id")
|
||||||
|
.ValueGeneratedOnAdd();
|
||||||
|
|
||||||
|
b.Property<int>("Count");
|
||||||
|
|
||||||
|
b.Property<DateTime?>("DateAdded");
|
||||||
|
|
||||||
|
b.Property<int?>("GuildConfigId");
|
||||||
|
|
||||||
|
b.Property<int>("Punishment");
|
||||||
|
|
||||||
|
b.Property<int>("Time");
|
||||||
|
|
||||||
|
b.HasKey("Id");
|
||||||
|
|
||||||
|
b.HasIndex("GuildConfigId");
|
||||||
|
|
||||||
|
b.ToTable("WarningPunishment");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.AntiRaidSetting", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig", "GuildConfig")
|
||||||
@ -922,6 +1299,17 @@ namespace NadekoBot.Migrations
|
|||||||
.HasForeignKey("BotConfigId");
|
.HasForeignKey("BotConfigId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.BlockedCmdOrMdl", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||||
|
.WithMany("BlockedCommands")
|
||||||
|
.HasForeignKey("BotConfigId");
|
||||||
|
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||||
|
.WithMany("BlockedModules")
|
||||||
|
.HasForeignKey("BotConfigId1");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ClashCaller", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar")
|
b.HasOne("NadekoBot.Services.Database.Models.ClashWar", "ClashWar")
|
||||||
@ -930,6 +1318,13 @@ namespace NadekoBot.Migrations
|
|||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandAlias", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("CommandAliases")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.CommandCooldown", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
@ -1036,6 +1431,13 @@ namespace NadekoBot.Migrations
|
|||||||
.HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId");
|
.HasForeignKey("NadekoBot.Services.Database.Models.Permission", "NextId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.Permissionv2", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("Permissions")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.PlayingStatus", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||||
@ -1058,6 +1460,55 @@ namespace NadekoBot.Migrations
|
|||||||
.HasForeignKey("BotConfigId");
|
.HasForeignKey("BotConfigId");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntry", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("ShopEntries")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.ShopEntryItem", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.ShopEntry")
|
||||||
|
.WithMany("Items")
|
||||||
|
.HasForeignKey("ShopEntryId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredRole", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("SlowmodeIgnoredRoles")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.SlowmodeIgnoredUser", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("SlowmodeIgnoredUsers")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.StartupCommand", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.BotConfig")
|
||||||
|
.WithMany("StartupCommands")
|
||||||
|
.HasForeignKey("BotConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.UnmuteTimer", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("UnmuteTimers")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.VcRoleInfo", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("VcRoleInfos")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
|
|
||||||
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WaifuInfo", b =>
|
||||||
{
|
{
|
||||||
b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity")
|
b.HasOne("NadekoBot.Services.Database.Models.DiscordUser", "Affinity")
|
||||||
@ -1089,6 +1540,13 @@ namespace NadekoBot.Migrations
|
|||||||
.HasForeignKey("UserId")
|
.HasForeignKey("UserId")
|
||||||
.OnDelete(DeleteBehavior.Cascade);
|
.OnDelete(DeleteBehavior.Cascade);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
modelBuilder.Entity("NadekoBot.Services.Database.Models.WarningPunishment", b =>
|
||||||
|
{
|
||||||
|
b.HasOne("NadekoBot.Services.Database.Models.GuildConfig")
|
||||||
|
.WithMany("WarnPunishments")
|
||||||
|
.HasForeignKey("GuildConfigId");
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,11 +12,12 @@ using NadekoBot.Services.Database.Models;
|
|||||||
using static NadekoBot.Modules.Permissions.Permissions;
|
using static NadekoBot.Modules.Permissions.Permissions;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
using NadekoBot.Modules.Permissions;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
[NadekoModule("Administration", ".")]
|
[NadekoModule("Administration", ".")]
|
||||||
public partial class Administration : NadekoModule
|
public partial class Administration : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static ConcurrentHashSet<ulong> deleteMessagesOnCommand { get; }
|
private static ConcurrentHashSet<ulong> deleteMessagesOnCommand { get; }
|
||||||
|
|
||||||
@ -31,7 +32,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Task DelMsgOnCmd_Handler(SocketUserMessage msg, CommandInfo cmd)
|
private static Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
@ -56,24 +57,33 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.Administrator)]
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
public async Task ResetPermissions()
|
public async Task ResetPermissions()
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.PermissionsFor(Context.Guild.Id);
|
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||||
config.RootPermission = Permission.GetDefaultRoot();
|
config.Permissions = Permissionv2.GetDefaultPermlist;
|
||||||
var toAdd = new PermissionCache()
|
|
||||||
{
|
|
||||||
RootPermission = config.RootPermission,
|
|
||||||
PermRole = config.PermissionRole,
|
|
||||||
Verbose = config.VerbosePermissions,
|
|
||||||
};
|
|
||||||
Cache.AddOrUpdate(channel.Guild.Id,
|
|
||||||
toAdd, (id, old) => toAdd);
|
|
||||||
await uow.CompleteAsync();
|
await uow.CompleteAsync();
|
||||||
|
UpdateCache(config);
|
||||||
}
|
}
|
||||||
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
await ReplyConfirmLocalized("perms_reset").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task ResetGlobalPermissions()
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var gc = uow.BotConfig.GetOrCreate();
|
||||||
|
gc.BlockedCommands.Clear();
|
||||||
|
gc.BlockedModules.Clear();
|
||||||
|
|
||||||
|
GlobalPermissionCommands.BlockedCommands.Clear();
|
||||||
|
GlobalPermissionCommands.BlockedModules.Clear();
|
||||||
|
await uow.CompleteAsync();
|
||||||
|
}
|
||||||
|
await ReplyConfirmLocalized("global_perms_reset").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.Administrator)]
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
@ -106,6 +116,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
public async Task Setrole(IGuildUser usr, [Remainder] IRole role)
|
public async Task Setrole(IGuildUser usr, [Remainder] IRole role)
|
||||||
{
|
{
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
var maxRole = guser.GetRoles().Max(x => x.Position);
|
||||||
|
if (maxRole < role.Position || maxRole <= usr.GetRoles().Max(x => x.Position))
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await usr.AddRolesAsync(role).ConfigureAwait(false);
|
await usr.AddRolesAsync(role).ConfigureAwait(false);
|
||||||
@ -125,6 +139,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
public async Task Removerole(IGuildUser usr, [Remainder] IRole role)
|
public async Task Removerole(IGuildUser usr, [Remainder] IRole role)
|
||||||
{
|
{
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= usr.GetRoles().Max(x => x.Position))
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await usr.RemoveRolesAsync(role).ConfigureAwait(false);
|
await usr.RemoveRolesAsync(role).ConfigureAwait(false);
|
||||||
@ -142,6 +159,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
public async Task RenameRole(IRole roleToEdit, string newname)
|
public async Task RenameRole(IRole roleToEdit, string newname)
|
||||||
{
|
{
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= roleToEdit.Position)
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (roleToEdit.Position > (await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).GetRoles().Max(r => r.Position))
|
if (roleToEdit.Position > (await Context.Guild.GetCurrentUserAsync().ConfigureAwait(false)).GetRoles().Max(r => r.Position))
|
||||||
@ -164,9 +184,15 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireBotPermission(GuildPermission.ManageRoles)]
|
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
public async Task RemoveAllRoles([Remainder] IGuildUser user)
|
public async Task RemoveAllRoles([Remainder] IGuildUser user)
|
||||||
{
|
{
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
|
||||||
|
var userRoles = user.GetRoles();
|
||||||
|
if (guser.Id != Context.Guild.OwnerId &&
|
||||||
|
(user.Id == Context.Guild.OwnerId || guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position)))
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await user.RemoveRolesAsync(user.GetRoles()).ConfigureAwait(false);
|
await user.RemoveRolesAsync(userRoles).ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false);
|
await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
@ -188,6 +214,19 @@ namespace NadekoBot.Modules.Administration
|
|||||||
await ReplyConfirmLocalized("cr", Format.Bold(r.Name)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("cr", Format.Bold(r.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
|
public async Task RoleHoist(string roleSearchName, PermissionAction targetState)
|
||||||
|
{
|
||||||
|
var roleName = roleSearchName.ToUpperInvariant();
|
||||||
|
var role = Context.Guild.Roles.FirstOrDefault(r => r.Name.ToUpperInvariant() == roleName);
|
||||||
|
|
||||||
|
await role.ModifyAsync(r => r.Hoist = targetState.Value).ConfigureAwait(false);
|
||||||
|
await ReplyConfirmLocalized("rh", Format.Bold(role.Name), Format.Bold(targetState.Value.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
@ -225,101 +264,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[RequireUserPermission(GuildPermission.BanMembers)]
|
|
||||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
|
||||||
public async Task Ban(IGuildUser user, [Remainder] string msg = null)
|
|
||||||
{
|
|
||||||
if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()))
|
|
||||||
{
|
|
||||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrWhiteSpace(msg))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg));
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
|
||||||
.WithTitle("⛔️ " + GetText("banned_user"))
|
|
||||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
|
||||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
|
||||||
[RequireBotPermission(GuildPermission.BanMembers)]
|
|
||||||
public async Task Softban(IGuildUser user, [Remainder] string msg = null)
|
|
||||||
{
|
|
||||||
if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
|
||||||
{
|
|
||||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(msg))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg));
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
|
||||||
try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
|
||||||
catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
|
||||||
.WithTitle("☣ " + GetText("sb_user"))
|
|
||||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
|
||||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
[RequireContext(ContextType.Guild)]
|
|
||||||
[RequireUserPermission(GuildPermission.KickMembers)]
|
|
||||||
[RequireBotPermission(GuildPermission.KickMembers)]
|
|
||||||
public async Task Kick(IGuildUser user, [Remainder] string msg = null)
|
|
||||||
{
|
|
||||||
if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
|
||||||
{
|
|
||||||
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!string.IsNullOrWhiteSpace(msg))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg));
|
|
||||||
}
|
|
||||||
catch { }
|
|
||||||
}
|
|
||||||
|
|
||||||
await user.KickAsync().ConfigureAwait(false);
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
|
||||||
.WithTitle(GetText("kicked_user"))
|
|
||||||
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
|
||||||
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.DeafenMembers)]
|
[RequireUserPermission(GuildPermission.DeafenMembers)]
|
||||||
@ -440,6 +384,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var enumerable = (await Context.Channel.GetMessagesAsync().Flatten()).AsEnumerable();
|
var enumerable = (await Context.Channel.GetMessagesAsync().Flatten()).AsEnumerable();
|
||||||
enumerable = enumerable.Where(x => x.Author.Id == user.Id);
|
enumerable = enumerable.Where(x => x.Author.Id == user.Id);
|
||||||
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
||||||
|
Context.Message.DeleteAfter(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// prune x
|
// prune x
|
||||||
@ -447,14 +392,18 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||||
|
[Priority(0)]
|
||||||
public async Task Prune(int count)
|
public async Task Prune(int count)
|
||||||
{
|
{
|
||||||
if (count < 1)
|
if (count < 1)
|
||||||
return;
|
return;
|
||||||
count += 1;
|
|
||||||
await Context.Message.DeleteAsync().ConfigureAwait(false);
|
await Context.Message.DeleteAsync().ConfigureAwait(false);
|
||||||
int limit = (count < 100) ? count : 100;
|
int limit = (count < 100) ? count + 1 : 100;
|
||||||
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false));
|
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten().ConfigureAwait(false));
|
||||||
|
if (enumerable.FirstOrDefault()?.Id == Context.Message.Id)
|
||||||
|
enumerable = enumerable.Skip(1).ToArray();
|
||||||
|
else
|
||||||
|
enumerable = enumerable.Take(count);
|
||||||
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -463,6 +412,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
[RequireUserPermission(ChannelPermission.ManageMessages)]
|
||||||
[RequireBotPermission(GuildPermission.ManageMessages)]
|
[RequireBotPermission(GuildPermission.ManageMessages)]
|
||||||
|
[Priority(1)]
|
||||||
public async Task Prune(IGuildUser user, int count = 100)
|
public async Task Prune(IGuildUser user, int count = 100)
|
||||||
{
|
{
|
||||||
if (count < 1)
|
if (count < 1)
|
||||||
@ -474,6 +424,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
int limit = (count < 100) ? count : 100;
|
int limit = (count < 100) ? count : 100;
|
||||||
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten()).Where(m => m.Author == user);
|
var enumerable = (await Context.Channel.GetMessagesAsync(limit: limit).Flatten()).Where(m => m.Author == user);
|
||||||
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
await Context.Channel.DeleteMessagesAsync(enumerable).ConfigureAwait(false);
|
||||||
|
|
||||||
|
Context.Message.DeleteAfter(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
@ -48,6 +49,11 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
public async Task AutoAssignRole([Remainder] IRole role = null)
|
public async Task AutoAssignRole([Remainder] IRole role = null)
|
||||||
{
|
{
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
if (role != null)
|
||||||
|
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||||
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
|
@ -0,0 +1,131 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Attributes;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using NLog;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Administration
|
||||||
|
{
|
||||||
|
public partial class Administration
|
||||||
|
{
|
||||||
|
[Group]
|
||||||
|
public class GameChannelCommands : NadekoSubmodule
|
||||||
|
{
|
||||||
|
//private static readonly Timer _t;
|
||||||
|
|
||||||
|
private static readonly ConcurrentHashSet<ulong> gameVoiceChannels = new ConcurrentHashSet<ulong>();
|
||||||
|
|
||||||
|
private static new readonly Logger _log;
|
||||||
|
|
||||||
|
static GameChannelCommands()
|
||||||
|
{
|
||||||
|
//_t = new Timer(_ => {
|
||||||
|
|
||||||
|
//}, null, );
|
||||||
|
|
||||||
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
gameVoiceChannels = new ConcurrentHashSet<ulong>(
|
||||||
|
NadekoBot.AllGuildConfigs.Where(gc => gc.GameVoiceChannel != null)
|
||||||
|
.Select(gc => gc.GameVoiceChannel.Value));
|
||||||
|
|
||||||
|
NadekoBot.Client.UserVoiceStateUpdated += Client_UserVoiceStateUpdated;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task Client_UserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
|
||||||
|
{
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var gUser = usr as SocketGuildUser;
|
||||||
|
if (gUser == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var game = gUser.Game?.Name.TrimTo(50).ToLowerInvariant();
|
||||||
|
|
||||||
|
if (oldState.VoiceChannel == newState.VoiceChannel ||
|
||||||
|
newState.VoiceChannel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!gameVoiceChannels.Contains(newState.VoiceChannel.Id) ||
|
||||||
|
string.IsNullOrWhiteSpace(game))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var vch = gUser.Guild.VoiceChannels
|
||||||
|
.FirstOrDefault(x => x.Name.ToLowerInvariant() == game);
|
||||||
|
|
||||||
|
if (vch == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
await Task.Delay(1000).ConfigureAwait(false);
|
||||||
|
await gUser.ModifyAsync(gu => gu.Channel = vch).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[RequireBotPermission(GuildPermission.MoveMembers)]
|
||||||
|
public async Task GameVoiceChannel()
|
||||||
|
{
|
||||||
|
var vch = ((IGuildUser)Context.User).VoiceChannel;
|
||||||
|
|
||||||
|
if (vch == null)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("not_in_voice").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ulong? id;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var gc = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
|
|
||||||
|
if (gc.GameVoiceChannel == vch.Id)
|
||||||
|
{
|
||||||
|
gameVoiceChannels.TryRemove(vch.Id);
|
||||||
|
id = gc.GameVoiceChannel = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(gc.GameVoiceChannel != null)
|
||||||
|
gameVoiceChannels.TryRemove(gc.GameVoiceChannel.Value);
|
||||||
|
gameVoiceChannels.Add(vch.Id);
|
||||||
|
id = gc.GameVoiceChannel = vch.Id;
|
||||||
|
}
|
||||||
|
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id == null)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("gvc_disabled").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gameVoiceChannels.Add(vch.Id);
|
||||||
|
await ReplyConfirmLocalized("gvc_enabled", Format.Bold(vch.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,10 +16,30 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public class LocalizationCommands : NadekoSubmodule
|
public class LocalizationCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
|
//Română, România
|
||||||
|
//Bahasa Indonesia, Indonesia
|
||||||
private ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
private ImmutableDictionary<string, string> supportedLocales { get; } = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
{"en-US", "English, United States" },
|
//{"ar", "العربية" },
|
||||||
{"sr-cyrl-rs", "Serbian, Cyrillic" }
|
{"zh-TW", "繁體中文, 台灣" },
|
||||||
|
{"zh-CN", "简体中文, 中华人民共和国"},
|
||||||
|
{"nl-NL", "Nederlands, Nederland"},
|
||||||
|
{"en-US", "English, United States"},
|
||||||
|
{"fr-FR", "Français, France"},
|
||||||
|
{"de-DE", "Deutsch, Deutschland"},
|
||||||
|
{"he-IL", "עברית, ישראל"},
|
||||||
|
{"id-ID", "Bahasa Indonesia, Indonesia" },
|
||||||
|
{"it-IT", "Italiano, Italia" },
|
||||||
|
//{"ja-JP", "日本語, 日本"},
|
||||||
|
{"ko-KR", "한국어, 대한민국" },
|
||||||
|
{"nb-NO", "Norsk, Norge"},
|
||||||
|
{"pl-PL", "Polski, Polska" },
|
||||||
|
{"pt-BR", "Português Brasileiro, Brasil"},
|
||||||
|
{"ru-RU", "Русский, Россия"},
|
||||||
|
{"sr-Cyrl-RS", "Српски, Србија"},
|
||||||
|
{"es-ES", "Español, España"},
|
||||||
|
{"sv-SE", "Svenska, Sverige"},
|
||||||
|
{"tr-TR", "Türkçe, Türkiye"}
|
||||||
}.ToImmutableDictionary();
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -91,12 +111,12 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[OwnerOnly]
|
|
||||||
public async Task LanguagesList()
|
public async Task LanguagesList()
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("lang_list",
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
string.Join("\n", supportedLocales.Select(x => $"{Format.Code(x.Key)} => {x.Value}")))
|
.WithTitle(GetText("lang_list"))
|
||||||
.ConfigureAwait(false);
|
.WithDescription(string.Join("\n",
|
||||||
|
supportedLocales.Select(x => $"{Format.Code(x.Key), -10} => {x.Value}"))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,6 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
embed.WithTitle("👥" + g.GetLogText("avatar_changed"))
|
embed.WithTitle("👥" + g.GetLogText("avatar_changed"))
|
||||||
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
.WithDescription($"{before.Username}#{before.Discriminator} | {before.Id}")
|
||||||
.WithTitle($"{before.Username}#{before.Discriminator} | {before.Id}")
|
|
||||||
.WithThumbnailUrl(before.AvatarUrl)
|
.WithThumbnailUrl(before.AvatarUrl)
|
||||||
.WithImageUrl(after.AvatarUrl)
|
.WithImageUrl(after.AvatarUrl)
|
||||||
.WithFooter(fb => fb.WithText(currentTime))
|
.WithFooter(fb => fb.WithText(currentTime))
|
||||||
@ -308,6 +307,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
punishment = "🔇 " + logChannel.Guild.GetLogText("muted_pl").ToUpperInvariant();
|
punishment = "🔇 " + logChannel.Guild.GetLogText("muted_pl").ToUpperInvariant();
|
||||||
break;
|
break;
|
||||||
case PunishmentAction.Kick:
|
case PunishmentAction.Kick:
|
||||||
|
punishment = "👢 " + logChannel.Guild.GetLogText("kicked_pl").ToUpperInvariant();
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Softban:
|
||||||
punishment = "☣ " + logChannel.Guild.GetLogText("soft_banned_pl").ToUpperInvariant();
|
punishment = "☣ " + logChannel.Guild.GetLogText("soft_banned_pl").ToUpperInvariant();
|
||||||
break;
|
break;
|
||||||
case PunishmentAction.Ban:
|
case PunishmentAction.Ban:
|
||||||
@ -530,7 +532,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
else if (afterVch == null)
|
else if (afterVch == null)
|
||||||
{
|
{
|
||||||
str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft",
|
str = "🎙" + Format.Code(prettyCurrentTime) + logChannel.Guild.GetLogText("user_vleft",
|
||||||
"👤" + Format.Code(prettyCurrentTime), "👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
"👤" + Format.Bold(usr.Username + "#" + usr.Discriminator),
|
||||||
Format.Bold(beforeVch.Name ?? ""));
|
Format.Bold(beforeVch.Name ?? ""));
|
||||||
}
|
}
|
||||||
if (str != null)
|
if (str != null)
|
||||||
@ -705,17 +707,18 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("🗑 " + logChannel.Guild.GetLogText("msg_del", ((ITextChannel)msg.Channel).Name))
|
.WithTitle("🗑 " + logChannel.Guild.GetLogText("msg_del", ((ITextChannel)msg.Channel).Name))
|
||||||
.WithDescription($"{msg.Author}")
|
.WithDescription(msg.Author.ToString())
|
||||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("content")).WithValue(string.IsNullOrWhiteSpace(msg.Content) ? "-" : msg.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
.AddField(efb => efb.WithName("Id").WithValue(msg.Id.ToString()).WithIsInline(false))
|
||||||
.WithFooter(efb => efb.WithText(currentTime));
|
.WithFooter(efb => efb.WithText(currentTime));
|
||||||
if (msg.Attachments.Any())
|
if (msg.Attachments.Any())
|
||||||
embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.ProxyUrl))).WithIsInline(false));
|
embed.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("attachments")).WithValue(string.Join(", ", msg.Attachments.Select(a => a.Url))).WithIsInline(false));
|
||||||
|
|
||||||
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await logChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -753,8 +756,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("📝 " + logChannel.Guild.GetLogText("msg_update", ((ITextChannel)after.Channel).Name))
|
.WithTitle("📝 " + logChannel.Guild.GetLogText("msg_update", ((ITextChannel)after.Channel).Name))
|
||||||
.WithDescription(after.Author.ToString())
|
.WithDescription(after.Author.ToString())
|
||||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("old_msg")).WithValue(string.IsNullOrWhiteSpace(before.Content) ? "-" : before.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
.AddField(efb => efb.WithName(logChannel.Guild.GetLogText("new_msg")).WithValue(string.IsNullOrWhiteSpace(after.Content) ? "-" : after.Resolve(userHandling: TagHandling.FullName)).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
.AddField(efb => efb.WithName("Id").WithValue(after.Id.ToString()).WithIsInline(false))
|
||||||
.WithFooter(efb => efb.WithText(currentTime));
|
.WithFooter(efb => efb.WithText(currentTime));
|
||||||
|
|
||||||
@ -988,7 +991,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task LogEvents()
|
public async Task LogEvents()
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalized("log_events", string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>())).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(GetText("log_events") + "\n" +
|
||||||
|
string.Join(", ", Enum.GetNames(typeof(LogType)).Cast<string>()))
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -1066,7 +1071,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public static class GuildExtensions
|
public static class GuildExtensions
|
||||||
{
|
{
|
||||||
public static string GetLogText(this IGuild guild, string key, params object[] replacements)
|
public static string GetLogText(this IGuild guild, string key, params object[] replacements)
|
||||||
=> NadekoModule.GetTextStatic(key,
|
=> NadekoTopLevelModule.GetTextStatic(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(guild),
|
NadekoBot.Localization.GetCultureInfo(guild),
|
||||||
typeof(Administration).Name.ToLowerInvariant(),
|
typeof(Administration).Name.ToLowerInvariant(),
|
||||||
replacements);
|
replacements);
|
||||||
|
@ -1,14 +1,15 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
@ -20,6 +21,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, string> guildMuteRoles { get; }
|
private static ConcurrentDictionary<ulong, string> guildMuteRoles { get; }
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> mutedUsers { get; }
|
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ulong>> mutedUsers { get; }
|
||||||
|
private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>> unmuteTimers { get; }
|
||||||
|
= new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, Timer>>();
|
||||||
|
|
||||||
public static event Action<IGuildUser, MuteType> UserMuted = delegate { };
|
public static event Action<IGuildUser, MuteType> UserMuted = delegate { };
|
||||||
public static event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
|
public static event Action<IGuildUser, MuteType> UserUnmuted = delegate { };
|
||||||
@ -30,6 +33,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
Chat,
|
Chat,
|
||||||
All
|
All
|
||||||
}
|
}
|
||||||
|
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
|
||||||
|
|
||||||
|
private static readonly new Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
static MuteCommands()
|
static MuteCommands()
|
||||||
{
|
{
|
||||||
@ -43,6 +49,23 @@ namespace NadekoBot.Modules.Administration
|
|||||||
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
|
v => new ConcurrentHashSet<ulong>(v.MutedUsers.Select(m => m.UserId))
|
||||||
));
|
));
|
||||||
|
|
||||||
|
foreach (var conf in configs)
|
||||||
|
{
|
||||||
|
foreach (var x in conf.UnmuteTimers)
|
||||||
|
{
|
||||||
|
TimeSpan after;
|
||||||
|
if (x.UnmuteAt - TimeSpan.FromMinutes(2) <= DateTime.UtcNow)
|
||||||
|
{
|
||||||
|
after = TimeSpan.FromMinutes(2);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
after = x.UnmuteAt - DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
StartUnmuteTimer(conf.GuildId, x.UserId, after);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NadekoBot.Client.UserJoined += Client_UserJoined;
|
NadekoBot.Client.UserJoined += Client_UserJoined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -67,10 +90,15 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public static async Task MuteUser(IGuildUser usr)
|
public static async Task MuteUser(IGuildUser usr)
|
||||||
{
|
{
|
||||||
await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
|
await usr.ModifyAsync(x => x.Mute = true).ConfigureAwait(false);
|
||||||
await usr.AddRolesAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false);
|
var muteRole = await GetMuteRole(usr.Guild);
|
||||||
|
if (!usr.RoleIds.Contains(muteRole.Id))
|
||||||
|
await usr.AddRolesAsync(muteRole).ConfigureAwait(false);
|
||||||
|
StopUnmuteTimer(usr.GuildId, usr.Id);
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(usr.Guild.Id, set => set.Include(gc => gc.MutedUsers));
|
var config = uow.GuildConfigs.For(usr.Guild.Id,
|
||||||
|
set => set.Include(gc => gc.MutedUsers)
|
||||||
|
.Include(gc => gc.UnmuteTimers));
|
||||||
config.MutedUsers.Add(new MutedUserId()
|
config.MutedUsers.Add(new MutedUserId()
|
||||||
{
|
{
|
||||||
UserId = usr.Id
|
UserId = usr.Id
|
||||||
@ -79,6 +107,8 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
||||||
muted.Add(usr.Id);
|
muted.Add(usr.Id);
|
||||||
|
|
||||||
|
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
UserMuted(usr, MuteType.All);
|
UserMuted(usr, MuteType.All);
|
||||||
@ -86,11 +116,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
public static async Task UnmuteUser(IGuildUser usr)
|
public static async Task UnmuteUser(IGuildUser usr)
|
||||||
{
|
{
|
||||||
await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false);
|
StopUnmuteTimer(usr.GuildId, usr.Id);
|
||||||
await usr.RemoveRolesAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false);
|
try { await usr.ModifyAsync(x => x.Mute = false).ConfigureAwait(false); } catch { }
|
||||||
|
try { await usr.RemoveRolesAsync(await GetMuteRole(usr.Guild)).ConfigureAwait(false); } catch { /*ignore*/ }
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(usr.Guild.Id, set => set.Include(gc => gc.MutedUsers));
|
var config = uow.GuildConfigs.For(usr.Guild.Id, set => set.Include(gc => gc.MutedUsers)
|
||||||
|
.Include(gc => gc.UnmuteTimers));
|
||||||
config.MutedUsers.Remove(new MutedUserId()
|
config.MutedUsers.Remove(new MutedUserId()
|
||||||
{
|
{
|
||||||
UserId = usr.Id
|
UserId = usr.Id
|
||||||
@ -98,6 +130,9 @@ namespace NadekoBot.Modules.Administration
|
|||||||
ConcurrentHashSet<ulong> muted;
|
ConcurrentHashSet<ulong> muted;
|
||||||
if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
if (mutedUsers.TryGetValue(usr.Guild.Id, out muted))
|
||||||
muted.TryRemove(usr.Id);
|
muted.TryRemove(usr.Id);
|
||||||
|
|
||||||
|
config.UnmuteTimers.RemoveWhere(x => x.UserId == usr.Id);
|
||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
UserUnmuted(usr, MuteType.All);
|
UserUnmuted(usr, MuteType.All);
|
||||||
@ -121,24 +156,102 @@ namespace NadekoBot.Modules.Administration
|
|||||||
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) ??
|
muteRole = guild.Roles.FirstOrDefault(r => r.Name == muteRoleName) ??
|
||||||
await guild.CreateRoleAsync(defaultMuteRoleName, GuildPermissions.None).ConfigureAwait(false);
|
await guild.CreateRoleAsync(defaultMuteRoleName, GuildPermissions.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var toOverwrite in (await guild.GetTextChannelsAsync()))
|
foreach (var toOverwrite in (await guild.GetTextChannelsAsync()))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await toOverwrite.AddPermissionOverwriteAsync(muteRole, new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny))
|
if (!toOverwrite.PermissionOverwrites.Select(x => x.Permissions).Contains(denyOverwrite))
|
||||||
|
{
|
||||||
|
await toOverwrite.AddPermissionOverwriteAsync(muteRole, denyOverwrite)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Task.Delay(200).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
await Task.Delay(200).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return muteRole;
|
return muteRole;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task TimedMute(IGuildUser user, TimeSpan after)
|
||||||
|
{
|
||||||
|
await MuteUser(user).ConfigureAwait(false); // mute the user. This will also remove any previous unmute timers
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(user.GuildId, set => set.Include(x => x.UnmuteTimers));
|
||||||
|
config.UnmuteTimers.Add(new UnmuteTimer()
|
||||||
|
{
|
||||||
|
UserId = user.Id,
|
||||||
|
UnmuteAt = DateTime.UtcNow + after,
|
||||||
|
}); // add teh unmute timer to the database
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
StartUnmuteTimer(user.GuildId, user.Id, after); // start the timer
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void StartUnmuteTimer(ulong guildId, ulong userId, TimeSpan after)
|
||||||
|
{
|
||||||
|
//load the unmute timers for this guild
|
||||||
|
var userUnmuteTimers = unmuteTimers.GetOrAdd(guildId, new ConcurrentDictionary<ulong, Timer>());
|
||||||
|
|
||||||
|
//unmute timer to be added
|
||||||
|
var toAdd = new Timer(async _ =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var guild = NadekoBot.Client.GetGuild(guildId); // load the guild
|
||||||
|
if (guild == null)
|
||||||
|
{
|
||||||
|
RemoveUnmuteTimerFromDb(guildId, userId);
|
||||||
|
return; // if guild can't be found, just remove the timer from db
|
||||||
|
}
|
||||||
|
// unmute the user, this will also remove the timer from the db
|
||||||
|
await UnmuteUser(guild.GetUser(userId)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
RemoveUnmuteTimerFromDb(guildId, userId); // if unmute errored, just remove unmute from db
|
||||||
|
Administration._log.Warn("Couldn't unmute user {0} in guild {1}", userId, guildId);
|
||||||
|
Administration._log.Warn(ex);
|
||||||
|
}
|
||||||
|
}, null, after, Timeout.InfiniteTimeSpan);
|
||||||
|
|
||||||
|
//add it, or stop the old one and add this one
|
||||||
|
userUnmuteTimers.AddOrUpdate(userId, (key) => toAdd, (key, old) =>
|
||||||
|
{
|
||||||
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
return toAdd;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void StopUnmuteTimer(ulong guildId, ulong userId)
|
||||||
|
{
|
||||||
|
ConcurrentDictionary<ulong, Timer> userUnmuteTimers;
|
||||||
|
if (!unmuteTimers.TryGetValue(guildId, out userUnmuteTimers)) return;
|
||||||
|
|
||||||
|
Timer removed;
|
||||||
|
if(userUnmuteTimers.TryRemove(userId, out removed))
|
||||||
|
{
|
||||||
|
removed.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RemoveUnmuteTimerFromDb(ulong guildId, ulong userId)
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(guildId, set => set.Include(x => x.UnmuteTimers));
|
||||||
|
config.UnmuteTimers.RemoveWhere(x => x.UserId == userId);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
@ -170,6 +283,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
[RequireUserPermission(GuildPermission.MuteMembers)]
|
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||||
|
[Priority(1)]
|
||||||
public async Task Mute(IGuildUser user)
|
public async Task Mute(IGuildUser user)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -183,6 +297,27 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
[RequireUserPermission(GuildPermission.MuteMembers)]
|
||||||
|
[Priority(0)]
|
||||||
|
public async Task Mute(int minutes, IGuildUser user)
|
||||||
|
{
|
||||||
|
if (minutes < 1 || minutes > 1440)
|
||||||
|
return;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await TimedMute(user, TimeSpan.FromMinutes(minutes)).ConfigureAwait(false);
|
||||||
|
await ReplyConfirmLocalized("user_muted_time", Format.Bold(user.ToString()), minutes).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
await ReplyErrorLocalized("mute_error").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
@ -46,16 +46,18 @@ namespace NadekoBot.Modules.Administration
|
|||||||
LastMessage = msg.ToUpperInvariant();
|
LastMessage = msg.ToUpperInvariant();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyNextMessage(string message)
|
public void ApplyNextMessage(IUserMessage message)
|
||||||
{
|
{
|
||||||
var upperMsg = message.ToUpperInvariant();
|
var upperMsg = message.Content.ToUpperInvariant();
|
||||||
if (upperMsg == LastMessage)
|
if (upperMsg != LastMessage || (string.IsNullOrWhiteSpace(upperMsg) && message.Attachments.Any()))
|
||||||
Count++;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
LastMessage = upperMsg;
|
LastMessage = upperMsg;
|
||||||
Count = 0;
|
Count = 0;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Count++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,7 +115,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content),
|
var stats = spamSettings.UserStats.AddOrUpdate(msg.Author.Id, new UserSpamStats(msg.Content),
|
||||||
(id, old) =>
|
(id, old) =>
|
||||||
{
|
{
|
||||||
old.ApplyNextMessage(msg.Content); return old;
|
old.ApplyNextMessage(msg); return old;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
if (stats.Count >= spamSettings.AntiSpamSettings.MessageThreshold)
|
||||||
@ -186,6 +188,13 @@ namespace NadekoBot.Modules.Administration
|
|||||||
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||||
break;
|
break;
|
||||||
case PunishmentAction.Kick:
|
case PunishmentAction.Kick:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await gu.KickAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex) { _log.Warn(ex, "I can't apply punishement"); }
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Softban:
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
await gu.Guild.AddBanAsync(gu, 7).ConfigureAwait(false);
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
@ -13,9 +19,12 @@ namespace NadekoBot.Modules.Administration
|
|||||||
public partial class Administration
|
public partial class Administration
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class RatelimitCommand : NadekoSubmodule
|
public class RatelimitCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>();
|
public static ConcurrentDictionary<ulong, Ratelimiter> RatelimitingChannels = new ConcurrentDictionary<ulong, Ratelimiter>();
|
||||||
|
public static ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||||
|
public static ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||||
|
|
||||||
private new static readonly Logger _log;
|
private new static readonly Logger _log;
|
||||||
|
|
||||||
public class Ratelimiter
|
public class Ratelimiter
|
||||||
@ -35,10 +44,17 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; } = new ConcurrentDictionary<ulong, RatelimitedUser>();
|
public ConcurrentDictionary<ulong, RatelimitedUser> Users { get; set; } = new ConcurrentDictionary<ulong, RatelimitedUser>();
|
||||||
|
|
||||||
public bool CheckUserRatelimit(ulong id)
|
public bool CheckUserRatelimit(ulong id, ulong guildId, SocketGuildUser optUser)
|
||||||
{
|
{
|
||||||
|
HashSet<ulong> ignoreUsers;
|
||||||
|
HashSet<ulong> ignoreRoles;
|
||||||
|
|
||||||
|
if ((IgnoredUsers.TryGetValue(guildId, out ignoreUsers) && ignoreUsers.Contains(id)) ||
|
||||||
|
(optUser != null && IgnoredRoles.TryGetValue(guildId, out ignoreRoles) && optUser.RoleIds.Any(x => ignoreRoles.Contains(x))))
|
||||||
|
return false;
|
||||||
|
|
||||||
var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
|
var usr = Users.GetOrAdd(id, (key) => new RatelimitedUser() { UserId = id });
|
||||||
if (usr.MessageCount == MaxMessages)
|
if (usr.MessageCount >= MaxMessages)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -56,16 +72,26 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static RatelimitCommand()
|
static RatelimitCommands()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
IgnoredRoles = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
||||||
|
NadekoBot.AllGuildConfigs
|
||||||
|
.ToDictionary(x => x.GuildId,
|
||||||
|
x => new HashSet<ulong>(x.SlowmodeIgnoredRoles.Select(y => y.RoleId))));
|
||||||
|
|
||||||
|
IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>(
|
||||||
|
NadekoBot.AllGuildConfigs
|
||||||
|
.ToDictionary(x => x.GuildId,
|
||||||
|
x => new HashSet<ulong>(x.SlowmodeIgnoredUsers.Select(y => y.UserId))));
|
||||||
|
|
||||||
NadekoBot.Client.MessageReceived += async (umsg) =>
|
NadekoBot.Client.MessageReceived += async (umsg) =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var usrMsg = umsg as IUserMessage;
|
var usrMsg = umsg as SocketUserMessage;
|
||||||
var channel = usrMsg?.Channel as ITextChannel;
|
var channel = usrMsg?.Channel as SocketTextChannel;
|
||||||
|
|
||||||
if (channel == null || usrMsg.IsAuthor())
|
if (channel == null || usrMsg.IsAuthor())
|
||||||
return;
|
return;
|
||||||
@ -73,7 +99,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter))
|
if (!RatelimitingChannels.TryGetValue(channel.Id, out limiter))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (limiter.CheckUserRatelimit(usrMsg.Author.Id))
|
if (limiter.CheckUserRatelimit(usrMsg.Author.Id, channel.Guild.Id, usrMsg.Author as SocketGuildUser))
|
||||||
await usrMsg.DeleteAsync();
|
await usrMsg.DeleteAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
@ -118,6 +144,70 @@ namespace NadekoBot.Modules.Administration
|
|||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
|
[Priority(1)]
|
||||||
|
public async Task SlowmodeWhitelist(IUser user)
|
||||||
|
{
|
||||||
|
var siu = new SlowmodeIgnoredUser
|
||||||
|
{
|
||||||
|
UserId = user.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
HashSet<SlowmodeIgnoredUser> usrs;
|
||||||
|
bool removed;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
usrs = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredUsers))
|
||||||
|
.SlowmodeIgnoredUsers;
|
||||||
|
|
||||||
|
if (!(removed = usrs.Remove(siu)))
|
||||||
|
usrs.Add(siu);
|
||||||
|
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
IgnoredUsers.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(usrs.Select(x => x.UserId)), (key, old) => new HashSet<ulong>(usrs.Select(x => x.UserId)));
|
||||||
|
|
||||||
|
if(removed)
|
||||||
|
await ReplyConfirmLocalized("slowmodewl_user_stop", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("slowmodewl_user_start", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
|
[Priority(0)]
|
||||||
|
public async Task SlowmodeWhitelist(IRole role)
|
||||||
|
{
|
||||||
|
var sir = new SlowmodeIgnoredRole
|
||||||
|
{
|
||||||
|
RoleId = role.Id
|
||||||
|
};
|
||||||
|
|
||||||
|
HashSet<SlowmodeIgnoredRole> roles;
|
||||||
|
bool removed;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
roles = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.SlowmodeIgnoredRoles))
|
||||||
|
.SlowmodeIgnoredRoles;
|
||||||
|
|
||||||
|
if (!(removed = roles.Remove(sir)))
|
||||||
|
roles.Add(sir);
|
||||||
|
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
IgnoredRoles.AddOrUpdate(Context.Guild.Id, new HashSet<ulong>(roles.Select(x => x.RoleId)), (key, old) => new HashSet<ulong>(roles.Select(x => x.RoleId)));
|
||||||
|
|
||||||
|
if (removed)
|
||||||
|
await ReplyConfirmLocalized("slowmodewl_role_stop", Format.Bold(role.ToString())).ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("slowmodewl_role_start", Format.Bold(role.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -43,6 +43,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
{
|
{
|
||||||
IEnumerable<SelfAssignedRole> roles;
|
IEnumerable<SelfAssignedRole> roles;
|
||||||
|
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||||
|
return;
|
||||||
|
|
||||||
string msg;
|
string msg;
|
||||||
var error = false;
|
var error = false;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
@ -75,6 +79,10 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[RequireUserPermission(GuildPermission.ManageRoles)]
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
public async Task Rsar([Remainder] IRole role)
|
public async Task Rsar([Remainder] IRole role)
|
||||||
{
|
{
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
if (Context.User.Id != guser.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= role.Position)
|
||||||
|
return;
|
||||||
|
|
||||||
bool success;
|
bool success;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
@ -150,11 +158,11 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var guildUser = (IGuildUser)Context.User;
|
var guildUser = (IGuildUser)Context.User;
|
||||||
|
|
||||||
GuildConfig conf;
|
GuildConfig conf;
|
||||||
IEnumerable<SelfAssignedRole> roles;
|
SelfAssignedRole[] roles;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
conf = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
||||||
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id);
|
roles = uow.SelfAssignedRoles.GetFromGuild(Context.Guild.Id).ToArray();
|
||||||
}
|
}
|
||||||
if (roles.FirstOrDefault(r=>r.RoleId == role.Id) == null)
|
if (roles.FirstOrDefault(r=>r.RoleId == role.Id) == null)
|
||||||
{
|
{
|
||||||
@ -167,14 +175,21 @@ namespace NadekoBot.Modules.Administration
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var roleIds = roles.Select(x => x.RoleId).ToArray();
|
||||||
if (conf.ExclusiveSelfAssignedRoles)
|
if (conf.ExclusiveSelfAssignedRoles)
|
||||||
{
|
{
|
||||||
var sameRoleId = guildUser.RoleIds.FirstOrDefault(r => roles.Select(sar => sar.RoleId).Contains(r));
|
var sameRoleId = guildUser.RoleIds.FirstOrDefault(r => roleIds.Contains(r));
|
||||||
var sameRole = Context.Guild.GetRole(sameRoleId);
|
|
||||||
if (sameRoleId != default(ulong))
|
if (sameRoleId != default(ulong))
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("self_assign_already_excl", Format.Bold(sameRole?.Name)).ConfigureAwait(false);
|
var sameRole = Context.Guild.GetRole(sameRoleId);
|
||||||
return;
|
if (sameRole != null)
|
||||||
|
{
|
||||||
|
await guildUser.RemoveRolesAsync(sameRole).ConfigureAwait(false);
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
//await ReplyErrorLocalized("self_assign_already_excl", Format.Bold(sameRole?.Name)).ConfigureAwait(false);
|
||||||
|
//return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
|
@ -10,6 +10,8 @@ using System.Net.Http;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Administration
|
namespace NadekoBot.Modules.Administration
|
||||||
{
|
{
|
||||||
@ -31,6 +33,166 @@ namespace NadekoBot.Modules.Administration
|
|||||||
_forwardDMs = config.ForwardMessages;
|
_forwardDMs = config.ForwardMessages;
|
||||||
_forwardDMsToAllOwners = config.ForwardToAllOwners;
|
_forwardDMsToAllOwners = config.ForwardToAllOwners;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
while(!NadekoBot.Ready)
|
||||||
|
await Task.Delay(1000);
|
||||||
|
|
||||||
|
foreach (var cmd in NadekoBot.BotConfig.StartupCommands)
|
||||||
|
{
|
||||||
|
if (cmd.GuildId != null)
|
||||||
|
{
|
||||||
|
var guild = NadekoBot.Client.GetGuild(cmd.GuildId.Value);
|
||||||
|
var channel = guild?.GetChannel(cmd.ChannelId) as SocketTextChannel;
|
||||||
|
if (channel == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
IUserMessage msg = await channel.SendMessageAsync(cmd.CommandText).ConfigureAwait(false);
|
||||||
|
msg = (IUserMessage)await channel.GetMessageAsync(msg.Id).ConfigureAwait(false);
|
||||||
|
await NadekoBot.CommandHandler.TryRunCommand(guild, channel, msg).ConfigureAwait(false);
|
||||||
|
//msg.DeleteAfter(5);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
await Task.Delay(400).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task StartupCommandAdd([Remainder] string cmdText)
|
||||||
|
{
|
||||||
|
var guser = ((IGuildUser)Context.User);
|
||||||
|
var cmd = new StartupCommand()
|
||||||
|
{
|
||||||
|
CommandText = cmdText,
|
||||||
|
ChannelId = Context.Channel.Id,
|
||||||
|
ChannelName = Context.Channel.Name,
|
||||||
|
GuildId = Context.Guild?.Id,
|
||||||
|
GuildName = Context.Guild?.Name,
|
||||||
|
VoiceChannelId = guser.VoiceChannel?.Id,
|
||||||
|
VoiceChannelName = guser.VoiceChannel?.Name,
|
||||||
|
};
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
uow.BotConfig
|
||||||
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
|
.StartupCommands.Add(cmd);
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("scadd"))
|
||||||
|
.AddField(efb => efb.WithName(GetText("server"))
|
||||||
|
.WithValue(cmd.GuildId == null ? $"-" : $"{cmd.GuildName}/{cmd.GuildId}").WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText("channel"))
|
||||||
|
.WithValue($"{cmd.ChannelName}/{cmd.ChannelId}").WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText("command_text"))
|
||||||
|
.WithValue(cmdText).WithIsInline(false)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task StartupCommands(int page = 1)
|
||||||
|
{
|
||||||
|
if (page < 1)
|
||||||
|
return;
|
||||||
|
page -= 1;
|
||||||
|
IEnumerable<StartupCommand> scmds;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
scmds = uow.BotConfig
|
||||||
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
|
.StartupCommands
|
||||||
|
.OrderBy(x => x.Id)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
scmds = scmds.Skip(page * 5).Take(5);
|
||||||
|
if (!scmds.Any())
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("startcmdlist_none").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await Context.Channel.SendConfirmAsync("", string.Join("\n--\n", scmds.Select(x =>
|
||||||
|
{
|
||||||
|
string str = Format.Code(GetText("server")) + ": " + (x.GuildId == null ? "-" : x.GuildName + "/" + x.GuildId);
|
||||||
|
|
||||||
|
str += $@"
|
||||||
|
{Format.Code(GetText("channel"))}: {x.ChannelName}/{x.ChannelId}
|
||||||
|
{Format.Code(GetText("command_text"))}: {x.CommandText}";
|
||||||
|
return str;
|
||||||
|
})),footer: GetText("page", page + 1))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task Wait(int miliseconds)
|
||||||
|
{
|
||||||
|
if (miliseconds <= 0)
|
||||||
|
return;
|
||||||
|
Context.Message.DeleteAfter(0);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var msg = await Context.Channel.SendConfirmAsync($"⏲ {miliseconds}ms")
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
msg.DeleteAfter(miliseconds / 1000);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
await Task.Delay(miliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task StartupCommandRemove([Remainder] string cmdText)
|
||||||
|
{
|
||||||
|
StartupCommand cmd;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var cmds = uow.BotConfig
|
||||||
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
|
.StartupCommands;
|
||||||
|
cmd = cmds
|
||||||
|
.FirstOrDefault(x => x.CommandText.ToLowerInvariant() == cmdText.ToLowerInvariant());
|
||||||
|
|
||||||
|
if (cmd != null)
|
||||||
|
{
|
||||||
|
cmds.Remove(cmd);
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cmd == null)
|
||||||
|
await ReplyErrorLocalized("scrm_fail").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("scrm").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task StartupCommandsClear()
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
uow.BotConfig
|
||||||
|
.GetOrCreate(set => set.Include(x => x.StartupCommands))
|
||||||
|
.StartupCommands
|
||||||
|
.Clear();
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyConfirmLocalized("startcmds_cleared").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -68,23 +230,41 @@ namespace NadekoBot.Modules.Administration
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task HandleDmForwarding(SocketMessage msg, List<IDMChannel> ownerChannels)
|
public static async Task HandleDmForwarding(IUserMessage msg, List<IDMChannel> ownerChannels)
|
||||||
{
|
{
|
||||||
if (_forwardDMs && ownerChannels.Any())
|
if (_forwardDMs && ownerChannels.Any())
|
||||||
{
|
{
|
||||||
var title =
|
var title = GetTextStatic("dm_from",
|
||||||
GetTextStatic("dm_from", NadekoBot.Localization.DefaultCultureInfo,
|
NadekoBot.Localization.DefaultCultureInfo,
|
||||||
typeof(Administration).Name.ToLowerInvariant()) + $" [{msg.Author}]({msg.Author.Id})";
|
typeof(Administration).Name.ToLowerInvariant()) +
|
||||||
|
$" [{msg.Author}]({msg.Author.Id})";
|
||||||
|
|
||||||
|
var attachamentsTxt = GetTextStatic("attachments",
|
||||||
|
NadekoBot.Localization.DefaultCultureInfo,
|
||||||
|
typeof(Administration).Name.ToLowerInvariant());
|
||||||
|
|
||||||
|
var toSend = msg.Content;
|
||||||
|
|
||||||
|
if (msg.Attachments.Count > 0)
|
||||||
|
{
|
||||||
|
toSend += $"\n\n{Format.Code(attachamentsTxt)}:\n" +
|
||||||
|
string.Join("\n", msg.Attachments.Select(a => a.ProxyUrl));
|
||||||
|
}
|
||||||
|
|
||||||
if (_forwardDMsToAllOwners)
|
if (_forwardDMsToAllOwners)
|
||||||
{
|
{
|
||||||
await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)
|
await Task.WhenAll(ownerChannels.Where(ch => ch.Recipient.Id != msg.Author.Id)
|
||||||
.Select(ch => ch.SendConfirmAsync(title, msg.Content))).ConfigureAwait(false);
|
.Select(ch => ch.SendConfirmAsync(title, toSend))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var firstOwnerChannel = ownerChannels.First();
|
var firstOwnerChannel = ownerChannels.First();
|
||||||
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
if (firstOwnerChannel.Recipient.Id != msg.Author.Id)
|
||||||
try { await firstOwnerChannel.SendConfirmAsync(title, msg.Content).ConfigureAwait(false); }
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await firstOwnerChannel.SendConfirmAsync(title, toSend).ConfigureAwait(false);
|
||||||
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
@ -92,6 +272,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -138,7 +319,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
await server.DeleteAsync().ConfigureAwait(false);
|
await server.DeleteAsync().ConfigureAwait(false);
|
||||||
await ReplyConfirmLocalized("deleted_server",Format.Bold(server.Name)).ConfigureAwait(false);
|
await ReplyConfirmLocalized("deleted_server", Format.Bold(server.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,436 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Attributes;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Administration
|
||||||
|
{
|
||||||
|
public partial class Administration
|
||||||
|
{
|
||||||
|
[Group]
|
||||||
|
public class UserPunishCommands : NadekoSubmodule
|
||||||
|
{
|
||||||
|
private async Task<PunishmentAction?> InternalWarn(IGuild guild, ulong userId, string modName, string reason)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
|
reason = "-";
|
||||||
|
|
||||||
|
var guildId = guild.Id;
|
||||||
|
|
||||||
|
var warn = new Warning()
|
||||||
|
{
|
||||||
|
UserId = userId,
|
||||||
|
GuildId = guildId,
|
||||||
|
Forgiven = false,
|
||||||
|
Reason = reason,
|
||||||
|
Moderator = modName,
|
||||||
|
};
|
||||||
|
|
||||||
|
int warnings = 1;
|
||||||
|
List<WarningPunishment> ps;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
ps = uow.GuildConfigs.For(guildId, set => set.Include(x => x.WarnPunishments))
|
||||||
|
.WarnPunishments;
|
||||||
|
|
||||||
|
warnings += uow.Warnings
|
||||||
|
.For(guildId, userId)
|
||||||
|
.Where(w => !w.Forgiven && w.UserId == userId)
|
||||||
|
.Count();
|
||||||
|
|
||||||
|
uow.Warnings.Add(warn);
|
||||||
|
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
var p = ps.FirstOrDefault(x => x.Count == warnings);
|
||||||
|
|
||||||
|
if (p != null)
|
||||||
|
{
|
||||||
|
var user = await guild.GetUserAsync(userId);
|
||||||
|
if (user == null)
|
||||||
|
return null;
|
||||||
|
switch (p.Punishment)
|
||||||
|
{
|
||||||
|
case PunishmentAction.Mute:
|
||||||
|
if (p.Time == 0)
|
||||||
|
await MuteCommands.MuteUser(user).ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await MuteCommands.TimedMute(user, TimeSpan.FromMinutes(p.Time)).ConfigureAwait(false);
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Kick:
|
||||||
|
await user.KickAsync().ConfigureAwait(false);
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Ban:
|
||||||
|
await guild.AddBanAsync(user).ConfigureAwait(false);
|
||||||
|
break;
|
||||||
|
case PunishmentAction.Softban:
|
||||||
|
await guild.AddBanAsync(user).ConfigureAwait(false);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await guild.RemoveBanAsync(user).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await guild.RemoveBanAsync(user).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return p.Punishment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task Warn(IGuildUser user, [Remainder] string reason = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await (await user.CreateDMChannelAsync()).EmbedAsync(new EmbedBuilder().WithErrorColor()
|
||||||
|
.WithDescription(GetText("warned_on", Context.Guild.ToString()))
|
||||||
|
.AddField(efb => efb.WithName(GetText("moderator")).WithValue(Context.User.ToString()))
|
||||||
|
.AddField(efb => efb.WithName(GetText("reason")).WithValue(reason ?? "-")))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
var punishment = await InternalWarn(Context.Guild, user.Id, Context.User.ToString(), reason).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (punishment == null)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("user_warned", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("user_warned_and_punished", Format.Bold(user.ToString()), Format.Bold(punishment.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public Task Warnlog(int page, IGuildUser user)
|
||||||
|
=> Warnlog(page, user.Id);
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public Task Warnlog(IGuildUser user)
|
||||||
|
=> Warnlog(user.Id);
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public Task Warnlog(int page, ulong userId)
|
||||||
|
=> InternalWarnlog(userId, page - 1);
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public Task Warnlog(ulong userId)
|
||||||
|
=> InternalWarnlog(userId, 0);
|
||||||
|
|
||||||
|
private async Task InternalWarnlog(ulong userId, int page)
|
||||||
|
{
|
||||||
|
if (page < 0)
|
||||||
|
return;
|
||||||
|
Warning[] warnings;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
warnings = uow.Warnings.For(Context.Guild.Id, userId);
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings = warnings.Skip(page * 9)
|
||||||
|
.Take(9)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("warnlog_for", (Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString()))
|
||||||
|
.WithFooter(efb => efb.WithText(GetText("page", page + 1)));
|
||||||
|
|
||||||
|
if (!warnings.Any())
|
||||||
|
{
|
||||||
|
embed.WithDescription(GetText("warnings_none"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var w in warnings)
|
||||||
|
{
|
||||||
|
var name = GetText("warned_on_by", w.DateAdded.Value.ToString("dd.MM.yyy"), w.DateAdded.Value.ToString("HH:mm"), w.Moderator);
|
||||||
|
if (w.Forgiven)
|
||||||
|
name = Format.Strikethrough(name) + " " + GetText("warn_cleared_by", w.ForgivenBy);
|
||||||
|
|
||||||
|
embed.AddField(x => x
|
||||||
|
.WithName(name)
|
||||||
|
.WithValue(w.Reason));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Context.Channel.EmbedAsync(embed);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public Task Warnclear(IGuildUser user)
|
||||||
|
=> Warnclear(user.Id);
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task Warnclear(ulong userId)
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
await uow.Warnings.ForgiveAll(Context.Guild.Id, userId, Context.User.ToString()).ConfigureAwait(false);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyConfirmLocalized("warnings_cleared",
|
||||||
|
Format.Bold((Context.Guild as SocketGuild)?.GetUser(userId)?.ToString() ?? userId.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task WarnPunish(int number, PunishmentAction punish, int time = 0)
|
||||||
|
{
|
||||||
|
if (punish != PunishmentAction.Mute && time != 0)
|
||||||
|
return;
|
||||||
|
if (number <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var ps = uow.GuildConfigs.For(Context.Guild.Id).WarnPunishments;
|
||||||
|
var p = ps.FirstOrDefault(x => x.Count == number);
|
||||||
|
|
||||||
|
if (p == null)
|
||||||
|
{
|
||||||
|
ps.Add(new WarningPunishment()
|
||||||
|
{
|
||||||
|
Count = number,
|
||||||
|
Punishment = punish,
|
||||||
|
Time = time,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
p.Count = number;
|
||||||
|
p.Punishment = punish;
|
||||||
|
p.Time = time;
|
||||||
|
uow._context.Update(p);
|
||||||
|
}
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyConfirmLocalized("warn_punish_set",
|
||||||
|
Format.Bold(punish.ToString()),
|
||||||
|
Format.Bold(number.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task WarnPunish(int number)
|
||||||
|
{
|
||||||
|
if (number <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var ps = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||||
|
var p = ps.FirstOrDefault(x => x.Count == number);
|
||||||
|
|
||||||
|
if (p != null)
|
||||||
|
{
|
||||||
|
uow._context.Remove(p);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await ReplyConfirmLocalized("warn_punish_rem",
|
||||||
|
Format.Bold(number.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task WarnPunishList()
|
||||||
|
{
|
||||||
|
WarningPunishment[] ps;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
ps = uow.GuildConfigs.For(Context.Guild.Id, gc => gc.Include(x => x.WarnPunishments))
|
||||||
|
.WarnPunishments
|
||||||
|
.OrderBy(x => x.Count)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
string list;
|
||||||
|
if (ps.Any())
|
||||||
|
{
|
||||||
|
list = string.Join("\n", ps.Select(x => $"{x.Count} -> {x.Punishment}"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
list = GetText("warnpl_none");
|
||||||
|
}
|
||||||
|
await Context.Channel.SendConfirmAsync(
|
||||||
|
GetText("warn_punish_list"),
|
||||||
|
list).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task Ban(IGuildUser user, [Remainder] string msg = null)
|
||||||
|
{
|
||||||
|
if (Context.User.Id != user.Guild.OwnerId && (user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max()))
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(msg))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await user.SendErrorAsync(GetText("bandm", Format.Bold(Context.Guild.Name), msg));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle("⛔️ " + GetText("banned_user"))
|
||||||
|
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task Unban([Remainder]string user)
|
||||||
|
{
|
||||||
|
var bans = await Context.Guild.GetBansAsync();
|
||||||
|
|
||||||
|
var bun = bans.FirstOrDefault(x => x.User.ToString().ToLowerInvariant() == user.ToLowerInvariant());
|
||||||
|
|
||||||
|
if (bun == null)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await UnbanInternal(bun.User).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.BanMembers)]
|
||||||
|
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task Unban(ulong userId)
|
||||||
|
{
|
||||||
|
var bans = await Context.Guild.GetBansAsync();
|
||||||
|
|
||||||
|
var bun = bans.FirstOrDefault(x => x.User.Id == userId);
|
||||||
|
|
||||||
|
if (bun == null)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("user_not_found").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await UnbanInternal(bun.User).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UnbanInternal(IUser user)
|
||||||
|
{
|
||||||
|
await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false);
|
||||||
|
|
||||||
|
await ReplyConfirmLocalized("unbanned_user", Format.Bold(user.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
|
[RequireBotPermission(GuildPermission.BanMembers)]
|
||||||
|
public async Task Softban(IGuildUser user, [Remainder] string msg = null)
|
||||||
|
{
|
||||||
|
if (Context.User.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(msg))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await user.SendErrorAsync(GetText("sbdm", Format.Bold(Context.Guild.Name), msg));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Context.Guild.AddBanAsync(user, 7).ConfigureAwait(false);
|
||||||
|
try { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
||||||
|
catch { await Context.Guild.RemoveBanAsync(user).ConfigureAwait(false); }
|
||||||
|
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle("☣ " + GetText("sb_user"))
|
||||||
|
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.KickMembers)]
|
||||||
|
[RequireBotPermission(GuildPermission.KickMembers)]
|
||||||
|
public async Task Kick(IGuildUser user, [Remainder] string msg = null)
|
||||||
|
{
|
||||||
|
if (Context.Message.Author.Id != user.Guild.OwnerId && user.GetRoles().Select(r => r.Position).Max() >= ((IGuildUser)Context.User).GetRoles().Select(r => r.Position).Max())
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("hierarchy").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!string.IsNullOrWhiteSpace(msg))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await user.SendErrorAsync(GetText("kickdm", Format.Bold(Context.Guild.Name), msg));
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
await user.KickAsync().ConfigureAwait(false);
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("kicked_user"))
|
||||||
|
.AddField(efb => efb.WithName(GetText("username")).WithValue(user.ToString()).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("ID").WithValue(user.Id.ToString()).WithIsInline(true)))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
186
src/NadekoBot/Modules/Administration/Commands/VcRoleCommands.cs
Normal file
186
src/NadekoBot/Modules/Administration/Commands/VcRoleCommands.cs
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Linq;
|
||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using NadekoBot.Attributes;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.WebSocket;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Administration
|
||||||
|
{
|
||||||
|
public partial class Administration
|
||||||
|
{
|
||||||
|
[Group]
|
||||||
|
public class VcRoleCommands : NadekoSubmodule
|
||||||
|
{
|
||||||
|
private static ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> vcRoles { get; }
|
||||||
|
|
||||||
|
static VcRoleCommands()
|
||||||
|
{
|
||||||
|
NadekoBot.Client.UserVoiceStateUpdated += ClientOnUserVoiceStateUpdated;
|
||||||
|
vcRoles = new ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>>();
|
||||||
|
foreach (var gconf in NadekoBot.AllGuildConfigs)
|
||||||
|
{
|
||||||
|
var g = NadekoBot.Client.GetGuild(gconf.GuildId);
|
||||||
|
if (g == null)
|
||||||
|
continue; //todo delete everything from db if guild doesn't exist?
|
||||||
|
|
||||||
|
var infos = new ConcurrentDictionary<ulong, IRole>();
|
||||||
|
vcRoles.TryAdd(gconf.GuildId, infos);
|
||||||
|
foreach (var ri in gconf.VcRoleInfos)
|
||||||
|
{
|
||||||
|
var role = g.GetRole(ri.RoleId);
|
||||||
|
if (role == null)
|
||||||
|
continue; //todo remove this entry from db
|
||||||
|
|
||||||
|
infos.TryAdd(ri.VoiceChannelId, role);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Task ClientOnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState,
|
||||||
|
SocketVoiceState newState)
|
||||||
|
{
|
||||||
|
|
||||||
|
var gusr = usr as SocketGuildUser;
|
||||||
|
if (gusr == null)
|
||||||
|
return Task.CompletedTask;
|
||||||
|
|
||||||
|
var oldVc = oldState.VoiceChannel;
|
||||||
|
var newVc = newState.VoiceChannel;
|
||||||
|
var _ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (oldVc != newVc)
|
||||||
|
{
|
||||||
|
ulong guildId;
|
||||||
|
guildId = newVc?.Guild.Id ?? oldVc.Guild.Id;
|
||||||
|
|
||||||
|
ConcurrentDictionary<ulong, IRole> guildVcRoles;
|
||||||
|
if (vcRoles.TryGetValue(guildId, out guildVcRoles))
|
||||||
|
{
|
||||||
|
IRole role;
|
||||||
|
//remove old
|
||||||
|
if (oldVc != null && guildVcRoles.TryGetValue(oldVc.Id, out role))
|
||||||
|
{
|
||||||
|
if (gusr.RoleIds.Contains(role.Id))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await gusr.RemoveRolesAsync(role).ConfigureAwait(false);
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
await Task.Delay(200).ConfigureAwait(false);
|
||||||
|
await gusr.RemoveRolesAsync(role).ConfigureAwait(false);
|
||||||
|
await Task.Delay(500).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//add new
|
||||||
|
if (newVc != null && guildVcRoles.TryGetValue(newVc.Id, out role))
|
||||||
|
{
|
||||||
|
if (!gusr.RoleIds.Contains(role.Id))
|
||||||
|
await gusr.AddRolesAsync(role).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Administration._log.Warn(ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageRoles)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageChannels)]
|
||||||
|
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
|
// todo wait for the fix [RequireBotPermission(GuildPermission.ManageChannels)]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task VcRole([Remainder]IRole role = null)
|
||||||
|
{
|
||||||
|
var user = (IGuildUser) Context.User;
|
||||||
|
|
||||||
|
var vc = user.VoiceChannel;
|
||||||
|
|
||||||
|
if (vc == null || vc.GuildId != user.GuildId)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var guildVcRoles = vcRoles.GetOrAdd(user.GuildId, new ConcurrentDictionary<ulong, IRole>());
|
||||||
|
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
if (guildVcRoles.TryRemove(vc.Id, out role))
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("vcrole_removed", Format.Bold(vc.Name)).ConfigureAwait(false);
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
||||||
|
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
guildVcRoles.AddOrUpdate(vc.Id, role, (key, old) => role);
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var conf = uow.GuildConfigs.For(Context.Guild.Id, set => set.Include(x => x.VcRoleInfos));
|
||||||
|
conf.VcRoleInfos.RemoveWhere(x => x.VoiceChannelId == vc.Id); // remove old one
|
||||||
|
conf.VcRoleInfos.Add(new VcRoleInfo()
|
||||||
|
{
|
||||||
|
VoiceChannelId = vc.Id,
|
||||||
|
RoleId = role.Id,
|
||||||
|
}); // add new one
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
await ReplyConfirmLocalized("vcrole_added", Format.Bold(vc.Name), Format.Bold(role.Name)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task VcRoleList()
|
||||||
|
{
|
||||||
|
var guild = (SocketGuild) Context.Guild;
|
||||||
|
string text;
|
||||||
|
ConcurrentDictionary<ulong, IRole> roles;
|
||||||
|
if (vcRoles.TryGetValue(Context.Guild.Id, out roles))
|
||||||
|
{
|
||||||
|
if (!roles.Any())
|
||||||
|
{
|
||||||
|
text = GetText("no_vcroles");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = string.Join("\n", roles.Select(x =>
|
||||||
|
$"{Format.Bold(guild.GetVoiceChannel(x.Key)?.Name ?? x.Key.ToString())} => {x.Value}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
text = GetText("no_vcroles");
|
||||||
|
}
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("vc_role_list"))
|
||||||
|
.WithDescription(text))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -166,7 +166,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false);
|
var botUser = await guild.GetCurrentUserAsync().ConfigureAwait(false);
|
||||||
if (!botUser.GuildPermissions.ManageRoles || !botUser.GuildPermissions.ManageChannels)
|
if (!botUser.GuildPermissions.ManageRoles || !botUser.GuildPermissions.ManageChannels)
|
||||||
{
|
{
|
||||||
await ReplyErrorLocalized("vt_no_perms").ConfigureAwait(false);
|
await ReplyErrorLocalized("vt_perms").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,15 +11,13 @@ using NadekoBot.Services.Database.Models;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Diagnostics;
|
|
||||||
using NLog;
|
|
||||||
|
|
||||||
namespace NadekoBot.Modules.ClashOfClans
|
namespace NadekoBot.Modules.ClashOfClans
|
||||||
{
|
{
|
||||||
[NadekoModule("ClashOfClans", ",")]
|
[NadekoModule("ClashOfClans", ",")]
|
||||||
public class ClashOfClans : NadekoModule
|
public class ClashOfClans : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } = new ConcurrentDictionary<ulong, List<ClashWar>>();
|
public static ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; }
|
||||||
|
|
||||||
private static Timer checkWarTimer { get; }
|
private static Timer checkWarTimer { get; }
|
||||||
|
|
||||||
@ -82,11 +80,9 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
public async Task CreateWar(int size, [Remainder] string enemyClan = null)
|
public async Task CreateWar(int size, [Remainder] string enemyClan = null)
|
||||||
{
|
{
|
||||||
if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(enemyClan))
|
if (string.IsNullOrWhiteSpace(enemyClan))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ namespace NadekoBot.Modules.ClashOfClans
|
|||||||
|
|
||||||
public static string Localize(this ClashWar cw, string key)
|
public static string Localize(this ClashWar cw, string key)
|
||||||
{
|
{
|
||||||
return NadekoModule.GetTextStatic(key,
|
return NadekoTopLevelModule.GetTextStatic(key,
|
||||||
NadekoBot.Localization.GetCultureInfo(cw.Channel?.GuildId),
|
NadekoBot.Localization.GetCultureInfo(cw.Channel?.GuildId),
|
||||||
typeof(ClashOfClans).Name.ToLowerInvariant());
|
typeof(ClashOfClans).Name.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
@ -11,13 +11,29 @@ using NLog;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using System;
|
using System;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using NadekoBot.DataStructures;
|
using NadekoBot.DataStructures;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.CustomReactions
|
namespace NadekoBot.Modules.CustomReactions
|
||||||
{
|
{
|
||||||
|
public static class CustomReactionExtensions
|
||||||
|
{
|
||||||
|
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage context)
|
||||||
|
{
|
||||||
|
var channel = cr.DmResponse ? await context.Author.CreateDMChannelAsync() : context.Channel;
|
||||||
|
|
||||||
|
CustomReactions.ReactionStats.AddOrUpdate(cr.Trigger, 1, (k, old) => ++old);
|
||||||
|
|
||||||
|
CREmbed crembed;
|
||||||
|
if (CREmbed.TryParse(cr.Response, out crembed))
|
||||||
|
{
|
||||||
|
return await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "");
|
||||||
|
}
|
||||||
|
return await channel.SendMessageAsync(cr.ResponseWithContext(context).SanitizeMentions());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoModule("CustomReactions", ".")]
|
[NadekoModule("CustomReactions", ".")]
|
||||||
public class CustomReactions : NadekoModule
|
public class CustomReactions : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static CustomReaction[] _globalReactions = new CustomReaction[] { };
|
private static CustomReaction[] _globalReactions = new CustomReaction[] { };
|
||||||
public static CustomReaction[] GlobalReactions => _globalReactions;
|
public static CustomReaction[] GlobalReactions => _globalReactions;
|
||||||
@ -25,7 +41,7 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
|
|
||||||
public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>();
|
public static ConcurrentDictionary<string, uint> ReactionStats { get; } = new ConcurrentDictionary<string, uint>();
|
||||||
|
|
||||||
private static new readonly Logger _log;
|
private new static readonly Logger _log;
|
||||||
|
|
||||||
static CustomReactions()
|
static CustomReactions()
|
||||||
{
|
{
|
||||||
@ -43,11 +59,11 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
|
|
||||||
public void ClearStats() => ReactionStats.Clear();
|
public void ClearStats() => ReactionStats.Clear();
|
||||||
|
|
||||||
public static async Task<bool> TryExecuteCustomReaction(SocketUserMessage umsg)
|
public static CustomReaction TryGetCustomReaction(IUserMessage umsg)
|
||||||
{
|
{
|
||||||
var channel = umsg.Channel as SocketTextChannel;
|
var channel = umsg.Channel as SocketTextChannel;
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
return false;
|
return null;
|
||||||
|
|
||||||
var content = umsg.Content.Trim().ToLowerInvariant();
|
var content = umsg.Content.Trim().ToLowerInvariant();
|
||||||
CustomReaction[] reactions;
|
CustomReaction[] reactions;
|
||||||
@ -70,26 +86,9 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
var reaction = rs[new NadekoRandom().Next(0, rs.Length)];
|
var reaction = rs[new NadekoRandom().Next(0, rs.Length)];
|
||||||
if (reaction != null)
|
if (reaction != null)
|
||||||
{
|
{
|
||||||
if (reaction.Response != "-")
|
if (reaction.Response == "-")
|
||||||
{
|
return null;
|
||||||
CREmbed crembed;
|
return reaction;
|
||||||
if (CREmbed.TryParse(reaction.Response, out crembed))
|
|
||||||
{
|
|
||||||
try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); }
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn("Sending CREmbed failed");
|
|
||||||
_log.Warn(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try { await channel.SendMessageAsync(reaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReactionStats.AddOrUpdate(reaction.Trigger, 1, (k, old) => ++old);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -103,29 +102,10 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
|
return ((hasTarget && content.StartsWith(trigger + " ")) || content == trigger);
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
if (grs.Length == 0)
|
if (grs.Length == 0)
|
||||||
return false;
|
return null;
|
||||||
var greaction = grs[new NadekoRandom().Next(0, grs.Length)];
|
var greaction = grs[new NadekoRandom().Next(0, grs.Length)];
|
||||||
|
|
||||||
if (greaction != null)
|
return greaction;
|
||||||
{
|
|
||||||
CREmbed crembed;
|
|
||||||
if (CREmbed.TryParse(greaction.Response, out crembed))
|
|
||||||
{
|
|
||||||
try { await channel.EmbedAsync(crembed.ToEmbed(), crembed.PlainText ?? "").ConfigureAwait(false); }
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
_log.Warn("Sending CREmbed failed");
|
|
||||||
_log.Warn(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try { await channel.SendMessageAsync(greaction.ResponseWithContext(umsg)).ConfigureAwait(false); } catch { }
|
|
||||||
}
|
|
||||||
ReactionStats.AddOrUpdate(greaction.Trigger, 1, (k, old) => ++old);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -208,7 +188,19 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
.WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger)
|
.WithDescription(string.Join("\n", customReactions.OrderBy(cr => cr.Trigger)
|
||||||
.Skip((curPage - 1) * 20)
|
.Skip((curPage - 1) * 20)
|
||||||
.Take(20)
|
.Take(20)
|
||||||
.Select(cr => $"`#{cr.Id}` `{GetText("trigger")}:` {cr.Trigger}"))), lastPage)
|
.Select(cr =>
|
||||||
|
{
|
||||||
|
var str = $"`#{cr.Id}` {cr.Trigger}";
|
||||||
|
if (cr.AutoDeleteTrigger)
|
||||||
|
{
|
||||||
|
str = "🗑" + str;
|
||||||
|
}
|
||||||
|
if (cr.DmResponse)
|
||||||
|
{
|
||||||
|
str = "📪" + str;
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}))), lastPage)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -359,6 +351,108 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
public async Task CrDm(int id)
|
||||||
|
{
|
||||||
|
if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) ||
|
||||||
|
(Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomReaction[] reactions = new CustomReaction[0];
|
||||||
|
|
||||||
|
if (Context.Guild == null)
|
||||||
|
reactions = GlobalReactions;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GuildReactions.TryGetValue(Context.Guild.Id, out reactions);
|
||||||
|
}
|
||||||
|
if (reactions.Any())
|
||||||
|
{
|
||||||
|
var reaction = reactions.FirstOrDefault(x => x.Id == id);
|
||||||
|
|
||||||
|
if (reaction == null)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("no_found_id").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var setValue = reaction.DmResponse = !reaction.DmResponse;
|
||||||
|
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
uow.CustomReactions.Get(id).DmResponse = setValue;
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setValue)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("crdm_enabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("crdm_disabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("no_found").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
public async Task CrAd(int id)
|
||||||
|
{
|
||||||
|
if ((Context.Guild == null && !NadekoBot.Credentials.IsOwner(Context.User)) ||
|
||||||
|
(Context.Guild != null && !((IGuildUser)Context.User).GuildPermissions.Administrator))
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("insuff_perms").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomReaction[] reactions = new CustomReaction[0];
|
||||||
|
|
||||||
|
if (Context.Guild == null)
|
||||||
|
reactions = GlobalReactions;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GuildReactions.TryGetValue(Context.Guild.Id, out reactions);
|
||||||
|
}
|
||||||
|
if (reactions.Any())
|
||||||
|
{
|
||||||
|
var reaction = reactions.FirstOrDefault(x => x.Id == id);
|
||||||
|
|
||||||
|
if (reaction == null)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("no_found_id").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var setValue = reaction.AutoDeleteTrigger = !reaction.AutoDeleteTrigger;
|
||||||
|
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
uow.CustomReactions.Get(id).AutoDeleteTrigger = setValue;
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setValue)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("crad_enabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("crad_disabled", Format.Code(reaction.Id.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("no_found").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async Task CrStatsClear(string trigger = null)
|
public async Task CrStatsClear(string trigger = null)
|
||||||
|
@ -15,7 +15,7 @@ namespace NadekoBot.Modules.CustomReactions
|
|||||||
{
|
{
|
||||||
public static Dictionary<string, Func<IUserMessage, string, string>> responsePlaceholders = new Dictionary<string, Func<IUserMessage, string, string>>()
|
public static Dictionary<string, Func<IUserMessage, string, string>> responsePlaceholders = new Dictionary<string, Func<IUserMessage, string, string>>()
|
||||||
{
|
{
|
||||||
{"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim(); } }
|
{"%target%", (ctx, trigger) => { return ctx.Content.Substring(trigger.Length).Trim().SanitizeMentions(); } }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static Dictionary<string, Func<IUserMessage, string>> placeholders = new Dictionary<string, Func<IUserMessage, string>>()
|
public static Dictionary<string, Func<IUserMessage, string>> placeholders = new Dictionary<string, Func<IUserMessage, string>>()
|
||||||
|
@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel, Prefix);
|
var ar = new AnimalRace(Context.Guild.Id, (ITextChannel)Context.Channel, Prefix);
|
||||||
|
|
||||||
if (ar.Fail)
|
if (ar.Fail)
|
||||||
await Context.Channel.SendErrorAsync("🏁 `Failed starting a race. Another race is probably running.`").ConfigureAwait(false);
|
await ReplyErrorLocalized("race_failed_starting").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
AnimalRace ar;
|
AnimalRace ar;
|
||||||
if (!AnimalRaces.TryGetValue(Context.Guild.Id, out ar))
|
if (!AnimalRaces.TryGetValue(Context.Guild.Id, out ar))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No race exists on this server").ConfigureAwait(false);
|
await ReplyErrorLocalized("race_not_exist").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await ar.JoinRace(Context.User as IGuildUser, amount);
|
await ar.JoinRace(Context.User as IGuildUser, amount);
|
||||||
@ -56,22 +56,22 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
public bool Fail { get; set; }
|
public bool Fail { get; set; }
|
||||||
|
|
||||||
public List<Participant> participants = new List<Participant>();
|
private readonly List<Participant> _participants = new List<Participant>();
|
||||||
private ulong serverId;
|
private readonly ulong _serverId;
|
||||||
private int messagesSinceGameStarted = 0;
|
private int _messagesSinceGameStarted;
|
||||||
private readonly string _prefix;
|
private readonly string _prefix;
|
||||||
|
|
||||||
private Logger _log { get; }
|
private readonly Logger _log;
|
||||||
|
|
||||||
public ITextChannel raceChannel { get; set; }
|
private readonly ITextChannel _raceChannel;
|
||||||
public bool Started { get; private set; } = false;
|
public bool Started { get; private set; }
|
||||||
|
|
||||||
public AnimalRace(ulong serverId, ITextChannel ch, string prefix)
|
public AnimalRace(ulong serverId, ITextChannel ch, string prefix)
|
||||||
{
|
{
|
||||||
this._prefix = prefix;
|
_prefix = prefix;
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
this.serverId = serverId;
|
_serverId = serverId;
|
||||||
this.raceChannel = ch;
|
_raceChannel = ch;
|
||||||
if (!AnimalRaces.TryAdd(serverId, this))
|
if (!AnimalRaces.TryAdd(serverId, this))
|
||||||
{
|
{
|
||||||
Fail = true;
|
Fail = true;
|
||||||
@ -90,8 +90,8 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"Starting in 20 seconds or when the room is full.",
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_starting"),
|
||||||
footer: $"Type {_prefix}jr to join the race.");
|
footer: GetText("animal_race_join_instr", _prefix));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -102,16 +102,16 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
cancelSource.Cancel();
|
cancelSource.Cancel();
|
||||||
if (t == fullgame)
|
if (t == fullgame)
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendConfirmAsync("Animal Race", "Full! Starting immediately."); } catch (Exception ex) { _log.Warn(ex); }
|
try { await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_full") ); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
else if (participants.Count > 1)
|
else if (_participants.Count > 1)
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendConfirmAsync("Animal Race", "Starting with " + participants.Count + " participants."); } catch (Exception ex) { _log.Warn(ex); }
|
try { await _raceChannel.SendConfirmAsync(GetText("animal_race"), GetText("animal_race_starting_with_x", _participants.Count)); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendErrorAsync("Animal Race", "Failed to start since there was not enough participants."); } catch (Exception ex) { _log.Warn(ex); }
|
try { await _raceChannel.SendErrorAsync(GetText("animal_race"), GetText("animal_race_failed")); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
var p = participants.FirstOrDefault();
|
var p = _participants.FirstOrDefault();
|
||||||
|
|
||||||
if (p != null && p.AmountBet > 0)
|
if (p != null && p.AmountBet > 0)
|
||||||
await CurrencyHandler.AddCurrencyAsync(p.User, "BetRace", p.AmountBet, false).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(p.User, "BetRace", p.AmountBet, false).ConfigureAwait(false);
|
||||||
@ -128,7 +128,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
private void End()
|
private void End()
|
||||||
{
|
{
|
||||||
AnimalRace throwaway;
|
AnimalRace throwaway;
|
||||||
AnimalRaces.TryRemove(serverId, out throwaway);
|
AnimalRaces.TryRemove(_serverId, out throwaway);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartRace()
|
private async Task StartRace()
|
||||||
@ -136,21 +136,21 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
Participant winner = null;
|
Participant winner = null;
|
||||||
IUserMessage msg = null;
|
IUserMessage msg = null;
|
||||||
int place = 1;
|
var place = 1;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
while (!participants.All(p => p.Total >= 60))
|
while (!_participants.All(p => p.Total >= 60))
|
||||||
{
|
{
|
||||||
//update the state
|
//update the state
|
||||||
participants.ForEach(p =>
|
_participants.ForEach(p =>
|
||||||
{
|
{
|
||||||
p.Total += 1 + rng.Next(0, 10);
|
p.Total += 1 + rng.Next(0, 10);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
participants
|
_participants
|
||||||
.OrderByDescending(p => p.Total)
|
.OrderByDescending(p => p.Total)
|
||||||
.ForEach(p =>
|
.ForEach(p =>
|
||||||
{
|
{
|
||||||
@ -170,14 +170,14 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
//draw the state
|
//draw the state
|
||||||
|
|
||||||
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
|
var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
|
||||||
{String.Join("\n", participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|
{String.Join("\n", _participants.Select(p => $"{(int)(p.Total / 60f * 100),-2}%|{p.ToString()}"))}
|
||||||
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
|
|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|";
|
||||||
if (msg == null || messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
|
if (msg == null || _messagesSinceGameStarted >= 10) // also resend the message if channel was spammed
|
||||||
{
|
{
|
||||||
if (msg != null)
|
if (msg != null)
|
||||||
try { await msg.DeleteAsync(); } catch { }
|
try { await msg.DeleteAsync(); } catch { }
|
||||||
messagesSinceGameStarted = 0;
|
_messagesSinceGameStarted = 0;
|
||||||
try { msg = await raceChannel.SendMessageAsync(text).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try { msg = await _raceChannel.SendMessageAsync(text).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -187,22 +187,33 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
await Task.Delay(2500);
|
await Task.Delay(2500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (winner != null)
|
||||||
|
{
|
||||||
if (winner.AmountBet > 0)
|
if (winner.AmountBet > 0)
|
||||||
{
|
{
|
||||||
var wonAmount = winner.AmountBet * (participants.Count - 1);
|
var wonAmount = winner.AmountBet * (_participants.Count - 1);
|
||||||
|
|
||||||
await CurrencyHandler.AddCurrencyAsync(winner.User, "Won a Race", wonAmount, true).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(winner.User, "Won a Race", wonAmount, true)
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"{winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{CurrencySign}!**").ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"),
|
||||||
|
Format.Bold(GetText("animal_race_won_money", winner.User.Mention,
|
||||||
|
winner.Animal, wonAmount + CurrencySign)))
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"{winner.User.Mention} as {winner.Animal} **Won the race!**").ConfigureAwait(false);
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"),
|
||||||
|
Format.Bold(GetText("animal_race_won", winner.User.Mention, winner.Animal))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -212,9 +223,9 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var msg = imsg as SocketUserMessage;
|
var msg = imsg as SocketUserMessage;
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != raceChannel)
|
if (msg.IsAuthor() || !(imsg.Channel is ITextChannel) || imsg.Channel != _raceChannel)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
messagesSinceGameStarted++;
|
_messagesSinceGameStarted++;
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,51 +239,66 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
public async Task JoinRace(IGuildUser u, int amount = 0)
|
public async Task JoinRace(IGuildUser u, int amount = 0)
|
||||||
{
|
{
|
||||||
var animal = "";
|
string animal;
|
||||||
if (!animals.TryDequeue(out animal))
|
if (!animals.TryDequeue(out animal))
|
||||||
{
|
{
|
||||||
await raceChannel.SendErrorAsync($"{u.Mention} `There is no running race on this server.`").ConfigureAwait(false);
|
await _raceChannel.SendErrorAsync(GetText("animal_race_no_race")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var p = new Participant(u, animal, amount);
|
var p = new Participant(u, animal, amount);
|
||||||
if (participants.Contains(p))
|
if (_participants.Contains(p))
|
||||||
{
|
{
|
||||||
await raceChannel.SendErrorAsync($"{u.Mention} `You already joined this race.`").ConfigureAwait(false);
|
await _raceChannel.SendErrorAsync(GetText("animal_race_already_in")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (Started)
|
if (Started)
|
||||||
{
|
{
|
||||||
await raceChannel.SendErrorAsync($"{u.Mention} `Race is already started`").ConfigureAwait(false);
|
await _raceChannel.SendErrorAsync(GetText("animal_race_already_started")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
if (!await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)u, "BetRace", amount, false).ConfigureAwait(false))
|
if (!await CurrencyHandler.RemoveCurrencyAsync(u, "BetRace", amount, false).ConfigureAwait(false))
|
||||||
{
|
{
|
||||||
try { await raceChannel.SendErrorAsync($"{u.Mention} You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false); } catch { }
|
await _raceChannel.SendErrorAsync(GetText("not_enough", CurrencySign)).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
participants.Add(p);
|
_participants.Add(p);
|
||||||
await raceChannel.SendConfirmAsync("Animal Race", $"{u.Mention} **joined as a {p.Animal}" + (amount > 0 ? $" and bet {amount} {CurrencySign}!**" : "**"))
|
string confStr;
|
||||||
.ConfigureAwait(false);
|
if (amount > 0)
|
||||||
|
confStr = GetText("animal_race_join_bet", u.Mention, p.Animal, amount + CurrencySign);
|
||||||
|
else
|
||||||
|
confStr = GetText("animal_race_join", u.Mention, p.Animal);
|
||||||
|
await _raceChannel.SendConfirmAsync(GetText("animal_race"), Format.Bold(confStr)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string text)
|
||||||
|
=> NadekoTopLevelModule.GetTextStatic(text,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild),
|
||||||
|
typeof(Gambling).Name.ToLowerInvariant());
|
||||||
|
|
||||||
|
private string GetText(string text, params object[] replacements)
|
||||||
|
=> NadekoTopLevelModule.GetTextStatic(text,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_raceChannel.Guild),
|
||||||
|
typeof(Gambling).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Participant
|
public class Participant
|
||||||
{
|
{
|
||||||
public IGuildUser User { get; set; }
|
public IGuildUser User { get; }
|
||||||
public string Animal { get; set; }
|
public string Animal { get; }
|
||||||
public int AmountBet { get; set; }
|
public int AmountBet { get; }
|
||||||
|
|
||||||
public float Coeff { get; set; }
|
public float Coeff { get; set; }
|
||||||
public int Total { get; set; }
|
public int Total { get; set; }
|
||||||
|
|
||||||
public int Place { get; set; } = 0;
|
public int Place { get; set; }
|
||||||
|
|
||||||
public Participant(IGuildUser u, string a, int amount)
|
public Participant(IGuildUser u, string a, int amount)
|
||||||
{
|
{
|
||||||
this.User = u;
|
User = u;
|
||||||
this.Animal = a;
|
Animal = a;
|
||||||
this.AmountBet = amount;
|
AmountBet = amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int GetHashCode() => User.GetHashCode();
|
public override int GetHashCode() => User.GetHashCode();
|
||||||
@ -288,23 +314,13 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var str = new string('‣', Total) + Animal;
|
var str = new string('‣', Total) + Animal;
|
||||||
if (Place == 0)
|
if (Place == 0)
|
||||||
return str;
|
return str;
|
||||||
if (Place == 1)
|
|
||||||
{
|
|
||||||
return str + "🏆";
|
|
||||||
}
|
|
||||||
else if (Place == 2)
|
|
||||||
{
|
|
||||||
return str + "`2nd`";
|
|
||||||
}
|
|
||||||
else if (Place == 3)
|
|
||||||
{
|
|
||||||
return str + "`3rd`";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return str + $"`{Place}th`";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
str += $"`#{Place}`";
|
||||||
|
|
||||||
|
if (Place == 1)
|
||||||
|
str += "🏆";
|
||||||
|
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
switch (e)
|
switch (e)
|
||||||
{
|
{
|
||||||
case CurrencyEvent.FlowerReaction:
|
case CurrencyEvent.FlowerReaction:
|
||||||
await FlowerReactionEvent(Context).ConfigureAwait(false);
|
await FlowerReactionEvent(Context, arg).ConfigureAwait(false);
|
||||||
break;
|
break;
|
||||||
case CurrencyEvent.SneakyGameStatus:
|
case CurrencyEvent.SneakyGameStatus:
|
||||||
await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false);
|
await SneakyGameStatusEvent(Context, arg).ConfigureAwait(false);
|
||||||
@ -115,23 +115,26 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
return Task.Delay(0);
|
return Task.Delay(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task FlowerReactionEvent(CommandContext context)
|
public async Task FlowerReactionEvent(CommandContext context, int amount)
|
||||||
{
|
{
|
||||||
|
if (amount <= 0)
|
||||||
|
amount = 100;
|
||||||
|
|
||||||
var title = GetText("flowerreaction_title");
|
var title = GetText("flowerreaction_title");
|
||||||
var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(100.ToString()) + CurrencySign);
|
var desc = GetText("flowerreaction_desc", "🌸", Format.Bold(amount.ToString()) + CurrencySign);
|
||||||
var footer = GetText("flowerreaction_footer", 24);
|
var footer = GetText("flowerreaction_footer", 24);
|
||||||
var msg = await context.Channel.SendConfirmAsync(title,
|
var msg = await context.Channel.SendConfirmAsync(title,
|
||||||
desc, footer: footer)
|
desc, footer: footer)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
await new FlowerReactionEvent().Start(msg, context);
|
await new FlowerReactionEvent().Start(msg, context, amount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class CurrencyEvent
|
public abstract class CurrencyEvent
|
||||||
{
|
{
|
||||||
public abstract Task Start(IUserMessage msg, CommandContext channel);
|
public abstract Task Start(IUserMessage msg, CommandContext channel, int amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class FlowerReactionEvent : CurrencyEvent
|
public class FlowerReactionEvent : CurrencyEvent
|
||||||
@ -172,7 +175,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task Start(IUserMessage umsg, CommandContext context)
|
public override async Task Start(IUserMessage umsg, CommandContext context, int amount)
|
||||||
{
|
{
|
||||||
msg = umsg;
|
msg = umsg;
|
||||||
NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler;
|
NadekoBot.Client.MessageDeleted += MessageDeletedEventHandler;
|
||||||
@ -193,7 +196,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
|
if (r.Emoji.Name == "🌸" && r.User.IsSpecified && ((DateTime.UtcNow - r.User.Value.CreatedAt).TotalDays > 5) && _flowerReactionAwardedUsers.Add(r.User.Value.Id))
|
||||||
{
|
{
|
||||||
await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", 100, false)
|
await CurrencyHandler.AddCurrencyAsync(r.User.Value, "Flower Reaction Event", amount, false)
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using ImageSharp;
|
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
@ -22,7 +21,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
private Regex dndRegex { get; } = new Regex(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$", RegexOptions.Compiled);
|
private Regex dndRegex { get; } = new Regex(@"^(?<n1>\d+)d(?<n2>\d+)(?:\+(?<add>\d+))?(?:\-(?<sub>\d+))?$", RegexOptions.Compiled);
|
||||||
private Regex fudgeRegex { get; } = new Regex(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled);
|
private Regex fudgeRegex { get; } = new Regex(@"^(?<n1>\d+)d(?:F|f)$", RegexOptions.Compiled);
|
||||||
|
|
||||||
private readonly char[] fateRolls = new[] { '-', ' ', '+' };
|
private readonly char[] _fateRolls = { '-', ' ', '+' };
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Roll()
|
public async Task Roll()
|
||||||
@ -35,12 +34,14 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var imageStream = await Task.Run(() =>
|
var imageStream = await Task.Run(() =>
|
||||||
{
|
{
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
new[] { GetDice(num1), GetDice(num2) }.Merge().SaveAsPng(ms);
|
new[] { GetDice(num1), GetDice(num2) }.Merge().Save(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
return ms;
|
return ms;
|
||||||
}).ConfigureAwait(false);
|
}).ConfigureAwait(false);
|
||||||
|
|
||||||
await Context.Channel.SendFileAsync(imageStream, "dice.png", $"{Context.User.Mention} rolled " + Format.Code(gen.ToString())).ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(imageStream,
|
||||||
|
"dice.png",
|
||||||
|
Context.User.Mention + " " + GetText("dice_rolled", Format.Code(gen.ToString()))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum RollOrderType
|
public enum RollOrderType
|
||||||
@ -59,7 +60,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task Rolluo(int num)
|
public async Task Rolluo(int num = 1)
|
||||||
{
|
{
|
||||||
await InternalRoll(num, false).ConfigureAwait(false);
|
await InternalRoll(num, false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -82,7 +83,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (num < 1 || num > 30)
|
if (num < 1 || num > 30)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Invalid number specified. You can roll up to 1-30 dice at a time.").ConfigureAwait(false);
|
await ReplyErrorLocalized("dice_invalid_number", 1, 30).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,9 +119,14 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
var bitmap = dice.Merge();
|
var bitmap = dice.Merge();
|
||||||
var ms = new MemoryStream();
|
var ms = new MemoryStream();
|
||||||
bitmap.SaveAsPng(ms);
|
bitmap.Save(ms);
|
||||||
ms.Position = 0;
|
ms.Position = 0;
|
||||||
await Context.Channel.SendFileAsync(ms, "dice.png", $"{Context.User.Mention} rolled {values.Count} {(values.Count == 1 ? "die" : "dice")}. Total: **{values.Sum()}** Average: **{(values.Sum() / (1.0f * values.Count)).ToString("N2")}**").ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(ms, "dice.png",
|
||||||
|
Context.User.Mention + " " +
|
||||||
|
GetText("dice_rolled_num", Format.Bold(values.Count.ToString())) +
|
||||||
|
" " + GetText("total_average",
|
||||||
|
Format.Bold(values.Sum().ToString()),
|
||||||
|
Format.Bold((values.Sum() / (1.0f * values.Count)).ToString("N2")))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InternallDndRoll(string arg, bool ordered)
|
private async Task InternallDndRoll(string arg, bool ordered)
|
||||||
@ -138,9 +144,9 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
for (int i = 0; i < n1; i++)
|
for (int i = 0; i < n1; i++)
|
||||||
{
|
{
|
||||||
rolls.Add(fateRolls[rng.Next(0, fateRolls.Length)]);
|
rolls.Add(_fateRolls[rng.Next(0, _fateRolls.Length)]);
|
||||||
}
|
}
|
||||||
var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} fate {(n1 == 1 ? "die" : "dice")}.")
|
var embed = new EmbedBuilder().WithOkColor().WithDescription(Context.User.Mention + " " + GetText("dice_rolled_num", Format.Bold(n1.ToString())))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Result"))
|
.AddField(efb => efb.WithName(Format.Bold("Result"))
|
||||||
.WithValue(string.Join(" ", rolls.Select(c => Format.Code($"[{c}]")))));
|
.WithValue(string.Join(" ", rolls.Select(c => Format.Code($"[{c}]")))));
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -164,7 +170,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
}
|
}
|
||||||
|
|
||||||
var sum = arr.Sum();
|
var sum = arr.Sum();
|
||||||
var embed = new EmbedBuilder().WithOkColor().WithDescription($"{Context.User.Mention} rolled {n1} {(n1 == 1 ? "die" : "dice")} `1 to {n2}`")
|
var embed = new EmbedBuilder().WithOkColor().WithDescription(Context.User.Mention + " " +GetText("dice_rolled_num", n1) + $"`1 - {n2}`")
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Rolls"))
|
.AddField(efb => efb.WithName(Format.Bold("Rolls"))
|
||||||
.WithValue(string.Join(" ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => Format.Code(x.ToString())))))
|
.WithValue(string.Join(" ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => Format.Code(x.ToString())))))
|
||||||
.AddField(efb => efb.WithName(Format.Bold("Sum"))
|
.AddField(efb => efb.WithName(Format.Bold("Sum"))
|
||||||
@ -176,8 +182,6 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task NRoll([Remainder] string range)
|
public async Task NRoll([Remainder] string range)
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
int rolled;
|
int rolled;
|
||||||
if (range.Contains("-"))
|
if (range.Contains("-"))
|
||||||
@ -187,7 +191,10 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
.Select(int.Parse)
|
.Select(int.Parse)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
if (arr[0] > arr[1])
|
if (arr[0] > arr[1])
|
||||||
throw new ArgumentException("Second argument must be larger than the first one.");
|
{
|
||||||
|
await ReplyErrorLocalized("second_larger_than_first").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
rolled = new NadekoRandom().Next(arr[0], arr[1] + 1);
|
rolled = new NadekoRandom().Next(arr[0], arr[1] + 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -195,12 +202,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
rolled = new NadekoRandom().Next(0, int.Parse(range) + 1);
|
rolled = new NadekoRandom().Next(0, int.Parse(range) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} rolled **{rolled}**.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("dice_rolled", Format.Bold(rolled.ToString())).ConfigureAwait(false);
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync($":anger: {ex.Message}").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Image GetDice(int num)
|
private Image GetDice(int num)
|
||||||
|
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
images.Add(new Image(stream));
|
images.Add(new Image(stream));
|
||||||
}
|
}
|
||||||
MemoryStream bitmapStream = new MemoryStream();
|
MemoryStream bitmapStream = new MemoryStream();
|
||||||
images.Merge().SaveAsPng(bitmapStream);
|
images.Merge().Save(bitmapStream);
|
||||||
bitmapStream.Position = 0;
|
bitmapStream.Position = 0;
|
||||||
var toSend = $"{Context.User.Mention}";
|
var toSend = $"{Context.User.Mention}";
|
||||||
if (cardObjects.Count == 5)
|
if (cardObjects.Count == 5)
|
||||||
|
@ -52,18 +52,23 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var imgs = new Image[count];
|
var imgs = new Image[count];
|
||||||
using (var heads = _images.Heads.ToStream())
|
|
||||||
using(var tails = _images.Tails.ToStream())
|
|
||||||
{
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
imgs[i] = rng.Next(0, 10) < 5 ?
|
using (var heads = _images.Heads.ToStream())
|
||||||
new Image(heads) :
|
using (var tails = _images.Tails.ToStream())
|
||||||
new Image(tails);
|
{
|
||||||
|
if (rng.Next(0, 10) < 5)
|
||||||
|
{
|
||||||
|
imgs[i] = new Image(heads);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
imgs[i] = new Image(tails);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
|
await Context.Channel.SendFileAsync(imgs.Merge().ToStream(), $"{count} coins.png").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Betflip(int amount, string guess)
|
public async Task Betflip(int amount, string guess)
|
||||||
@ -105,7 +110,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier);
|
var toWin = (int)Math.Round(amount * NadekoBot.BotConfig.BetflipMultiplier);
|
||||||
str = Context.User.Mention + " " + GetText("flip_guess", toWin + CurrencySign);
|
str = Context.User.Mention + " " + GetText("flip_guess", toWin + CurrencySign);
|
||||||
await CurrencyHandler.AddCurrencyAsync(Context.User, GetText("betflip_gamble"), toWin, false).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(Context.User, "Betflip Gamble", toWin, false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
349
src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs
Normal file
349
src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NadekoBot.Attributes;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database;
|
||||||
|
using NadekoBot.Services.Database.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Gambling
|
||||||
|
{
|
||||||
|
public partial class Gambling
|
||||||
|
{
|
||||||
|
[Group]
|
||||||
|
public class FlowerShop : NadekoSubmodule
|
||||||
|
{
|
||||||
|
public enum Role
|
||||||
|
{
|
||||||
|
Role
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum List
|
||||||
|
{
|
||||||
|
List
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task Shop(int page = 1)
|
||||||
|
{
|
||||||
|
if (page <= 0)
|
||||||
|
return;
|
||||||
|
page -= 1;
|
||||||
|
List<ShopEntry> entries;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
entries = new IndexedCollection<ShopEntry>(uow.GuildConfigs.For(Context.Guild.Id,
|
||||||
|
set => set.Include(x => x.ShopEntries)
|
||||||
|
.ThenInclude(x => x.Items)).ShopEntries);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Context.Channel.SendPaginatedConfirmAsync(page + 1, (curPage) =>
|
||||||
|
{
|
||||||
|
var theseEntries = entries.Skip((curPage - 1) * 9).Take(9);
|
||||||
|
|
||||||
|
if (!theseEntries.Any())
|
||||||
|
return new EmbedBuilder().WithErrorColor()
|
||||||
|
.WithDescription(GetText("shop_none"));
|
||||||
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("shop", CurrencySign));
|
||||||
|
|
||||||
|
for (int i = 0; i < entries.Count; i++)
|
||||||
|
{
|
||||||
|
var entry = entries[i];
|
||||||
|
embed.AddField(efb => efb.WithName($"#{i + 1} - {entry.Price}{CurrencySign}").WithValue(EntryToString(entry)).WithIsInline(true));
|
||||||
|
}
|
||||||
|
return embed;
|
||||||
|
}, entries.Count / 9, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task Buy(int index, [Remainder]string message = null)
|
||||||
|
{
|
||||||
|
index -= 1;
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
|
ShopEntry entry;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set
|
||||||
|
.Include(x => x.ShopEntries)
|
||||||
|
.ThenInclude(x => x.Items));
|
||||||
|
var entries = new IndexedCollection<ShopEntry>(config.ShopEntries);
|
||||||
|
entry = entries.ElementAtOrDefault(index);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == null)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("shop_item_not_found").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry.Type == ShopEntryType.Role)
|
||||||
|
{
|
||||||
|
var guser = (IGuildUser)Context.User;
|
||||||
|
var role = Context.Guild.GetRole(entry.RoleId);
|
||||||
|
|
||||||
|
if (role == null)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("shop_role_not_found").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, $"Shop purchase - {entry.Type}", entry.Price))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await guser.AddRolesAsync(role).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
await CurrencyHandler.AddCurrencyAsync(Context.User.Id, $"Shop error refund", entry.Price);
|
||||||
|
await ReplyErrorLocalized("shop_role_purchase_error").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await CurrencyHandler.AddCurrencyAsync(entry.AuthorId, $"Shop sell item - {entry.Type}", GetProfitAmount(entry.Price));
|
||||||
|
await ReplyConfirmLocalized("shop_role_purchase", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("not_enough", CurrencySign).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (entry.Type == ShopEntryType.List)
|
||||||
|
{
|
||||||
|
if (entry.Items.Count == 0)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("out_of_stock").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = entry.Items.ToArray()[new NadekoRandom().Next(0, entry.Items.Count)];
|
||||||
|
|
||||||
|
if (await CurrencyHandler.RemoveCurrencyAsync(Context.User.Id, $"Shop purchase - {entry.Type}", entry.Price))
|
||||||
|
{
|
||||||
|
int removed;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var x = uow._context.Set<ShopEntryItem>().Remove(item);
|
||||||
|
|
||||||
|
removed = uow.Complete();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await (await Context.User.CreateDMChannelAsync())
|
||||||
|
.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("shop_purchase", Context.Guild.Name))
|
||||||
|
.AddField(efb => efb.WithName(GetText("item")).WithValue(item.Text).WithIsInline(false))
|
||||||
|
.AddField(efb => efb.WithName(GetText("price")).WithValue(entry.Price.ToString()).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText("name")).WithValue(entry.Name).WithIsInline(true)))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
|
||||||
|
await CurrencyHandler.AddCurrencyAsync(entry.AuthorId,
|
||||||
|
$"Shop sell item - {entry.Name}",
|
||||||
|
GetProfitAmount(entry.Price)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
uow._context.Set<ShopEntryItem>().Add(item);
|
||||||
|
uow.Complete();
|
||||||
|
|
||||||
|
await CurrencyHandler.AddCurrencyAsync(Context.User.Id,
|
||||||
|
$"Shop error refund - {entry.Name}",
|
||||||
|
entry.Price,
|
||||||
|
uow).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
await ReplyErrorLocalized("shop_buy_error").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await ReplyConfirmLocalized("shop_item_purchase").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("not_enough", CurrencySign).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private long GetProfitAmount(int price) =>
|
||||||
|
(int)(Math.Ceiling(0.90 * price));
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
[RequireBotPermission(GuildPermission.ManageRoles)]
|
||||||
|
public async Task ShopAdd(Role _, int price, [Remainder] IRole role)
|
||||||
|
{
|
||||||
|
var entry = new ShopEntry()
|
||||||
|
{
|
||||||
|
Name = "-",
|
||||||
|
Price = price,
|
||||||
|
Type = ShopEntryType.Role,
|
||||||
|
AuthorId = Context.User.Id,
|
||||||
|
RoleId = role.Id,
|
||||||
|
RoleName = role.Name
|
||||||
|
};
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigs.For(Context.Guild.Id,
|
||||||
|
set => set.Include(x => x.ShopEntries)
|
||||||
|
.ThenInclude(x => x.Items)).ShopEntries);
|
||||||
|
entries.Add(entry);
|
||||||
|
uow.GuildConfigs.For(Context.Guild.Id, set => set).ShopEntries = entries;
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
await Context.Channel.EmbedAsync(EntryToEmbed(entry)
|
||||||
|
.WithTitle(GetText("shop_item_add")));
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
public async Task ShopAdd(List _, int price, [Remainder]string name)
|
||||||
|
{
|
||||||
|
var entry = new ShopEntry()
|
||||||
|
{
|
||||||
|
Name = name.TrimTo(100),
|
||||||
|
Price = price,
|
||||||
|
Type = ShopEntryType.List,
|
||||||
|
AuthorId = Context.User.Id,
|
||||||
|
Items = new HashSet<ShopEntryItem>(),
|
||||||
|
};
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigs.For(Context.Guild.Id,
|
||||||
|
set => set.Include(x => x.ShopEntries)
|
||||||
|
.ThenInclude(x => x.Items)).ShopEntries);
|
||||||
|
entries.Add(entry);
|
||||||
|
uow.GuildConfigs.For(Context.Guild.Id, set => set).ShopEntries = entries;
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
await Context.Channel.EmbedAsync(EntryToEmbed(entry)
|
||||||
|
.WithTitle(GetText("shop_item_add")));
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
public async Task ShopListAdd(int index, [Remainder] string itemText)
|
||||||
|
{
|
||||||
|
index -= 1;
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
|
var item = new ShopEntryItem()
|
||||||
|
{
|
||||||
|
Text = itemText
|
||||||
|
};
|
||||||
|
ShopEntry entry;
|
||||||
|
bool rightType = false;
|
||||||
|
bool added = false;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var entries = new IndexedCollection<ShopEntry>(uow.GuildConfigs.For(Context.Guild.Id,
|
||||||
|
set => set.Include(x => x.ShopEntries)
|
||||||
|
.ThenInclude(x => x.Items)).ShopEntries);
|
||||||
|
entry = entries.ElementAtOrDefault(index);
|
||||||
|
if (entry != null && (rightType = (entry.Type == ShopEntryType.List)))
|
||||||
|
{
|
||||||
|
if (added = entry.Items.Add(item))
|
||||||
|
{
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry == null)
|
||||||
|
await ReplyErrorLocalized("shop_item_not_found").ConfigureAwait(false);
|
||||||
|
else if (!rightType)
|
||||||
|
await ReplyErrorLocalized("shop_item_wrong_type").ConfigureAwait(false);
|
||||||
|
else if (added == false)
|
||||||
|
await ReplyErrorLocalized("shop_list_item_not_unique").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("shop_list_item_added").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
[RequireUserPermission(GuildPermission.Administrator)]
|
||||||
|
public async Task ShopRemove(int index)
|
||||||
|
{
|
||||||
|
index -= 1;
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
|
ShopEntry removed;
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set
|
||||||
|
.Include(x => x.ShopEntries)
|
||||||
|
.ThenInclude(x => x.Items));
|
||||||
|
|
||||||
|
var entries = new IndexedCollection<ShopEntry>(config.ShopEntries);
|
||||||
|
removed = entries.ElementAtOrDefault(index);
|
||||||
|
if (removed != null)
|
||||||
|
{
|
||||||
|
entries.Remove(removed);
|
||||||
|
|
||||||
|
config.ShopEntries = entries;
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removed == null)
|
||||||
|
await ReplyErrorLocalized("shop_item_not_found").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await Context.Channel.EmbedAsync(EntryToEmbed(removed)
|
||||||
|
.WithTitle(GetText("shop_item_rm")));
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmbedBuilder EntryToEmbed(ShopEntry entry)
|
||||||
|
{
|
||||||
|
var embed = new EmbedBuilder().WithOkColor();
|
||||||
|
|
||||||
|
if (entry.Type == ShopEntryType.Role)
|
||||||
|
return embed.AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(entry.RoleName))).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText("price")).WithValue(entry.Price.ToString()).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText("type")).WithValue(entry.Type.ToString()).WithIsInline(true));
|
||||||
|
else if (entry.Type == ShopEntryType.List)
|
||||||
|
return embed.AddField(efb => efb.WithName(GetText("name")).WithValue(entry.Name).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText("price")).WithValue(entry.Price.ToString()).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName(GetText("type")).WithValue(GetText("random_unique_item")).WithIsInline(true));
|
||||||
|
//else if (entry.Type == ShopEntryType.Infinite_List)
|
||||||
|
// return embed.AddField(efb => efb.WithName(GetText("name")).WithValue(GetText("shop_role", Format.Bold(entry.RoleName))).WithIsInline(true))
|
||||||
|
// .AddField(efb => efb.WithName(GetText("price")).WithValue(entry.Price.ToString()).WithIsInline(true))
|
||||||
|
// .AddField(efb => efb.WithName(GetText("type")).WithValue(entry.Type.ToString()).WithIsInline(true));
|
||||||
|
else return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string EntryToString(ShopEntry entry)
|
||||||
|
{
|
||||||
|
if (entry.Type == ShopEntryType.Role)
|
||||||
|
{
|
||||||
|
return GetText("shop_role", Format.Bold(entry.RoleName));
|
||||||
|
}
|
||||||
|
else if (entry.Type == ShopEntryType.List)
|
||||||
|
{
|
||||||
|
return GetText("unique_items_left", entry.Items.Count) + "\n" + entry.Name;
|
||||||
|
}
|
||||||
|
//else if (entry.Type == ShopEntryType.Infinite_List)
|
||||||
|
//{
|
||||||
|
|
||||||
|
//}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
197
src/NadekoBot/Modules/Gambling/Commands/Lucky7Commands.cs
Normal file
197
src/NadekoBot/Modules/Gambling/Commands/Lucky7Commands.cs
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Discord.Commands;
|
||||||
|
using Discord;
|
||||||
|
using NadekoBot.Attributes;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Gambling
|
||||||
|
{
|
||||||
|
//public partial class Gambling
|
||||||
|
//{
|
||||||
|
// [Group]
|
||||||
|
// public class Lucky7Commands : NadekoSubmodule
|
||||||
|
// {
|
||||||
|
// [NadekoCommand, Usage, Description, Aliases]
|
||||||
|
// [RequireContext(ContextType.Guild)]
|
||||||
|
// [OwnerOnly]
|
||||||
|
// public async Task Lucky7Test(uint tests)
|
||||||
|
// {
|
||||||
|
// if (tests <= 0)
|
||||||
|
// return;
|
||||||
|
|
||||||
|
// var dict = new Dictionary<float, int>();
|
||||||
|
// var totalWon = 0;
|
||||||
|
// for (var i = 0; i < tests; i++)
|
||||||
|
// {
|
||||||
|
// var g = new Lucky7Game(10);
|
||||||
|
// while (!g.Ended)
|
||||||
|
// {
|
||||||
|
// if (g.CurrentPosition == 0)
|
||||||
|
// g.Stay();
|
||||||
|
// else
|
||||||
|
// g.Move();
|
||||||
|
// }
|
||||||
|
// totalWon += (int)(g.CurrentMultiplier * g.Bet);
|
||||||
|
// if (!dict.ContainsKey(g.CurrentMultiplier))
|
||||||
|
// dict.Add(g.CurrentMultiplier, 0);
|
||||||
|
|
||||||
|
// dict[g.CurrentMultiplier] ++;
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
// .WithTitle("Move Or Stay test")
|
||||||
|
// .WithDescription(string.Join("\n",
|
||||||
|
// dict.Select(x => $"x{x.Key} occured {x.Value} times {x.Value * 1.0f / tests * 100:F2}%")))
|
||||||
|
// .WithFooter(
|
||||||
|
// efb => efb.WithText($"Total Bet: {tests * 10} | Payout: {totalWon} | {totalWon *1.0f / tests * 10}%")));
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private static readonly ConcurrentDictionary<ulong, Lucky7Game> _games =
|
||||||
|
// new ConcurrentDictionary<ulong, Lucky7Game>();
|
||||||
|
|
||||||
|
// [NadekoCommand, Usage, Description, Aliases]
|
||||||
|
// [RequireContext(ContextType.Guild)]
|
||||||
|
// public async Task Lucky7(int bet)
|
||||||
|
// {
|
||||||
|
// if (bet < 4)
|
||||||
|
// return;
|
||||||
|
// var game = new Lucky7Game(bet);
|
||||||
|
// if (!_games.TryAdd(Context.User.Id, game))
|
||||||
|
// {
|
||||||
|
// await ReplyAsync("You're already betting on move or stay.").ConfigureAwait(false);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (!await CurrencyHandler.RemoveCurrencyAsync(Context.User, "MoveOrStay bet", bet, false))
|
||||||
|
// {
|
||||||
|
// _games.TryRemove(Context.User.Id, out game);
|
||||||
|
// await ReplyConfirmLocalized("not_enough", CurrencySign).ConfigureAwait(false);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// await Context.Channel.EmbedAsync(GetGameState(game),
|
||||||
|
// string.Format("{0} rolled {1}.", Context.User, game.Rolled)).ConfigureAwait(false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public enum MoveOrStay
|
||||||
|
// {
|
||||||
|
// Move = 1,
|
||||||
|
// M = 1,
|
||||||
|
// Stay = 2,
|
||||||
|
// S = 2
|
||||||
|
// }
|
||||||
|
|
||||||
|
// [NadekoCommand, Usage, Description, Aliases]
|
||||||
|
// [RequireContext(ContextType.Guild)]
|
||||||
|
// public async Task Lucky7(MoveOrStay action)
|
||||||
|
// {
|
||||||
|
// Lucky7Game game;
|
||||||
|
// if (!_games.TryGetValue(Context.User.Id, out game))
|
||||||
|
// {
|
||||||
|
// await ReplyAsync("You're not betting on move or stay.").ConfigureAwait(false);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (action == MoveOrStay.Move)
|
||||||
|
// {
|
||||||
|
// game.Move();
|
||||||
|
// await Context.Channel.EmbedAsync(GetGameState(game),
|
||||||
|
// string.Format("{0} rolled {1}.", Context.User, game.Rolled)).ConfigureAwait(false);
|
||||||
|
// if (game.Ended)
|
||||||
|
// _games.TryRemove(Context.User.Id, out game);
|
||||||
|
// }
|
||||||
|
// else if (action == MoveOrStay.Stay)
|
||||||
|
// {
|
||||||
|
// var won = game.Stay();
|
||||||
|
// await CurrencyHandler.AddCurrencyAsync(Context.User, "MoveOrStay stay", won, false)
|
||||||
|
// .ConfigureAwait(false);
|
||||||
|
// _games.TryRemove(Context.User.Id, out game);
|
||||||
|
// await ReplyAsync(string.Format("You've finished with {0}",
|
||||||
|
// won + CurrencySign))
|
||||||
|
// .ConfigureAwait(false);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// }
|
||||||
|
|
||||||
|
// private EmbedBuilder GetGameState(Lucky7Game game)
|
||||||
|
// {
|
||||||
|
// var arr = Lucky7Game.Winnings.ToArray();
|
||||||
|
// var sb = new StringBuilder();
|
||||||
|
// for (var i = 0; i < arr.Length; i++)
|
||||||
|
// {
|
||||||
|
// if (i == game.CurrentPosition)
|
||||||
|
// {
|
||||||
|
// sb.Append("[" + arr[i] + "]");
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// sb.Append(arr[i].ToString());
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (i != arr.Length - 1)
|
||||||
|
// sb.Append(' ');
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return new EmbedBuilder().WithOkColor()
|
||||||
|
// .WithTitle("Lucky7")
|
||||||
|
// .WithDescription(sb.ToString())
|
||||||
|
// .AddField(efb => efb.WithName("Bet")
|
||||||
|
// .WithValue(game.Bet.ToString())
|
||||||
|
// .WithIsInline(true))
|
||||||
|
// .AddField(efb => efb.WithName("Current Value")
|
||||||
|
// .WithValue((game.CurrentMultiplier * game.Bet).ToString(_cultureInfo))
|
||||||
|
// .WithIsInline(true));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public class Lucky7Game
|
||||||
|
// {
|
||||||
|
// public int Bet { get; }
|
||||||
|
// public bool Ended { get; private set; }
|
||||||
|
// public int PreviousPosition { get; private set; }
|
||||||
|
// public int CurrentPosition { get; private set; } = -1;
|
||||||
|
// public int Rolled { get; private set; }
|
||||||
|
// public float CurrentMultiplier => Winnings[CurrentPosition];
|
||||||
|
// private readonly NadekoRandom _rng = new NadekoRandom();
|
||||||
|
|
||||||
|
// public static readonly ImmutableArray<float> Winnings = new[]
|
||||||
|
// {
|
||||||
|
// 1.2f, 0.8f, 0.75f, 0.90f, 0.7f, 0.5f, 1.8f, 0f, 0f
|
||||||
|
// }.ToImmutableArray();
|
||||||
|
|
||||||
|
// public Lucky7Game(int bet)
|
||||||
|
// {
|
||||||
|
// Bet = bet;
|
||||||
|
// Move();
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public void Move()
|
||||||
|
// {
|
||||||
|
// if (Ended)
|
||||||
|
// return;
|
||||||
|
// PreviousPosition = CurrentPosition;
|
||||||
|
// Rolled = _rng.Next(1, 4);
|
||||||
|
// CurrentPosition += Rolled;
|
||||||
|
|
||||||
|
// if (CurrentPosition >= 6)
|
||||||
|
// Ended = true;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// public int Stay()
|
||||||
|
// {
|
||||||
|
// if (Ended)
|
||||||
|
// return 0;
|
||||||
|
|
||||||
|
// Ended = true;
|
||||||
|
// return (int) (CurrentMultiplier * Bet);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
}
|
@ -1,5 +1,6 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
|
using ImageSharp;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
@ -143,11 +144,11 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
await ReplyErrorLocalized("min_bet_limit", 1 + CurrencySign).ConfigureAwait(false);
|
await ReplyErrorLocalized("min_bet_limit", 1 + CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const int maxAmount = 9999;
|
||||||
if (amount > 999)
|
if (amount > maxAmount)
|
||||||
{
|
{
|
||||||
GetText("slot_maxbet", 999 + CurrencySign);
|
GetText("slot_maxbet", maxAmount + CurrencySign);
|
||||||
await ReplyErrorLocalized("max_bet_limit", 999 + CurrencySign).ConfigureAwait(false);
|
await ReplyErrorLocalized("max_bet_limit", maxAmount + CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,28 +164,13 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
var result = SlotMachine.Pull();
|
var result = SlotMachine.Pull();
|
||||||
int[] numbers = result.Numbers;
|
int[] numbers = result.Numbers;
|
||||||
using (var bgPixels = bgImage.Lock())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < 3; i++)
|
for (int i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
|
using (var file = _images.SlotEmojis[numbers[i]].ToStream())
|
||||||
|
using (var randomImage = new ImageSharp.Image(file))
|
||||||
{
|
{
|
||||||
var randomImage = new ImageSharp.Image(file);
|
bgImage.DrawImage(randomImage, 100, default(Size), new Point(95 + 142 * i, 330));
|
||||||
using (var toAdd = randomImage.Lock())
|
|
||||||
{
|
|
||||||
for (int j = 0; j < toAdd.Width; j++)
|
|
||||||
{
|
|
||||||
for (int k = 0; k < toAdd.Height; k++)
|
|
||||||
{
|
|
||||||
var x = 95 + 142 * i + j;
|
|
||||||
int y = 330 + k;
|
|
||||||
var toSet = toAdd[j, k];
|
|
||||||
if (toSet.A < _alphaCutOut)
|
|
||||||
continue;
|
|
||||||
bgPixels[x, y] = toAdd[j, k];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,21 +181,9 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var digit = printWon % 10;
|
var digit = printWon % 10;
|
||||||
using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream())
|
using (var fs = NadekoBot.Images.SlotNumbers[digit].ToStream())
|
||||||
|
using (var img = new ImageSharp.Image(fs))
|
||||||
{
|
{
|
||||||
var img = new ImageSharp.Image(fs);
|
bgImage.DrawImage(img, 100, default(Size), new Point(230 - n * 16, 462));
|
||||||
using (var pixels = img.Lock())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < pixels.Width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < pixels.Height; j++)
|
|
||||||
{
|
|
||||||
if (pixels[i, j].A < _alphaCutOut)
|
|
||||||
continue;
|
|
||||||
var x = 230 - n * 16 + i;
|
|
||||||
bgPixels[x, 462 + j] = pixels[i, j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
} while ((printWon /= 10) != 0);
|
} while ((printWon /= 10) != 0);
|
||||||
@ -220,25 +194,12 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var digit = printAmount % 10;
|
var digit = printAmount % 10;
|
||||||
using (var fs = _images.SlotNumbers[digit].ToStream())
|
using (var fs = _images.SlotNumbers[digit].ToStream())
|
||||||
|
using (var img = new ImageSharp.Image(fs))
|
||||||
{
|
{
|
||||||
var img = new ImageSharp.Image(fs);
|
bgImage.DrawImage(img, 100, default(Size), new Point(395 - n * 16, 462));
|
||||||
using (var pixels = img.Lock())
|
|
||||||
{
|
|
||||||
for (int i = 0; i < pixels.Width; i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < pixels.Height; j++)
|
|
||||||
{
|
|
||||||
if (pixels[i, j].A < _alphaCutOut)
|
|
||||||
continue;
|
|
||||||
var x = 395 - n * 16 + i;
|
|
||||||
bgPixels[x, 462 + j] = pixels[i, j];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
n++;
|
n++;
|
||||||
} while ((printAmount /= 10) != 0);
|
} while ((printAmount /= 10) != 0);
|
||||||
}
|
|
||||||
|
|
||||||
var msg = GetText("better_luck");
|
var msg = GetText("better_luck");
|
||||||
if (result.Multiplier != 0)
|
if (result.Multiplier != 0)
|
||||||
@ -262,7 +223,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(2000);
|
await Task.Delay(1500);
|
||||||
_runningUsers.Remove(Context.User.Id);
|
_runningUsers.Remove(Context.User.Id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -3,13 +3,11 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NadekoBot.Services.Database;
|
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
@ -49,8 +47,8 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
[Group]
|
[Group]
|
||||||
public class WaifuClaimCommands : NadekoSubmodule
|
public class WaifuClaimCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentDictionary<ulong, DateTime> _divorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
private static ConcurrentDictionary<ulong, DateTime> divorceCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||||
private static ConcurrentDictionary<ulong, DateTime> _affinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
private static ConcurrentDictionary<ulong, DateTime> affinityCooldowns { get; } = new ConcurrentDictionary<ulong, DateTime>();
|
||||||
|
|
||||||
enum WaifuClaimResult
|
enum WaifuClaimResult
|
||||||
{
|
{
|
||||||
@ -65,20 +63,19 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (amount < 50)
|
if (amount < 50)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} No waifu is that cheap. You must pay at least 50{NadekoBot.BotConfig.CurrencySign} to get a waifu, even if their actual value is lower.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_isnt_cheap", 50 + CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target.Id == Context.User.Id)
|
if (target.Id == Context.User.Id)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync(Context.User.Mention + " You can't claim yourself.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_not_yourself").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WaifuClaimResult result = WaifuClaimResult.NotEnoughFunds;
|
WaifuClaimResult result;
|
||||||
int? oldPrice = null;
|
|
||||||
WaifuInfo w;
|
WaifuInfo w;
|
||||||
var isAffinity = false;
|
bool isAffinity;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
w = uow.Waifus.ByWaifuUserId(target.Id);
|
w = uow.Waifus.ByWaifuUserId(target.Id);
|
||||||
@ -120,7 +117,6 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var oldClaimer = w.Claimer;
|
var oldClaimer = w.Claimer;
|
||||||
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
||||||
oldPrice = w.Price;
|
|
||||||
w.Price = amount + (amount / 4);
|
w.Price = amount + (amount / 4);
|
||||||
result = WaifuClaimResult.Success;
|
result = WaifuClaimResult.Success;
|
||||||
|
|
||||||
@ -143,7 +139,6 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
var oldClaimer = w.Claimer;
|
var oldClaimer = w.Claimer;
|
||||||
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
w.Claimer = uow.DiscordUsers.GetOrCreate(Context.User);
|
||||||
oldPrice = w.Price;
|
|
||||||
w.Price = amount;
|
w.Price = amount;
|
||||||
result = WaifuClaimResult.Success;
|
result = WaifuClaimResult.Success;
|
||||||
|
|
||||||
@ -165,22 +160,20 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
if (result == WaifuClaimResult.InsufficientAmount)
|
if (result == WaifuClaimResult.InsufficientAmount)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must pay {Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))} or more to claim that waifu!").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_not_enough", Math.Ceiling(w.Price * (isAffinity ? 0.88f : 1.1f))).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (result == WaifuClaimResult.NotEnoughFunds)
|
if (result == WaifuClaimResult.NotEnoughFunds)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} you don't have {amount}{NadekoBot.BotConfig.CurrencySign}!")
|
await ReplyErrorLocalized("not_enough", CurrencySign).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
return;
|
||||||
}
|
}
|
||||||
else
|
var msg = GetText("waifu_claimed",
|
||||||
{
|
Format.Bold(target.ToString()),
|
||||||
var msg = $"{Context.User.Mention} claimed {target.Mention} as their waifu for {amount}{NadekoBot.BotConfig.CurrencySign}!";
|
amount + CurrencySign);
|
||||||
if (w.Affinity?.UserId == Context.User.Id)
|
if (w.Affinity?.UserId == Context.User.Id)
|
||||||
msg += $"\n🎉 Their love is fulfilled! 🎉\n**{target}'s** new value is {w.Price}{NadekoBot.BotConfig.CurrencySign}!";
|
msg += "\n" + GetText("waifu_fulfilled", target, w.Price + CurrencySign);
|
||||||
await Context.Channel.SendConfirmAsync(msg)
|
await Context.Channel.SendConfirmAsync(Context.User.Mention + msg).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum DivorceResult
|
public enum DivorceResult
|
||||||
@ -192,7 +185,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static readonly TimeSpan DivorceLimit = TimeSpan.FromHours(6);
|
private static readonly TimeSpan _divorceLimit = TimeSpan.FromHours(6);
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Divorce([Remainder]IUser target)
|
public async Task Divorce([Remainder]IUser target)
|
||||||
@ -200,19 +193,19 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
if (target.Id == Context.User.Id)
|
if (target.Id == Context.User.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var result = DivorceResult.NotYourWife;
|
DivorceResult result;
|
||||||
TimeSpan difference = TimeSpan.Zero;
|
var difference = TimeSpan.Zero;
|
||||||
var amount = 0;
|
var amount = 0;
|
||||||
WaifuInfo w = null;
|
WaifuInfo w = null;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
w = uow.Waifus.ByWaifuUserId(target.Id);
|
w = uow.Waifus.ByWaifuUserId(target.Id);
|
||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
if (w == null || w.Claimer == null || w.Claimer.UserId != Context.User.Id)
|
if (w?.Claimer == null || w.Claimer.UserId != Context.User.Id)
|
||||||
result = DivorceResult.NotYourWife;
|
result = DivorceResult.NotYourWife;
|
||||||
else if (_divorceCooldowns.AddOrUpdate(Context.User.Id,
|
else if (divorceCooldowns.AddOrUpdate(Context.User.Id,
|
||||||
now,
|
now,
|
||||||
(key, old) => ((difference = now.Subtract(old)) > DivorceLimit) ? now : old) != now)
|
(key, old) => ((difference = now.Subtract(old)) > _divorceLimit) ? now : old) != now)
|
||||||
{
|
{
|
||||||
result = DivorceResult.Cooldown;
|
result = DivorceResult.Cooldown;
|
||||||
}
|
}
|
||||||
@ -249,37 +242,39 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
if (result == DivorceResult.SucessWithPenalty)
|
if (result == DivorceResult.SucessWithPenalty)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who likes you. You heartless monster.\n{w.Waifu} received {amount}{NadekoBot.BotConfig.CurrencySign} as a compensation.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("waifu_divorced_like", Format.Bold(w.Waifu.ToString()), amount + CurrencySign).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (result == DivorceResult.Success)
|
else if (result == DivorceResult.Success)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} You have divorced a waifu who doesn't like you. You received {amount}{NadekoBot.BotConfig.CurrencySign} back.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("waifu_divorced_notlike", amount + CurrencySign).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else if (result == DivorceResult.NotYourWife)
|
else if (result == DivorceResult.NotYourWife)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} That waifu is not yours.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_not_yours").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var remaining = DivorceLimit.Subtract(difference);
|
var remaining = _divorceLimit.Subtract(difference);
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You divorced recently. You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** to divorce again.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_recent_divorce",
|
||||||
|
Format.Bold(((int)remaining.TotalHours).ToString()),
|
||||||
|
Format.Bold(remaining.Minutes.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly TimeSpan AffinityLimit = TimeSpan.FromMinutes(30);
|
private static readonly TimeSpan _affinityLimit = TimeSpan.FromMinutes(30);
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task WaifuClaimerAffinity([Remainder]IUser u = null)
|
public async Task WaifuClaimerAffinity([Remainder]IUser u = null)
|
||||||
{
|
{
|
||||||
if (u?.Id == Context.User.Id)
|
if (u?.Id == Context.User.Id)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} you can't set affinity to yourself, you egomaniac.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_egomaniac").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DiscordUser oldAff = null;
|
DiscordUser oldAff = null;
|
||||||
var sucess = false;
|
var sucess = false;
|
||||||
var cooldown = false;
|
var cooldown = false;
|
||||||
TimeSpan difference = TimeSpan.Zero;
|
var difference = TimeSpan.Zero;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var w = uow.Waifus.ByWaifuUserId(Context.User.Id);
|
var w = uow.Waifus.ByWaifuUserId(Context.User.Id);
|
||||||
@ -287,13 +282,11 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var now = DateTime.UtcNow;
|
var now = DateTime.UtcNow;
|
||||||
if (w?.Affinity?.UserId == u?.Id)
|
if (w?.Affinity?.UserId == u?.Id)
|
||||||
{
|
{
|
||||||
sucess = false;
|
|
||||||
}
|
}
|
||||||
else if (_affinityCooldowns.AddOrUpdate(Context.User.Id,
|
else if (affinityCooldowns.AddOrUpdate(Context.User.Id,
|
||||||
now,
|
now,
|
||||||
(key, old) => ((difference = now.Subtract(old)) > AffinityLimit) ? now : old) != now)
|
(key, old) => ((difference = now.Subtract(old)) > _affinityLimit) ? now : old) != now)
|
||||||
{
|
{
|
||||||
sucess = false;
|
|
||||||
cooldown = true;
|
cooldown = true;
|
||||||
}
|
}
|
||||||
else if (w == null)
|
else if (w == null)
|
||||||
@ -338,19 +331,29 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
{
|
{
|
||||||
if (cooldown)
|
if (cooldown)
|
||||||
{
|
{
|
||||||
var remaining = AffinityLimit.Subtract(difference);
|
var remaining = _affinityLimit.Subtract(difference);
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} You must wait **{remaining.Hours} hours and {remaining.Minutes} minutes** in order to change your affinity again.").ConfigureAwait(false);
|
await ReplyErrorLocalized("waifu_affinity_cooldown",
|
||||||
|
Format.Bold(((int)remaining.TotalHours).ToString()),
|
||||||
|
Format.Bold(remaining.Minutes.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await Context.Channel.SendErrorAsync($"{Context.User.Mention} your affinity is already set to that waifu or you're trying to remove your affinity while not having one.").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyErrorLocalized("waifu_affinity_already").ConfigureAwait(false);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (u == null)
|
if (u == null)
|
||||||
await Context.Channel.SendConfirmAsync("Affinity Reset", $"{Context.User.Mention} Your affinity is reset. You no longer have a person you like.").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("waifu_affinity_reset").ConfigureAwait(false);
|
||||||
|
}
|
||||||
else if (oldAff == null)
|
else if (oldAff == null)
|
||||||
await Context.Channel.SendConfirmAsync("Affinity Set", $"{Context.User.Mention} wants to be {u.Mention}'s waifu. Aww <3").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("waifu_affinity_set", Format.Bold(u.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync("Affinity Changed", $"{Context.User.Mention} changed their affinity from {oldAff} to {u.Mention}.\n\n*This is morally questionable.*🤔").ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("waifu_affinity_changed", Format.Bold(oldAff.ToString()), Format.Bold(u.ToString())).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -365,19 +368,20 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
if (waifus.Count == 0)
|
if (waifus.Count == 0)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync("No waifus have been claimed yet.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("waifus_none").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithTitle("Top Waifus")
|
.WithTitle(GetText("waifus_top_waifus"))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
for (int i = 0; i < waifus.Count; i++)
|
for (var i = 0; i < waifus.Count; i++)
|
||||||
{
|
{
|
||||||
var w = waifus[i];
|
var w = waifus[i];
|
||||||
|
|
||||||
embed.AddField(efb => efb.WithName("#" + (i + 1) + " - " + w.Price + NadekoBot.BotConfig.CurrencySign).WithValue(w.ToString()).WithIsInline(false));
|
var j = i;
|
||||||
|
embed.AddField(efb => efb.WithName("#" + (j + 1) + " - " + w.Price + NadekoBot.BotConfig.CurrencySign).WithValue(w.ToString()).WithIsInline(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -391,7 +395,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
target = Context.User;
|
target = Context.User;
|
||||||
WaifuInfo w;
|
WaifuInfo w;
|
||||||
IList<WaifuInfo> claims;
|
IList<WaifuInfo> claims;
|
||||||
int divorces = 0;
|
int divorces;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
w = uow.Waifus.ByWaifuUserId(target.Id);
|
w = uow.Waifus.ByWaifuUserId(target.Id);
|
||||||
@ -419,15 +423,18 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
var claimInfo = GetClaimTitle(target.Id);
|
var claimInfo = GetClaimTitle(target.Id);
|
||||||
var affInfo = GetAffinityTitle(target.Id);
|
var affInfo = GetAffinityTitle(target.Id);
|
||||||
|
|
||||||
|
var rng = new NadekoRandom();
|
||||||
|
|
||||||
|
var nobody = GetText("nobody");
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("Waifu " + w.Waifu + " - \"the " + claimInfo.Title + "\"")
|
.WithTitle("Waifu " + w.Waifu + " - \"the " + claimInfo.Title + "\"")
|
||||||
.AddField(efb => efb.WithName("Price").WithValue(w.Price.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("price")).WithValue(w.Price.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Claimed by").WithValue(w.Claimer?.ToString() ?? "No one").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("claimed_by")).WithValue(w.Claimer?.ToString() ?? nobody).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Likes").WithValue(w.Affinity?.ToString() ?? "Nobody").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("likes")).WithValue(w.Affinity?.ToString() ?? nobody).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Changes Of Heart").WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("changes_of_heart")).WithValue($"{affInfo.Count} - \"the {affInfo.Title}\"").WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName("Divorces").WithValue(divorces.ToString()).WithIsInline(true))
|
.AddField(efb => efb.WithName(GetText("divorces")).WithValue(divorces.ToString()).WithIsInline(true))
|
||||||
.AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? "Nobody" : string.Join("\n", claims.Select(x => x.Waifu))).WithIsInline(true));
|
.AddField(efb => efb.WithName($"Waifus ({claims.Count})").WithValue(claims.Count == 0 ? nobody : string.Join("\n", claims.OrderBy(x => rng.Next()).Take(30).Select(x => x.Waifu))).WithIsInline(true));
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -447,13 +454,13 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
private static WaifuProfileTitle GetClaimTitle(ulong userId)
|
private static WaifuProfileTitle GetClaimTitle(ulong userId)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
count = uow.Waifus.ByClaimerUserId(userId).Count;
|
count = uow.Waifus.ByClaimerUserId(userId).Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
ClaimTitles title = ClaimTitles.Lonely;
|
ClaimTitles title;
|
||||||
if (count == 0)
|
if (count == 0)
|
||||||
title = ClaimTitles.Lonely;
|
title = ClaimTitles.Lonely;
|
||||||
else if (count == 1)
|
else if (count == 1)
|
||||||
@ -484,13 +491,16 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
|
|
||||||
private static WaifuProfileTitle GetAffinityTitle(ulong userId)
|
private static WaifuProfileTitle GetAffinityTitle(ulong userId)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
count = uow._context.WaifuUpdates.Count(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged);
|
count = uow._context.WaifuUpdates
|
||||||
|
.Where(w => w.User.UserId == userId && w.UpdateType == WaifuUpdateType.AffinityChanged && w.New != null)
|
||||||
|
.GroupBy(x => x.New)
|
||||||
|
.Count();
|
||||||
}
|
}
|
||||||
|
|
||||||
AffinityTitles title = AffinityTitles.Pure;
|
AffinityTitles title;
|
||||||
if (count < 1)
|
if (count < 1)
|
||||||
title = AffinityTitles.Pure;
|
title = AffinityTitles.Pure;
|
||||||
else if (count < 2)
|
else if (count < 2)
|
||||||
|
@ -12,7 +12,7 @@ using System.Collections.Generic;
|
|||||||
namespace NadekoBot.Modules.Gambling
|
namespace NadekoBot.Modules.Gambling
|
||||||
{
|
{
|
||||||
[NadekoModule("Gambling", "$")]
|
[NadekoModule("Gambling", "$")]
|
||||||
public partial class Gambling : NadekoModule
|
public partial class Gambling : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public static string CurrencyName { get; set; }
|
public static string CurrencyName { get; set; }
|
||||||
public static string CurrencyPluralName { get; set; }
|
public static string CurrencyPluralName { get; set; }
|
||||||
@ -49,7 +49,9 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async Task Cash([Remainder] IUser user = null)
|
public async Task Cash([Remainder] IUser user = null)
|
||||||
{
|
{
|
||||||
user = user ?? Context.User;
|
if(user == null)
|
||||||
|
await ConfirmLocalized("has", Format.Bold(Context.User.ToString()), $"{GetCurrency(Context.User.Id)} {CurrencySign}").ConfigureAwait(false);
|
||||||
|
else
|
||||||
await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false);
|
await ReplyConfirmLocalized("has", Format.Bold(user.ToString()), $"{GetCurrency(user.Id)} {CurrencySign}").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,25 +240,33 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
(int) (amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
|
(int) (amount * NadekoBot.BotConfig.Betroll100Multiplier), false).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Console.WriteLine("started sending");
|
|
||||||
await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(str).ConfigureAwait(false);
|
||||||
Console.WriteLine("done sending");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Leaderboard()
|
public async Task Leaderboard(int page = 1)
|
||||||
{
|
{
|
||||||
|
if (page < 1)
|
||||||
|
return;
|
||||||
|
|
||||||
List<Currency> richest;
|
List<Currency> richest;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
richest = uow.Currency.GetTopRichest(9).ToList();
|
richest = uow.Currency.GetTopRichest(9, 9 * (page - 1)).ToList();
|
||||||
}
|
}
|
||||||
if (!richest.Any())
|
|
||||||
return;
|
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle(NadekoBot.BotConfig.CurrencySign + " " + GetText("leaderboard"));
|
.WithTitle(NadekoBot.BotConfig.CurrencySign +
|
||||||
|
" " + GetText("leaderboard"))
|
||||||
|
.WithFooter(efb => efb.WithText(GetText("page", page)));
|
||||||
|
|
||||||
|
if (!richest.Any())
|
||||||
|
{
|
||||||
|
embed.WithDescription(GetText("no_users_found"));
|
||||||
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < richest.Count; i++)
|
for (var i = 0; i < richest.Count; i++)
|
||||||
{
|
{
|
||||||
@ -267,7 +277,7 @@ namespace NadekoBot.Modules.Gambling
|
|||||||
: usr.Username?.TrimTo(20, true);
|
: usr.Username?.TrimTo(20, true);
|
||||||
|
|
||||||
var j = i;
|
var j = i;
|
||||||
embed.AddField(efb => efb.WithName("#" + (j + 1) + " " + usrStr)
|
embed.AddField(efb => efb.WithName("#" + (9 * (page - 1) + j + 1) + " " + usrStr)
|
||||||
.WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign)
|
.WithValue(x.Amount.ToString() + " " + NadekoBot.BotConfig.CurrencySign)
|
||||||
.WithIsInline(true));
|
.WithIsInline(true));
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class Acropobia : ModuleBase
|
public class Acropobia : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
||||||
@ -28,6 +28,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Acro(int time = 60)
|
public async Task Acro(int time = 60)
|
||||||
{
|
{
|
||||||
|
if (time < 10 || time > 120)
|
||||||
|
return;
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
var game = new AcrophobiaGame(channel, time);
|
var game = new AcrophobiaGame(channel, time);
|
||||||
@ -45,7 +47,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Acrophobia game is already running in this channel.").ConfigureAwait(false);
|
await ReplyErrorLocalized("acro_running").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -59,44 +61,44 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public class AcrophobiaGame
|
public class AcrophobiaGame
|
||||||
{
|
{
|
||||||
private readonly ITextChannel channel;
|
private readonly ITextChannel _channel;
|
||||||
private readonly int time;
|
private readonly int _time;
|
||||||
private readonly NadekoRandom rng;
|
private readonly NadekoRandom _rng;
|
||||||
private readonly ImmutableArray<char> startingLetters;
|
private readonly ImmutableArray<char> _startingLetters;
|
||||||
private readonly CancellationTokenSource source;
|
private readonly CancellationTokenSource _source;
|
||||||
private AcroPhase phase { get; set; } = AcroPhase.Submitting;
|
private AcroPhase phase { get; set; } = AcroPhase.Submitting;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<string, IGuildUser> submissions = new ConcurrentDictionary<string, IGuildUser>();
|
private readonly ConcurrentDictionary<string, IGuildUser> _submissions = new ConcurrentDictionary<string, IGuildUser>();
|
||||||
public IReadOnlyDictionary<string, IGuildUser> Submissions => submissions;
|
public IReadOnlyDictionary<string, IGuildUser> Submissions => _submissions;
|
||||||
|
|
||||||
private readonly ConcurrentHashSet<ulong> usersWhoSubmitted = new ConcurrentHashSet<ulong>();
|
private readonly ConcurrentHashSet<ulong> _usersWhoSubmitted = new ConcurrentHashSet<ulong>();
|
||||||
private readonly ConcurrentHashSet<ulong> usersWhoVoted = new ConcurrentHashSet<ulong>();
|
private readonly ConcurrentHashSet<ulong> _usersWhoVoted = new ConcurrentHashSet<ulong>();
|
||||||
|
|
||||||
private int spamCount = 0;
|
private int _spamCount;
|
||||||
|
|
||||||
//text, votes
|
//text, votes
|
||||||
private readonly ConcurrentDictionary<string, int> votes = new ConcurrentDictionary<string, int>();
|
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public AcrophobiaGame(ITextChannel channel, int time)
|
public AcrophobiaGame(ITextChannel channel, int time)
|
||||||
{
|
{
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
this.channel = channel;
|
_channel = channel;
|
||||||
this.time = time;
|
_time = time;
|
||||||
this.source = new CancellationTokenSource();
|
_source = new CancellationTokenSource();
|
||||||
|
|
||||||
this.rng = new NadekoRandom();
|
_rng = new NadekoRandom();
|
||||||
var wordCount = rng.Next(3, 6);
|
var wordCount = _rng.Next(3, 6);
|
||||||
|
|
||||||
var lettersArr = new char[wordCount];
|
var lettersArr = new char[wordCount];
|
||||||
|
|
||||||
for (int i = 0; i < wordCount; i++)
|
for (int i = 0; i < wordCount; i++)
|
||||||
{
|
{
|
||||||
var randChar = (char)rng.Next(65, 91);
|
var randChar = (char)_rng.Next(65, 91);
|
||||||
lettersArr[i] = randChar == 'X' ? (char)rng.Next(65, 88) : randChar;
|
lettersArr[i] = randChar == 'X' ? (char)_rng.Next(65, 88) : randChar;
|
||||||
}
|
}
|
||||||
startingLetters = lettersArr.ToImmutableArray();
|
_startingLetters = lettersArr.ToImmutableArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private EmbedBuilder GetEmbed()
|
private EmbedBuilder GetEmbed()
|
||||||
@ -105,18 +107,18 @@ namespace NadekoBot.Modules.Games
|
|||||||
return phase == AcroPhase.Submitting
|
return phase == AcroPhase.Submitting
|
||||||
|
|
||||||
? new EmbedBuilder().WithOkColor()
|
? new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Acrophobia")
|
.WithTitle(GetText("acrophobia"))
|
||||||
.WithDescription($"Game started. Create a sentence with the following acronym: **{string.Join(".", startingLetters)}.**\n")
|
.WithDescription(GetText("acro_started", Format.Bold(string.Join(".", _startingLetters))))
|
||||||
.WithFooter(efb => efb.WithText("You have " + this.time + " seconds to make a submission."))
|
.WithFooter(efb => efb.WithText(GetText("acro_started_footer", _time)))
|
||||||
|
|
||||||
: new EmbedBuilder()
|
: new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithTitle("Acrophobia - Submissions Closed")
|
.WithTitle(GetText("acrophobia") + " - " + GetText("submissions_closed"))
|
||||||
.WithDescription($@"Acronym was **{string.Join(".", startingLetters)}.**
|
.WithDescription(GetText("acro_nym_was", Format.Bold(string.Join(".", _startingLetters)) + "\n" +
|
||||||
--
|
$@"--
|
||||||
{this.submissions.Aggregate("", (agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")}
|
{_submissions.Aggregate("",(agg, cur) => agg + $"`{++i}.` **{cur.Key.ToLowerInvariant().ToTitleCase()}**\n")}
|
||||||
--")
|
--"))
|
||||||
.WithFooter(efb => efb.WithText("Vote by typing a number of the submission"));
|
.WithFooter(efb => efb.WithText(GetText("acro_vote")));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Run()
|
public async Task Run()
|
||||||
@ -125,10 +127,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
var embed = GetEmbed();
|
var embed = GetEmbed();
|
||||||
|
|
||||||
//SUBMISSIONS PHASE
|
//SUBMISSIONS PHASE
|
||||||
await channel.EmbedAsync(embed).ConfigureAwait(false);
|
await _channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.Delay(time * 1000, source.Token).ConfigureAwait(false);
|
await Task.Delay(_time * 1000, _source.Token).ConfigureAwait(false);
|
||||||
phase = AcroPhase.Idle;
|
phase = AcroPhase.Idle;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
@ -137,30 +139,32 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
//var i = 0;
|
//var i = 0;
|
||||||
if (submissions.Count == 0)
|
if (_submissions.Count == 0)
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Acrophobia", "Game ended with no submissions.");
|
await _channel.SendErrorAsync(GetText("acrophobia"), GetText("acro_ended_no_sub"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (submissions.Count == 1)
|
if (_submissions.Count == 1)
|
||||||
{
|
{
|
||||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await _channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithDescription($"{submissions.First().Value.Mention} is the winner for being the only user who made a submission!")
|
.WithDescription(
|
||||||
.WithFooter(efb => efb.WithText(submissions.First().Key.ToLowerInvariant().ToTitleCase())))
|
GetText("acro_winner_only",
|
||||||
|
Format.Bold(_submissions.First().Value.ToString())))
|
||||||
|
.WithFooter(efb => efb.WithText(_submissions.First().Key.ToLowerInvariant().ToTitleCase())))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var submissionClosedEmbed = GetEmbed();
|
var submissionClosedEmbed = GetEmbed();
|
||||||
|
|
||||||
await channel.EmbedAsync(submissionClosedEmbed).ConfigureAwait(false);
|
await _channel.EmbedAsync(submissionClosedEmbed).ConfigureAwait(false);
|
||||||
|
|
||||||
//VOTING PHASE
|
//VOTING PHASE
|
||||||
this.phase = AcroPhase.Voting;
|
phase = AcroPhase.Voting;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//30 secondds for voting
|
//30 secondds for voting
|
||||||
await Task.Delay(30000, source.Token).ConfigureAwait(false);
|
await Task.Delay(30000, _source.Token).ConfigureAwait(false);
|
||||||
this.phase = AcroPhase.Idle;
|
phase = AcroPhase.Idle;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
@ -174,10 +178,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var msg = arg as SocketUserMessage;
|
var msg = arg as SocketUserMessage;
|
||||||
if (msg == null || msg.Author.IsBot || msg.Channel.Id != channel.Id)
|
if (msg == null || msg.Author.IsBot || msg.Channel.Id != _channel.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
++spamCount;
|
++_spamCount;
|
||||||
|
|
||||||
var guildUser = (IGuildUser)msg.Author;
|
var guildUser = (IGuildUser)msg.Author;
|
||||||
|
|
||||||
@ -185,37 +189,39 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
if (phase == AcroPhase.Submitting)
|
if (phase == AcroPhase.Submitting)
|
||||||
{
|
{
|
||||||
if (spamCount > 10)
|
if (_spamCount > 10)
|
||||||
{
|
{
|
||||||
spamCount = 0;
|
_spamCount = 0;
|
||||||
try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
var inputWords = input.Split(' '); //get all words
|
var inputWords = input.Split(' '); //get all words
|
||||||
|
|
||||||
if (inputWords.Length != startingLetters.Length) // number of words must be the same as the number of the starting letters
|
if (inputWords.Length != _startingLetters.Length) // number of words must be the same as the number of the starting letters
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (int i = 0; i < startingLetters.Length; i++)
|
for (int i = 0; i < _startingLetters.Length; i++)
|
||||||
{
|
{
|
||||||
var letter = startingLetters[i];
|
var letter = _startingLetters[i];
|
||||||
|
|
||||||
if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
|
if (!inputWords[i].StartsWith(letter.ToString())) // all first letters must match
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!usersWhoSubmitted.Add(guildUser.Id))
|
if (!_usersWhoSubmitted.Add(guildUser.Id))
|
||||||
return;
|
return;
|
||||||
//try adding it to the list of answers
|
//try adding it to the list of answers
|
||||||
if (!submissions.TryAdd(input, guildUser))
|
if (!_submissions.TryAdd(input, guildUser))
|
||||||
{
|
{
|
||||||
usersWhoSubmitted.TryRemove(guildUser.Id);
|
_usersWhoSubmitted.TryRemove(guildUser.Id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// all good. valid input. answer recorded
|
// all good. valid input. answer recorded
|
||||||
await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} submitted their sentence. ({submissions.Count} total)");
|
await _channel.SendConfirmAsync(GetText("acrophobia"),
|
||||||
|
GetText("acro_submit", guildUser.Mention,
|
||||||
|
_submissions.Count));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await msg.DeleteAsync();
|
await msg.DeleteAsync();
|
||||||
@ -227,14 +233,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
else if (phase == AcroPhase.Voting)
|
else if (phase == AcroPhase.Voting)
|
||||||
{
|
{
|
||||||
if (spamCount > 10)
|
if (_spamCount > 10)
|
||||||
{
|
{
|
||||||
spamCount = 0;
|
_spamCount = 0;
|
||||||
try { await channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
try { await _channel.EmbedAsync(GetEmbed()).ConfigureAwait(false); }
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
IGuildUser usr;
|
|
||||||
//if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
|
//if (submissions.TryGetValue(input, out usr) && usr.Id != guildUser.Id)
|
||||||
//{
|
//{
|
||||||
// if (!usersWhoVoted.Add(guildUser.Id))
|
// if (!usersWhoVoted.Add(guildUser.Id))
|
||||||
@ -246,17 +251,17 @@ namespace NadekoBot.Modules.Games
|
|||||||
//}
|
//}
|
||||||
|
|
||||||
int num;
|
int num;
|
||||||
if (int.TryParse(input, out num) && num > 0 && num <= submissions.Count)
|
if (int.TryParse(input, out num) && num > 0 && num <= _submissions.Count)
|
||||||
{
|
{
|
||||||
var kvp = submissions.Skip(num - 1).First();
|
var kvp = _submissions.Skip(num - 1).First();
|
||||||
usr = kvp.Value;
|
var usr = kvp.Value;
|
||||||
//can't vote for yourself, can't vote multiple times
|
//can't vote for yourself, can't vote multiple times
|
||||||
if (usr.Id == guildUser.Id || !usersWhoVoted.Add(guildUser.Id))
|
if (usr.Id == guildUser.Id || !_usersWhoVoted.Add(guildUser.Id))
|
||||||
return;
|
return;
|
||||||
votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
|
_votes.AddOrUpdate(kvp.Key, 1, (key, old) => ++old);
|
||||||
await channel.SendConfirmAsync("Acrophobia", $"{guildUser.Mention} cast their vote!").ConfigureAwait(false);
|
await _channel.SendConfirmAsync(GetText("acrophobia"),
|
||||||
|
GetText("acro_vote_cast", Format.Bold(guildUser.ToString()))).ConfigureAwait(false);
|
||||||
await msg.DeleteAsync().ConfigureAwait(false);
|
await msg.DeleteAsync().ConfigureAwait(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -269,27 +274,34 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public async Task End()
|
public async Task End()
|
||||||
{
|
{
|
||||||
if (!votes.Any())
|
if (!_votes.Any())
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Acrophobia", "No votes cast. Game ended with no winner.").ConfigureAwait(false);
|
await _channel.SendErrorAsync(GetText("acrophobia"), GetText("acro_no_votes_cast")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var table = votes.OrderByDescending(v => v.Value);
|
var table = _votes.OrderByDescending(v => v.Value);
|
||||||
var winner = table.First();
|
var winner = table.First();
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Acrophobia")
|
.WithTitle(GetText("acrophobia"))
|
||||||
.WithDescription($"Winner is {submissions[winner.Key].Mention} with {winner.Value} points.\n")
|
.WithDescription(GetText("acro_winner", Format.Bold(_submissions[winner.Key].ToString()),
|
||||||
|
Format.Bold(winner.Value.ToString())))
|
||||||
.WithFooter(efb => efb.WithText(winner.Key.ToLowerInvariant().ToTitleCase()));
|
.WithFooter(efb => efb.WithText(winner.Key.ToLowerInvariant().ToTitleCase()));
|
||||||
|
|
||||||
await channel.EmbedAsync(embed).ConfigureAwait(false);
|
await _channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnsureStopped()
|
public void EnsureStopped()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= PotentialAcro;
|
NadekoBot.Client.MessageReceived -= PotentialAcro;
|
||||||
if (!source.IsCancellationRequested)
|
if (!_source.IsCancellationRequested)
|
||||||
source.Cancel();
|
_source.Cancel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements)
|
||||||
|
=> GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_channel.Guild),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,54 +1,55 @@
|
|||||||
using Discord;
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using NLog;
|
using NLog;
|
||||||
using Services.CleverBotApi;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CleverBotCommands : ModuleBase
|
public class CleverBotCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Logger _log { get; }
|
private new static Logger _log { get; }
|
||||||
|
|
||||||
public static ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> CleverbotGuilds { get; } = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>();
|
public static ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> CleverbotGuilds { get; }
|
||||||
|
|
||||||
static CleverBotCommands()
|
static CleverBotCommands()
|
||||||
{
|
{
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
|
||||||
var bot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT);
|
|
||||||
CleverbotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
CleverbotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
||||||
NadekoBot.AllGuildConfigs
|
NadekoBot.AllGuildConfigs
|
||||||
.Where(gc => gc.CleverbotEnabled)
|
.Where(gc => gc.CleverbotEnabled)
|
||||||
.ToDictionary(gc => gc.GuildId, gc => new Lazy<ChatterBotSession>(() => bot.CreateSession(), true)));
|
.ToDictionary(gc => gc.GuildId, gc => new Lazy<ChatterBotSession>(() => new ChatterBotSession(gc.GuildId), true)));
|
||||||
|
|
||||||
sw.Stop();
|
sw.Stop();
|
||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task<bool> TryAsk(SocketUserMessage msg)
|
public static string PrepareMessage(IUserMessage msg, out ChatterBotSession cleverbot)
|
||||||
{
|
{
|
||||||
var channel = msg.Channel as ITextChannel;
|
var channel = msg.Channel as ITextChannel;
|
||||||
|
cleverbot = null;
|
||||||
|
|
||||||
if (channel == null)
|
if (channel == null)
|
||||||
return false;
|
return null;
|
||||||
|
|
||||||
Lazy<ChatterBotSession> cleverbot;
|
Lazy<ChatterBotSession> lazyCleverbot;
|
||||||
if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out cleverbot))
|
if (!CleverbotGuilds.TryGetValue(channel.Guild.Id, out lazyCleverbot))
|
||||||
return false;
|
return null;
|
||||||
|
|
||||||
|
cleverbot = lazyCleverbot.Value;
|
||||||
|
|
||||||
var nadekoId = NadekoBot.Client.CurrentUser.Id;
|
var nadekoId = NadekoBot.Client.CurrentUser.Id;
|
||||||
var normalMention = $"<@{nadekoId}> ";
|
var normalMention = $"<@{nadekoId}> ";
|
||||||
@ -64,19 +65,24 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
await msg.Channel.TriggerTypingAsync().ConfigureAwait(false);
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
var response = await cleverbot.Value.Think(message).ConfigureAwait(false);
|
public static async Task<bool> TryAsk(ChatterBotSession cleverbot, ITextChannel channel, string message)
|
||||||
|
{
|
||||||
|
await channel.TriggerTypingAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
|
var response = await cleverbot.Think(message).ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await msg.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false);
|
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
await msg.Channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\
|
await channel.SendConfirmAsync(response.SanitizeMentions()).ConfigureAwait(false); // try twice :\
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -96,13 +102,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false);
|
uow.GuildConfigs.SetCleverbotEnabled(Context.Guild.Id, false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Disabled cleverbot on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("cleverbot_disabled").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var cleverbot = ChatterBotFactory.Create(ChatterBotType.CLEVERBOT);
|
CleverbotGuilds.TryAdd(channel.Guild.Id, new Lazy<ChatterBotSession>(() => new ChatterBotSession(Context.Guild.Id), true));
|
||||||
|
|
||||||
CleverbotGuilds.TryAdd(channel.Guild.Id, new Lazy<ChatterBotSession>(() => cleverbot.CreateSession(), true));
|
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
@ -110,8 +114,45 @@ namespace NadekoBot.Modules.Games
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Enabled cleverbot on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("cleverbot_enabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class ChatterBotSession
|
||||||
|
{
|
||||||
|
private static NadekoRandom rng { get; } = new NadekoRandom();
|
||||||
|
public string ChatterbotId { get; }
|
||||||
|
public string ChannelId { get; }
|
||||||
|
private int _botId = 6;
|
||||||
|
|
||||||
|
public ChatterBotSession(ulong channelId)
|
||||||
|
{
|
||||||
|
ChannelId = channelId.ToString().ToBase64();
|
||||||
|
ChatterbotId = rng.Next(0, 1000000).ToString().ToBase64();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string apiEndpoint => "http://api.program-o.com/v2/chatbot/" +
|
||||||
|
$"?bot_id={_botId}&" +
|
||||||
|
"say={0}&" +
|
||||||
|
$"convo_id=nadekobot_{ChatterbotId}_{ChannelId}&" +
|
||||||
|
"format=json";
|
||||||
|
|
||||||
|
public async Task<string> Think(string message)
|
||||||
|
{
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
{
|
||||||
|
var res = await http.GetStringAsync(string.Format(apiEndpoint, message)).ConfigureAwait(false);
|
||||||
|
var cbr = JsonConvert.DeserializeObject<ChatterBotResponse>(res);
|
||||||
|
//Console.WriteLine(cbr.Convo_id);
|
||||||
|
return cbr.BotSay.Replace("<br/>", "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ChatterBotResponse
|
||||||
|
{
|
||||||
|
public string Convo_id { get; set; }
|
||||||
|
public string BotSay { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,12 +9,13 @@ using System.Collections.Generic;
|
|||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NadekoBot.Modules.Games.Commands.Hangman;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games.Commands.Hangman
|
namespace NadekoBot.Modules.Games.Hangman
|
||||||
{
|
{
|
||||||
public class HangmanTermPool
|
public class HangmanTermPool
|
||||||
{
|
{
|
||||||
const string termsPath = "data/hangman.json";
|
const string termsPath = "data/hangman2.json";
|
||||||
public static IReadOnlyDictionary<string, HangmanObject[]> data { get; }
|
public static IReadOnlyDictionary<string, HangmanObject[]> data { get; }
|
||||||
static HangmanTermPool()
|
static HangmanTermPool()
|
||||||
{
|
{
|
||||||
@ -70,7 +71,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
return $" {c}";
|
return $" {c}";
|
||||||
|
|
||||||
c = char.ToUpperInvariant(c);
|
c = char.ToUpperInvariant(c);
|
||||||
return Guesses.Contains(c) ? $" {c}" : " _";
|
return Guesses.Contains(c) ? $" {c}" : " ◯";
|
||||||
})) + "`";
|
})) + "`";
|
||||||
|
|
||||||
public bool GuessedAll => Guesses.IsSupersetOf(Term.Word.ToUpperInvariant()
|
public bool GuessedAll => Guesses.IsSupersetOf(Term.Word.ToUpperInvariant()
|
||||||
@ -145,7 +146,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
MessagesSinceLastPost = 0;
|
MessagesSinceLastPost = 0;
|
||||||
++Errors;
|
++Errors;
|
||||||
if (Errors < MaxErrors)
|
if (Errors < MaxErrors)
|
||||||
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
|
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` has already been used.\n" + ScrambledWord + "\n" + GetHangman(),
|
||||||
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await End().ConfigureAwait(false);
|
await End().ConfigureAwait(false);
|
||||||
@ -158,7 +159,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
{
|
{
|
||||||
if (GuessedAll)
|
if (GuessedAll)
|
||||||
{
|
{
|
||||||
try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
|
try { await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!").ConfigureAwait(false); } catch { }
|
||||||
|
|
||||||
await End().ConfigureAwait(false);
|
await End().ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
@ -166,7 +167,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
MessagesSinceLastPost = 0;
|
MessagesSinceLastPost = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author.Mention} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
|
await GameChannel.SendConfirmAsync("Hangman Game", $"{msg.Author} guessed a letter `{guess}`!\n" + ScrambledWord + "\n" + GetHangman(),
|
||||||
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
@ -177,7 +178,7 @@ namespace NadekoBot.Modules.Games.Commands.Hangman
|
|||||||
MessagesSinceLastPost = 0;
|
MessagesSinceLastPost = 0;
|
||||||
++Errors;
|
++Errors;
|
||||||
if (Errors < MaxErrors)
|
if (Errors < MaxErrors)
|
||||||
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author.Mention} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
|
await GameChannel.SendErrorAsync("Hangman Game", $"{msg.Author} Letter `{guess}` does not exist.\n" + ScrambledWord + "\n" + GetHangman(),
|
||||||
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
footer: string.Join(" ", Guesses)).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await End().ConfigureAwait(false);
|
await End().ConfigureAwait(false);
|
||||||
|
@ -1,36 +1,25 @@
|
|||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Games.Commands.Hangman;
|
|
||||||
using NLog;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NadekoBot.Modules.Games.Hangman;
|
||||||
|
using Discord;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class HangmanCommands : ModuleBase
|
public class HangmanCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static Logger _log { get; }
|
|
||||||
|
|
||||||
//channelId, game
|
//channelId, game
|
||||||
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
public static ConcurrentDictionary<ulong, HangmanGame> HangmanGames { get; } = new ConcurrentDictionary<ulong, HangmanGame>();
|
||||||
private static string typesStr { get; } = "";
|
|
||||||
|
|
||||||
static HangmanCommands()
|
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
typesStr =
|
|
||||||
string.Format("`List of \"{0}hangman\" term types:`\n", NadekoBot.ModulePrefixes[typeof(Games).Name]) + String.Join(", ", HangmanTermPool.data.Keys);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Hangmanlist()
|
public async Task Hangmanlist()
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync(typesStr);
|
await Context.Channel.SendConfirmAsync(Format.Code(GetText("hangman_types", Prefix)) + "\n" + string.Join(", ", HangmanTermPool.data.Keys));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -40,11 +29,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
if (!HangmanGames.TryAdd(Context.Channel.Id, hm))
|
if (!HangmanGames.TryAdd(Context.Channel.Id, hm))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Hangman game already running on this channel.").ConfigureAwait(false);
|
await ReplyErrorLocalized("hangman_running").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
hm.OnEnded += (g) =>
|
hm.OnEnded += g =>
|
||||||
{
|
{
|
||||||
HangmanGame throwaway;
|
HangmanGame throwaway;
|
||||||
HangmanGames.TryRemove(g.GameChannel.Id, out throwaway);
|
HangmanGames.TryRemove(g.GameChannel.Id, out throwaway);
|
||||||
@ -55,14 +44,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
try { await Context.Channel.SendErrorAsync($"Starting errored: {ex.Message}").ConfigureAwait(false); } catch { }
|
try { await Context.Channel.SendErrorAsync(GetText("hangman_start_errored") + " " + ex.Message).ConfigureAwait(false); } catch { }
|
||||||
HangmanGame throwaway;
|
HangmanGame throwaway;
|
||||||
HangmanGames.TryRemove(Context.Channel.Id, out throwaway);
|
HangmanGames.TryRemove(Context.Channel.Id, out throwaway);
|
||||||
throwaway.Dispose();
|
throwaway.Dispose();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("Hangman game started", hm.ScrambledWord + "\n" + hm.GetHangman());
|
await Context.Channel.SendConfirmAsync(GetText("hangman_game_started"), hm.ScrambledWord + "\n" + hm.GetHangman());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,10 +11,7 @@ using System;
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Security.Cryptography;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
@ -31,7 +28,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
[Group]
|
[Group]
|
||||||
public class PlantPickCommands : NadekoSubmodule
|
public class PlantPickCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static ConcurrentHashSet<ulong> generationChannels { get; } = new ConcurrentHashSet<ulong>();
|
private static ConcurrentHashSet<ulong> generationChannels { get; }
|
||||||
//channelid/message
|
//channelid/message
|
||||||
private static ConcurrentDictionary<ulong, List<IUserMessage>> plantedFlowers { get; } = new ConcurrentDictionary<ulong, List<IUserMessage>>();
|
private static ConcurrentDictionary<ulong, List<IUserMessage>> plantedFlowers { get; } = new ConcurrentDictionary<ulong, List<IUserMessage>>();
|
||||||
//channelId/last generation
|
//channelId/last generation
|
||||||
@ -82,25 +79,19 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (dropAmount > 0)
|
if (dropAmount > 0)
|
||||||
{
|
{
|
||||||
var msgs = new IUserMessage[dropAmount];
|
var msgs = new IUserMessage[dropAmount];
|
||||||
|
var prefix = NadekoBot.ModulePrefixes[typeof(Games).Name];
|
||||||
string firstPart;
|
var toSend = dropAmount == 1
|
||||||
if (dropAmount == 1)
|
? GetLocalText(channel, "curgen_sn", NadekoBot.BotConfig.CurrencySign)
|
||||||
{
|
+ GetLocalText(channel, "pick_sn", prefix)
|
||||||
firstPart = $"A random { NadekoBot.BotConfig.CurrencyName } appeared!";
|
: GetLocalText(channel, "curgen_pl", dropAmount, NadekoBot.BotConfig.CurrencySign)
|
||||||
}
|
+ GetLocalText(channel, "pick_pl", prefix);
|
||||||
else
|
|
||||||
{
|
|
||||||
firstPart = $"{dropAmount} random { NadekoBot.BotConfig.CurrencyPluralName } appeared!";
|
|
||||||
}
|
|
||||||
var file = GetRandomCurrencyImage();
|
var file = GetRandomCurrencyImage();
|
||||||
using (var fileStream = file.Value.ToStream())
|
using (var fileStream = file.Value.ToStream())
|
||||||
{
|
{
|
||||||
var sent = await channel.SendFileAsync(
|
var sent = await channel.SendFileAsync(
|
||||||
fileStream,
|
fileStream,
|
||||||
file.Key,
|
file.Key,
|
||||||
string.Format("❗ {0} Pick it up by typing `{1}pick`", firstPart,
|
toSend).ConfigureAwait(false);
|
||||||
NadekoBot.ModulePrefixes[typeof(Games).Name]))
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
|
|
||||||
msgs[0] = sent;
|
msgs[0] = sent;
|
||||||
}
|
}
|
||||||
@ -117,6 +108,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetLocalText(ITextChannel channel, string key, params object[] replacements) =>
|
||||||
|
NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(channel.GuildId),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Pick()
|
public async Task Pick()
|
||||||
@ -135,7 +132,8 @@ namespace NadekoBot.Modules.Games
|
|||||||
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
await Task.WhenAll(msgs.Where(m => m != null).Select(toDelete => toDelete.DeleteAsync())).ConfigureAwait(false);
|
||||||
|
|
||||||
await CurrencyHandler.AddCurrencyAsync((IGuildUser)Context.User, $"Picked {NadekoBot.BotConfig.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}{NadekoBot.BotConfig.CurrencySign}!").ConfigureAwait(false);
|
var msg = await ReplyConfirmLocalized("picked", msgs.Count + NadekoBot.BotConfig.CurrencySign)
|
||||||
|
.ConfigureAwait(false);
|
||||||
msg.DeleteAfter(10);
|
msg.DeleteAfter(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,14 +147,24 @@ namespace NadekoBot.Modules.Games
|
|||||||
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false);
|
var removed = await CurrencyHandler.RemoveCurrencyAsync((IGuildUser)Context.User, $"Planted a {NadekoBot.BotConfig.CurrencyName}", amount, false).ConfigureAwait(false);
|
||||||
if (!removed)
|
if (!removed)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"You don't have enough {NadekoBot.BotConfig.CurrencyPluralName}.").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_enough", NadekoBot.BotConfig.CurrencySign).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var imgData = GetRandomCurrencyImage();
|
var imgData = GetRandomCurrencyImage();
|
||||||
var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.BotConfig.CurrencyName[0]);
|
|
||||||
|
|
||||||
var msgToSend = $"Oh how Nice! **{Context.User.Username}** planted {(amount == 1 ? (vowelFirst ? "an" : "a") : amount.ToString())} {(amount > 1 ? NadekoBot.BotConfig.CurrencyPluralName : NadekoBot.BotConfig.CurrencyName)}. Pick it using {Prefix}pick";
|
//todo upload all currency images to transfer.sh and use that one as cdn
|
||||||
|
//and then
|
||||||
|
|
||||||
|
var msgToSend = GetText("planted",
|
||||||
|
Format.Bold(Context.User.ToString()),
|
||||||
|
amount + NadekoBot.BotConfig.CurrencySign,
|
||||||
|
Prefix);
|
||||||
|
|
||||||
|
if (amount > 1)
|
||||||
|
msgToSend += " " + GetText("pick_pl", Prefix);
|
||||||
|
else
|
||||||
|
msgToSend += " " + GetText("pick_sn", Prefix);
|
||||||
|
|
||||||
IUserMessage msg;
|
IUserMessage msg;
|
||||||
using (var toSend = imgData.Value.ToStream())
|
using (var toSend = imgData.Value.ToStream())
|
||||||
@ -173,7 +181,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
return old;
|
return old;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#if !GLOBAL_NADEKO
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
@ -203,13 +211,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync("Currency generation enabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("curgen_enabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync("Currency generation disabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("curgen_disabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
private static KeyValuePair<string, ImmutableArray<byte>> GetRandomCurrencyImage()
|
private static KeyValuePair<string, ImmutableArray<byte>> GetRandomCurrencyImage()
|
||||||
{
|
{
|
||||||
|
@ -1,22 +1,22 @@
|
|||||||
using Discord;
|
using System;
|
||||||
|
using Discord;
|
||||||
using Discord.Commands;
|
using Discord.Commands;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using ImageSharp.Processing;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class PollCommands : ModuleBase
|
public class PollCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
public static ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
||||||
|
|
||||||
@ -24,32 +24,30 @@ namespace NadekoBot.Modules.Games
|
|||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public Task Poll([Remainder] string arg = null)
|
public Task Poll([Remainder] string arg = null)
|
||||||
=> InternalStartPoll(arg, isPublic: false);
|
=> InternalStartPoll(arg, false);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public Task PublicPoll([Remainder] string arg = null)
|
public Task PublicPoll([Remainder] string arg = null)
|
||||||
=> InternalStartPoll(arg, isPublic: true);
|
=> InternalStartPoll(arg, true);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireUserPermission(GuildPermission.ManageMessages)]
|
[RequireUserPermission(GuildPermission.ManageMessages)]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task PollStats()
|
public async Task PollStats()
|
||||||
{
|
{
|
||||||
Games.Poll poll;
|
Poll poll;
|
||||||
if (!ActivePolls.TryGetValue(Context.Guild.Id, out poll))
|
if (!ActivePolls.TryGetValue(Context.Guild.Id, out poll))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(poll.GetStats("Current Poll Results"));
|
await Context.Channel.EmbedAsync(poll.GetStats(GetText("current_poll_results")));
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task InternalStartPoll(string arg, bool isPublic = false)
|
private async Task InternalStartPoll(string arg, bool isPublic = false)
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
if (!(Context.User as IGuildUser).GuildPermissions.ManageChannels)
|
|
||||||
return;
|
|
||||||
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
|
if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
|
||||||
return;
|
return;
|
||||||
var data = arg.Split(';');
|
var data = arg.Split(';');
|
||||||
@ -62,7 +60,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
await poll.StartPoll().ConfigureAwait(false);
|
await poll.StartPoll().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
await channel.SendErrorAsync("Poll is already running on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -80,27 +78,25 @@ namespace NadekoBot.Modules.Games
|
|||||||
|
|
||||||
public class Poll
|
public class Poll
|
||||||
{
|
{
|
||||||
private readonly IUserMessage originalMessage;
|
private readonly IUserMessage _originalMessage;
|
||||||
private readonly IGuild guild;
|
private readonly IGuild _guild;
|
||||||
private string[] Answers { get; }
|
private string[] answers { get; }
|
||||||
private ConcurrentDictionary<ulong, int> participants = new ConcurrentDictionary<ulong, int>();
|
private readonly ConcurrentDictionary<ulong, int> _participants = new ConcurrentDictionary<ulong, int>();
|
||||||
private readonly string question;
|
private readonly string _question;
|
||||||
private DateTime started;
|
|
||||||
private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
|
|
||||||
public bool IsPublic { get; }
|
public bool IsPublic { get; }
|
||||||
|
|
||||||
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
public Poll(IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
|
||||||
{
|
{
|
||||||
this.originalMessage = umsg;
|
_originalMessage = umsg;
|
||||||
this.guild = ((ITextChannel)umsg.Channel).Guild;
|
_guild = ((ITextChannel)umsg.Channel).Guild;
|
||||||
this.question = question;
|
_question = question;
|
||||||
this.Answers = enumerable as string[] ?? enumerable.ToArray();
|
answers = enumerable as string[] ?? enumerable.ToArray();
|
||||||
this.IsPublic = isPublic;
|
IsPublic = isPublic;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EmbedBuilder GetStats(string title)
|
public EmbedBuilder GetStats(string title)
|
||||||
{
|
{
|
||||||
var results = participants.GroupBy(kvp => kvp.Value)
|
var results = _participants.GroupBy(kvp => kvp.Value)
|
||||||
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
.ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
|
||||||
.OrderByDescending(kvp => kvp.Value)
|
.OrderByDescending(kvp => kvp.Value)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
@ -108,49 +104,51 @@ namespace NadekoBot.Modules.Games
|
|||||||
var eb = new EmbedBuilder().WithTitle(title);
|
var eb = new EmbedBuilder().WithTitle(title);
|
||||||
|
|
||||||
var sb = new StringBuilder()
|
var sb = new StringBuilder()
|
||||||
.AppendLine(Format.Bold(question))
|
.AppendLine(Format.Bold(_question))
|
||||||
.AppendLine();
|
.AppendLine();
|
||||||
|
|
||||||
var totalVotesCast = 0;
|
var totalVotesCast = 0;
|
||||||
if (results.Length == 0)
|
if (results.Length == 0)
|
||||||
{
|
{
|
||||||
sb.AppendLine("No votes cast.");
|
sb.AppendLine(GetText("no_votes_cast"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (int i = 0; i < results.Length; i++)
|
for (int i = 0; i < results.Length; i++)
|
||||||
{
|
{
|
||||||
var result = results[i];
|
var result = results[i];
|
||||||
sb.AppendLine($"`{i + 1}.` {Format.Bold(Answers[result.Key - 1])} with {Format.Bold(result.Value.ToString())} votes.");
|
sb.AppendLine(GetText("poll_result",
|
||||||
|
result.Key,
|
||||||
|
Format.Bold(answers[result.Key - 1]),
|
||||||
|
Format.Bold(result.Value.ToString())));
|
||||||
totalVotesCast += result.Value;
|
totalVotesCast += result.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
eb.WithDescription(sb.ToString())
|
eb.WithDescription(sb.ToString())
|
||||||
.WithFooter(efb => efb.WithText(totalVotesCast + " total votes cast."));
|
.WithFooter(efb => efb.WithText(GetText("x_votes_cast", totalVotesCast)));
|
||||||
|
|
||||||
return eb;
|
return eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StartPoll()
|
public async Task StartPoll()
|
||||||
{
|
{
|
||||||
started = DateTime.Now;
|
|
||||||
NadekoBot.Client.MessageReceived += Vote;
|
NadekoBot.Client.MessageReceived += Vote;
|
||||||
var msgToSend = $"📃**{originalMessage.Author.Username}** has created a poll which requires your attention:\n\n**{question}**\n";
|
var msgToSend = GetText("poll_created", Format.Bold(_originalMessage.Author.Username)) + "\n\n" + Format.Bold(_question) + "\n";
|
||||||
var num = 1;
|
var num = 1;
|
||||||
msgToSend = Answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
|
||||||
if (!IsPublic)
|
if (!IsPublic)
|
||||||
msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
|
msgToSend += "\n" + Format.Bold(GetText("poll_vote_private"));
|
||||||
else
|
else
|
||||||
msgToSend += "\n**Send a Message here with the corresponding number of the answer.**";
|
msgToSend += "\n" + Format.Bold(GetText("poll_vote_public"));
|
||||||
await originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false);
|
await _originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopPoll()
|
public async Task StopPoll()
|
||||||
{
|
{
|
||||||
NadekoBot.Client.MessageReceived -= Vote;
|
NadekoBot.Client.MessageReceived -= Vote;
|
||||||
await originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
await _originalMessage.Channel.EmbedAsync(GetStats("POLL CLOSED")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task Vote(SocketMessage imsg)
|
private async Task Vote(SocketMessage imsg)
|
||||||
@ -166,14 +164,14 @@ namespace NadekoBot.Modules.Games
|
|||||||
int vote;
|
int vote;
|
||||||
if (!int.TryParse(imsg.Content, out vote))
|
if (!int.TryParse(imsg.Content, out vote))
|
||||||
return;
|
return;
|
||||||
if (vote < 1 || vote > Answers.Length)
|
if (vote < 1 || vote > answers.Length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IMessageChannel ch;
|
IMessageChannel ch;
|
||||||
if (IsPublic)
|
if (IsPublic)
|
||||||
{
|
{
|
||||||
//if public, channel must be the same the poll started in
|
//if public, channel must be the same the poll started in
|
||||||
if (originalMessage.Channel.Id != imsg.Channel.Id)
|
if (_originalMessage.Channel.Id != imsg.Channel.Id)
|
||||||
return;
|
return;
|
||||||
ch = imsg.Channel;
|
ch = imsg.Channel;
|
||||||
}
|
}
|
||||||
@ -184,27 +182,33 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// user must be a member of the guild this poll is in
|
// user must be a member of the guild this poll is in
|
||||||
var guildUsers = await guild.GetUsersAsync().ConfigureAwait(false);
|
var guildUsers = await _guild.GetUsersAsync().ConfigureAwait(false);
|
||||||
if (!guildUsers.Any(u => u.Id == imsg.Author.Id))
|
if (guildUsers.All(u => u.Id != imsg.Author.Id))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//user can vote only once
|
//user can vote only once
|
||||||
if (participants.TryAdd(msg.Author.Id, vote))
|
if (_participants.TryAdd(msg.Author.Id, vote))
|
||||||
{
|
{
|
||||||
if (!IsPublic)
|
if (!IsPublic)
|
||||||
{
|
{
|
||||||
await ch.SendConfirmAsync($"Thanks for voting **{msg.Author.Username}**.").ConfigureAwait(false);
|
await ch.SendConfirmAsync(GetText("thanks_for_voting", Format.Bold(msg.Author.Username))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var toDelete = await ch.SendConfirmAsync($"{msg.Author.Mention} cast their vote.").ConfigureAwait(false);
|
var toDelete = await ch.SendConfirmAsync(GetText("poll_voted", Format.Bold(msg.Author.ToString()))).ConfigureAwait(false);
|
||||||
toDelete.DeleteAfter(5);
|
toDelete.DeleteAfter(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements)
|
||||||
|
=> NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_guild.Id),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -147,11 +147,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class SpeedTypingCommands : ModuleBase
|
public class SpeedTypingCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
public static List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
|
||||||
|
|
||||||
private const string _typingArticlesPath = "data/typing_articles.json";
|
private const string _typingArticlesPath = "data/typing_articles2.json";
|
||||||
|
|
||||||
static SpeedTypingCommands()
|
static SpeedTypingCommands()
|
||||||
{
|
{
|
||||||
|
@ -4,9 +4,7 @@ using NadekoBot.Attributes;
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NLog;
|
using NLog;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
@ -15,21 +13,13 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
//todo timeout
|
|
||||||
[Group]
|
[Group]
|
||||||
public class TicTacToeCommands : ModuleBase
|
public class TicTacToeCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
//channelId/game
|
//channelId/game
|
||||||
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
||||||
private readonly Logger _log;
|
|
||||||
|
|
||||||
public TicTacToeCommands()
|
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1);
|
||||||
{
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly SemaphoreSlim sem = new SemaphoreSlim(1, 1);
|
|
||||||
private readonly object tttLockObj = new object();
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -37,7 +27,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
await sem.WaitAsync(1000);
|
await _sem.WaitAsync(1000);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
TicTacToe game;
|
TicTacToe game;
|
||||||
@ -51,7 +41,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
game = new TicTacToe(channel, (IGuildUser)Context.User);
|
game = new TicTacToe(channel, (IGuildUser)Context.User);
|
||||||
_games.Add(channel.Id, game);
|
_games.Add(channel.Id, game);
|
||||||
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} Created a TicTacToe game.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("ttt_created").ConfigureAwait(false);
|
||||||
|
|
||||||
game.OnEnded += (g) =>
|
game.OnEnded += (g) =>
|
||||||
{
|
{
|
||||||
@ -60,7 +50,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
sem.Release();
|
_sem.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,46 +65,49 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly ITextChannel _channel;
|
private readonly ITextChannel _channel;
|
||||||
private readonly Logger _log;
|
|
||||||
private readonly IGuildUser[] _users;
|
private readonly IGuildUser[] _users;
|
||||||
private readonly int?[,] _state;
|
private readonly int?[,] _state;
|
||||||
private Phase _phase;
|
private Phase _phase;
|
||||||
int curUserIndex = 0;
|
private int _curUserIndex;
|
||||||
private readonly SemaphoreSlim moveLock;
|
private readonly SemaphoreSlim _moveLock;
|
||||||
|
|
||||||
private IGuildUser _winner = null;
|
private IGuildUser _winner;
|
||||||
|
|
||||||
private readonly string[] numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" };
|
private readonly string[] _numbers = { ":one:", ":two:", ":three:", ":four:", ":five:", ":six:", ":seven:", ":eight:", ":nine:" };
|
||||||
|
|
||||||
public Action<TicTacToe> OnEnded;
|
public Action<TicTacToe> OnEnded;
|
||||||
|
|
||||||
private IUserMessage previousMessage = null;
|
private IUserMessage _previousMessage;
|
||||||
private Timer timeoutTimer;
|
private Timer _timeoutTimer;
|
||||||
|
|
||||||
public TicTacToe(ITextChannel channel, IGuildUser firstUser)
|
public TicTacToe(ITextChannel channel, IGuildUser firstUser)
|
||||||
{
|
{
|
||||||
_channel = channel;
|
_channel = channel;
|
||||||
_users = new IGuildUser[2] { firstUser, null };
|
_users = new[] { firstUser, null };
|
||||||
_state = new int?[3, 3] {
|
_state = new int?[,] {
|
||||||
{ null, null, null },
|
{ null, null, null },
|
||||||
{ null, null, null },
|
{ null, null, null },
|
||||||
{ null, null, null },
|
{ null, null, null },
|
||||||
};
|
};
|
||||||
|
|
||||||
_log = LogManager.GetCurrentClassLogger();
|
|
||||||
_log.Warn($"User {firstUser} created a TicTacToe game.");
|
|
||||||
_phase = Phase.Starting;
|
_phase = Phase.Starting;
|
||||||
moveLock = new SemaphoreSlim(1, 1);
|
_moveLock = new SemaphoreSlim(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements) =>
|
||||||
|
NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(_channel.GuildId),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
public string GetState()
|
public string GetState()
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
for (int i = 0; i < _state.GetLength(0); i++)
|
for (var i = 0; i < _state.GetLength(0); i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < _state.GetLength(1); j++)
|
for (var j = 0; j < _state.GetLength(1); j++)
|
||||||
{
|
{
|
||||||
sb.Append(_state[i, j] == null ? numbers[i * 3 + j] : GetIcon(_state[i, j]));
|
sb.Append(_state[i, j] == null ? _numbers[i * 3 + j] : GetIcon(_state[i, j]));
|
||||||
if (j < _state.GetLength(1) - 1)
|
if (j < _state.GetLength(1) - 1)
|
||||||
sb.Append("┃");
|
sb.Append("┃");
|
||||||
}
|
}
|
||||||
@ -130,7 +123,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithDescription(Environment.NewLine + GetState())
|
.WithDescription(Environment.NewLine + GetState())
|
||||||
.WithAuthor(eab => eab.WithName($"{_users[0]} vs {_users[1]}"));
|
.WithAuthor(eab => eab.WithName(GetText("vs", _users[0], _users[1])));
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(title))
|
if (!string.IsNullOrWhiteSpace(title))
|
||||||
embed.WithTitle(title);
|
embed.WithTitle(title);
|
||||||
@ -138,12 +131,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (_winner == null)
|
if (_winner == null)
|
||||||
{
|
{
|
||||||
if (_phase == Phase.Ended)
|
if (_phase == Phase.Ended)
|
||||||
embed.WithFooter(efb => efb.WithText($"No moves left!"));
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_no_moves")));
|
||||||
else
|
else
|
||||||
embed.WithFooter(efb => efb.WithText($"{_users[curUserIndex]}'s move"));
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_users_move", _users[_curUserIndex])));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
embed.WithFooter(efb => efb.WithText($"{_winner} Won!"));
|
embed.WithFooter(efb => efb.WithText(GetText("ttt_has_won", _winner)));
|
||||||
|
|
||||||
return embed;
|
return embed;
|
||||||
}
|
}
|
||||||
@ -169,23 +162,22 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
if (_phase == Phase.Started || _phase == Phase.Ended)
|
if (_phase == Phase.Started || _phase == Phase.Ended)
|
||||||
{
|
{
|
||||||
await _channel.SendErrorAsync(user.Mention + " TicTacToe Game is already running in this channel.").ConfigureAwait(false);
|
await _channel.SendErrorAsync(user.Mention + GetText("ttt_already_running")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (_users[0] == user)
|
else if (_users[0] == user)
|
||||||
{
|
{
|
||||||
await _channel.SendErrorAsync(user.Mention + " You can't play against yourself.").ConfigureAwait(false);
|
await _channel.SendErrorAsync(user.Mention + GetText("ttt_against_yourself")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_users[1] = user;
|
_users[1] = user;
|
||||||
_log.Warn($"User {user} joined a TicTacToe game.");
|
|
||||||
|
|
||||||
_phase = Phase.Started;
|
_phase = Phase.Started;
|
||||||
|
|
||||||
timeoutTimer = new Timer(async (_) =>
|
_timeoutTimer = new Timer(async (_) =>
|
||||||
{
|
{
|
||||||
await moveLock.WaitAsync();
|
await _moveLock.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_phase == Phase.Ended)
|
if (_phase == Phase.Ended)
|
||||||
@ -194,11 +186,12 @@ namespace NadekoBot.Modules.Games
|
|||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
if (_users[1] != null)
|
if (_users[1] != null)
|
||||||
{
|
{
|
||||||
_winner = _users[curUserIndex ^= 1];
|
_winner = _users[_curUserIndex ^= 1];
|
||||||
var del = previousMessage?.DeleteAsync();
|
var del = _previousMessage?.DeleteAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _channel.EmbedAsync(GetEmbed("Time Expired!")).ConfigureAwait(false);
|
await _channel.EmbedAsync(GetEmbed(GetText("ttt_time_expired"))).ConfigureAwait(false);
|
||||||
|
if (del != null)
|
||||||
await del.ConfigureAwait(false);
|
await del.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
@ -209,21 +202,21 @@ namespace NadekoBot.Modules.Games
|
|||||||
catch { }
|
catch { }
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
moveLock.Release();
|
_moveLock.Release();
|
||||||
}
|
}
|
||||||
}, null, 15000, Timeout.Infinite);
|
}, null, 15000, Timeout.Infinite);
|
||||||
|
|
||||||
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
NadekoBot.Client.MessageReceived += Client_MessageReceived;
|
||||||
|
|
||||||
|
|
||||||
previousMessage = await _channel.EmbedAsync(GetEmbed("Game Started")).ConfigureAwait(false);
|
_previousMessage = await _channel.EmbedAsync(GetEmbed(GetText("game_started"))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsDraw()
|
private bool IsDraw()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 3; i++)
|
for (var i = 0; i < 3; i++)
|
||||||
{
|
{
|
||||||
for (int j = 0; j < 3; j++)
|
for (var j = 0; j < 3; j++)
|
||||||
{
|
{
|
||||||
if (_state[i, j] == null)
|
if (_state[i, j] == null)
|
||||||
return false;
|
return false;
|
||||||
@ -236,10 +229,10 @@ namespace NadekoBot.Modules.Games
|
|||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
var _ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await moveLock.WaitAsync().ConfigureAwait(false);
|
await _moveLock.WaitAsync().ConfigureAwait(false);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var curUser = _users[curUserIndex];
|
var curUser = _users[_curUserIndex];
|
||||||
if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id)
|
if (_phase == Phase.Ended || msg.Author?.Id != curUser.Id)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -249,53 +242,53 @@ namespace NadekoBot.Modules.Games
|
|||||||
index <= 9 &&
|
index <= 9 &&
|
||||||
_state[index / 3, index % 3] == null)
|
_state[index / 3, index % 3] == null)
|
||||||
{
|
{
|
||||||
_state[index / 3, index % 3] = curUserIndex;
|
_state[index / 3, index % 3] = _curUserIndex;
|
||||||
|
|
||||||
// i'm lazy
|
// i'm lazy
|
||||||
if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2])
|
if (_state[index / 3, 0] == _state[index / 3, 1] && _state[index / 3, 1] == _state[index / 3, 2])
|
||||||
{
|
{
|
||||||
_state[index / 3, 0] = curUserIndex + 2;
|
_state[index / 3, 0] = _curUserIndex + 2;
|
||||||
_state[index / 3, 1] = curUserIndex + 2;
|
_state[index / 3, 1] = _curUserIndex + 2;
|
||||||
_state[index / 3, 2] = curUserIndex + 2;
|
_state[index / 3, 2] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3])
|
else if (_state[0, index % 3] == _state[1, index % 3] && _state[1, index % 3] == _state[2, index % 3])
|
||||||
{
|
{
|
||||||
_state[0, index % 3] = curUserIndex + 2;
|
_state[0, index % 3] = _curUserIndex + 2;
|
||||||
_state[1, index % 3] = curUserIndex + 2;
|
_state[1, index % 3] = _curUserIndex + 2;
|
||||||
_state[2, index % 3] = curUserIndex + 2;
|
_state[2, index % 3] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
else if (curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2])
|
else if (_curUserIndex == _state[0, 0] && _state[0, 0] == _state[1, 1] && _state[1, 1] == _state[2, 2])
|
||||||
{
|
{
|
||||||
_state[0, 0] = curUserIndex + 2;
|
_state[0, 0] = _curUserIndex + 2;
|
||||||
_state[1, 1] = curUserIndex + 2;
|
_state[1, 1] = _curUserIndex + 2;
|
||||||
_state[2, 2] = curUserIndex + 2;
|
_state[2, 2] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
else if (curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0])
|
else if (_curUserIndex == _state[0, 2] && _state[0, 2] == _state[1, 1] && _state[1, 1] == _state[2, 0])
|
||||||
{
|
{
|
||||||
_state[0, 2] = curUserIndex + 2;
|
_state[0, 2] = _curUserIndex + 2;
|
||||||
_state[1, 1] = curUserIndex + 2;
|
_state[1, 1] = _curUserIndex + 2;
|
||||||
_state[2, 0] = curUserIndex + 2;
|
_state[2, 0] = _curUserIndex + 2;
|
||||||
|
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
}
|
}
|
||||||
string reason = "";
|
var reason = "";
|
||||||
|
|
||||||
if (_phase == Phase.Ended) // if user won, stop receiving moves
|
if (_phase == Phase.Ended) // if user won, stop receiving moves
|
||||||
{
|
{
|
||||||
reason = "Matched three!";
|
reason = GetText("ttt_matched_three");
|
||||||
_winner = _users[curUserIndex];
|
_winner = _users[_curUserIndex];
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||||
OnEnded?.Invoke(this);
|
OnEnded?.Invoke(this);
|
||||||
}
|
}
|
||||||
else if (IsDraw())
|
else if (IsDraw())
|
||||||
{
|
{
|
||||||
reason = "A draw!";
|
reason = GetText("ttt_a_draw");
|
||||||
_phase = Phase.Ended;
|
_phase = Phase.Ended;
|
||||||
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
NadekoBot.Client.MessageReceived -= Client_MessageReceived;
|
||||||
OnEnded?.Invoke(this);
|
OnEnded?.Invoke(this);
|
||||||
@ -304,19 +297,19 @@ namespace NadekoBot.Modules.Games
|
|||||||
var sendstate = Task.Run(async () =>
|
var sendstate = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var del1 = msg.DeleteAsync();
|
var del1 = msg.DeleteAsync();
|
||||||
var del2 = previousMessage?.DeleteAsync();
|
var del2 = _previousMessage?.DeleteAsync();
|
||||||
try { previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { }
|
try { _previousMessage = await _channel.EmbedAsync(GetEmbed(reason)); } catch { }
|
||||||
try { await del1; } catch { }
|
try { await del1; } catch { }
|
||||||
try { if (del2 != null) await del2; } catch { }
|
try { if (del2 != null) await del2; } catch { }
|
||||||
});
|
});
|
||||||
curUserIndex ^= 1;
|
_curUserIndex ^= 1;
|
||||||
|
|
||||||
timeoutTimer.Change(15000, Timeout.Infinite);
|
_timeoutTimer.Change(15000, Timeout.Infinite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
moveLock.Release();
|
_moveLock.Release();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -17,36 +17,44 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
public class TriviaGame
|
public class TriviaGame
|
||||||
{
|
{
|
||||||
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
|
||||||
private Logger _log { get; }
|
private readonly Logger _log;
|
||||||
|
|
||||||
public IGuild guild { get; }
|
public IGuild Guild { get; }
|
||||||
public ITextChannel channel { get; }
|
public ITextChannel Channel { get; }
|
||||||
|
|
||||||
private int QuestionDurationMiliseconds { get; } = 30000;
|
private int questionDurationMiliseconds { get; } = 30000;
|
||||||
private int HintTimeoutMiliseconds { get; } = 6000;
|
private int hintTimeoutMiliseconds { get; } = 6000;
|
||||||
public bool ShowHints { get; } = true;
|
public bool ShowHints { get; }
|
||||||
|
public bool IsPokemon { get; }
|
||||||
private CancellationTokenSource triviaCancelSource { get; set; }
|
private CancellationTokenSource triviaCancelSource { get; set; }
|
||||||
|
|
||||||
public TriviaQuestion CurrentQuestion { get; private set; }
|
public TriviaQuestion CurrentQuestion { get; private set; }
|
||||||
public HashSet<TriviaQuestion> oldQuestions { get; } = new HashSet<TriviaQuestion>();
|
public HashSet<TriviaQuestion> OldQuestions { get; } = new HashSet<TriviaQuestion>();
|
||||||
|
|
||||||
public ConcurrentDictionary<IGuildUser, int> Users { get; } = new ConcurrentDictionary<IGuildUser, int>();
|
public ConcurrentDictionary<IGuildUser, int> Users { get; } = new ConcurrentDictionary<IGuildUser, int>();
|
||||||
|
|
||||||
public bool GameActive { get; private set; } = false;
|
public bool GameActive { get; private set; }
|
||||||
public bool ShouldStopGame { get; private set; }
|
public bool ShouldStopGame { get; private set; }
|
||||||
|
|
||||||
public int WinRequirement { get; } = 10;
|
public int WinRequirement { get; }
|
||||||
|
|
||||||
public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq)
|
public TriviaGame(IGuild guild, ITextChannel channel, bool showHints, int winReq, bool isPokemon)
|
||||||
{
|
{
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
this.ShowHints = showHints;
|
ShowHints = showHints;
|
||||||
this.guild = guild;
|
Guild = guild;
|
||||||
this.channel = channel;
|
Channel = channel;
|
||||||
this.WinRequirement = winReq;
|
WinRequirement = winReq;
|
||||||
|
IsPokemon = isPokemon;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private string GetText(string key, params object[] replacements) =>
|
||||||
|
NadekoTopLevelModule.GetTextStatic(key,
|
||||||
|
NadekoBot.Localization.GetCultureInfo(Channel.GuildId),
|
||||||
|
typeof(Games).Name.ToLowerInvariant(),
|
||||||
|
replacements);
|
||||||
|
|
||||||
public async Task StartGame()
|
public async Task StartGame()
|
||||||
{
|
{
|
||||||
while (!ShouldStopGame)
|
while (!ShouldStopGame)
|
||||||
@ -55,26 +63,25 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
triviaCancelSource = new CancellationTokenSource();
|
triviaCancelSource = new CancellationTokenSource();
|
||||||
|
|
||||||
// load question
|
// load question
|
||||||
CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(oldQuestions);
|
CurrentQuestion = TriviaQuestionPool.Instance.GetRandomQuestion(OldQuestions, IsPokemon);
|
||||||
if (CurrentQuestion == null ||
|
if (string.IsNullOrWhiteSpace(CurrentQuestion?.Answer) || string.IsNullOrWhiteSpace(CurrentQuestion.Question))
|
||||||
string.IsNullOrWhiteSpace(CurrentQuestion.Answer) ||
|
|
||||||
string.IsNullOrWhiteSpace(CurrentQuestion.Question))
|
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Trivia Game", "Failed loading a question.").ConfigureAwait(false);
|
await Channel.SendErrorAsync(GetText("trivia_game"), GetText("failed_loading_question")).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
oldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again
|
OldQuestions.Add(CurrentQuestion); //add it to exclusion list so it doesn't show up again
|
||||||
|
|
||||||
EmbedBuilder questionEmbed;
|
EmbedBuilder questionEmbed;
|
||||||
IUserMessage questionMessage;
|
IUserMessage questionMessage;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
questionEmbed = new EmbedBuilder().WithOkColor()
|
questionEmbed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Trivia Game")
|
.WithTitle(GetText("trivia_game"))
|
||||||
.AddField(eab => eab.WithName("Category").WithValue(CurrentQuestion.Category))
|
.AddField(eab => eab.WithName(GetText("category")).WithValue(CurrentQuestion.Category))
|
||||||
.AddField(eab => eab.WithName("Question").WithValue(CurrentQuestion.Question));
|
.AddField(eab => eab.WithName(GetText("question")).WithValue(CurrentQuestion.Question))
|
||||||
|
.WithImageUrl(CurrentQuestion.ImageUrl);
|
||||||
|
|
||||||
questionMessage = await channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
|
questionMessage = await Channel.EmbedAsync(questionEmbed).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound ||
|
catch (HttpException ex) when (ex.HttpCode == System.Net.HttpStatusCode.NotFound ||
|
||||||
ex.HttpCode == System.Net.HttpStatusCode.Forbidden ||
|
ex.HttpCode == System.Net.HttpStatusCode.Forbidden ||
|
||||||
@ -99,7 +106,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
//hint
|
//hint
|
||||||
await Task.Delay(HintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
await Task.Delay(hintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
||||||
if (ShowHints)
|
if (ShowHints)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -113,7 +120,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
|
|
||||||
//timeout
|
//timeout
|
||||||
await Task.Delay(QuestionDurationMiliseconds - HintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
await Task.Delay(questionDurationMiliseconds - hintTimeoutMiliseconds, triviaCancelSource.Token).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException) { } //means someone guessed the answer
|
catch (TaskCanceledException) { } //means someone guessed the answer
|
||||||
@ -124,8 +131,21 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
NadekoBot.Client.MessageReceived -= PotentialGuess;
|
||||||
}
|
}
|
||||||
if (!triviaCancelSource.IsCancellationRequested)
|
if (!triviaCancelSource.IsCancellationRequested)
|
||||||
try { await channel.SendErrorAsync("Trivia Game", $"**Time's up!** The correct answer was **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
{
|
||||||
await Task.Delay(2000).ConfigureAwait(false);
|
try
|
||||||
|
{
|
||||||
|
await Channel.EmbedAsync(new EmbedBuilder().WithErrorColor()
|
||||||
|
.WithTitle(GetText("trivia_game"))
|
||||||
|
.WithDescription(GetText("trivia_times_up", Format.Bold(CurrentQuestion.Answer)))
|
||||||
|
.WithImageUrl(CurrentQuestion.AnswerImageUrl))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,7 +153,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
{
|
{
|
||||||
ShouldStopGame = true;
|
ShouldStopGame = true;
|
||||||
|
|
||||||
await channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Trivia Game Ended"))
|
.WithAuthor(eab => eab.WithName("Trivia Game Ended"))
|
||||||
.WithTitle("Final Results")
|
.WithTitle("Final Results")
|
||||||
.WithDescription(GetLeaderboard())).ConfigureAwait(false);
|
.WithDescription(GetLeaderboard())).ConfigureAwait(false);
|
||||||
@ -144,7 +164,7 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
var old = ShouldStopGame;
|
var old = ShouldStopGame;
|
||||||
ShouldStopGame = true;
|
ShouldStopGame = true;
|
||||||
if (!old)
|
if (!old)
|
||||||
try { await channel.SendConfirmAsync("Trivia Game", "Stopping after this question.").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try { await Channel.SendConfirmAsync(GetText("trivia_game"), GetText("trivia_stopping")).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task PotentialGuess(SocketMessage imsg)
|
private async Task PotentialGuess(SocketMessage imsg)
|
||||||
@ -155,11 +175,9 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var umsg = imsg as SocketUserMessage;
|
var umsg = imsg as SocketUserMessage;
|
||||||
if (umsg == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var textChannel = umsg.Channel as ITextChannel;
|
var textChannel = umsg?.Channel as ITextChannel;
|
||||||
if (textChannel == null || textChannel.Guild != guild)
|
if (textChannel == null || textChannel.Guild != Guild)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var guildUser = (IGuildUser)umsg.Author;
|
var guildUser = (IGuildUser)umsg.Author;
|
||||||
@ -182,14 +200,31 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
if (Users[guildUser] == WinRequirement)
|
if (Users[guildUser] == WinRequirement)
|
||||||
{
|
{
|
||||||
ShouldStopGame = true;
|
ShouldStopGame = true;
|
||||||
try { await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it and WON the game! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false); } catch { }
|
try
|
||||||
|
{
|
||||||
|
await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("trivia_game"))
|
||||||
|
.WithDescription(GetText("trivia_win",
|
||||||
|
guildUser.Mention,
|
||||||
|
Format.Bold(CurrentQuestion.Answer)))
|
||||||
|
.WithImageUrl(CurrentQuestion.AnswerImageUrl))
|
||||||
|
.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
var reward = NadekoBot.BotConfig.TriviaCurrencyReward;
|
var reward = NadekoBot.BotConfig.TriviaCurrencyReward;
|
||||||
if (reward > 0)
|
if (reward > 0)
|
||||||
await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
await CurrencyHandler.AddCurrencyAsync(guildUser, "Won trivia", reward, true).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await channel.SendConfirmAsync("Trivia Game", $"{guildUser.Mention} guessed it! The answer was: **{CurrentQuestion.Answer}**").ConfigureAwait(false);
|
|
||||||
|
|
||||||
|
await Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("trivia_game"))
|
||||||
|
.WithDescription(GetText("trivia_guess", guildUser.Mention, Format.Bold(CurrentQuestion.Answer)))
|
||||||
|
.WithImageUrl(CurrentQuestion.AnswerImageUrl))
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) { _log.Warn(ex); }
|
catch (Exception ex) { _log.Warn(ex); }
|
||||||
}
|
}
|
||||||
@ -197,13 +232,13 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
public string GetLeaderboard()
|
public string GetLeaderboard()
|
||||||
{
|
{
|
||||||
if (Users.Count == 0)
|
if (Users.Count == 0)
|
||||||
return "No results.";
|
return GetText("no_results");
|
||||||
|
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
foreach (var kvp in Users.OrderByDescending(kvp => kvp.Value))
|
foreach (var kvp in Users.OrderByDescending(kvp => kvp.Value))
|
||||||
{
|
{
|
||||||
sb.AppendLine($"**{kvp.Key.Username}** has {kvp.Value} points".ToString().SnPl(kvp.Value));
|
sb.AppendLine(GetText("trivia_points", Format.Bold(kvp.Key.ToString()), kvp.Value).SnPl(kvp.Value));
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
|
@ -20,13 +20,17 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
|
|
||||||
public string Category { get; set; }
|
public string Category { get; set; }
|
||||||
public string Question { get; set; }
|
public string Question { get; set; }
|
||||||
|
public string ImageUrl { get; set; }
|
||||||
|
public string AnswerImageUrl { get; set; }
|
||||||
public string Answer { get; set; }
|
public string Answer { get; set; }
|
||||||
|
|
||||||
public TriviaQuestion(string q, string a, string c)
|
public TriviaQuestion(string q, string a, string c, string img = null, string answerImage = null)
|
||||||
{
|
{
|
||||||
this.Question = q;
|
this.Question = q;
|
||||||
this.Answer = a;
|
this.Answer = a;
|
||||||
this.Category = c;
|
this.Category = c;
|
||||||
|
this.ImageUrl = img;
|
||||||
|
this.AnswerImageUrl = answerImage ?? img;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetHint() => Scramble(Answer);
|
public string GetHint() => Scramble(Answer);
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
@ -12,27 +11,50 @@ namespace NadekoBot.Modules.Games.Trivia
|
|||||||
{
|
{
|
||||||
public class TriviaQuestionPool
|
public class TriviaQuestionPool
|
||||||
{
|
{
|
||||||
|
public class PokemonNameId
|
||||||
|
{
|
||||||
|
public int Id { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
private static TriviaQuestionPool _instance;
|
private static TriviaQuestionPool _instance;
|
||||||
public static TriviaQuestionPool Instance { get; } = _instance ?? (_instance = new TriviaQuestionPool());
|
public static TriviaQuestionPool Instance { get; } = _instance ?? (_instance = new TriviaQuestionPool());
|
||||||
|
|
||||||
private const string questionsFile = "data/trivia_questions.json";
|
private const string questionsFile = "data/trivia_questions.json";
|
||||||
|
private const string pokemonMapPath = "data/pokemon/name-id_map4.json";
|
||||||
|
private readonly int maxPokemonId;
|
||||||
|
|
||||||
private Random rng { get; } = new NadekoRandom();
|
private Random rng { get; } = new NadekoRandom();
|
||||||
|
|
||||||
private TriviaQuestion[] pool { get; }
|
private TriviaQuestion[] pool { get; }
|
||||||
|
private ImmutableDictionary<int, string> map { get; }
|
||||||
|
|
||||||
static TriviaQuestionPool() { }
|
static TriviaQuestionPool() { }
|
||||||
|
|
||||||
private TriviaQuestionPool()
|
private TriviaQuestionPool()
|
||||||
{
|
{
|
||||||
pool = JsonConvert.DeserializeObject<TriviaQuestion[]>(File.ReadAllText(questionsFile));
|
pool = JsonConvert.DeserializeObject<TriviaQuestion[]>(File.ReadAllText(questionsFile));
|
||||||
|
map = JsonConvert.DeserializeObject<PokemonNameId[]>(File.ReadAllText(pokemonMapPath))
|
||||||
|
.ToDictionary(x => x.Id, x => x.Name)
|
||||||
|
.ToImmutableDictionary();
|
||||||
|
|
||||||
|
maxPokemonId = 721; //xd
|
||||||
}
|
}
|
||||||
|
|
||||||
public TriviaQuestion GetRandomQuestion(HashSet<TriviaQuestion> exclude)
|
public TriviaQuestion GetRandomQuestion(HashSet<TriviaQuestion> exclude, bool isPokemon)
|
||||||
{
|
{
|
||||||
if (pool.Length == 0)
|
if (pool.Length == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
|
if (isPokemon)
|
||||||
|
{
|
||||||
|
var num = rng.Next(1, maxPokemonId + 1);
|
||||||
|
return new TriviaQuestion("Who's That Pokémon?",
|
||||||
|
map[num].ToTitleCase(),
|
||||||
|
"Pokemon",
|
||||||
|
$@"http://nadekobot.xyz/images/pokemon/shadows/{num}.png",
|
||||||
|
$@"http://nadekobot.xyz/images/pokemon/real/{num}.png");
|
||||||
|
}
|
||||||
TriviaQuestion randomQuestion;
|
TriviaQuestion randomQuestion;
|
||||||
while (exclude.Contains(randomQuestion = pool[rng.Next(0, pool.Length)])) ;
|
while (exclude.Contains(randomQuestion = pool[rng.Next(0, pool.Length)])) ;
|
||||||
|
|
||||||
|
@ -3,9 +3,7 @@ using Discord.Commands;
|
|||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using NadekoBot.Modules.Games.Trivia;
|
using NadekoBot.Modules.Games.Trivia;
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
|
||||||
@ -14,24 +12,30 @@ namespace NadekoBot.Modules.Games
|
|||||||
public partial class Games
|
public partial class Games
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class TriviaCommands : ModuleBase
|
public class TriviaCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public Task Trivia([Remainder] string additionalArgs = "")
|
public Task Trivia([Remainder] string additionalArgs = "")
|
||||||
=> Trivia(10, additionalArgs);
|
=> InternalTrivia(10, additionalArgs);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Trivia(int winReq = 10, [Remainder] string additionalArgs = "")
|
public Task Trivia(int winReq = 10, [Remainder] string additionalArgs = "")
|
||||||
|
=> InternalTrivia(winReq, additionalArgs);
|
||||||
|
|
||||||
|
public async Task InternalTrivia(int winReq, string additionalArgs = "")
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
var showHints = !additionalArgs.Contains("nohint");
|
additionalArgs = additionalArgs?.Trim()?.ToLowerInvariant();
|
||||||
|
|
||||||
TriviaGame trivia = new TriviaGame(channel.Guild, channel, showHints, winReq);
|
var showHints = !additionalArgs.Contains("nohint");
|
||||||
|
var isPokemon = additionalArgs.Contains("pokemon");
|
||||||
|
|
||||||
|
var trivia = new TriviaGame(channel.Guild, channel, showHints, winReq, isPokemon);
|
||||||
if (RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
if (RunningTrivias.TryAdd(channel.Guild.Id, trivia))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -45,8 +49,9 @@ namespace NadekoBot.Modules.Games
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
await Context.Channel.SendErrorAsync("Trivia game is already running on this server.\n" + trivia.CurrentQuestion).ConfigureAwait(false);
|
await Context.Channel.SendErrorAsync(GetText("trivia_already_running") + "\n" + trivia.CurrentQuestion)
|
||||||
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -58,11 +63,11 @@ namespace NadekoBot.Modules.Games
|
|||||||
TriviaGame trivia;
|
TriviaGame trivia;
|
||||||
if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
|
if (RunningTrivias.TryGetValue(channel.Guild.Id, out trivia))
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync("Leaderboard", trivia.GetLeaderboard()).ConfigureAwait(false);
|
await channel.SendConfirmAsync(GetText("leaderboard"), trivia.GetLeaderboard()).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await channel.SendErrorAsync("No trivia is running on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("trivia_none").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -78,7 +83,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
await channel.SendErrorAsync("No trivia is running on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("trivia_none").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,16 +4,29 @@ using NadekoBot.Services;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Attributes;
|
using NadekoBot.Attributes;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Immutable;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
|
using System.Net.Http;
|
||||||
|
using ImageSharp;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NLog;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Games
|
namespace NadekoBot.Modules.Games
|
||||||
{
|
{
|
||||||
[NadekoModule("Games", ">")]
|
[NadekoModule("Games", ">")]
|
||||||
public partial class Games : NadekoModule
|
public partial class Games : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static string[] _8BallResponses { get; } = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToArray();
|
private static readonly ImmutableArray<string> _8BallResponses = NadekoBot.BotConfig.EightBallResponses.Select(ebr => ebr.Text).ToImmutableArray();
|
||||||
|
|
||||||
|
private static readonly Timer _t = new Timer((_) =>
|
||||||
|
{
|
||||||
|
_girlRatings.Clear();
|
||||||
|
|
||||||
|
}, null, TimeSpan.FromDays(1), TimeSpan.FromDays(1));
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Choose([Remainder] string list = null)
|
public async Task Choose([Remainder] string list = null)
|
||||||
@ -21,7 +34,7 @@ namespace NadekoBot.Modules.Games
|
|||||||
if (string.IsNullOrWhiteSpace(list))
|
if (string.IsNullOrWhiteSpace(list))
|
||||||
return;
|
return;
|
||||||
var listArr = list.Split(';');
|
var listArr = list.Split(';');
|
||||||
if (listArr.Count() < 2)
|
if (listArr.Length < 2)
|
||||||
return;
|
return;
|
||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
await Context.Channel.SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync("🤔", listArr[rng.Next(0, listArr.Length)]).ConfigureAwait(false);
|
||||||
@ -34,21 +47,24 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithColor(NadekoBot.OkColor)
|
||||||
.AddField(efb => efb.WithName("❓ Question").WithValue(question).WithIsInline(false))
|
.AddField(efb => efb.WithName("❓ " + GetText("question") ).WithValue(question).WithIsInline(false))
|
||||||
.AddField(efb => efb.WithName("🎱 8Ball").WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false)));
|
.AddField(efb => efb.WithName("🎱 " + GetText("8ball")).WithValue(_8BallResponses[new NadekoRandom().Next(0, _8BallResponses.Length)]).WithIsInline(false)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Rps(string input)
|
public async Task Rps(string input)
|
||||||
{
|
{
|
||||||
Func<int,string> GetRPSPick = (p) =>
|
Func<int,string> getRpsPick = (p) =>
|
||||||
{
|
{
|
||||||
if (p == 0)
|
switch (p)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
return "🚀";
|
return "🚀";
|
||||||
else if (p == 1)
|
case 1:
|
||||||
return "📎";
|
return "📎";
|
||||||
else
|
default:
|
||||||
return "✂️";
|
return "✂️";
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
int pick;
|
int pick;
|
||||||
@ -72,19 +88,176 @@ namespace NadekoBot.Modules.Games
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var nadekoPick = new NadekoRandom().Next(0, 3);
|
var nadekoPick = new NadekoRandom().Next(0, 3);
|
||||||
var msg = "";
|
string msg;
|
||||||
if (pick == nadekoPick)
|
if (pick == nadekoPick)
|
||||||
msg = $"It's a draw! Both picked {GetRPSPick(pick)}";
|
msg = GetText("rps_draw", getRpsPick(pick));
|
||||||
else if ((pick == 0 && nadekoPick == 1) ||
|
else if ((pick == 0 && nadekoPick == 1) ||
|
||||||
(pick == 1 && nadekoPick == 2) ||
|
(pick == 1 && nadekoPick == 2) ||
|
||||||
(pick == 2 && nadekoPick == 0))
|
(pick == 2 && nadekoPick == 0))
|
||||||
msg = $"{NadekoBot.Client.CurrentUser.Mention} won! {GetRPSPick(nadekoPick)} beats {GetRPSPick(pick)}";
|
msg = GetText("rps_win", NadekoBot.Client.CurrentUser.Mention,
|
||||||
|
getRpsPick(nadekoPick), getRpsPick(pick));
|
||||||
else
|
else
|
||||||
msg = $"{Context.User.Mention} won! {GetRPSPick(pick)} beats {GetRPSPick(nadekoPick)}";
|
msg = GetText("rps_win", Context.User.Mention, getRpsPick(pick),
|
||||||
|
getRpsPick(nadekoPick));
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
await Context.Channel.SendConfirmAsync(msg).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly ConcurrentDictionary<ulong, GirlRating> _girlRatings = new ConcurrentDictionary<ulong, GirlRating>();
|
||||||
|
|
||||||
|
public class GirlRating
|
||||||
|
{
|
||||||
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
|
|
||||||
|
public double Crazy { get; }
|
||||||
|
public double Hot { get; }
|
||||||
|
public int Roll { get; }
|
||||||
|
public string Advice { get; }
|
||||||
|
public AsyncLazy<string> Url { get; }
|
||||||
|
|
||||||
|
public GirlRating(double crazy, double hot, int roll, string advice)
|
||||||
|
{
|
||||||
|
Crazy = crazy;
|
||||||
|
Hot = hot;
|
||||||
|
Roll = roll;
|
||||||
|
Advice = advice; // convenient to have it here, even though atm there are only few different ones.
|
||||||
|
|
||||||
|
Url = new AsyncLazy<string>(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream(NadekoBot.Images.WifeMatrix.ToArray(), false))
|
||||||
|
using (var img = new ImageSharp.Image(ms))
|
||||||
|
{
|
||||||
|
const int minx = 35;
|
||||||
|
const int miny = 385;
|
||||||
|
const int length = 345;
|
||||||
|
|
||||||
|
var pointx = (int)(minx + length * (Hot / 10));
|
||||||
|
var pointy = (int)(miny - length * ((Crazy - 4) / 6));
|
||||||
|
|
||||||
|
using (var pointMs = new MemoryStream(NadekoBot.Images.RategirlDot.ToArray(), false))
|
||||||
|
using (var pointImg = new ImageSharp.Image(pointMs))
|
||||||
|
{
|
||||||
|
img.DrawImage(pointImg, 100, default(Size), new Point(pointx - 10, pointy - 10));
|
||||||
|
}
|
||||||
|
|
||||||
|
string url;
|
||||||
|
using (var http = new HttpClient())
|
||||||
|
using (var imgStream = new MemoryStream())
|
||||||
|
{
|
||||||
|
img.Save(imgStream);
|
||||||
|
var byteContent = new ByteArrayContent(imgStream.ToArray());
|
||||||
|
http.AddFakeHeaders();
|
||||||
|
|
||||||
|
var reponse = await http.PutAsync("https://transfer.sh/img.png", byteContent);
|
||||||
|
url = await reponse.Content.ReadAsStringAsync();
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_log.Warn(ex);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[RequireContext(ContextType.Guild)]
|
||||||
|
public async Task RateGirl(IGuildUser usr)
|
||||||
|
{
|
||||||
|
var gr = _girlRatings.GetOrAdd(usr.Id, GetGirl);
|
||||||
|
var img = await gr.Url;
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle("Girl Rating For " + usr)
|
||||||
|
.AddField(efb => efb.WithName("Hot").WithValue(gr.Hot.ToString("F2")).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("Crazy").WithValue(gr.Crazy.ToString("F2")).WithIsInline(true))
|
||||||
|
.AddField(efb => efb.WithName("Advice").WithValue(gr.Advice).WithIsInline(false))
|
||||||
|
.WithImageUrl(img)).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double NextDouble(double x, double y)
|
||||||
|
{
|
||||||
|
var rng = new Random();
|
||||||
|
return rng.NextDouble() * (y - x) + x;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GirlRating GetGirl(ulong uid)
|
||||||
|
{
|
||||||
|
var rng = new NadekoRandom();
|
||||||
|
|
||||||
|
var roll = rng.Next(1, 1001);
|
||||||
|
|
||||||
|
if ((uid == 185968432783687681 ||
|
||||||
|
uid == 265642040950390784) && roll >= 900)
|
||||||
|
roll = 1000;
|
||||||
|
|
||||||
|
|
||||||
|
double hot;
|
||||||
|
double crazy;
|
||||||
|
string advice;
|
||||||
|
if (roll < 500)
|
||||||
|
{
|
||||||
|
hot = NextDouble(0, 5);
|
||||||
|
crazy = NextDouble(4, 10);
|
||||||
|
advice =
|
||||||
|
"This is your NO-GO ZONE. We do not hang around, and date, and marry women who are atleast, in our mind, a 5. " +
|
||||||
|
"So, this is your no-go zone. You don't go here. You just rule this out. Life is better this way, that's the way it is.";
|
||||||
|
}
|
||||||
|
else if (roll < 750)
|
||||||
|
{
|
||||||
|
hot = NextDouble(5, 8);
|
||||||
|
crazy = NextDouble(4, .6 * hot + 4);
|
||||||
|
advice = "Above a 5, and to about an 8, and below the crazy line - this is your FUN ZONE. You can " +
|
||||||
|
"hang around here, and meet these girls and spend time with them. Keep in mind, while you're " +
|
||||||
|
"in the fun zone, you want to move OUT of the fun zone to a more permanent location. " +
|
||||||
|
"These girls are most of the time not crazy.";
|
||||||
|
}
|
||||||
|
else if (roll < 900)
|
||||||
|
{
|
||||||
|
hot = NextDouble(5, 10);
|
||||||
|
crazy = NextDouble(.61 * hot + 4, 10);
|
||||||
|
advice = "Above the crazy line - it's the DANGER ZONE. This is redheads, strippers, anyone named Tiffany, " +
|
||||||
|
"hairdressers... This is where your car gets keyed, you get bunny in the pot, your tires get slashed, " +
|
||||||
|
"and you wind up in jail.";
|
||||||
|
}
|
||||||
|
else if (roll < 951)
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(7, .6 * hot + 4);
|
||||||
|
advice = "Below the crazy line, above an 8 hot, but still about 7 crazy. This is your DATE ZONE. " +
|
||||||
|
"You can stay in the date zone indefinitely. These are the girls you introduce to your friends and your family. " +
|
||||||
|
"They're good looking, and they're reasonably not crazy most of the time. You can stay here indefinitely.";
|
||||||
|
}
|
||||||
|
else if (roll < 990)
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(5, 7);
|
||||||
|
advice = "Above an 8 hot, and between about 7 and a 5 crazy - this is WIFE ZONE. If you meet this girl, you should consider long-term " +
|
||||||
|
"relationship. Rare.";
|
||||||
|
}
|
||||||
|
else if (roll < 999)
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(2, 3.99d);
|
||||||
|
advice = "You've met a girl she's above 8 hot, and not crazy at all (below 4)... totally cool?" +
|
||||||
|
" You should be careful. That's a dude. You're talking to a tranny!";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hot = NextDouble(8, 10);
|
||||||
|
crazy = NextDouble(4, 5);
|
||||||
|
advice = "Below 5 crazy, and above 8 hot, this is the UNICORN ZONE, these things don't exist." +
|
||||||
|
"If you find a unicorn, please capture it safely, keep it alive, we'd like to study it, " +
|
||||||
|
"and maybe look at how to replicate that.";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new GirlRating(crazy, hot, roll, advice);
|
||||||
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Linux(string guhnoo, string loonix)
|
public async Task Linux(string guhnoo, string loonix)
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@ using System.Collections.Generic;
|
|||||||
namespace NadekoBot.Modules.Help
|
namespace NadekoBot.Modules.Help
|
||||||
{
|
{
|
||||||
[NadekoModule("Help", "-")]
|
[NadekoModule("Help", "-")]
|
||||||
public class Help : NadekoModule
|
public class Help : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static string helpString { get; } = NadekoBot.BotConfig.HelpString;
|
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]);
|
||||||
@ -31,6 +31,7 @@ namespace NadekoBot.Modules.Help
|
|||||||
.WithTitle(GetText("list_of_modules"))
|
.WithTitle(GetText("list_of_modules"))
|
||||||
.WithDescription(string.Join("\n",
|
.WithDescription(string.Join("\n",
|
||||||
NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule())
|
NadekoBot.CommandService.Modules.GroupBy(m => m.GetTopLevelModule())
|
||||||
|
.Where(m => !Permissions.Permissions.GlobalPermissionCommands.BlockedModules.Contains(m.Key.Name.ToLowerInvariant()))
|
||||||
.Select(m => "• " + m.Key.Name)
|
.Select(m => "• " + m.Key.Name)
|
||||||
.OrderBy(s => s)));
|
.OrderBy(s => s)));
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
@ -45,6 +46,7 @@ namespace NadekoBot.Modules.Help
|
|||||||
if (string.IsNullOrWhiteSpace(module))
|
if (string.IsNullOrWhiteSpace(module))
|
||||||
return;
|
return;
|
||||||
var cmds = NadekoBot.CommandService.Commands.Where(c => c.Module.GetTopLevelModule().Name.ToUpperInvariant().StartsWith(module))
|
var cmds = NadekoBot.CommandService.Commands.Where(c => c.Module.GetTopLevelModule().Name.ToUpperInvariant().StartsWith(module))
|
||||||
|
.Where(c => !Permissions.Permissions.GlobalPermissionCommands.BlockedCommands.Contains(c.Aliases.First().ToLowerInvariant()))
|
||||||
.OrderBy(c => c.Aliases.First())
|
.OrderBy(c => c.Aliases.First())
|
||||||
.Distinct(new CommandTextEqualityComparer())
|
.Distinct(new CommandTextEqualityComparer())
|
||||||
.AsEnumerable();
|
.AsEnumerable();
|
||||||
@ -55,8 +57,14 @@ namespace NadekoBot.Modules.Help
|
|||||||
await ReplyErrorLocalized("module_not_found").ConfigureAwait(false);
|
await ReplyErrorLocalized("module_not_found").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
var j = 0;
|
||||||
|
var groups = cmdsArray.GroupBy(x => j++ / 48).ToArray();
|
||||||
|
|
||||||
|
for (int i = 0; i < groups.Count(); i++)
|
||||||
|
{
|
||||||
|
await channel.SendTableAsync(i == 0 ? $"📃 **{GetText("list_of_commands")}**\n" : "", groups.ElementAt(i), el => $"{el.Aliases.First(),-15} {"[" + el.Aliases.Skip(1).FirstOrDefault() + "]",-8}").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
await channel.SendTableAsync($"📃 **{GetText("list_of_commands")}**\n", cmdsArray, el => $"{el.Aliases.First(),-15} {"["+el.Aliases.Skip(1).FirstOrDefault()+"]",-8}").ConfigureAwait(false);
|
|
||||||
|
|
||||||
await ConfirmLocalized("commands_instr", Prefix).ConfigureAwait(false);
|
await ConfirmLocalized("commands_instr", Prefix).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
@ -77,10 +77,10 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
public IVoiceChannel PlaybackVoiceChannel { get; private set; }
|
public IVoiceChannel PlaybackVoiceChannel { get; private set; }
|
||||||
public ITextChannel OutputTextChannel { get; set; }
|
public ITextChannel OutputTextChannel { get; set; }
|
||||||
|
|
||||||
private bool destroyed { get; set; } = false;
|
private bool destroyed { get; set; }
|
||||||
public bool RepeatSong { get; private set; } = false;
|
public bool RepeatSong { get; private set; }
|
||||||
public bool RepeatPlaylist { get; private set; } = false;
|
public bool RepeatPlaylist { get; private set; }
|
||||||
public bool Autoplay { get; set; } = false;
|
public bool Autoplay { get; set; }
|
||||||
public uint MaxQueueSize { get; set; } = 0;
|
public uint MaxQueueSize { get; set; } = 0;
|
||||||
|
|
||||||
private ConcurrentQueue<Action> actionQueue { get; } = new ConcurrentQueue<Action>();
|
private ConcurrentQueue<Action> actionQueue { get; } = new ConcurrentQueue<Action>();
|
||||||
@ -163,7 +163,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (RepeatPlaylist)
|
if (RepeatPlaylist & !RepeatSong)
|
||||||
AddSong(CurrentSong, CurrentSong.QueuerName);
|
AddSong(CurrentSong, CurrentSong.QueuerName);
|
||||||
|
|
||||||
if (RepeatSong)
|
if (RepeatSong)
|
||||||
|
@ -5,12 +5,9 @@ using System;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics.Contracts;
|
using System.Diagnostics.Contracts;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using VideoLibrary;
|
|
||||||
using System.Net;
|
using System.Net;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Modules.Music.Classes
|
||||||
@ -32,22 +29,22 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
public string QueuerName { get; set; }
|
public string QueuerName { get; set; }
|
||||||
|
|
||||||
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
|
public TimeSpan TotalTime { get; set; } = TimeSpan.Zero;
|
||||||
public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / frameBytes / (1000 / milliseconds));
|
public TimeSpan CurrentTime => TimeSpan.FromSeconds(bytesSent / (float)_frameBytes / (1000 / (float)_milliseconds));
|
||||||
|
|
||||||
const int milliseconds = 20;
|
private const int _milliseconds = 20;
|
||||||
const int samplesPerFrame = (48000 / 1000) * milliseconds;
|
private const int _samplesPerFrame = (48000 / 1000) * _milliseconds;
|
||||||
const int frameBytes = 3840; //16-bit, 2 channels
|
private const int _frameBytes = 3840; //16-bit, 2 channels
|
||||||
|
|
||||||
private ulong bytesSent { get; set; } = 0;
|
private ulong bytesSent { get; set; }
|
||||||
|
|
||||||
//pwetty
|
//pwetty
|
||||||
|
|
||||||
public string PrettyProvider =>
|
public string PrettyProvider =>
|
||||||
$"{(SongInfo.Provider ?? "No Provider")}";
|
$"{(SongInfo.Provider ?? "???")}";
|
||||||
|
|
||||||
public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime;
|
public string PrettyFullTime => PrettyCurrentTime + " / " + PrettyTotalTime;
|
||||||
|
|
||||||
public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({songUrl})**";
|
public string PrettyName => $"**[{SongInfo.Title.TrimTo(65)}]({SongUrl})**";
|
||||||
|
|
||||||
public string PrettyInfo => $"{MusicPlayer.PrettyVolume} | {PrettyTotalTime} | {PrettyProvider} | {QueuerName}";
|
public string PrettyInfo => $"{MusicPlayer.PrettyVolume} | {PrettyTotalTime} | {PrettyProvider} | {QueuerName}";
|
||||||
|
|
||||||
@ -65,37 +62,34 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string PrettyTotalTime {
|
public string PrettyTotalTime {
|
||||||
get {
|
get
|
||||||
|
{
|
||||||
if (TotalTime == TimeSpan.Zero)
|
if (TotalTime == TimeSpan.Zero)
|
||||||
return "(?)";
|
return "(?)";
|
||||||
else if (TotalTime == TimeSpan.MaxValue)
|
if (TotalTime == TimeSpan.MaxValue)
|
||||||
return "∞";
|
return "∞";
|
||||||
else
|
|
||||||
{
|
|
||||||
var time = TotalTime.ToString(@"mm\:ss");
|
var time = TotalTime.ToString(@"mm\:ss");
|
||||||
var hrs = (int)TotalTime.TotalHours;
|
var hrs = (int)TotalTime.TotalHours;
|
||||||
|
|
||||||
if (hrs > 0)
|
if (hrs > 0)
|
||||||
return hrs + ":" + time;
|
return hrs + ":" + time;
|
||||||
else
|
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public string Thumbnail {
|
public string Thumbnail {
|
||||||
get {
|
get {
|
||||||
switch (SongInfo.ProviderType)
|
switch (SongInfo.ProviderType)
|
||||||
{
|
{
|
||||||
case MusicType.Radio:
|
case MusicType.Radio:
|
||||||
return $"https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links
|
return "https://cdn.discordapp.com/attachments/155726317222887425/261850925063340032/1482522097_radio.png"; //test links
|
||||||
case MusicType.Normal:
|
case MusicType.Normal:
|
||||||
//todo have videoid in songinfo from the start
|
//todo have videoid in songinfo from the start
|
||||||
var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
|
var videoId = Regex.Match(SongInfo.Query, "<=v=[a-zA-Z0-9-]+(?=&)|(?<=[0-9])[^&\n]+|(?<=v=)[^&\n]+");
|
||||||
return $"https://img.youtube.com/vi/{ videoId }/0.jpg";
|
return $"https://img.youtube.com/vi/{ videoId }/0.jpg";
|
||||||
case MusicType.Local:
|
case MusicType.Local:
|
||||||
return $"https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links
|
return "https://cdn.discordapp.com/attachments/155726317222887425/261850914783100928/1482522077_music.png"; //test links
|
||||||
case MusicType.Soundcloud:
|
case MusicType.Soundcloud:
|
||||||
return SongInfo.AlbumArt;
|
return SongInfo.AlbumArt;
|
||||||
default:
|
default:
|
||||||
@ -104,7 +98,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string songUrl {
|
public string SongUrl {
|
||||||
get {
|
get {
|
||||||
switch (SongInfo.ProviderType)
|
switch (SongInfo.ProviderType)
|
||||||
{
|
{
|
||||||
@ -122,36 +116,32 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int skipTo = 0;
|
public int SkipTo { get; set; }
|
||||||
public int SkipTo {
|
|
||||||
get { return skipTo; }
|
|
||||||
set {
|
|
||||||
skipTo = value;
|
|
||||||
bytesSent = (ulong)skipTo * 3840 * 50;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly Logger _log;
|
private readonly Logger _log;
|
||||||
|
|
||||||
public Song(SongInfo songInfo)
|
public Song(SongInfo songInfo)
|
||||||
{
|
{
|
||||||
this.SongInfo = songInfo;
|
SongInfo = songInfo;
|
||||||
this._log = LogManager.GetCurrentClassLogger();
|
_log = LogManager.GetCurrentClassLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Song Clone()
|
public Song Clone()
|
||||||
{
|
{
|
||||||
var s = new Song(SongInfo);
|
var s = new Song(SongInfo)
|
||||||
s.MusicPlayer = MusicPlayer;
|
{
|
||||||
s.QueuerName = QueuerName;
|
MusicPlayer = MusicPlayer,
|
||||||
|
QueuerName = QueuerName
|
||||||
|
};
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
|
public async Task Play(IAudioClient voiceClient, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
|
bytesSent = (ulong) SkipTo * 3840 * 50;
|
||||||
var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
|
var filename = Path.Combine(Music.MusicDataPath, DateTime.Now.UnixTimestamp().ToString());
|
||||||
|
|
||||||
SongBuffer inStream = new SongBuffer(MusicPlayer, filename, SongInfo, skipTo, frameBytes * 100);
|
var inStream = new SongBuffer(MusicPlayer, filename, SongInfo, SkipTo, _frameBytes * 100);
|
||||||
var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
|
var bufferTask = inStream.BufferSong(cancelToken).ConfigureAwait(false);
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -200,22 +190,22 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
|
|
||||||
var outStream = voiceClient.CreatePCMStream(960);
|
var outStream = voiceClient.CreatePCMStream(960);
|
||||||
|
|
||||||
int nextTime = Environment.TickCount + milliseconds;
|
int nextTime = Environment.TickCount + _milliseconds;
|
||||||
|
|
||||||
byte[] buffer = new byte[frameBytes];
|
byte[] buffer = new byte[_frameBytes];
|
||||||
while (!cancelToken.IsCancellationRequested && //song canceled for whatever reason
|
while (!cancelToken.IsCancellationRequested && //song canceled for whatever reason
|
||||||
!(MusicPlayer.MaxPlaytimeSeconds != 0 && CurrentTime.TotalSeconds >= MusicPlayer.MaxPlaytimeSeconds)) // or exceedded max playtime
|
!(MusicPlayer.MaxPlaytimeSeconds != 0 && CurrentTime.TotalSeconds >= MusicPlayer.MaxPlaytimeSeconds)) // or exceedded max playtime
|
||||||
{
|
{
|
||||||
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
|
//Console.WriteLine($"Read: {songBuffer.ReadPosition}\nWrite: {songBuffer.WritePosition}\nContentLength:{songBuffer.ContentLength}\n---------");
|
||||||
var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
var read = await inStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
|
||||||
//await inStream.CopyToAsync(voiceClient.OutputStream);
|
//await inStream.CopyToAsync(voiceClient.OutputStream);
|
||||||
if (read < frameBytes)
|
if (read < _frameBytes)
|
||||||
_log.Debug("read {0}", read);
|
_log.Debug("read {0}", read);
|
||||||
unchecked
|
unchecked
|
||||||
{
|
{
|
||||||
bytesSent += (ulong)read;
|
bytesSent += (ulong)read;
|
||||||
}
|
}
|
||||||
if (read < frameBytes)
|
if (read < _frameBytes)
|
||||||
{
|
{
|
||||||
if (read == 0)
|
if (read == 0)
|
||||||
{
|
{
|
||||||
@ -231,12 +221,12 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
_log.Warn("Slow connection has disrupted music, waiting a bit for buffer");
|
_log.Warn("Slow connection has disrupted music, waiting a bit for buffer");
|
||||||
|
|
||||||
await Task.Delay(1000, cancelToken).ConfigureAwait(false);
|
await Task.Delay(1000, cancelToken).ConfigureAwait(false);
|
||||||
nextTime = Environment.TickCount + milliseconds;
|
nextTime = Environment.TickCount + _milliseconds;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await Task.Delay(100, cancelToken).ConfigureAwait(false);
|
await Task.Delay(100, cancelToken).ConfigureAwait(false);
|
||||||
nextTime = Environment.TickCount + milliseconds;
|
nextTime = Environment.TickCount + _milliseconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -245,16 +235,16 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
else
|
else
|
||||||
attempt = 0;
|
attempt = 0;
|
||||||
|
|
||||||
while (this.MusicPlayer.Paused)
|
while (MusicPlayer.Paused)
|
||||||
{
|
{
|
||||||
await Task.Delay(200, cancelToken).ConfigureAwait(false);
|
await Task.Delay(200, cancelToken).ConfigureAwait(false);
|
||||||
nextTime = Environment.TickCount + milliseconds;
|
nextTime = Environment.TickCount + _milliseconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
buffer = AdjustVolume(buffer, MusicPlayer.Volume);
|
buffer = AdjustVolume(buffer, MusicPlayer.Volume);
|
||||||
if (read != frameBytes) continue;
|
if (read != _frameBytes) continue;
|
||||||
nextTime = unchecked(nextTime + milliseconds);
|
nextTime = unchecked(nextTime + _milliseconds);
|
||||||
int delayMillis = unchecked(nextTime - Environment.TickCount);
|
int delayMillis = unchecked(nextTime - Environment.TickCount);
|
||||||
if (delayMillis > 0)
|
if (delayMillis > 0)
|
||||||
await Task.Delay(delayMillis, cancelToken).ConfigureAwait(false);
|
await Task.Delay(delayMillis, cancelToken).ConfigureAwait(false);
|
||||||
@ -264,7 +254,6 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await bufferTask;
|
await bufferTask;
|
||||||
if (inStream != null)
|
|
||||||
inStream.Dispose();
|
inStream.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,25 +268,20 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
|
|
||||||
//aidiakapi ftw
|
//aidiakapi ftw
|
||||||
public unsafe static byte[] AdjustVolume(byte[] audioSamples, float volume)
|
public static unsafe byte[] AdjustVolume(byte[] audioSamples, float volume)
|
||||||
{
|
{
|
||||||
Contract.Requires(audioSamples != null);
|
|
||||||
Contract.Requires(audioSamples.Length % 2 == 0);
|
|
||||||
Contract.Requires(volume >= 0f && volume <= 1f);
|
|
||||||
Contract.Assert(BitConverter.IsLittleEndian);
|
|
||||||
|
|
||||||
if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples;
|
if (Math.Abs(volume - 1f) < 0.0001f) return audioSamples;
|
||||||
|
|
||||||
// 16-bit precision for the multiplication
|
// 16-bit precision for the multiplication
|
||||||
int volumeFixed = (int)Math.Round(volume * 65536d);
|
var volumeFixed = (int)Math.Round(volume * 65536d);
|
||||||
|
|
||||||
int count = audioSamples.Length / 2;
|
var count = audioSamples.Length / 2;
|
||||||
|
|
||||||
fixed (byte* srcBytes = audioSamples)
|
fixed (byte* srcBytes = audioSamples)
|
||||||
{
|
{
|
||||||
short* src = (short*)srcBytes;
|
var src = (short*)srcBytes;
|
||||||
|
|
||||||
for (int i = count; i != 0; i--, src++)
|
for (var i = count; i != 0; i--, src++)
|
||||||
*src = (short)(((*src) * volumeFixed) >> 16);
|
*src = (short)(((*src) * volumeFixed) >> 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,8 +99,8 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
Console.WriteLine(@"You have not properly installed or configured FFMPEG.
|
Console.WriteLine(@"You have not properly installed or configured FFMPEG.
|
||||||
Please install and configure FFMPEG to play music.
|
Please install and configure FFMPEG to play music.
|
||||||
Check the guides for your platform on how to setup ffmpeg correctly:
|
Check the guides for your platform on how to setup ffmpeg correctly:
|
||||||
Windows Guide: https://goo.gl/SCv72y
|
Windows Guide: https://goo.gl/OjKk8F
|
||||||
Linux Guide: https://goo.gl/rRhjCp");
|
Linux Guide: https://goo.gl/ShjCUo");
|
||||||
Console.ForegroundColor = oldclr;
|
Console.ForegroundColor = oldclr;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
@ -6,12 +6,14 @@ using System.Net.Http;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using NLog;
|
||||||
using VideoLibrary;
|
using VideoLibrary;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music.Classes
|
namespace NadekoBot.Modules.Music.Classes
|
||||||
{
|
{
|
||||||
public static class SongHandler
|
public static class SongHandler
|
||||||
{
|
{
|
||||||
|
private static readonly Logger _log = LogManager.GetCurrentClassLogger();
|
||||||
public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal)
|
public static async Task<Song> ResolveSong(string query, MusicType musicType = MusicType.Normal)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(query))
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
@ -106,7 +108,8 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed resolving the link.{ex.Message}");
|
_log.Warn($"Failed resolving the link.{ex.Message}");
|
||||||
|
_log.Warn(ex);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -137,7 +140,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .pls:\n{file}");
|
_log.Warn($"Failed reading .pls:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -156,7 +159,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .m3u:\n{file}");
|
_log.Warn($"Failed reading .m3u:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -172,7 +175,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .asx:\n{file}");
|
_log.Warn($"Failed reading .asx:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -192,7 +195,7 @@ namespace NadekoBot.Modules.Music.Classes
|
|||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Console.WriteLine($"Failed reading .xspf:\n{file}");
|
_log.Warn($"Failed reading .xspf:\n{file}");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,14 +14,13 @@ using System.Net.Http;
|
|||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Music
|
namespace NadekoBot.Modules.Music
|
||||||
{
|
{
|
||||||
[NadekoModule("Music", "!!")]
|
[NadekoModule("Music", "!!")]
|
||||||
[DontAutoLoad]
|
[DontAutoLoad]
|
||||||
public partial class Music : NadekoModule
|
public class Music : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>();
|
public static ConcurrentDictionary<ulong, MusicPlayer> MusicPlayers { get; } = new ConcurrentDictionary<ulong, MusicPlayer>();
|
||||||
|
|
||||||
@ -78,7 +77,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +155,14 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
var val = musicPlayer.FairPlay = !musicPlayer.FairPlay;
|
var val = musicPlayer.FairPlay = !musicPlayer.FairPlay;
|
||||||
|
|
||||||
await channel.SendConfirmAsync("Fair play " + (val ? "enabled" : "disabled") + ".").ConfigureAwait(false);
|
if (val)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("fp_enabled").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("fp_disabled").ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -182,57 +191,56 @@ namespace NadekoBot.Modules.Music
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ListQueue(int page = 1)
|
public async Task ListQueue(int page = 1)
|
||||||
{
|
{
|
||||||
|
Song currentSong;
|
||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer) ||
|
||||||
|
(currentSong = musicPlayer?.CurrentSong) == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("🎵 No active music player.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_player").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (page <= 0)
|
if (page <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var currentSong = musicPlayer.CurrentSong;
|
|
||||||
if (currentSong == null)
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("🎵 No active music player.").ConfigureAwait(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
||||||
|
|
||||||
const int itemsPerPage = 10;
|
const int itemsPerPage = 10;
|
||||||
|
|
||||||
var total = musicPlayer.TotalPlaytime;
|
var total = musicPlayer.TotalPlaytime;
|
||||||
var totalStr = total == TimeSpan.MaxValue ? "∞" : $"{(int)total.TotalHours}h {total.Minutes}m {total.Seconds}s";
|
var totalStr = total == TimeSpan.MaxValue ? "∞" : GetText("time_format",
|
||||||
|
(int) total.TotalHours,
|
||||||
|
total.Minutes,
|
||||||
|
total.Seconds);
|
||||||
var maxPlaytime = musicPlayer.MaxPlaytimeSeconds;
|
var maxPlaytime = musicPlayer.MaxPlaytimeSeconds;
|
||||||
var lastPage = musicPlayer.Playlist.Count / itemsPerPage;
|
var lastPage = musicPlayer.Playlist.Count / itemsPerPage;
|
||||||
Func<int, EmbedBuilder> printAction = (curPage) =>
|
Func<int, EmbedBuilder> printAction = curPage =>
|
||||||
{
|
{
|
||||||
int startAt = itemsPerPage * (curPage - 1);
|
var startAt = itemsPerPage * (curPage - 1);
|
||||||
var number = 0 + startAt;
|
var number = 0 + startAt;
|
||||||
var desc = string.Join("\n", musicPlayer.Playlist
|
var desc = string.Join("\n", musicPlayer.Playlist
|
||||||
.Skip(startAt)
|
.Skip(startAt)
|
||||||
.Take(itemsPerPage)
|
.Take(itemsPerPage)
|
||||||
.Select(v => $"`{++number}.` {v.PrettyFullName}"));
|
.Select(v => $"`{++number}.` {v.PrettyFullName}"));
|
||||||
|
|
||||||
if (currentSong != null)
|
|
||||||
desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc;
|
desc = $"`🔊` {currentSong.PrettyFullName}\n\n" + desc;
|
||||||
|
|
||||||
if (musicPlayer.RepeatSong)
|
if (musicPlayer.RepeatSong)
|
||||||
desc = "🔂 Repeating Current Song\n\n" + desc;
|
desc = "🔂 " + GetText("repeating_cur_song") +"\n\n" + desc;
|
||||||
else if (musicPlayer.RepeatPlaylist)
|
else if (musicPlayer.RepeatPlaylist)
|
||||||
desc = "🔁 Repeating Playlist\n\n" + desc;
|
desc = "🔁 " + GetText("repeating_playlist")+"\n\n" + desc;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithAuthor(eab => eab.WithName($"Player Queue - Page {curPage}/{lastPage + 1}")
|
.WithAuthor(eab => eab.WithName(GetText("player_queue", curPage, lastPage + 1))
|
||||||
.WithMusicIcon())
|
.WithMusicIcon())
|
||||||
.WithDescription(desc)
|
.WithDescription(desc)
|
||||||
.WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " +
|
.WithFooter(ef => ef.WithText($"{musicPlayer.PrettyVolume} | {musicPlayer.Playlist.Count} " +
|
||||||
$"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " +
|
$"{("tracks".SnPl(musicPlayer.Playlist.Count))} | {totalStr} | " +
|
||||||
(musicPlayer.FairPlay ? "✔️fairplay" : "✖️fairplay") + $" | " + (maxPlaytime == 0 ? "unlimited" : $"{maxPlaytime}s limit")))
|
(musicPlayer.FairPlay
|
||||||
|
? "✔️" + GetText("fairplay")
|
||||||
|
: "✖️" + GetText("fairplay")) + " | " +
|
||||||
|
(maxPlaytime == 0 ? "unlimited" : GetText("play_limit", maxPlaytime))))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
|
|
||||||
return embed;
|
return embed;
|
||||||
@ -253,7 +261,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
try { await musicPlayer.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
||||||
|
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Now Playing").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("now_playing")).WithMusicIcon())
|
||||||
.WithDescription(currentSong.PrettyName)
|
.WithDescription(currentSong.PrettyName)
|
||||||
.WithThumbnailUrl(currentSong.Thumbnail)
|
.WithThumbnailUrl(currentSong.Thumbnail)
|
||||||
.WithFooter(ef => ef.WithText(musicPlayer.PrettyVolume + " | " + currentSong.PrettyFullTime + $" | {currentSong.PrettyProvider} | {currentSong.QueuerName}"));
|
.WithFooter(ef => ef.WithText(musicPlayer.PrettyVolume + " | " + currentSong.PrettyFullTime + $" | {currentSong.PrettyProvider} | {currentSong.QueuerName}"));
|
||||||
@ -270,21 +278,22 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||||
return;
|
return;
|
||||||
if (val < 0)
|
if (val < 0 || val > 100)
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("volume_input_invalid").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
var volume = musicPlayer.SetVolume(val);
|
var volume = musicPlayer.SetVolume(val);
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Volume set to {volume}%").ConfigureAwait(false);
|
await ReplyConfirmLocalized("volume_set", volume).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Defvol([Remainder] int val)
|
public async Task Defvol([Remainder] int val)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
if (val < 0 || val > 100)
|
if (val < 0 || val > 100)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Volume number invalid. Must be between 0 and 100").ConfigureAwait(false);
|
await ReplyErrorLocalized("volume_input_invalid").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
@ -292,7 +301,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
uow.GuildConfigs.For(Context.Guild.Id, set => set).DefaultMusicVolume = val / 100.0f;
|
uow.GuildConfigs.For(Context.Guild.Id, set => set).DefaultMusicVolume = val / 100.0f;
|
||||||
uow.Complete();
|
uow.Complete();
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Default volume set to {val}%").ConfigureAwait(false);
|
await ReplyConfirmLocalized("defvol_set", val).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -306,13 +315,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
if (((IGuildUser)Context.User).VoiceChannel != musicPlayer.PlaybackVoiceChannel)
|
||||||
return;
|
return;
|
||||||
if (musicPlayer.Playlist.Count < 2)
|
if (musicPlayer.Playlist.Count < 2)
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("💢 Not enough songs in order to perform the shuffle.").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
musicPlayer.Shuffle();
|
musicPlayer.Shuffle();
|
||||||
await Context.Channel.SendConfirmAsync("🎵 Songs shuffled.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("songs_shuffled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -325,29 +331,29 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"💢 You need to be in a **voice channel** on this server.").ConfigureAwait(false);
|
await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault();
|
var plId = (await NadekoBot.Google.GetPlaylistIdsByKeywordsAsync(arg).ConfigureAwait(false)).FirstOrDefault();
|
||||||
if (plId == null)
|
if (plId == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("No search results for that query.");
|
await ReplyErrorLocalized("no_search_results").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var ids = await NadekoBot.Google.GetPlaylistTracksAsync(plId, 500).ConfigureAwait(false);
|
var ids = await NadekoBot.Google.GetPlaylistTracksAsync(plId, 500).ConfigureAwait(false);
|
||||||
if (!ids.Any())
|
if (!ids.Any())
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"🎵 Failed to find any songs.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_search_results").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var count = ids.Count();
|
var count = ids.Count();
|
||||||
|
var msg = await Context.Channel.SendMessageAsync("🎵 " + GetText("attempting_to_queue",
|
||||||
var msg = await Context.Channel.SendMessageAsync($"🎵 Attempting to queue **{count}** songs".SnPl(count) + "...").ConfigureAwait(false);
|
Format.Bold(count.ToString()))).ConfigureAwait(false);
|
||||||
|
|
||||||
var cancelSource = new CancellationTokenSource();
|
var cancelSource = new CancellationTokenSource();
|
||||||
|
|
||||||
var gusr = (IGuildUser)Context.User;
|
var gusr = (IGuildUser)Context.User;
|
||||||
|
//todo use grouping
|
||||||
while (ids.Any() && !cancelSource.IsCancellationRequested)
|
while (ids.Any() && !cancelSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
var tasks = Task.WhenAll(ids.Take(5).Select(async id =>
|
var tasks = Task.WhenAll(ids.Take(5).Select(async id =>
|
||||||
@ -366,7 +372,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
ids = ids.Skip(5);
|
ids = ids.Skip(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
await msg.ModifyAsync(m => m.Content = "✅ Playlist queue complete.").ConfigureAwait(false);
|
await msg.ModifyAsync(m => m.Content = "✅ " + Format.Bold(GetText("playlist_queue_complete"))).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -392,7 +398,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
mp.AddSong(new Song(new Classes.SongInfo
|
mp.AddSong(new Song(new SongInfo
|
||||||
{
|
{
|
||||||
Title = svideo.FullName,
|
Title = svideo.FullName,
|
||||||
Provider = "SoundCloud",
|
Provider = "SoundCloud",
|
||||||
@ -434,20 +440,20 @@ namespace NadekoBot.Modules.Music
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync("🎵 Directory queue complete.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("dir_queue_complete").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Radio(string radio_link)
|
public async Task Radio(string radioLink)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
if (((IGuildUser)Context.User).VoiceChannel?.Guild != Context.Guild)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("💢 You need to be in a voice channel on this server.\n If you are already in a voice (ITextChannel)Context.Channel, try rejoining it.").ConfigureAwait(false);
|
await ReplyErrorLocalized("must_be_in_voice").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, radio_link, musicType: MusicType.Radio).ConfigureAwait(false);
|
await QueueSong(((IGuildUser)Context.User), (ITextChannel)Context.Channel, ((IGuildUser)Context.User).VoiceChannel, radioLink, musicType: MusicType.Radio).ConfigureAwait(false);
|
||||||
if ((await Context.Guild.GetCurrentUserAsync()).GetPermissions((IGuildChannel)Context.Channel).ManageMessages)
|
if ((await Context.Guild.GetCurrentUserAsync()).GetPermissions((IGuildChannel)Context.Channel).ManageMessages)
|
||||||
{
|
{
|
||||||
Context.Message.DeleteAfter(10);
|
Context.Message.DeleteAfter(10);
|
||||||
@ -504,20 +510,20 @@ namespace NadekoBot.Modules.Music
|
|||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) return;
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer)) return;
|
||||||
musicPlayer.ClearQueue();
|
musicPlayer.ClearQueue();
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Queue cleared!").ConfigureAwait(false);
|
await ReplyConfirmLocalized("queue_cleared").ConfigureAwait(false);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task MoveSong([Remainder] string fromto)
|
public async Task MoveSong([Remainder] string fromto)
|
||||||
{
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(fromto))
|
||||||
|
return;
|
||||||
|
|
||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||||
{
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
fromto = fromto?.Trim();
|
fromto = fromto?.Trim();
|
||||||
var fromtoArr = fromto.Split('>');
|
var fromtoArr = fromto.Split('>');
|
||||||
|
|
||||||
@ -530,7 +536,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
!int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
|
!int.TryParse(fromtoArr[1], out n2) || n1 < 1 || n2 < 1 || n1 == n2 ||
|
||||||
n1 > playlist.Count || n2 > playlist.Count)
|
n1 > playlist.Count || n2 > playlist.Count)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Invalid input.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invalid_input").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -541,10 +547,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithTitle($"{s.SongInfo.Title.TrimTo(70)}")
|
.WithTitle($"{s.SongInfo.Title.TrimTo(70)}")
|
||||||
.WithUrl($"{s.SongInfo.Query}")
|
.WithUrl(s.SongUrl)
|
||||||
.WithAuthor(eab => eab.WithName("Song Moved").WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
|
.WithAuthor(eab => eab.WithName(GetText("song_moved")).WithIconUrl("https://cdn.discordapp.com/attachments/155726317222887425/258605269972549642/music1.png"))
|
||||||
.AddField(fb => fb.WithName("**From Position**").WithValue($"#{n1}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("from_position")).WithValue($"#{n1}").WithIsInline(true))
|
||||||
.AddField(fb => fb.WithName("**To Position**").WithValue($"#{n2}").WithIsInline(true))
|
.AddField(fb => fb.WithName(GetText("to_position")).WithValue($"#{n2}").WithIsInline(true))
|
||||||
.WithColor(NadekoBot.OkColor);
|
.WithColor(NadekoBot.OkColor);
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
|
||||||
@ -562,7 +568,11 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
musicPlayer.MaxQueueSize = size;
|
musicPlayer.MaxQueueSize = size;
|
||||||
await Context.Channel.SendConfirmAsync($"🎵 Max queue set to {(size == 0 ? ("unlimited") : size + " tracks")}.");
|
|
||||||
|
if(size == 0)
|
||||||
|
await ReplyConfirmLocalized("max_queue_unlimited").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("max_queue_x", size).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -578,9 +588,9 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
musicPlayer.MaxPlaytimeSeconds = seconds;
|
musicPlayer.MaxPlaytimeSeconds = seconds;
|
||||||
if (seconds == 0)
|
if (seconds == 0)
|
||||||
await channel.SendConfirmAsync($"🎵 Max playtime has no limit now.");
|
await ReplyConfirmLocalized("max_playtime_none").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await channel.SendConfirmAsync($"🎵 Max playtime set to {seconds} seconds.");
|
await ReplyConfirmLocalized("max_playtime_set", seconds).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -599,11 +609,11 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (currentValue)
|
if (currentValue)
|
||||||
await Context.Channel.EmbedAsync(new EmbedBuilder()
|
await Context.Channel.EmbedAsync(new EmbedBuilder()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithMusicIcon().WithName("🔂 Repeating track"))
|
.WithAuthor(eab => eab.WithMusicIcon().WithName("🔂 " + GetText("repeating_track")))
|
||||||
.WithDescription(currentSong.PrettyName)
|
.WithDescription(currentSong.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(currentSong.PrettyInfo))).ConfigureAwait(false);
|
.WithFooter(ef => ef.WithText(currentSong.PrettyInfo))).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync($"🔂 Current track repeat stopped.")
|
await Context.Channel.SendConfirmAsync("🔂 " + GetText("repeating_track_stopped"))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +626,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||||
return;
|
return;
|
||||||
var currentValue = musicPlayer.ToggleRepeatPlaylist();
|
var currentValue = musicPlayer.ToggleRepeatPlaylist();
|
||||||
await Context.Channel.SendConfirmAsync($"🔁 Repeat playlist {(currentValue ? "**enabled**." : "**disabled**.")}").ConfigureAwait(false);
|
if(currentValue)
|
||||||
|
await ReplyConfirmLocalized("rpl_enabled").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await ReplyConfirmLocalized("rpl_disabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -653,7 +666,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync(($"🎵 Saved playlist as **{name}**, ID: {playlist.Id}.")).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithTitle(GetText("playlist_saved"))
|
||||||
|
.AddField(efb => efb.WithName(GetText("name")).WithValue(name))
|
||||||
|
.AddField(efb => efb.WithName(GetText("id")).WithValue(playlist.Id.ToString())));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -668,11 +684,11 @@ namespace NadekoBot.Modules.Music
|
|||||||
|
|
||||||
if (mpl == null)
|
if (mpl == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Can't find playlist with that ID.").ConfigureAwait(false);
|
await ReplyErrorLocalized("playlist_id_not_found").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
IUserMessage msg = null;
|
IUserMessage msg = null;
|
||||||
try { msg = await Context.Channel.SendMessageAsync($"🎶 Attempting to load **{mpl.Songs.Count}** songs...").ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
try { msg = await Context.Channel.SendMessageAsync(GetText("attempting_to_queue", Format.Bold(mpl.Songs.Count.ToString()))).ConfigureAwait(false); } catch (Exception ex) { _log.Warn(ex); }
|
||||||
foreach (var item in mpl.Songs)
|
foreach (var item in mpl.Songs)
|
||||||
{
|
{
|
||||||
var usr = (IGuildUser)Context.User;
|
var usr = (IGuildUser)Context.User;
|
||||||
@ -684,15 +700,13 @@ namespace NadekoBot.Modules.Music
|
|||||||
catch { break; }
|
catch { break; }
|
||||||
}
|
}
|
||||||
if (msg != null)
|
if (msg != null)
|
||||||
await msg.ModifyAsync(m => m.Content = $"✅ Done loading playlist **{mpl.Name}**.").ConfigureAwait(false);
|
await msg.ModifyAsync(m => m.Content = GetText("playlist_queue_complete")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task Playlists([Remainder] int num = 1)
|
public async Task Playlists([Remainder] int num = 1)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
if (num <= 0)
|
if (num <= 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -704,8 +718,9 @@ namespace NadekoBot.Modules.Music
|
|||||||
}
|
}
|
||||||
|
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithAuthor(eab => eab.WithName($"Page {num} of Saved Playlists").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("playlists_page", num)).WithMusicIcon())
|
||||||
.WithDescription(string.Join("\n", playlists.Select(r => $"`#{r.Id}` - **{r.Name}** by *{r.Author}* ({r.Songs.Count} songs)")))
|
.WithDescription(string.Join("\n", playlists.Select(r =>
|
||||||
|
GetText("playlists", r.Id, r.Name, r.Author, r.Songs.Count))))
|
||||||
.WithOkColor();
|
.WithOkColor();
|
||||||
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
|
||||||
@ -715,13 +730,12 @@ namespace NadekoBot.Modules.Music
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task DeletePlaylist([Remainder] int id)
|
public async Task DeletePlaylist([Remainder] int id)
|
||||||
{
|
{
|
||||||
bool success = false;
|
var success = false;
|
||||||
MusicPlaylist pl = null;
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
pl = uow.MusicPlaylists.Get(id);
|
var pl = uow.MusicPlaylists.Get(id);
|
||||||
|
|
||||||
if (pl != null)
|
if (pl != null)
|
||||||
{
|
{
|
||||||
@ -731,15 +745,13 @@ namespace NadekoBot.Modules.Music
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
success = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
await Context.Channel.SendErrorAsync("Failed to delete that playlist. It either doesn't exist, or you are not its author.").ConfigureAwait(false);
|
await ReplyErrorLocalized("playlist_delete_fail").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync("🗑 Playlist successfully **deleted**.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("playlist_deleted").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -779,7 +791,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
if (seconds.Length == 1)
|
if (seconds.Length == 1)
|
||||||
seconds = "0" + seconds;
|
seconds = "0" + seconds;
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"Skipped to `{minutes}:{seconds}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("skipped_to", minutes, seconds).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -791,9 +803,9 @@ namespace NadekoBot.Modules.Music
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (!musicPlayer.ToggleAutoplay())
|
if (!musicPlayer.ToggleAutoplay())
|
||||||
await Context.Channel.SendConfirmAsync("❌ Autoplay disabled.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("autoplay_disabled").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync("✅ Autoplay enabled.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("autoplay_enabled").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -804,29 +816,29 @@ namespace NadekoBot.Modules.Music
|
|||||||
MusicPlayer musicPlayer;
|
MusicPlayer musicPlayer;
|
||||||
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
if (!MusicPlayers.TryGetValue(Context.Guild.Id, out musicPlayer))
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync("Music must be playing before you set an ouput channel.").ConfigureAwait(false);
|
await ReplyErrorLocalized("no_player").ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel;
|
musicPlayer.OutputTextChannel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("I will now output playing, finished, paused and removed songs in this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("set_music_channel").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
public async Task QueueSong(IGuildUser queuer, ITextChannel textCh, IVoiceChannel voiceCh, string query, bool silent = false, MusicType musicType = MusicType.Normal)
|
||||||
{
|
{
|
||||||
if (voiceCh == null || voiceCh.Guild != textCh.Guild)
|
if (voiceCh == null || voiceCh.Guild != textCh.Guild)
|
||||||
{
|
{
|
||||||
if (!silent)
|
if (!silent)
|
||||||
await textCh.SendErrorAsync($"💢 You need to be in a voice channel on this server.").ConfigureAwait(false);
|
await textCh.SendErrorAsync(GetText("must_be_in_voice")).ConfigureAwait(false);
|
||||||
throw new ArgumentNullException(nameof(voiceCh));
|
throw new ArgumentNullException(nameof(voiceCh));
|
||||||
}
|
}
|
||||||
if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
|
if (string.IsNullOrWhiteSpace(query) || query.Length < 3)
|
||||||
throw new ArgumentException("💢 Invalid query for queue song.", nameof(query));
|
throw new ArgumentException("Invalid song query.", nameof(query));
|
||||||
|
|
||||||
var musicPlayer = MusicPlayers.GetOrAdd(textCh.Guild.Id, server =>
|
var musicPlayer = MusicPlayers.GetOrAdd(textCh.Guild.Id, server =>
|
||||||
{
|
{
|
||||||
float vol = 1;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
|
float vol;// SpecificConfigurations.Default.Of(server.Id).DefaultMusicVolume;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume;
|
vol = uow.GuildConfigs.For(textCh.Guild.Id, set => set).DefaultMusicVolume;
|
||||||
@ -843,7 +855,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
lastFinishedMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Finished Song").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("finished_song")).WithMusicIcon())
|
||||||
.WithDescription(song.PrettyName)
|
.WithDescription(song.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
@ -861,17 +873,23 @@ namespace NadekoBot.Modules.Music
|
|||||||
textCh,
|
textCh,
|
||||||
voiceCh,
|
voiceCh,
|
||||||
relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)],
|
relatedVideos[new NadekoRandom().Next(0, relatedVideos.Count)],
|
||||||
true,
|
true).ConfigureAwait(false);
|
||||||
musicType).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mp.OnStarted += async (player, song) =>
|
mp.OnStarted += async (player, song) =>
|
||||||
{
|
{
|
||||||
try { await mp.UpdateSongDurationsAsync().ConfigureAwait(false); } catch { }
|
try { await mp.UpdateSongDurationsAsync().ConfigureAwait(false); }
|
||||||
var sender = player as MusicPlayer;
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
var sender = player;
|
||||||
if (sender == null)
|
if (sender == null)
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
@ -879,12 +897,15 @@ namespace NadekoBot.Modules.Music
|
|||||||
playingMessage?.DeleteAfter(0);
|
playingMessage?.DeleteAfter(0);
|
||||||
|
|
||||||
playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
playingMessage = await mp.OutputTextChannel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Playing Song").WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("playing_song")).WithMusicIcon())
|
||||||
.WithDescription(song.PrettyName)
|
.WithDescription(song.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
.WithFooter(ef => ef.WithText(song.PrettyInfo)))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
mp.OnPauseChanged += async (paused) =>
|
mp.OnPauseChanged += async (paused) =>
|
||||||
{
|
{
|
||||||
@ -892,13 +913,16 @@ namespace NadekoBot.Modules.Music
|
|||||||
{
|
{
|
||||||
IUserMessage msg;
|
IUserMessage msg;
|
||||||
if (paused)
|
if (paused)
|
||||||
msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **paused**.").ConfigureAwait(false);
|
msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("paused")).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
msg = await mp.OutputTextChannel.SendConfirmAsync("🎵 Music playback **resumed**.").ConfigureAwait(false);
|
msg = await mp.OutputTextChannel.SendConfirmAsync(GetText("resumed")).ConfigureAwait(false);
|
||||||
|
|
||||||
msg?.DeleteAfter(10);
|
msg?.DeleteAfter(10);
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mp.SongRemoved += async (song, index) =>
|
mp.SongRemoved += async (song, index) =>
|
||||||
@ -906,7 +930,7 @@ namespace NadekoBot.Modules.Music
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var embed = new EmbedBuilder()
|
var embed = new EmbedBuilder()
|
||||||
.WithAuthor(eab => eab.WithName("Removed song #" + (index + 1)).WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("removed_song") + " #" + (index + 1)).WithMusicIcon())
|
||||||
.WithDescription(song.PrettyName)
|
.WithDescription(song.PrettyName)
|
||||||
.WithFooter(ef => ef.WithText(song.PrettyInfo))
|
.WithFooter(ef => ef.WithText(song.PrettyInfo))
|
||||||
.WithErrorColor();
|
.WithErrorColor();
|
||||||
@ -914,7 +938,10 @@ namespace NadekoBot.Modules.Music
|
|||||||
await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false);
|
await mp.OutputTextChannel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch { }
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return mp;
|
return mp;
|
||||||
});
|
});
|
||||||
@ -931,7 +958,14 @@ namespace NadekoBot.Modules.Music
|
|||||||
}
|
}
|
||||||
catch (PlaylistFullException)
|
catch (PlaylistFullException)
|
||||||
{
|
{
|
||||||
try { await textCh.SendConfirmAsync($"🎵 Queue is full at **{musicPlayer.MaxQueueSize}/{musicPlayer.MaxQueueSize}**."); } catch { }
|
try
|
||||||
|
{
|
||||||
|
await textCh.SendConfirmAsync(GetText("queue_full", musicPlayer.MaxQueueSize));
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
if (!silent)
|
if (!silent)
|
||||||
@ -940,15 +974,17 @@ namespace NadekoBot.Modules.Music
|
|||||||
{
|
{
|
||||||
//var queuedMessage = await textCh.SendConfirmAsync($"🎵 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
|
//var queuedMessage = await textCh.SendConfirmAsync($"🎵 Queued **{resolvedSong.SongInfo.Title}** at `#{musicPlayer.Playlist.Count + 1}`").ConfigureAwait(false);
|
||||||
var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
|
var queuedMessage = await textCh.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
.WithAuthor(eab => eab.WithName("Queued Song #" + (musicPlayer.Playlist.Count + 1)).WithMusicIcon())
|
.WithAuthor(eab => eab.WithName(GetText("queued_song") + " #" + (musicPlayer.Playlist.Count + 1)).WithMusicIcon())
|
||||||
.WithDescription($"{resolvedSong.PrettyName}\nQueue ")
|
.WithDescription($"{resolvedSong.PrettyName}\n{GetText("queue")} ")
|
||||||
.WithThumbnailUrl(resolvedSong.Thumbnail)
|
.WithThumbnailUrl(resolvedSong.Thumbnail)
|
||||||
.WithFooter(ef => ef.WithText(resolvedSong.PrettyProvider)))
|
.WithFooter(ef => ef.WithText(resolvedSong.PrettyProvider)))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
if (queuedMessage != null)
|
queuedMessage?.DeleteAfter(10);
|
||||||
queuedMessage.DeleteAfter(10);
|
|
||||||
}
|
}
|
||||||
catch { } // if queued message sending fails, don't attempt to delete it
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
} // if queued message sending fails, don't attempt to delete it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,6 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Services;
|
using NadekoBot.Services;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
using System.Xml;
|
using System.Xml;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@ -17,11 +15,11 @@ using System.Collections.Concurrent;
|
|||||||
namespace NadekoBot.Modules.NSFW
|
namespace NadekoBot.Modules.NSFW
|
||||||
{
|
{
|
||||||
[NadekoModule("NSFW", "~")]
|
[NadekoModule("NSFW", "~")]
|
||||||
public class NSFW : NadekoModule
|
public class NSFW : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
|
|
||||||
private static readonly ConcurrentDictionary<ulong, Timer> AutoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
private static readonly ConcurrentDictionary<ulong, Timer> _autoHentaiTimers = new ConcurrentDictionary<ulong, Timer>();
|
||||||
private static readonly ConcurrentHashSet<ulong> HentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
private static readonly ConcurrentHashSet<ulong> _hentaiBombBlacklist = new ConcurrentHashSet<ulong>();
|
||||||
|
|
||||||
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
private async Task InternalHentai(IMessageChannel channel, string tag, bool noError)
|
||||||
{
|
{
|
||||||
@ -72,7 +70,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
if (interval == 0)
|
if (interval == 0)
|
||||||
{
|
{
|
||||||
if (!AutoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return;
|
if (!_autoHentaiTimers.TryRemove(Context.Channel.Id, out t)) return;
|
||||||
|
|
||||||
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
t.Change(Timeout.Infinite, Timeout.Infinite); //proper way to disable the timer
|
||||||
await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false);
|
await ReplyConfirmLocalized("autohentai_stopped").ConfigureAwait(false);
|
||||||
@ -99,7 +97,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
}
|
}
|
||||||
}, null, interval * 1000, interval * 1000);
|
}, null, interval * 1000, interval * 1000);
|
||||||
|
|
||||||
AutoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) =>
|
_autoHentaiTimers.AddOrUpdate(Context.Channel.Id, t, (key, old) =>
|
||||||
{
|
{
|
||||||
old.Change(Timeout.Infinite, Timeout.Infinite);
|
old.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
return t;
|
return t;
|
||||||
@ -114,7 +112,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task HentaiBomb([Remainder] string tag = null)
|
public async Task HentaiBomb([Remainder] string tag = null)
|
||||||
{
|
{
|
||||||
if (!HentaiBombBlacklist.Add(Context.User.Id))
|
if (!_hentaiBombBlacklist.Add(Context.User.Id))
|
||||||
return;
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -138,17 +136,17 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
await Task.Delay(5000).ConfigureAwait(false);
|
await Task.Delay(5000).ConfigureAwait(false);
|
||||||
HentaiBombBlacklist.TryRemove(Context.User.Id);
|
_hentaiBombBlacklist.TryRemove(Context.User.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Yandere([Remainder] string tag = null)
|
public Task Yandere([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Yandere);
|
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Yandere);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Konachan([Remainder] string tag = null)
|
public Task Konachan([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Konachan);
|
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Konachan);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task E621([Remainder] string tag = null)
|
public async Task E621([Remainder] string tag = null)
|
||||||
@ -169,7 +167,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Rule34([Remainder] string tag = null)
|
public Task Rule34([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Rule34);
|
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Rule34);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Danbooru([Remainder] string tag = null)
|
public async Task Danbooru([Remainder] string tag = null)
|
||||||
@ -212,13 +210,7 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public Task Gelbooru([Remainder] string tag = null)
|
public Task Gelbooru([Remainder] string tag = null)
|
||||||
=> Searches.Searches.InternalDapiCommand(Context.Message, tag, Searches.Searches.DapiSearchType.Gelbooru);
|
=> InternalDapiCommand(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
|
||||||
public async Task Cp()
|
|
||||||
{
|
|
||||||
await Context.Channel.SendMessageAsync("http://i.imgur.com/MZkY1md.jpg").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task Boobs()
|
public async Task Boobs()
|
||||||
@ -289,5 +281,20 @@ namespace NadekoBot.Modules.NSFW
|
|||||||
|
|
||||||
public static Task<string> GetGelbooruImageLink(string tag) =>
|
public static Task<string> GetGelbooruImageLink(string tag) =>
|
||||||
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
Searches.Searches.InternalDapiSearch(tag, Searches.Searches.DapiSearchType.Gelbooru);
|
||||||
|
|
||||||
|
public async Task InternalDapiCommand(string tag, Searches.Searches.DapiSearchType type)
|
||||||
|
{
|
||||||
|
tag = tag?.Trim() ?? "";
|
||||||
|
|
||||||
|
var url = await Searches.Searches.InternalDapiSearch(tag, type).ConfigureAwait(false);
|
||||||
|
|
||||||
|
if (url == null)
|
||||||
|
await ReplyErrorLocalized("not_found").ConfigureAwait(false);
|
||||||
|
else
|
||||||
|
await Context.Channel.EmbedAsync(new EmbedBuilder().WithOkColor()
|
||||||
|
.WithDescription(Context.User + " " + tag)
|
||||||
|
.WithImageUrl(url)
|
||||||
|
.WithFooter(efb => efb.WithText(type.ToString()))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -9,7 +9,7 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace NadekoBot.Modules
|
namespace NadekoBot.Modules
|
||||||
{
|
{
|
||||||
public abstract class NadekoModule : ModuleBase
|
public abstract class NadekoTopLevelModule : ModuleBase
|
||||||
{
|
{
|
||||||
protected readonly Logger _log;
|
protected readonly Logger _log;
|
||||||
protected CultureInfo _cultureInfo;
|
protected CultureInfo _cultureInfo;
|
||||||
@ -17,7 +17,7 @@ namespace NadekoBot.Modules
|
|||||||
public readonly string ModuleTypeName;
|
public readonly string ModuleTypeName;
|
||||||
public readonly string LowerModuleTypeName;
|
public readonly string LowerModuleTypeName;
|
||||||
|
|
||||||
protected NadekoModule(bool isTopLevelModule = true)
|
protected NadekoTopLevelModule(bool isTopLevelModule = true)
|
||||||
{
|
{
|
||||||
//if it's top level module
|
//if it's top level module
|
||||||
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
ModuleTypeName = isTopLevelModule ? this.GetType().Name : this.GetType().DeclaringType.Name;
|
||||||
@ -69,7 +69,7 @@ namespace NadekoBot.Modules
|
|||||||
LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS.");
|
LogManager.GetCurrentClassLogger().Warn(lowerModuleTypeName + "_" + key + " key is missing from " + cultureInfo + " response strings. PLEASE REPORT THIS.");
|
||||||
text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!";
|
text = NadekoBot.ResponsesResourceManager.GetString(lowerModuleTypeName + "_" + key, _usCultureInfo) ?? $"Error: dkey {lowerModuleTypeName + "_" + key} not found!";
|
||||||
if (string.IsNullOrWhiteSpace(text))
|
if (string.IsNullOrWhiteSpace(text))
|
||||||
return "I cant tell if you command is executed, because there was an error printing out the response. Key '" +
|
return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" +
|
||||||
lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this.";
|
lowerModuleTypeName + "_" + key + "' " + "is missing from resources. Please report this.";
|
||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
@ -84,7 +84,7 @@ namespace NadekoBot.Modules
|
|||||||
}
|
}
|
||||||
catch (FormatException)
|
catch (FormatException)
|
||||||
{
|
{
|
||||||
return "I cant tell if you command is executed, because there was an error printing out the response. Key '" +
|
return "I can't tell you if the command is executed, because there was an error printing out the response. Key '" +
|
||||||
lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this.";
|
lowerModuleTypeName + "_" + key + "' " + "is not properly formatted. Please report this.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ namespace NadekoBot.Modules
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class NadekoSubmodule : NadekoModule
|
public abstract class NadekoSubmodule : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
protected NadekoSubmodule() : base(false)
|
protected NadekoSubmodule() : base(false)
|
||||||
{
|
{
|
||||||
|
@ -21,11 +21,11 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class BlacklistCommands : ModuleBase
|
public class BlacklistCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentHashSet<ulong> BlacklistedUsers { get; set; } = new ConcurrentHashSet<ulong>();
|
public static ConcurrentHashSet<ulong> BlacklistedUsers { get; set; }
|
||||||
public static ConcurrentHashSet<ulong> BlacklistedGuilds { get; set; } = new ConcurrentHashSet<ulong>();
|
public static ConcurrentHashSet<ulong> BlacklistedGuilds { get; set; }
|
||||||
public static ConcurrentHashSet<ulong> BlacklistedChannels { get; set; } = new ConcurrentHashSet<ulong>();
|
public static ConcurrentHashSet<ulong> BlacklistedChannels { get; set; }
|
||||||
|
|
||||||
static BlacklistCommands()
|
static BlacklistCommands()
|
||||||
{
|
{
|
||||||
@ -115,7 +115,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case BlacklistType.Channel:
|
case BlacklistType.Channel:
|
||||||
var item = Games.Games.TriviaCommands.RunningTrivias.FirstOrDefault(kvp => kvp.Value.channel.Id == id);
|
var item = Games.Games.TriviaCommands.RunningTrivias.FirstOrDefault(kvp => kvp.Value.Channel.Id == id);
|
||||||
Games.Games.TriviaCommands.RunningTrivias.TryRemove(item.Key, out tg);
|
Games.Games.TriviaCommands.RunningTrivias.TryRemove(item.Key, out tg);
|
||||||
if (tg != null)
|
if (tg != null)
|
||||||
{
|
{
|
||||||
@ -124,16 +124,14 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
break;
|
break;
|
||||||
case BlacklistType.User:
|
case BlacklistType.User:
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(action == AddRemove.Add)
|
if(action == AddRemove.Add)
|
||||||
await Context.Channel.SendConfirmAsync($"Blacklisted a `{type}` with id `{id}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("blacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await Context.Channel.SendConfirmAsync($"Unblacklisted a `{type}` with id `{id}`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("unblacklisted", Format.Code(type.ToString()), Format.Code(id.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,15 +21,15 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Group]
|
[Group]
|
||||||
public class CmdCdsCommands : ModuleBase
|
public class CmdCdsCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> commandCooldowns { get; }
|
public static ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>> CommandCooldowns { get; }
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> activeCooldowns { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>>();
|
private static ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>> activeCooldowns { get; } = new ConcurrentDictionary<ulong, ConcurrentHashSet<ActiveCooldown>>();
|
||||||
|
|
||||||
static CmdCdsCommands()
|
static CmdCdsCommands()
|
||||||
{
|
{
|
||||||
var configs = NadekoBot.AllGuildConfigs;
|
var configs = NadekoBot.AllGuildConfigs;
|
||||||
commandCooldowns = new ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>>(configs.ToDictionary(k => k.GuildId, v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns)));
|
CommandCooldowns = new ConcurrentDictionary<ulong, ConcurrentHashSet<CommandCooldown>>(configs.ToDictionary(k => k.GuildId, v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns)));
|
||||||
}
|
}
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
@ -38,14 +38,14 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
if (secs < 0 || secs > 3600)
|
if (secs < 0 || secs > 3600)
|
||||||
{
|
{
|
||||||
await channel.SendErrorAsync("Invalid second parameter. (Must be a number between 0 and 3600)").ConfigureAwait(false);
|
await ReplyErrorLocalized("invalid_second_param_between", 0, 3600).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns));
|
var config = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.CommandCooldowns));
|
||||||
var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||||
|
|
||||||
config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
config.CommandCooldowns.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
||||||
localSet.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
localSet.RemoveWhere(cc => cc.CommandName == command.Aliases.First().ToLowerInvariant());
|
||||||
@ -65,13 +65,14 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<ActiveCooldown>());
|
var activeCds = activeCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<ActiveCooldown>());
|
||||||
activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant());
|
activeCds.RemoveWhere(ac => ac.Command == command.Aliases.First().ToLowerInvariant());
|
||||||
await channel.SendConfirmAsync($"🚮 Command **{command.Aliases.First()}** has no coooldown now and all existing cooldowns have been cleared.")
|
await ReplyConfirmLocalized("cmdcd_cleared",
|
||||||
.ConfigureAwait(false);
|
Format.Bold(command.Aliases.First())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await channel.SendConfirmAsync($"✅ Command **{command.Aliases.First()}** now has a **{secs} {"seconds".SnPl(secs)}** cooldown.")
|
await ReplyConfirmLocalized("cmdcd_add",
|
||||||
.ConfigureAwait(false);
|
Format.Bold(command.Aliases.First()),
|
||||||
|
Format.Bold(secs.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,19 +81,19 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
public async Task AllCmdCooldowns()
|
public async Task AllCmdCooldowns()
|
||||||
{
|
{
|
||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
var localSet = commandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
var localSet = CommandCooldowns.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||||
|
|
||||||
if (!localSet.Any())
|
if (!localSet.Any())
|
||||||
await channel.SendConfirmAsync("ℹ️ `No command cooldowns set.`").ConfigureAwait(false);
|
await ReplyConfirmLocalized("cmdcd_none").ConfigureAwait(false);
|
||||||
else
|
else
|
||||||
await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + " secs"), s => $"{s,-30}", 2).ConfigureAwait(false);
|
await channel.SendTableAsync("", localSet.Select(c => c.CommandName + ": " + c.Seconds + GetText("sec")), s => $"{s,-30}", 2).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasCooldown(CommandInfo cmd, IGuild guild, IUser user)
|
public static bool HasCooldown(CommandInfo cmd, IGuild guild, IUser user)
|
||||||
{
|
{
|
||||||
if (guild == null)
|
if (guild == null)
|
||||||
return false;
|
return false;
|
||||||
var cmdcds = CmdCdsCommands.commandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
var cmdcds = CmdCdsCommands.CommandCooldowns.GetOrAdd(guild.Id, new ConcurrentHashSet<CommandCooldown>());
|
||||||
CommandCooldown cdRule;
|
CommandCooldown cdRule;
|
||||||
if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == cmd.Aliases.First().ToLowerInvariant())) != null)
|
if ((cdRule = cmdcds.FirstOrDefault(cc => cc.CommandName == cmd.Aliases.First().ToLowerInvariant())) != null)
|
||||||
{
|
{
|
||||||
|
@ -17,7 +17,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
public partial class Permissions
|
public partial class Permissions
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class CommandCostCommands : ModuleBase
|
public class CommandCostCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private static readonly ConcurrentDictionary<string, int> _commandCosts = new ConcurrentDictionary<string, int>();
|
private static readonly ConcurrentDictionary<string, int> _commandCosts = new ConcurrentDictionary<string, int>();
|
||||||
public static IReadOnlyDictionary<string, int> CommandCosts => _commandCosts;
|
public static IReadOnlyDictionary<string, int> CommandCosts => _commandCosts;
|
||||||
@ -29,29 +29,29 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
// x => x.Cost));
|
// x => x.Cost));
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
public async Task CmdCosts(int page = 1)
|
//public async Task CmdCosts(int page = 1)
|
||||||
{
|
//{
|
||||||
var prices = _commandCosts.ToList();
|
// var prices = _commandCosts.ToList();
|
||||||
|
|
||||||
if (!prices.Any())
|
// if (!prices.Any())
|
||||||
{
|
// {
|
||||||
await Context.Channel.SendConfirmAsync("No costs set.").ConfigureAwait(false);
|
// await Context.Channel.SendConfirmAsync(GetText("no_costs")).ConfigureAwait(false);
|
||||||
return;
|
// return;
|
||||||
}
|
// }
|
||||||
|
|
||||||
await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => {
|
// await Context.Channel.SendPaginatedConfirmAsync(page, (curPage) => {
|
||||||
var embed = new EmbedBuilder().WithOkColor()
|
// var embed = new EmbedBuilder().WithOkColor()
|
||||||
.WithTitle("Command Costs");
|
// .WithTitle(GetText("command_costs"));
|
||||||
var current = prices.Skip((curPage - 1) * 9)
|
// var current = prices.Skip((curPage - 1) * 9)
|
||||||
.Take(9);
|
// .Take(9);
|
||||||
foreach (var price in current)
|
// foreach (var price in current)
|
||||||
{
|
// {
|
||||||
embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true));
|
// embed.AddField(efb => efb.WithName(price.Key).WithValue(price.Value.ToString()).WithIsInline(true));
|
||||||
}
|
// }
|
||||||
return embed;
|
// return embed;
|
||||||
}, prices.Count / 9).ConfigureAwait(false);
|
// }, prices.Count / 9).ConfigureAwait(false);
|
||||||
}
|
//}
|
||||||
|
|
||||||
//[NadekoCommand, Usage, Description, Aliases]
|
//[NadekoCommand, Usage, Description, Aliases]
|
||||||
//public async Task CommandCost(int cost, CommandInfo cmd)
|
//public async Task CommandCost(int cost, CommandInfo cmd)
|
||||||
|
@ -13,13 +13,13 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
public partial class Permissions
|
public partial class Permissions
|
||||||
{
|
{
|
||||||
[Group]
|
[Group]
|
||||||
public class FilterCommands : ModuleBase
|
public class FilterCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
public static ConcurrentHashSet<ulong> InviteFilteringChannels { get; }
|
public static ConcurrentHashSet<ulong> InviteFilteringChannels { get; }
|
||||||
public static ConcurrentHashSet<ulong> InviteFilteringServers { get; }
|
public static ConcurrentHashSet<ulong> InviteFilteringServers { get; }
|
||||||
|
|
||||||
//serverid, filteredwords
|
//serverid, filteredwords
|
||||||
private static ConcurrentDictionary<ulong, ConcurrentHashSet<string>> ServerFilteredWords { get; }
|
private static ConcurrentDictionary<ulong, ConcurrentHashSet<string>> serverFilteredWords { get; }
|
||||||
|
|
||||||
public static ConcurrentHashSet<ulong> WordFilteringChannels { get; }
|
public static ConcurrentHashSet<ulong> WordFilteringChannels { get; }
|
||||||
public static ConcurrentHashSet<ulong> WordFilteringServers { get; }
|
public static ConcurrentHashSet<ulong> WordFilteringServers { get; }
|
||||||
@ -28,7 +28,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
ConcurrentHashSet<string> words = new ConcurrentHashSet<string>();
|
ConcurrentHashSet<string> words = new ConcurrentHashSet<string>();
|
||||||
if(WordFilteringChannels.Contains(channelId))
|
if(WordFilteringChannels.Contains(channelId))
|
||||||
ServerFilteredWords.TryGetValue(guildId, out words);
|
serverFilteredWords.TryGetValue(guildId, out words);
|
||||||
return words;
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
var words = new ConcurrentHashSet<string>();
|
var words = new ConcurrentHashSet<string>();
|
||||||
if(WordFilteringServers.Contains(guildId))
|
if(WordFilteringServers.Contains(guildId))
|
||||||
ServerFilteredWords.TryGetValue(guildId, out words);
|
serverFilteredWords.TryGetValue(guildId, out words);
|
||||||
return words;
|
return words;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +49,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
|
|
||||||
var dict = guildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet<string>(gc.FilteredWords.Select(fw => fw.Word)));
|
var dict = guildConfigs.ToDictionary(gc => gc.GuildId, gc => new ConcurrentHashSet<string>(gc.FilteredWords.Select(fw => fw.Word)));
|
||||||
|
|
||||||
ServerFilteredWords = new ConcurrentDictionary<ulong, ConcurrentHashSet<string>>(dict);
|
serverFilteredWords = new ConcurrentDictionary<ulong, ConcurrentHashSet<string>>(dict);
|
||||||
|
|
||||||
var serverFiltering = guildConfigs.Where(gc => gc.FilterWords);
|
var serverFiltering = guildConfigs.Where(gc => gc.FilterWords);
|
||||||
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
|
WordFilteringServers = new ConcurrentHashSet<ulong>(serverFiltering.Select(gc => gc.GuildId));
|
||||||
@ -74,12 +74,12 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
InviteFilteringServers.Add(channel.Guild.Id);
|
InviteFilteringServers.Add(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Invite filtering enabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invite_filter_server_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InviteFilteringServers.TryRemove(channel.Guild.Id);
|
InviteFilteringServers.TryRemove(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Invite filtering disabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invite_filter_server_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,12 +107,11 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
InviteFilteringChannels.Add(channel.Id);
|
InviteFilteringChannels.Add(channel.Id);
|
||||||
await channel.SendConfirmAsync("Invite filtering enabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("invite_filter_channel_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
InviteFilteringChannels.TryRemove(channel.Id);
|
await ReplyConfirmLocalized("invite_filter_channel_off").ConfigureAwait(false);
|
||||||
await channel.SendConfirmAsync("Invite filtering disabled on this channel.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -133,12 +132,12 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
WordFilteringServers.Add(channel.Guild.Id);
|
WordFilteringServers.Add(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering enabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_server_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WordFilteringServers.TryRemove(channel.Guild.Id);
|
WordFilteringServers.TryRemove(channel.Guild.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering disabled on this server.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_server_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,12 +165,12 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
WordFilteringChannels.Add(channel.Id);
|
WordFilteringChannels.Add(channel.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering enabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_channel_on").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
WordFilteringChannels.TryRemove(channel.Id);
|
WordFilteringChannels.TryRemove(channel.Id);
|
||||||
await channel.SendConfirmAsync("Word filtering disabled on this channel.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("word_filter_channel_off").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,19 +198,17 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var filteredWords = ServerFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<string>());
|
var filteredWords = serverFilteredWords.GetOrAdd(channel.Guild.Id, new ConcurrentHashSet<string>());
|
||||||
|
|
||||||
if (removed == 0)
|
if (removed == 0)
|
||||||
{
|
{
|
||||||
filteredWords.Add(word);
|
filteredWords.Add(word);
|
||||||
await channel.SendConfirmAsync($"Word `{word}` successfully added to the list of filtered words.")
|
await ReplyConfirmLocalized("filter_word_add", Format.Code(word)).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
filteredWords.TryRemove(word);
|
filteredWords.TryRemove(word);
|
||||||
await channel.SendConfirmAsync($"Word `{word}` removed from the list of filtered words.")
|
await ReplyConfirmLocalized("filter_word_remove", Format.Code(word)).ConfigureAwait(false);
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,9 +219,9 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
var channel = (ITextChannel)Context.Channel;
|
var channel = (ITextChannel)Context.Channel;
|
||||||
|
|
||||||
ConcurrentHashSet<string> filteredWords;
|
ConcurrentHashSet<string> filteredWords;
|
||||||
ServerFilteredWords.TryGetValue(channel.Guild.Id, out filteredWords);
|
serverFilteredWords.TryGetValue(channel.Guild.Id, out filteredWords);
|
||||||
|
|
||||||
await channel.SendConfirmAsync($"List of filtered words", string.Join("\n", filteredWords))
|
await channel.SendConfirmAsync(GetText("filter_word_list"), string.Join("\n", filteredWords))
|
||||||
.ConfigureAwait(false);
|
.ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,118 @@
|
|||||||
|
using Discord;
|
||||||
|
using Discord.Commands;
|
||||||
|
using NadekoBot.Attributes;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NadekoBot.Extensions;
|
||||||
|
using NadekoBot.Services;
|
||||||
|
using NadekoBot.Services.Database;
|
||||||
|
using NadekoBot.TypeReaders;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace NadekoBot.Modules.Permissions
|
||||||
|
{
|
||||||
|
public partial class Permissions
|
||||||
|
{
|
||||||
|
[Group]
|
||||||
|
public class GlobalPermissionCommands : NadekoSubmodule
|
||||||
|
{
|
||||||
|
public static readonly ConcurrentHashSet<string> BlockedModules;
|
||||||
|
public static readonly ConcurrentHashSet<string> BlockedCommands;
|
||||||
|
|
||||||
|
static GlobalPermissionCommands()
|
||||||
|
{
|
||||||
|
BlockedModules = new ConcurrentHashSet<string>(NadekoBot.BotConfig.BlockedModules.Select(x => x.Name));
|
||||||
|
BlockedCommands = new ConcurrentHashSet<string>(NadekoBot.BotConfig.BlockedCommands.Select(x => x.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task Lgp()
|
||||||
|
{
|
||||||
|
if (!BlockedModules.Any() && !BlockedCommands.Any())
|
||||||
|
{
|
||||||
|
await ReplyErrorLocalized("lgp_none").ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var embed = new EmbedBuilder().WithOkColor();
|
||||||
|
|
||||||
|
if (BlockedModules.Any())
|
||||||
|
embed.AddField(efb => efb.WithName(GetText("blocked_modules")).WithValue(string.Join("\n", BlockedModules)).WithIsInline(false));
|
||||||
|
|
||||||
|
if (BlockedCommands.Any())
|
||||||
|
embed.AddField(efb => efb.WithName(GetText("blocked_commands")).WithValue(string.Join("\n", BlockedCommands)).WithIsInline(false));
|
||||||
|
|
||||||
|
await Context.Channel.EmbedAsync(embed).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task Gmod(ModuleOrCrInfo module)
|
||||||
|
{
|
||||||
|
var moduleName = module.Name.ToLowerInvariant();
|
||||||
|
if (BlockedModules.Add(moduleName))
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var bc = uow.BotConfig.GetOrCreate();
|
||||||
|
bc.BlockedModules.Add(new Services.Database.Models.BlockedCmdOrMdl
|
||||||
|
{
|
||||||
|
Name = moduleName,
|
||||||
|
});
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
await ReplyConfirmLocalized("gmod_add", Format.Bold(module.Name)).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (BlockedModules.TryRemove(moduleName))
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var bc = uow.BotConfig.GetOrCreate();
|
||||||
|
bc.BlockedModules.RemoveWhere(x => x.Name == moduleName);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
await ReplyConfirmLocalized("gmod_remove", Format.Bold(module.Name)).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
|
[OwnerOnly]
|
||||||
|
public async Task Gcmd(CommandOrCrInfo cmd)
|
||||||
|
{
|
||||||
|
var commandName = cmd.Name.ToLowerInvariant();
|
||||||
|
if (BlockedCommands.Add(commandName))
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var bc = uow.BotConfig.GetOrCreate();
|
||||||
|
bc.BlockedCommands.Add(new Services.Database.Models.BlockedCmdOrMdl
|
||||||
|
{
|
||||||
|
Name = commandName,
|
||||||
|
});
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
await ReplyConfirmLocalized("gcmd_add", Format.Bold(cmd.Name)).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (BlockedCommands.TryRemove(commandName))
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var bc = uow.BotConfig.GetOrCreate();
|
||||||
|
bc.BlockedCommands.RemoveWhere(x => x.Name == commandName);
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
await ReplyConfirmLocalized("gcmd_remove", Format.Bold(cmd.Name)).ConfigureAwait(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -10,25 +10,12 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
public static class PermissionExtensions
|
public static class PermissionExtensions
|
||||||
{
|
{
|
||||||
public static bool CheckPermissions(this IEnumerable<Permission> permsEnumerable, IUserMessage message, CommandInfo command)
|
public static bool CheckPermissions(this IEnumerable<Permissionv2> permsEnumerable, IUserMessage message,
|
||||||
|
string commandName, string moduleName, out int permIndex)
|
||||||
{
|
{
|
||||||
var perms = permsEnumerable as List<Permission> ?? permsEnumerable.ToList();
|
var perms = permsEnumerable as List<Permissionv2> ?? permsEnumerable.ToList();
|
||||||
int throwaway;
|
|
||||||
return perms.CheckPermissions(message, command.Name, command.Module.Name, out throwaway);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CheckPermissions(this IEnumerable<Permission> permsEnumerable, IUserMessage message, string commandName, string moduleName)
|
for (int i = perms.Count - 1; i >= 0; i--)
|
||||||
{
|
|
||||||
var perms = permsEnumerable as List<Permission> ?? permsEnumerable.ToList();
|
|
||||||
int throwaway;
|
|
||||||
return perms.CheckPermissions(message, commandName, moduleName, out throwaway);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool CheckPermissions(this IEnumerable<Permission> permsEnumerable, IUserMessage message, string commandName, string moduleName, out int permIndex)
|
|
||||||
{
|
|
||||||
var perms = permsEnumerable as List<Permission> ?? permsEnumerable.ToList();
|
|
||||||
|
|
||||||
for (int i = 0; i < perms.Count; i++)
|
|
||||||
{
|
{
|
||||||
var perm = perms[i];
|
var perm = perms[i];
|
||||||
|
|
||||||
@ -38,12 +25,9 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
permIndex = i;
|
permIndex = i;
|
||||||
return result.Value;
|
return result.Value;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
permIndex = -1; //defaut behaviour
|
permIndex = -1; //defaut behaviour
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -51,7 +35,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
//null = not applicable
|
//null = not applicable
|
||||||
//true = applicable, allowed
|
//true = applicable, allowed
|
||||||
//false = applicable, not allowed
|
//false = applicable, not allowed
|
||||||
public static bool? CheckPermission(this Permission perm, IUserMessage message, string commandName, string moduleName)
|
public static bool? CheckPermission(this Permissionv2 perm, IUserMessage message, string commandName, string moduleName)
|
||||||
{
|
{
|
||||||
if (!((perm.SecondaryTarget == SecondaryPermissionType.Command &&
|
if (!((perm.SecondaryTarget == SecondaryPermissionType.Command &&
|
||||||
perm.SecondaryTargetName.ToLowerInvariant() == commandName.ToLowerInvariant()) ||
|
perm.SecondaryTargetName.ToLowerInvariant() == commandName.ToLowerInvariant()) ||
|
||||||
@ -86,7 +70,7 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetCommand(this Permission perm, SocketGuild guild = null)
|
public static string GetCommand(this Permissionv2 perm, SocketGuild guild = null)
|
||||||
{
|
{
|
||||||
var com = "";
|
var com = "";
|
||||||
switch (perm.PrimaryTarget)
|
switch (perm.PrimaryTarget)
|
||||||
@ -122,19 +106,13 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
switch (perm.PrimaryTarget)
|
switch (perm.PrimaryTarget)
|
||||||
{
|
{
|
||||||
case PrimaryPermissionType.User:
|
case PrimaryPermissionType.User:
|
||||||
if (guild == null)
|
com += guild?.GetUser(perm.PrimaryTargetId)?.ToString() ?? $"<@{perm.PrimaryTargetId}>";
|
||||||
com += $"<@{perm.PrimaryTargetId}>";
|
|
||||||
else
|
|
||||||
com += guild.GetUser(perm.PrimaryTargetId).ToString() ?? $"<@{perm.PrimaryTargetId}>";
|
|
||||||
break;
|
break;
|
||||||
case PrimaryPermissionType.Channel:
|
case PrimaryPermissionType.Channel:
|
||||||
com += $"<#{perm.PrimaryTargetId}>";
|
com += $"<#{perm.PrimaryTargetId}>";
|
||||||
break;
|
break;
|
||||||
case PrimaryPermissionType.Role:
|
case PrimaryPermissionType.Role:
|
||||||
if(guild == null)
|
com += guild?.GetRole(perm.PrimaryTargetId)?.ToString() ?? $"<@&{perm.PrimaryTargetId}>";
|
||||||
com += $"<@&{perm.PrimaryTargetId}>";
|
|
||||||
else
|
|
||||||
com += guild.GetRole(perm.PrimaryTargetId).ToString() ?? $"<@{perm.PrimaryTargetId}>";
|
|
||||||
break;
|
break;
|
||||||
case PrimaryPermissionType.Server:
|
case PrimaryPermissionType.Server:
|
||||||
break;
|
break;
|
||||||
@ -143,98 +121,10 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
return NadekoBot.ModulePrefixes[typeof(Permissions).Name] + com;
|
return NadekoBot.ModulePrefixes[typeof(Permissions).Name] + com;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Prepend(this Permission perm, Permission toAdd)
|
|
||||||
{
|
|
||||||
perm = perm.GetRoot();
|
|
||||||
|
|
||||||
perm.Previous = toAdd;
|
|
||||||
toAdd.Next = perm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* /this can't work if index < 0 and perm isn't roo
|
|
||||||
public static void Insert(this Permission perm, int index, Permission toAdd)
|
|
||||||
{
|
|
||||||
if (index < 0)
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
|
|
||||||
if (index == 0)
|
|
||||||
{
|
|
||||||
perm.Prepend(toAdd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var atIndex = perm;
|
|
||||||
var i = 0;
|
|
||||||
while (i != index)
|
|
||||||
{
|
|
||||||
atIndex = atIndex.Next;
|
|
||||||
i++;
|
|
||||||
if (atIndex == null)
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
}
|
|
||||||
var previous = atIndex.Previous;
|
|
||||||
|
|
||||||
//connect right side
|
|
||||||
atIndex.Previous = toAdd;
|
|
||||||
toAdd.Next = atIndex;
|
|
||||||
|
|
||||||
//connect left side
|
|
||||||
toAdd.Previous = previous;
|
|
||||||
previous.Next = toAdd;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public static Permission RemoveAt(this Permission perm, int index)
|
|
||||||
{
|
|
||||||
if (index <= 0) //can't really remove at 0, that means deleting the element right now. Just use perm.Next if its 0
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
|
|
||||||
var toRemove = perm;
|
|
||||||
var i = 0;
|
|
||||||
while (i != index)
|
|
||||||
{
|
|
||||||
toRemove = toRemove.Next;
|
|
||||||
i++;
|
|
||||||
if (toRemove == null)
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
}
|
|
||||||
|
|
||||||
toRemove.Previous.Next = toRemove.Next;
|
|
||||||
if (toRemove.Next != null)
|
|
||||||
toRemove.Next.Previous = toRemove.Previous;
|
|
||||||
return toRemove;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Permission GetAt(this Permission perm, int index)
|
|
||||||
{
|
|
||||||
if (index < 0)
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
var temp = perm;
|
|
||||||
while (index > 0) { temp = temp?.Next; index--; }
|
|
||||||
if (temp == null)
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
return temp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int Count(this Permission perm)
|
|
||||||
{
|
|
||||||
var i = 1;
|
|
||||||
var temp = perm;
|
|
||||||
while ((temp = temp.Next) != null) { i++; }
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IEnumerable<Permission> AsEnumerable(this Permission perm)
|
public static IEnumerable<Permission> AsEnumerable(this Permission perm)
|
||||||
{
|
{
|
||||||
do yield return perm;
|
do yield return perm;
|
||||||
while ((perm = perm.Next) != null);
|
while ((perm = perm.Next) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Permission GetRoot(this Permission perm)
|
|
||||||
{
|
|
||||||
Permission toReturn;
|
|
||||||
do toReturn = perm;
|
|
||||||
while ((perm = perm.Previous) != null);
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,46 +7,170 @@ using NadekoBot.Services;
|
|||||||
using Discord;
|
using Discord;
|
||||||
using NadekoBot.Services.Database.Models;
|
using NadekoBot.Services.Database.Models;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using NadekoBot.Extensions;
|
using System.Collections.Generic;
|
||||||
using Discord.WebSocket;
|
using Discord.WebSocket;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using NadekoBot.DataStructures;
|
||||||
|
using NadekoBot.TypeReaders;
|
||||||
using NLog;
|
using NLog;
|
||||||
|
|
||||||
namespace NadekoBot.Modules.Permissions
|
namespace NadekoBot.Modules.Permissions
|
||||||
{
|
{
|
||||||
[NadekoModule("Permissions", ";")]
|
[NadekoModule("Permissions", ";")]
|
||||||
public partial class Permissions : NadekoModule
|
public partial class Permissions : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
public class PermissionCache
|
public class OldPermissionCache
|
||||||
{
|
{
|
||||||
public string PermRole { get; set; }
|
public string PermRole { get; set; }
|
||||||
public bool Verbose { get; set; } = true;
|
public bool Verbose { get; set; } = true;
|
||||||
public Permission RootPermission { get; set; }
|
public Permission RootPermission { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PermissionCache
|
||||||
|
{
|
||||||
|
public string PermRole { get; set; }
|
||||||
|
public bool Verbose { get; set; } = true;
|
||||||
|
public PermissionsCollection<Permissionv2> Permissions { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
//guildid, root permission
|
//guildid, root permission
|
||||||
public static ConcurrentDictionary<ulong, PermissionCache> Cache { get; }
|
public static ConcurrentDictionary<ulong, PermissionCache> Cache { get; } =
|
||||||
|
new ConcurrentDictionary<ulong, PermissionCache>();
|
||||||
|
|
||||||
static Permissions()
|
static Permissions()
|
||||||
{
|
{
|
||||||
var _log = LogManager.GetCurrentClassLogger();
|
var log = LogManager.GetCurrentClassLogger();
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
|
TryMigratePermissions();
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
Cache = new ConcurrentDictionary<ulong, PermissionCache>(uow.GuildConfigs
|
foreach (var x in uow.GuildConfigs.Permissionsv2ForAll())
|
||||||
.PermissionsForAll()
|
{
|
||||||
|
Cache.TryAdd(x.GuildId, new PermissionCache()
|
||||||
|
{
|
||||||
|
Verbose = x.VerbosePermissions,
|
||||||
|
PermRole = x.PermissionRole,
|
||||||
|
Permissions = new PermissionsCollection<Permissionv2>(x.Permissions)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sw.Stop();
|
||||||
|
log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PermissionCache GetCache(ulong guildId)
|
||||||
|
{
|
||||||
|
PermissionCache pc;
|
||||||
|
if (!Permissions.Cache.TryGetValue(guildId, out pc))
|
||||||
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.For(guildId,
|
||||||
|
set => set.Include(x => x.Permissions));
|
||||||
|
Permissions.UpdateCache(config);
|
||||||
|
}
|
||||||
|
Permissions.Cache.TryGetValue(guildId, out pc);
|
||||||
|
if (pc == null)
|
||||||
|
throw new Exception("Cache is null.");
|
||||||
|
}
|
||||||
|
return pc;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void TryMigratePermissions()
|
||||||
|
{
|
||||||
|
var log = LogManager.GetCurrentClassLogger();
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var oldCache = new ConcurrentDictionary<ulong, OldPermissionCache>(uow.GuildConfigs
|
||||||
|
.OldPermissionsForAll()
|
||||||
|
.Where(x => x.RootPermission != null) // there is a check inside already, but just in case
|
||||||
.ToDictionary(k => k.GuildId,
|
.ToDictionary(k => k.GuildId,
|
||||||
v => new PermissionCache()
|
v => new OldPermissionCache()
|
||||||
{
|
{
|
||||||
RootPermission = v.RootPermission,
|
RootPermission = v.RootPermission,
|
||||||
Verbose = v.VerbosePermissions,
|
Verbose = v.VerbosePermissions,
|
||||||
PermRole = v.PermissionRole
|
PermRole = v.PermissionRole
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (oldCache.Any())
|
||||||
|
{
|
||||||
|
log.Info("Old permissions found. Performing one-time migration to v2.");
|
||||||
|
var i = 0;
|
||||||
|
foreach (var oc in oldCache)
|
||||||
|
{
|
||||||
|
if (i % 3 == 0)
|
||||||
|
log.Info("Migrating Permissions #" + i + " - GuildId: " + oc.Key);
|
||||||
|
i++;
|
||||||
|
var gc = uow.GuildConfigs.GcWithPermissionsv2For(oc.Key);
|
||||||
|
|
||||||
|
var oldPerms = oc.Value.RootPermission.AsEnumerable().Reverse().ToList();
|
||||||
|
uow._context.Set<Permission>().RemoveRange(oldPerms);
|
||||||
|
gc.RootPermission = null;
|
||||||
|
if (oldPerms.Count > 2)
|
||||||
|
{
|
||||||
|
|
||||||
|
var newPerms = oldPerms.Take(oldPerms.Count - 1)
|
||||||
|
.Select(x => x.Tov2())
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
var allowPerm = Permissionv2.AllowAllPerm;
|
||||||
|
var firstPerm = newPerms[0];
|
||||||
|
if (allowPerm.State != firstPerm.State ||
|
||||||
|
allowPerm.PrimaryTarget != firstPerm.PrimaryTarget ||
|
||||||
|
allowPerm.SecondaryTarget != firstPerm.SecondaryTarget ||
|
||||||
|
allowPerm.PrimaryTargetId != firstPerm.PrimaryTargetId ||
|
||||||
|
allowPerm.SecondaryTargetName != firstPerm.SecondaryTargetName)
|
||||||
|
newPerms.Insert(0, Permissionv2.AllowAllPerm);
|
||||||
|
Cache.TryAdd(oc.Key, new PermissionCache
|
||||||
|
{
|
||||||
|
Permissions = new PermissionsCollection<Permissionv2>(newPerms),
|
||||||
|
Verbose = gc.VerbosePermissions,
|
||||||
|
PermRole = gc.PermissionRole,
|
||||||
|
});
|
||||||
|
gc.Permissions = newPerms;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log.Info("Permission migration to v2 is done.");
|
||||||
|
uow.Complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sw.Stop();
|
private static async Task AddPermissions(ulong guildId, params Permissionv2[] perms)
|
||||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
{
|
||||||
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
|
{
|
||||||
|
var config = uow.GuildConfigs.GcWithPermissionsv2For(guildId);
|
||||||
|
//var orderedPerms = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||||
|
var max = config.Permissions.Max(x => x.Index); //have to set its index to be the highest
|
||||||
|
foreach (var perm in perms)
|
||||||
|
{
|
||||||
|
perm.Index = ++max;
|
||||||
|
config.Permissions.Add(perm);
|
||||||
|
}
|
||||||
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
UpdateCache(config);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void UpdateCache(GuildConfig config)
|
||||||
|
{
|
||||||
|
Cache.AddOrUpdate(config.GuildId, new PermissionCache()
|
||||||
|
{
|
||||||
|
Permissions = new PermissionsCollection<Permissionv2>(config.Permissions),
|
||||||
|
PermRole = config.PermissionRole,
|
||||||
|
Verbose = config.VerbosePermissions
|
||||||
|
}, (id, old) =>
|
||||||
|
{
|
||||||
|
old.Permissions = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||||
|
old.PermRole = config.PermissionRole;
|
||||||
|
old.Verbose = config.VerbosePermissions;
|
||||||
|
return old;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -55,18 +179,19 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||||
config.VerbosePermissions = action.Value;
|
config.VerbosePermissions = action.Value;
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
|
||||||
{
|
|
||||||
PermRole = config.PermissionRole,
|
|
||||||
RootPermission = Permission.GetDefaultRoot(),
|
|
||||||
Verbose = config.VerbosePermissions
|
|
||||||
}, (id, old) => { old.Verbose = config.VerbosePermissions; return old; });
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
UpdateCache(config);
|
||||||
|
}
|
||||||
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("verbose_true").ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("verbose_false").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync("ℹ️ I will " + (action.Value ? "now" : "no longer") + " show permission warnings.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -78,40 +203,52 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.For(Context.Guild.Id, set => set);
|
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||||
if (role == null)
|
if (role == null)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendConfirmAsync($"ℹ️ Current permission role is **{config.PermissionRole}**.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("permrole", Format.Bold(config.PermissionRole)).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
config.PermissionRole = role.Name.Trim();
|
config.PermissionRole = role.Name.Trim();
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
|
||||||
{
|
|
||||||
PermRole = config.PermissionRole,
|
|
||||||
RootPermission = Permission.GetDefaultRoot(),
|
|
||||||
Verbose = config.VerbosePermissions
|
|
||||||
}, (id, old) => { old.PermRole = role.Name.Trim(); return old; });
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
}
|
UpdateCache(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"Users now require **{role.Name}** role in order to edit permissions.").ConfigureAwait(false);
|
await ReplyConfirmLocalized("permrole_changed", Format.Bold(role.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ListPerms(int page = 1)
|
public async Task ListPerms(int page = 1)
|
||||||
{
|
{
|
||||||
if (page < 1 || page > 4)
|
if (page < 1)
|
||||||
return;
|
return;
|
||||||
string toSend = "";
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
PermissionCache permCache;
|
||||||
|
IList<Permissionv2> perms;
|
||||||
|
|
||||||
|
if (Cache.TryGetValue(Context.Guild.Id, out permCache))
|
||||||
{
|
{
|
||||||
var perms = uow.GuildConfigs.PermissionsFor(Context.Guild.Id).RootPermission;
|
perms = permCache.Permissions.Source.ToList();
|
||||||
var i = 1 + 20 * (page - 1);
|
|
||||||
toSend = Format.Code($"📄 Permissions page {page}") + "\n\n" + String.Join("\n", perms.AsEnumerable().Skip((page - 1) * 20).Take(20).Select(p => $"`{(i++)}.` {(p.Next == null ? Format.Bold(p.GetCommand((SocketGuild)Context.Guild) + " [uneditable]") : (p.GetCommand((SocketGuild)Context.Guild)))}"));
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
perms = Permissionv2.GetDefaultPermlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
var startPos = 20 * (page - 1);
|
||||||
|
var toSend = Format.Bold(GetText("page", page)) + "\n\n" + string.Join("\n",
|
||||||
|
perms.Reverse()
|
||||||
|
.Skip(startPos)
|
||||||
|
.Take(20)
|
||||||
|
.Select(p =>
|
||||||
|
{
|
||||||
|
var str =
|
||||||
|
$"`{p.Index + 1}.` {Format.Bold(p.GetCommand((SocketGuild) Context.Guild))}";
|
||||||
|
if (p.Index == 0)
|
||||||
|
str += $" [{GetText("uneditable")}]";
|
||||||
|
return str;
|
||||||
|
}));
|
||||||
|
|
||||||
await Context.Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
await Context.Channel.SendMessageAsync(toSend).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
@ -121,46 +258,28 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
public async Task RemovePerm(int index)
|
public async Task RemovePerm(int index)
|
||||||
{
|
{
|
||||||
index -= 1;
|
index -= 1;
|
||||||
|
if (index < 0)
|
||||||
|
return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Permission p;
|
Permissionv2 p;
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.PermissionsFor(Context.Guild.Id);
|
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||||
var perms = config.RootPermission;
|
var permsCol = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||||
if (index == perms.Count() - 1)
|
p = permsCol[index];
|
||||||
{
|
permsCol.RemoveAt(index);
|
||||||
return;
|
uow._context.Remove(p);
|
||||||
}
|
|
||||||
else if (index == 0)
|
|
||||||
{
|
|
||||||
p = perms;
|
|
||||||
config.RootPermission = perms.Next;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
p = perms.RemoveAt(index);
|
|
||||||
}
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
|
||||||
{
|
|
||||||
PermRole = config.PermissionRole,
|
|
||||||
RootPermission = config.RootPermission,
|
|
||||||
Verbose = config.VerbosePermissions
|
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
|
UpdateCache(config);
|
||||||
}
|
}
|
||||||
|
await ReplyConfirmLocalized("removed",
|
||||||
using (var uow2 = DbHandler.UnitOfWork())
|
index + 1,
|
||||||
|
Format.Code(p.GetCommand((SocketGuild) Context.Guild))).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
catch (IndexOutOfRangeException)
|
||||||
{
|
{
|
||||||
uow2._context.Remove<Permission>(p);
|
await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false);
|
||||||
uow2._context.SaveChanges();
|
|
||||||
}
|
|
||||||
|
|
||||||
await Context.Channel.SendConfirmAsync($"✅ {Context.User.Mention} removed permission **{p.GetCommand((SocketGuild)Context.Guild)}** from position #{index + 1}.").ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
catch (ArgumentOutOfRangeException)
|
|
||||||
{
|
|
||||||
await Context.Channel.SendErrorAsync("❗️`No command on that index found.`").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,350 +293,305 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Permission fromPerm = null;
|
Permissionv2 fromPerm;
|
||||||
Permission toPerm = null;
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
using (var uow = DbHandler.UnitOfWork())
|
||||||
{
|
{
|
||||||
var config = uow.GuildConfigs.PermissionsFor(Context.Guild.Id);
|
var config = uow.GuildConfigs.GcWithPermissionsv2For(Context.Guild.Id);
|
||||||
var perms = config.RootPermission;
|
var permsCol = new PermissionsCollection<Permissionv2>(config.Permissions);
|
||||||
var root = perms;
|
|
||||||
var index = 0;
|
var fromFound = from < permsCol.Count;
|
||||||
var fromFound = false;
|
var toFound = to < permsCol.Count;
|
||||||
var toFound = false;
|
|
||||||
while ((!toFound || !fromFound) && perms != null)
|
|
||||||
{
|
|
||||||
if (index == from)
|
|
||||||
{
|
|
||||||
fromPerm = perms;
|
|
||||||
fromFound = true;
|
|
||||||
}
|
|
||||||
if (index == to)
|
|
||||||
{
|
|
||||||
toPerm = perms;
|
|
||||||
toFound = true;
|
|
||||||
}
|
|
||||||
if (!toFound)
|
|
||||||
{
|
|
||||||
toPerm = perms; //In case of to > size
|
|
||||||
}
|
|
||||||
perms = perms.Next;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
if (perms == null)
|
|
||||||
{
|
|
||||||
if (!fromFound)
|
if (!fromFound)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"Can't find permission at index `#{++from}`").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found", ++from).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!toFound)
|
if (!toFound)
|
||||||
{
|
{
|
||||||
await Context.Channel.SendErrorAsync($"Can't find permission at index `#{++to}`").ConfigureAwait(false);
|
await ReplyErrorLocalized("not_found", ++to).ConfigureAwait(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
fromPerm = permsCol[from];
|
||||||
|
|
||||||
//Change chain for from indx
|
permsCol.RemoveAt(from);
|
||||||
var next = fromPerm.Next;
|
permsCol.Insert(to, fromPerm);
|
||||||
var pre = fromPerm.Previous;
|
|
||||||
if (pre != null)
|
|
||||||
pre.Next = next;
|
|
||||||
if (fromPerm.Next == null || toPerm.Next == null)
|
|
||||||
{
|
|
||||||
throw new IndexOutOfRangeException();
|
|
||||||
}
|
|
||||||
next.Previous = pre;
|
|
||||||
if (from == 0)
|
|
||||||
{
|
|
||||||
root = next;
|
|
||||||
}
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await uow.CompleteAsync().ConfigureAwait(false);
|
||||||
//Inserting
|
UpdateCache(config);
|
||||||
if (to > from)
|
|
||||||
{
|
|
||||||
fromPerm.Previous = toPerm;
|
|
||||||
fromPerm.Next = toPerm.Next;
|
|
||||||
|
|
||||||
toPerm.Next.Previous = fromPerm;
|
|
||||||
toPerm.Next = fromPerm;
|
|
||||||
}
|
}
|
||||||
else
|
await ReplyConfirmLocalized("moved_permission",
|
||||||
{
|
Format.Code(fromPerm.GetCommand((SocketGuild) Context.Guild)),
|
||||||
pre = toPerm.Previous;
|
++from,
|
||||||
|
++to)
|
||||||
fromPerm.Next = toPerm;
|
.ConfigureAwait(false);
|
||||||
fromPerm.Previous = pre;
|
|
||||||
|
|
||||||
toPerm.Previous = fromPerm;
|
|
||||||
if (pre != null)
|
|
||||||
pre.Next = fromPerm;
|
|
||||||
}
|
|
||||||
|
|
||||||
config.RootPermission = fromPerm.GetRoot();
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
|
||||||
{
|
|
||||||
PermRole = config.PermissionRole,
|
|
||||||
RootPermission = config.RootPermission,
|
|
||||||
Verbose = config.VerbosePermissions
|
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
await Context.Channel.SendConfirmAsync($"`Moved permission:` \"{fromPerm.GetCommand((SocketGuild)Context.Guild)}\" `from #{++from} to #{++to}.`").ConfigureAwait(false);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (Exception e) when (e is ArgumentOutOfRangeException || e is IndexOutOfRangeException)
|
catch (Exception e) when (e is ArgumentOutOfRangeException || e is IndexOutOfRangeException)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Context.Channel.SendErrorAsync("`Invalid index(es) specified.`").ConfigureAwait(false);
|
await ReplyErrorLocalized("perm_out_of_range").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task SrvrCmd(CommandInfo command, PermissionAction action)
|
public async Task SrvrCmd(CommandOrCrInfo command, PermissionAction action)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Server,
|
PrimaryTarget = PrimaryPermissionType.Server,
|
||||||
PrimaryTargetId = 0,
|
PrimaryTargetId = 0,
|
||||||
SecondaryTarget = SecondaryPermissionType.Command,
|
SecondaryTarget = SecondaryPermissionType.Command,
|
||||||
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(),
|
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
|
||||||
{
|
|
||||||
PermRole = config.PermissionRole,
|
|
||||||
RootPermission = config.RootPermission,
|
|
||||||
Verbose = config.VerbosePermissions
|
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
|
||||||
|
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
if (action.Value)
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("sx_enable",
|
||||||
|
Format.Code(command.Name),
|
||||||
|
GetText("of_command")).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("sx_disable",
|
||||||
|
Format.Code(command.Name),
|
||||||
|
GetText("of_command")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command on this server.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task SrvrMdl(ModuleInfo module, PermissionAction action)
|
public async Task SrvrMdl(ModuleOrCrInfo module, PermissionAction action)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Server,
|
PrimaryTarget = PrimaryPermissionType.Server,
|
||||||
PrimaryTargetId = 0,
|
PrimaryTargetId = 0,
|
||||||
SecondaryTarget = SecondaryPermissionType.Module,
|
SecondaryTarget = SecondaryPermissionType.Module,
|
||||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("sx_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(module.Name),
|
||||||
Verbose = config.VerbosePermissions
|
GetText("of_module")).ConfigureAwait(false);
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
}
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("sx_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module")).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of **`{module.Name}`** module on this server.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task UsrCmd(CommandInfo command, PermissionAction action, [Remainder] IGuildUser user)
|
public async Task UsrCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IGuildUser user)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.User,
|
PrimaryTarget = PrimaryPermissionType.User,
|
||||||
PrimaryTargetId = user.Id,
|
PrimaryTargetId = user.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.Command,
|
SecondaryTarget = SecondaryPermissionType.Command,
|
||||||
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(),
|
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("ux_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(command.Name),
|
||||||
Verbose = config.VerbosePermissions
|
GetText("of_command"),
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("ux_disable",
|
||||||
|
Format.Code(command.Name),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{user}` user.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task UsrMdl(ModuleInfo module, PermissionAction action, [Remainder] IGuildUser user)
|
public async Task UsrMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] IGuildUser user)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.User,
|
PrimaryTarget = PrimaryPermissionType.User,
|
||||||
PrimaryTargetId = user.Id,
|
PrimaryTargetId = user.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.Module,
|
SecondaryTarget = SecondaryPermissionType.Module,
|
||||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("ux_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(module.Name),
|
||||||
Verbose = config.VerbosePermissions
|
GetText("of_module"),
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("ux_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{user}` user.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task RoleCmd(CommandInfo command, PermissionAction action, [Remainder] IRole role)
|
public async Task RoleCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] IRole role)
|
||||||
{
|
{
|
||||||
if (role == role.Guild.EveryoneRole)
|
if (role == role.Guild.EveryoneRole)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Role,
|
PrimaryTarget = PrimaryPermissionType.Role,
|
||||||
PrimaryTargetId = role.Id,
|
PrimaryTargetId = role.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.Command,
|
SecondaryTarget = SecondaryPermissionType.Command,
|
||||||
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(),
|
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("rx_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(command.Name),
|
||||||
Verbose = config.VerbosePermissions
|
GetText("of_command"),
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("rx_disable",
|
||||||
|
Format.Code(command.Name),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{role}` role.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task RoleMdl(ModuleInfo module, PermissionAction action, [Remainder] IRole role)
|
public async Task RoleMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] IRole role)
|
||||||
{
|
{
|
||||||
if (role == role.Guild.EveryoneRole)
|
if (role == role.Guild.EveryoneRole)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Role,
|
PrimaryTarget = PrimaryPermissionType.Role,
|
||||||
PrimaryTargetId = role.Id,
|
PrimaryTargetId = role.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.Module,
|
SecondaryTarget = SecondaryPermissionType.Module,
|
||||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
|
||||||
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("rx_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(module.Name),
|
||||||
Verbose = config.VerbosePermissions
|
GetText("of_module"),
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("rx_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{role}` role.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ChnlCmd(CommandInfo command, PermissionAction action, [Remainder] ITextChannel chnl)
|
public async Task ChnlCmd(CommandOrCrInfo command, PermissionAction action, [Remainder] ITextChannel chnl)
|
||||||
{
|
{
|
||||||
try
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Channel,
|
PrimaryTarget = PrimaryPermissionType.Channel,
|
||||||
PrimaryTargetId = chnl.Id,
|
PrimaryTargetId = chnl.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.Command,
|
SecondaryTarget = SecondaryPermissionType.Command,
|
||||||
SecondaryTargetName = command.Aliases.First().ToLowerInvariant(),
|
SecondaryTargetName = command.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("cx_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(command.Name),
|
||||||
Verbose = config.VerbosePermissions
|
GetText("of_command"),
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("cx_disable",
|
||||||
|
Format.Code(command.Name),
|
||||||
|
GetText("of_command"),
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
|
||||||
_log.Error(ex);
|
|
||||||
}
|
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{command.Aliases.First()}` command for `{chnl}` channel.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task ChnlMdl(ModuleInfo module, PermissionAction action, [Remainder] ITextChannel chnl)
|
public async Task ChnlMdl(ModuleOrCrInfo module, PermissionAction action, [Remainder] ITextChannel chnl)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Channel,
|
PrimaryTarget = PrimaryPermissionType.Channel,
|
||||||
PrimaryTargetId = chnl.Id,
|
PrimaryTargetId = chnl.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.Module,
|
SecondaryTarget = SecondaryPermissionType.Module,
|
||||||
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
SecondaryTargetName = module.Name.ToLowerInvariant(),
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("cx_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(module.Name),
|
||||||
Verbose = config.VerbosePermissions
|
GetText("of_module"),
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await ReplyConfirmLocalized("cx_disable",
|
||||||
|
Format.Code(module.Name),
|
||||||
|
GetText("of_module"),
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `{module.Name}` module for `{chnl}` channel.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task AllChnlMdls(PermissionAction action, [Remainder] ITextChannel chnl)
|
public async Task AllChnlMdls(PermissionAction action, [Remainder] ITextChannel chnl)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Channel,
|
PrimaryTarget = PrimaryPermissionType.Channel,
|
||||||
PrimaryTargetId = chnl.Id,
|
PrimaryTargetId = chnl.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||||
SecondaryTargetName = "*",
|
SecondaryTargetName = "*",
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("acm_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
Verbose = config.VerbosePermissions
|
}
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
else
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("acm_disable",
|
||||||
|
Format.Code(chnl.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{chnl}` channel.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
@ -527,61 +601,57 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
if (role == role.Guild.EveryoneRole)
|
if (role == role.Guild.EveryoneRole)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Role,
|
PrimaryTarget = PrimaryPermissionType.Role,
|
||||||
PrimaryTargetId = role.Id,
|
PrimaryTargetId = role.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||||
SecondaryTargetName = "*",
|
SecondaryTargetName = "*",
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("arm_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
Verbose = config.VerbosePermissions
|
}
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
else
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("arm_disable",
|
||||||
|
Format.Code(role.Name)).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{role}` role.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task AllUsrMdls(PermissionAction action, [Remainder] IUser user)
|
public async Task AllUsrMdls(PermissionAction action, [Remainder] IUser user)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
await AddPermissions(Context.Guild.Id, new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.User,
|
PrimaryTarget = PrimaryPermissionType.User,
|
||||||
PrimaryTargetId = user.Id,
|
PrimaryTargetId = user.Id,
|
||||||
SecondaryTarget = SecondaryPermissionType.AllModules,
|
SecondaryTarget = SecondaryPermissionType.AllModules,
|
||||||
SecondaryTargetName = "*",
|
SecondaryTargetName = "*",
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
});
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("aum_enable",
|
||||||
RootPermission = config.RootPermission,
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
Verbose = config.VerbosePermissions
|
}
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
else
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
{
|
||||||
|
await ReplyConfirmLocalized("aum_disable",
|
||||||
|
Format.Code(user.ToString())).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` for `{user}` user.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[NadekoCommand, Usage, Description, Aliases]
|
[NadekoCommand, Usage, Description, Aliases]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
public async Task AllSrvrMdls(PermissionAction action)
|
public async Task AllSrvrMdls(PermissionAction action)
|
||||||
{
|
{
|
||||||
using (var uow = DbHandler.UnitOfWork())
|
var newPerm = new Permissionv2
|
||||||
{
|
|
||||||
var newPerm = new Permission
|
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.Server,
|
PrimaryTarget = PrimaryPermissionType.Server,
|
||||||
PrimaryTargetId = 0,
|
PrimaryTargetId = 0,
|
||||||
@ -589,9 +659,8 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
SecondaryTargetName = "*",
|
SecondaryTargetName = "*",
|
||||||
State = action.Value,
|
State = action.Value,
|
||||||
};
|
};
|
||||||
uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, newPerm);
|
|
||||||
|
|
||||||
var allowUser = new Permission
|
var allowUser = new Permissionv2
|
||||||
{
|
{
|
||||||
PrimaryTarget = PrimaryPermissionType.User,
|
PrimaryTarget = PrimaryPermissionType.User,
|
||||||
PrimaryTargetId = Context.User.Id,
|
PrimaryTargetId = Context.User.Id,
|
||||||
@ -600,16 +669,18 @@ namespace NadekoBot.Modules.Permissions
|
|||||||
State = true,
|
State = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
var config = uow.GuildConfigs.SetNewRootPermission(Context.Guild.Id, allowUser);
|
await AddPermissions(Context.Guild.Id,
|
||||||
Cache.AddOrUpdate(Context.Guild.Id, new PermissionCache()
|
newPerm,
|
||||||
|
allowUser);
|
||||||
|
|
||||||
|
if (action.Value)
|
||||||
{
|
{
|
||||||
PermRole = config.PermissionRole,
|
await ReplyConfirmLocalized("asm_enable").ConfigureAwait(false);
|
||||||
RootPermission = config.RootPermission,
|
}
|
||||||
Verbose = config.VerbosePermissions
|
else
|
||||||
}, (id, old) => { old.RootPermission = config.RootPermission; return old; });
|
{
|
||||||
await uow.CompleteAsync().ConfigureAwait(false);
|
await ReplyConfirmLocalized("asm_disable").ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
await Context.Channel.SendConfirmAsync($"{(action.Value ? "✅ Allowed" : "🆗 Denied")} usage of `ALL MODULES` on this server.").ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,7 +16,7 @@ using System.Collections.Concurrent;
|
|||||||
namespace NadekoBot.Modules.Pokemon
|
namespace NadekoBot.Modules.Pokemon
|
||||||
{
|
{
|
||||||
[NadekoModule("Pokemon", ">")]
|
[NadekoModule("Pokemon", ">")]
|
||||||
public class Pokemon : NadekoModule
|
public class Pokemon : NadekoTopLevelModule
|
||||||
{
|
{
|
||||||
private static readonly List<PokemonType> _pokemonTypes = new List<PokemonType>();
|
private static readonly List<PokemonType> _pokemonTypes = new List<PokemonType>();
|
||||||
private static readonly ConcurrentDictionary<ulong, PokeStats> _stats = new ConcurrentDictionary<ulong, PokeStats>();
|
private static readonly ConcurrentDictionary<ulong, PokeStats> _stats = new ConcurrentDictionary<ulong, PokeStats>();
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user