diff --git a/.gitignore b/.gitignore
index 67d693a9..1a4d6c6f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,85 @@
+#Manually added files
+
+src/NadekoBot/credentials.json
+src/NadekoBot/data/NadekoBot.db
+src/NadekoBot/data/musicdata
+
+# Created by https://www.gitignore.io/api/visualstudio,visualstudiocode,windows,linux,macos
+
+### VisualStudioCode ###
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+
+
+### Windows ###
+# Windows image file caches
+Thumbs.db
+ehthumbs.db
+
+# Folder config file
+Desktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+
+### macOS ###
+*.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### VisualStudio ###
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
@@ -6,26 +88,154 @@
*.user
*.userosscache
*.sln.docstates
-*.pfx
-obj/
+
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
-**/Bin/Release/
-**/Bin/PRIVATE/
-!**/Bin/Debug/opus.dll
-!**/Bin/Debug/libsodium.dll
-!**/Bin/Debug/Nito.AsyncEx.Enlightenment.dll
-!**/Bin/Debug/Nito.AsyncEx.dll
-!**/Bin/Debug/WebSocket4Net.dll
-!**/Bin/Debug/sqlite3.dll
-!**/Bin/Debug/credentials_example.json
-NadekoBot/bin/debug/*.*
-NadekoBot/bin/debug/data/permissions
-NadekoBot/bin/debug/data/incidents
-NadekoBot/bin/debug/data/musicdata
-NadekoBot/bin/NadekoRelease/*.*
-!NadekoBot/bin/Debug/data/currency_images/*
-Tests/bin
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+bld/
+[Bb]in/
+[Oo]bj/
+[Ll]og/
+
+# Visual Studio 2015 cache/options directory
+.vs/
+# Uncomment if you have tasks that create the project's static files in wwwroot
+#wwwroot/
+
+# MSTest test Results
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+
+# NUNIT
+*.VisualState.xml
+TestResult.xml
+
+# Build Results of an ATL Project
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+
+# DNX
+project.lock.json
+project.fragment.lock.json
+artifacts/
+
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+
+# Chutzpah Test files
+_Chutzpah*
+
+# Visual C++ cache files
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.VC.VC.opendb
+
+# Visual Studio profiler
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+# TFS 2012 Local Workspace
+$tf/
+
+# Guidance Automation Toolkit
+*.gpState
+
+# ReSharper is a .NET coding add-in
+_ReSharper*/
+*.[Rr]e[Ss]harper
+*.DotSettings.user
+
+# JustCode is a .NET coding add-in
+.JustCode
+
+# TeamCity is a build add-in
+_TeamCity*
+
+# DotCover is a Code Coverage Tool
+*.dotCover
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
+# NCrunch
+_NCrunch_*
+.*crunch*.local.xml
+nCrunchTemp_*
+
+# MightyMoose
+*.mm.*
+AutoTest.Net/
+
+# Web workbench (sass)
+.sass-cache/
+
+# Installshield output folder
+[Ee]xpress/
+
+# DocProject is a documentation generator add-in
+DocProject/buildhelp/
+DocProject/Help/*.HxT
+DocProject/Help/*.HxC
+DocProject/Help/*.hhc
+DocProject/Help/*.hhk
+DocProject/Help/*.hhp
+DocProject/Help/Html2
+DocProject/Help/html
+
+# Click-Once directory
+publish/
+
+# Publish Web Output
+*.[Pp]ublish.xml
+*.azurePubxml
+# TODO: Comment the next line if you want to checkin your web deploy settings
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
+*.publishproj
+
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
# NuGet Packages
*.nupkg
@@ -35,11 +245,109 @@ Tests/bin
!**/packages/build/
# Uncomment if necessary however generally it will be regenerated when needed
#!**/packages/repositories.config
-NadekoBot/bin/Debug/data/nadekobot.sqlite
-NadekoBot/bin/Debug/data/config.json
-NadekoBot/bin/Debug/data/ServerSpecificConfigs.json
-NadekoBot.sln.iml
-.idea/workspace.xml
-.idea/vcs.xml
-.idea/modules.xml
-NadekoBot/bin/Debug/data/config_xnaas.json
\ No newline at end of file
+# NuGet v3's project.json files produces more ignoreable files
+*.nuget.props
+*.nuget.targets
+
+# Microsoft Azure Build Output
+csx/
+*.build.csdef
+
+# Microsoft Azure Emulator
+ecf/
+rcf/
+
+# Windows Store app package directories and files
+AppPackages/
+BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+
+# Visual Studio cache files
+# files ending in .cache can be ignored
+*.[Cc]ache
+# but keep track of directories ending in .cache
+!*.[Cc]ache/
+
+# Others
+ClientBin/
+~$*
+*~
+*.dbmdl
+*.dbproj.schemaview
+*.jfm
+*.pfx
+*.publishsettings
+node_modules/
+orleans.codegen.cs
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
+# RIA/Silverlight projects
+Generated_Code/
+
+# Backup & report files from converting an old project file
+# to a newer Visual Studio version. Backup files are not needed,
+# because we have git ;-)
+_UpgradeReport_Files/
+Backup*/
+UpgradeLog*.XML
+UpgradeLog*.htm
+
+# SQL Server files
+*.mdf
+*.ldf
+
+# Business Intelligence projects
+*.rdl.data
+*.bim.layout
+*.bim_*.settings
+
+# Microsoft Fakes
+FakesAssemblies/
+
+# GhostDoc plugin setting file
+*.GhostDoc.xml
+
+# Node.js Tools for Visual Studio
+.ntvs_analysis.dat
+
+# Visual Studio 6 build log
+*.plg
+
+# Visual Studio 6 workspace options file
+*.opt
+
+# Visual Studio LightSwitch build output
+**/*.HTMLClient/GeneratedArtifacts
+**/*.DesktopClient/GeneratedArtifacts
+**/*.DesktopClient/ModelManifest.xml
+**/*.Server/GeneratedArtifacts
+**/*.Server/ModelManifest.xml
+_Pvt_Extensions
+
+# Paket dependency manager
+.paket/paket.exe
+paket-files/
+
+# FAKE - F# Make
+.fake/
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+# CodeRush
+.cr/
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/
+
+### VisualStudio Patch ###
+build/
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
index 3f0608a0..0f1296be 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,6 +1,4 @@
[submodule "discord.net"]
path = discord.net
- url = git://github.com/kwoth/discord.net.git
-[submodule "ffmpeg-installer"]
- path = ffmpeg-installer
- url = https://github.com/kwoth/ffmpeg-installer
+ url = https://github.com/kwoth/discord.net
+ branch = dev
diff --git a/ComprehensiveGuide.md b/ComprehensiveGuide.md
deleted file mode 100644
index 1666d345..00000000
--- a/ComprehensiveGuide.md
+++ /dev/null
@@ -1,112 +0,0 @@
-________________________________________________________________________________
-*Thanks to @Flatbread and Mirai for making this guide*
-________________________________________________________________________________
-
-### Setting Up NadekoBot on Windows
-#### Prerequisites
-- 1) [NET Framework][NET Framework] 4.5.2 (or 4.6)
-- 2) [FFMPEG][FFMPEG]
-- 3) Google Account
-- 4) Soundcloud Account (if you want soundcloud support)
-- 5) [7zip][7zip] (or whatever you are using, WinRar)
-- 6) [Notepad++][Notepad++]
-
-####Guide:
-
-- Create a folder, name it `Nadeko`.
-- Head to [Releases][Releases]* and download `WINDOWS.-.nadeupdater.7z`.
-- Copy `WINDOWS.-.nadeupdater.7z` to the `Nadeko` (folder we created before) and extract everything.
-- You will see a file `NadekoUpdater.bat ` and a folder `publish ` after extraction.
-- Run/Launch/Open the file `NadekoUpdater.bat ` and you will see it running in cmd.exe asking you with **3 options** *1-3*.
- - 1) Stable release - current stable release, but might not contain all the newest Nadeko updates.
- - 2) Newest release - release with all features/upgrades.
- - 3) Exit
-- Press `2` on your keyboard and hit `Enter`. Type `y` and hit `Enter` again. Downloading might take a while, so just be patient and wait. When download is done, press `3` on your keyboard and close the updater.
-- You should have a new folder named `NadekoBot` inside the `Nadeko` folder we previously created.
-
-####Creating DiscordBot application
-- Go to [DiscordApp][DiscordApp].
-- Log in with your Discord account.
-- On the left side, press `New Application`.
-- Fill out the `App Name` (your bot's name, in this case), put the image you want, and add an app description(optional).
-- Create the application.
-- Once the application is created, click on `Create a Bot User` and confirm it.
-- Keep this window open for now.
-
-####Setting up Credentials.json file
-- In our `NadekoBot` folder you should have `.json` file named `credentials_example.json`. (Note: If you do not see a **.json** after `credentials_example.json `, do not add the `**.json**`. You most likely have `"Hide file extensions"` enabled.)
-- Rename `credentials_example.json` to `credentials.json`.
-- Open the file with your [Notepad++][Notepad++].
-- In there you will see fields like `Token`, `ClientId`, `BotId`, `OwnerIDs`.
-- In your [DiscordApp][DiscordApp], under `Bot User` part, you will see the `Token:click to reveal` part, click to reveal it.
-- Copy your bot's token, and put it between `" "` in your `credentials.json` file.
-- Copy `Client ID` and replace it with the example one in your `credentials.json`.
-- Copy `Bot ID` and replace it with the example one in your `credentials.json`.
-- Save your `credentials.json` but keep it open. We need to put your `User ID` and owner.
-
-####Inviting your bot to your server [Invite Guide][Invite Guide]
-- Create a new server in Discord.
-- Copy your `Client ID` from your [DiscordApp][DiscordApp].
-- Replace `12345678` in this link `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with your `Client ID`.
-- Link should look like this: `https://discordapp.com/oauth2/authorize?client_id=**YOUR_CLENT_ID**&scope=bot&permissions=66186303`.
-- Go to newly created link and pick the server we created, and click `Authorize`.
-- Bot should be added to your server.
-
-####Starting the bot
-- Enter your `NadekoBot` folder that should be (hopefully) in your `Nadeko` folder.
-- Run `NadekoBot.exe` (Note: There is `NadekoBot.exe` and `NadekoBot.exe.config`, dont run the second one)
-- Your bot should now be online in the server we added him to.
-- Note: Your bot will be offline in case you close `NadekoBot.exe`.
-
-####Setting up OwnerIds:
-- In the server where your bot is, in a text channel, type `.uid`
-- Your `User ID` should show, copy it.
-- Close `NadekoBot.exe`
-- Replace your `User ID` in the `credentials.json` between `[ ]` and save the changes.
-- Run `NadekoBot.exe` again.
-- Now you are the bot owner.
-- You can add `User IDs` from the other users by separating IDs with a comma if you want to have more owners.
-
-`*Alternatively, you can download nadekobot from [Releases][Releases] and extract the zip yourself. That is what updater does, except it makes it easier for you to update because it doesn't overwrite important files. If you are downloading releases you will have to be careful about your config, credentials, and other files you edited in order to preserve your data every time you update.`
-
-________________________________________________________________________________
-
-#### Setting Up NadekoBot For Music
-##### Prerequisites
-- 1) [FFMPEG][FFMPEG] installed.
-- 2) Setting up API keys.
-
-- Follow these steps on how to setup Google API keys:
- - 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."
- - Under the "Other Popular APIs" section, enable `URL Shortener API` and `Custom Search Api`. Under the `YouTube APIs` section, enable `YouTube Data API`.
- - On the left tab, access `Credentials`. Click `Create Credentials` button. Click on `API Key`, and then `Server Key` in the new window that appears. Enter in a name for the `Server Key`. A new window will appear with your `Google API key`.
- - Copy the key.
- - Open up `credentials.json`.
- - For `"GoogleAPIKey"`, fill in with the new key we copied.
-- Follow these steps on how to setup Soundcloud API key:
- - Go to [Soundcloud][Soundcloud].
- - Enter a name for the app and create it.
- - You will see a page with the title of your app, and a field labeled `Client ID`. Copy the ID.
- - In `credentials.json`, fill in `"SoundcloudClientID"` with the copied ID.
-- Restart your computer.
-
-##### Prerequisites for manual `ffmpeg` setup:
-**Do this step in case you were not able to install `ffmpeg` with the installer.**
-- Create a folder named `ffmpeg` in your main Windows directory. We will use **C:\ffmpeg** (for our guide)
-- Download FFMPEG through the link https://ffmpeg.zeranoe.com/builds/ (download static build)
-- Extract it using `7zip` and place the folder `ffmpeg-xxxxx-git-xxxxx-xxxx-static` inside **C:\ffmpeg**
-- Before proceeding, check out this gif to set up `ffmpeg` PATH correctly http://i.imgur.com/aR5l1Hn.gif *(thanks to PooPeePants#7135)*
-- Go to My Computer, right click and select Properties. On the left tab, select Advanced System Settings. Under the Advanced tab, select Environmental Variables near the bottom. One of the variables should be called "Path". Add a semi-colon (;) to the end followed by your FFMPEG's **bin** install location (**for example C:\ffmpeg\ffmpeg-xxxxx-git-xxxxx-xxxx-static\bin**). Save and close.
-- Setup your API keys as explained above.
-- Restart your computer.
-
-[NET Framework]: https://www.microsoft.com/en-us/download/details.aspx?id=48130
-[FFMPEG]: https://github.com/Soundofdarkness/FFMPEG-Installer
-[7zip]: http://www.7-zip.org/download.html
-[Releases]: //github.com/Kwoth/NadekoUpdater/releases/tag/v1.0
-[DiscordApp]: https://discordapp.com/developers/applications/me
-[Notepad++]: https://notepad-plus-plus.org/
-[Invite Guide]: http://discord.kongslien.net/guide.html
-[Google Console]: https://console.developers.google.com
-[Soundcloud]: https://soundcloud.com/you/apps/new
diff --git a/DockerGuide.md b/DockerGuide.md
deleted file mode 100644
index 5a87bc22..00000000
--- a/DockerGuide.md
+++ /dev/null
@@ -1,54 +0,0 @@
-## Docker guide with digitalocean
-
-#####Prerequisites:
-- Digital ocean account (you can use my [reflink][reflink] to support the project and get 10$ after you register)
-- [PuTTY][PuTTY]
-- A bot account - follow this [guide][guide]
-- $5
-- Common sense
-
-#####Guide
-- Click on the create droplet button
-![img](http://i.imgur.com/g2ayOcC.png)
-
-- Pick one click apps and select docker on 14.04
-
-![img](http://imgur.com/065Xkme.png)
-
-- Pick any droplet size you want (5$ will work ok-ish on a few servers)
-- Pick location closest to your discord server's location
-- Pick a hostname
-![img](http://imgur.com/ifPKB6p.png)
-
-- Click create
-
-You will get an email from DigitalOcean with your credentials now.
-
-Open putty and type ip adress **you got in your email** with port 22
-
-![img](http://imgur.com/Mh5ehsh.png)
-
-- Console will open and you will be prompted for a username, type `root`.
-- Type in the password you got in the email.
-- Confirm the password you just typed in.
-- Type in the new password.
-- Confirm new password.
-
-- When you are successfully logged in, type
-`docker run --name nadeko -v /nadeko:/config uirel/nadeko`
-
-- Wait for it to download and at one point it is going to start throwing errors due to `credentials.json` being empty
-- CTRL+C to exit that
-- Type `docker stop nadeko`
-- Type `nano /nadeko/credentials.json` and type in your `credentials`
-- CTRL+X then CTRL+Y to save
-- Type `docker start nadeko`
-- Type `docker logs -f nadeko` to see the console output
-
-**Your bot is running, enjoy! o/**
-
-*When you want to update the bot, just type `docker restart nadeko` as it always downloads latest prerelease*
-
-[reflink]: http://m.do.co/c/46b4d3d44795/
-[PuTTY]: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
-[guide]: http://discord.kongslien.net/guide.html
diff --git a/LinuxSetup.md b/LinuxSetup.md
deleted file mode 100644
index 39acd7be..00000000
--- a/LinuxSetup.md
+++ /dev/null
@@ -1,270 +0,0 @@
-#Setting up NadekoBot on Linux
-
-####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][DigitalOcean] (and using this link will be supporting Nadeko and will give you **$10 credit**)
-
-######Keep this helpful video handy [Linux Setup Video][Linux Setup Video] (thanks to klincheR) it contains how to set up the Digital Ocean droplet aswell.
-
-####Setting up NadekoBot
-Assuming you have followed the link above to created an account in Digital Ocean and video to set up the bot until you get the `IP address and root password (in email)` to login, its time to begin.
-
-#### Prerequisites
-- Download [PuTTY][PuTTY]
-- Download [CyberDuck][CyberDuck]
-
-#### Follow these steps
-
-- **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.
-- Now for **login as:**, type `root` and hit enter.
-- It should then, ask for password, type the `root password` you have received in your **email address registered with Digital Ocean**, then hit Enter.
-
-*(as you are running it for the first time, it will most likely to ask you to change your root password, for that, type the "password you received through email", hit Enter, enter a "new password", hit Enter and confirm that "new password" again.*
-**SAVE that new password somewhere safe not just in mind**. After you done that, you are ready to write commands.
-
-**Copy and just paste** using **mouse right-click** (it should paste automatically)
-
-######MONO (Source: [Mono Source][Mono Source])
-
-**1) Installing Mono**
-
-`sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF`
-
-`echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list`
-
-`sudo apt-get update`
-
-Note if the command is not being initiated, hit **Enter**
-
-**2)**
-
-`echo "deb http://download.mono-project.com/repo/debian wheezy-apache24-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list`
-
-**2.5)**
-*ONLY DEBIAN 8 and later*
-
-`echo "deb http://download.mono-project.com/repo/debian wheezy-libjpeg62-compat main" | sudo tee -a /etc/apt/sources.list.d/mono-xamarin.list`
-
-**2.6)**
-*ONLY CentOS 7, Fedora 19 (and later)*
-
-`yum install yum-utils`
-
-`rpm --import "http://keyserver.ubuntu.com/pks/lookup?op=get&search=0x3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF"`
-
-`yum-config-manager --add-repo http://download.mono-project.com/repo/centos/`
-
-**3)**
-*Mono Devel*
-
-`apt-get install mono-devel`
-
-**Type** `y` **hit Enter**
-
-
-**4)**
-Opus Voice Codec
-
-`sudo apt-get install libopus0 opus-tools`
-
-**Type** `y` **hit Enter**
-
-**5)**
-`sudo apt-get install libopus-dev`
-
-**In case you are having issues with Mono where you get a random string and the bot won't run, do this:**
-
-`sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF`
-
-`echo "deb http://download.mono-project.com/repo/debian wheezy main" | sudo tee /etc/apt/sources.list.d/mono-xamarin.list`
-
-`apt-get install ca-certificates-mono`
-
-`mozroots --import --sync`
-
-
-####FFMPEG
-
-**6)**
-`apt-get install ffmpeg`
-
-**Type** `y` **hit Enter**
-
-NOTE: if its "not installing" then, follow the guide here: [FFMPEG Help Guide][FFMPEG Help Guide]
-
-**All you need to do, if you are running UBUNTU 14.04 is initiate these:**
-
-`sudo add-apt-repository ppa:mc3man/trusty-media`
-
-`sudo apt-get update`
-
-`sudo apt-get dist-upgrade`
-
-*Before executing* `sudo apt-get install ffmpeg`
-
-**If you are running Debian 8 Jessie, please, follow these steps:**
-
-`wget http://luxcaeli.de/installer.sh && sudo bash installer.sh` (Thanks to Eleria<3)
-
-In case you are not able to install it with installer ^up there, 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`
-
-####Uncomplicated Firewall UFW
-
-**7)**
-`apt-get install ufw`
-
-**it is most likely to have it already installed so if you see it is already installed, check with following command, and/or enable it**
-
-**8)**
-`ufw status`
-
-**9)**
-`ufw enable`
-
-**Type** `y` **hit Enter**
-
-**10)**
-`sudo ufw allow ssh`
-
-
-
-**11)**
-Unzip
-
-`apt-get install unzip`
-
-**12)**
-TMUX
-
-`apt-get install tmux`
-
-**Type** `y` **hit Enter**
-
-####NOW WE NEED TO IMPORT SOME DISCORD CERTS
-**13)**
-`certmgr -ssl https://discordapp.com`
-
-**14)**
-`certmgr -ssl https://gateway.discord.gg`
-
-Type `yes` and hit Enter **(three times - as it will ask for three times)**
-
-
-**15)**
-Create a new folder “nadeko” or anything you prefer
-
-`mkdir nadeko`
-
-**16)**
-Move to “nadeko” folder (note `cd --` to go back the directory)
-
-`cd nadeko`
-
-**NOW WE NEED TO GET NADEKO FROM RELEASES**
-
-Go to this link: [Releases][Releases] and **copy the zip file address** of the lalest version available,
-it should look like `https://github.com/Kwoth/NadekoBot/releases/download/vx.xx/NadekoBot.vx.x.zip`
-
-**17)**
-Get the correct link, type `wget`, then *paste the link*, then hit **Enter**.
-
-`wget https://github.com/Kwoth/NadekoBot/releases/download/vx.xx/NadekoBot.vx.x.zip`
-
-**^Do not copy-paste it**
-
-**18)**
-
-Now we need to `unzip` the downloaded zip file and to do that, type the file name as it showed in your screen or just copy from the screen, should be like ` NadekoBot.vx.x.zip`
-
-`unzip NadekoBot.vx.x.zip`
-
-**^Do not copy-paste it**
-
-#####NOW TO SETUP NADEKO
-
-- Open **CyberDuck**
-- Click on **Open Connection** (top-left corner), a new window should appear.
-- You should see **FTP (File Transfer Protocol)** in drop-down.
-- Change it to **SFTP (SSH File Transfer Protocol)**
-- Now, in **Server:** paste or type in your `Digital Ocean Droplets IP address`, leave `Port: 22` (no need to change it)
-- In **Username:** type `root`
-- In **Password:** type `the new root password (you changed at the start)`
-- Click on **Connect**
-- It should show you the new folder you created.
-- Open it.
-
-#####MAKE SURE YOU READ THE README BEFORE PROCEEDING
-
-- Copy the `credentials_example.json` to desktop
-- EDIT it as it is guided here: [Readme][Readme]
-- Rename it to `credentials.json` and paste/put it back in the folder. `(Yes, using CyberDuck)`
-- You should see two files `credentials_example.json` and `credentials.json`
-- Also if you already have nadeko setup and have `credentials.json`, `config.json`, `nadekobot.sqlite`, and `"permissions" folder`, you can just copy and paste it to the Droplets folder using CyberDuck.
-
-######TIME TO RUN
-
-Go back to **PuTTY**, `(hope its still running xD)`
-
-**19)**
-Type/ Copy and hit **Enter**.
-
-`tmux new -s nadeko`
-
-**^this will create a new session named “nadeko”** `(you can replace “nadeko” with anything you prefer and remember its your session name) so you can run the bot in background without having to keep running PuTTY in the background.`
-
-`cd nadeko`
-
-**20)**
-`mono NadekoBot.exe`
-
-**CHECK THE BOT IN DISCORD, IF EVERYTHING IS WORKING**
-
-Now time to **move bot to background** and to do that, press **CTRL+B**,release and press **D** (this will detach the nadeko session using TMUX), and you can finally close PuTTY now.
-
-Copy your CLIENT ID (that's in the same Developer page where you brought your token) and replace `12345678` in this link: `https://discordapp.com/oauth2/authorize?client_id=12345678&scope=bot&permissions=66186303` with it. Go to that link and you will be able to add your bot to your server.
-
-**NOW YOU HAVE YOUR OWN NADEKO BOT** `Thanks to Kwoth <3`
-
-######SOME MORE INFO (JUST TO KNOW):
-
--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.)
-
-**21)**
--If you want to **kill** NadekoBot **session**, type `tmux kill-session -t nadeko`
-
-######TO RESTART YOUR BOT ALONG WITH THE WHOLE SERVER (for science):
-**22)**
-Open **PuTTY** and login as you have before, type `reboot` and hit Enter.
-
-######IF YOU WANT TO UPDATE YOUR BOT
-
-**FOLLOW THESE STEPS SERIALLY**
-
-- **-21 OR 22**
-- **-19**
-- **-16**
-- **-17**
-- **-18**
-- **-20**
-
-HIT **CTRL+B**,release, press **D** and close **PuTTY**
-
-`IF YOU FACE ANY TROUBLE ANYWHERE IN THE GUIDE JUST FIND US IN NADEKO'S DISCORD SERVER`
-
-[PuTTY]: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
-[CyberDuck]: https://cyberduck.io
-[Linux Setup Video]: https://www.youtube.com/watch?v=icV4_WPqPQk&feature=youtu.be
-[Releases]: https://github.com/Kwoth/NadekoBot/releases
-[Readme]: https://github.com/Kwoth/NadekoBot/blob/master/README.md
-[FFMPEG Help Guide]: http://www.faqforge.com/linux/how-to-install-ffmpeg-on-ubuntu-14-04/
-[Mono Source]: http://www.mono-project.com/docs/getting-started/install/linux/
-[DigitalOcean]: http://m.do.co/c/46b4d3d44795/
diff --git a/NadekoBot.sln b/NadekoBot.sln
index d41210c6..7b8981b8 100644
--- a/NadekoBot.sln
+++ b/NadekoBot.sln
@@ -3,116 +3,49 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NadekoBot", "NadekoBot\NadekoBot.csproj", "{27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Audio", "discord.net\src\Discord.Net.Audio.Net45\Discord.Net.Audio.csproj", "{7BFEF748-B934-4621-9B11-6302E3A9F6B3}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{0B2F1537-4BF0-422B-A0DD-8F9CCEFB340F}"
+ ProjectSection(SolutionItems) = preProject
+ global.json = global.json
+ EndProjectSection
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net", "discord.net\src\Discord.Net.Net45\Discord.Net.csproj", "{8D71A857-879A-4A10-859E-5FF824ED6688}"
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "NadekoBot", "src\NadekoBot\NadekoBot.xproj", "{45EC1473-C678-4857-A544-07DFE0D0B478}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Modules", "discord.net\src\Discord.Net.Modules.Net45\Discord.Net.Modules.csproj", "{3091164F-66AE-4543-A63D-167C1116241D}"
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net", "discord.net\src\Discord.Net\Discord.Net.xproj", "{91E9E7BD-75C9-4E98-84AA-2C271922E5C2}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Discord.Net.Commands", "discord.net\src\Discord.Net.Commands.Net45\Discord.Net.Commands.csproj", "{1B5603B4-6F8F-4289-B945-7BAAE523D740}"
+Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Discord.Net.Commands", "discord.net\src\Discord.Net.Commands\Discord.Net.Commands.xproj", "{078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}"
EndProject
Global
- GlobalSection(SharedMSBuildProjectFiles) = preSolution
- discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{1b5603b4-6f8f-4289-b945-7baae523d740}*SharedItemsImports = 4
- discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{3091164f-66ae-4543-a63d-167c1116241d}*SharedItemsImports = 4
- discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{7bfef748-b934-4621-9b11-6302e3a9f6b3}*SharedItemsImports = 4
- discord.net\src\Discord.Net.Shared\Discord.Net.Shared.projitems*{8d71a857-879a-4a10-859e-5ff824ed6688}*SharedItemsImports = 4
- EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- FullDebug|Any CPU = FullDebug|Any CPU
- FullDebug|x64 = FullDebug|x64
- NadekoRelease|Any CPU = NadekoRelease|Any CPU
- NadekoRelease|x64 = NadekoRelease|x64
+ GlobalNadeko|Any CPU = GlobalNadeko|Any CPU
Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|x64.ActiveCfg = Debug|x64
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Debug|x64.Build.0 = Debug|x64
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|x64.ActiveCfg = Debug|x64
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.FullDebug|x64.Build.0 = Debug|x64
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|Any CPU.ActiveCfg = NadekoRelease|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|Any CPU.Build.0 = NadekoRelease|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|x64.ActiveCfg = NadekoRelease|x64
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.NadekoRelease|x64.Build.0 = NadekoRelease|x64
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|Any CPU.Build.0 = Release|Any CPU
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|x64.ActiveCfg = Release|x64
- {27A886F5-CDDA-4F4A-81EE-6DAFCCE9DE46}.Release|x64.Build.0 = Release|x64
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Debug|x64.Build.0 = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|x64.ActiveCfg = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.FullDebug|x64.Build.0 = Debug|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.NadekoRelease|x64.Build.0 = Release|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|Any CPU.Build.0 = Release|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|x64.ActiveCfg = Release|Any CPU
- {7BFEF748-B934-4621-9B11-6302E3A9F6B3}.Release|x64.Build.0 = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Debug|x64.Build.0 = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|x64.ActiveCfg = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.FullDebug|x64.Build.0 = Debug|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.NadekoRelease|x64.Build.0 = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|Any CPU.Build.0 = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|x64.ActiveCfg = Release|Any CPU
- {8D71A857-879A-4A10-859E-5FF824ED6688}.Release|x64.Build.0 = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Debug|x64.ActiveCfg = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Debug|x64.Build.0 = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|x64.ActiveCfg = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.FullDebug|x64.Build.0 = Debug|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.NadekoRelease|x64.Build.0 = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Release|Any CPU.Build.0 = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Release|x64.ActiveCfg = Release|Any CPU
- {3091164F-66AE-4543-A63D-167C1116241D}.Release|x64.Build.0 = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Debug|x64.Build.0 = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.ActiveCfg = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|Any CPU.Build.0 = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|x64.ActiveCfg = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.FullDebug|x64.Build.0 = Debug|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.ActiveCfg = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|Any CPU.Build.0 = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|x64.ActiveCfg = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.NadekoRelease|x64.Build.0 = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|Any CPU.Build.0 = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|x64.ActiveCfg = Release|Any CPU
- {1B5603B4-6F8F-4289-B945-7BAAE523D740}.Release|x64.Build.0 = Release|Any CPU
+ {45EC1473-C678-4857-A544-07DFE0D0B478}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {45EC1473-C678-4857-A544-07DFE0D0B478}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {45EC1473-C678-4857-A544-07DFE0D0B478}.GlobalNadeko|Any CPU.ActiveCfg = GlobalNadeko|Any CPU
+ {45EC1473-C678-4857-A544-07DFE0D0B478}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
+ {45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {45EC1473-C678-4857-A544-07DFE0D0B478}.Release|Any CPU.Build.0 = Release|Any CPU
+ {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.GlobalNadeko|Any CPU.ActiveCfg = GlobalNadeko|Any CPU
+ {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
+ {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {91E9E7BD-75C9-4E98-84AA-2C271922E5C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.GlobalNadeko|Any CPU.ActiveCfg = GlobalNadeko|Any CPU
+ {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.GlobalNadeko|Any CPU.Build.0 = GlobalNadeko|Any CPU
+ {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {078DD7E6-943D-4D09-AFC2-D2BA58B76C9C}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {45EC1473-C678-4857-A544-07DFE0D0B478} = {04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}
+ EndGlobalSection
EndGlobal
diff --git a/NadekoBot/App.config b/NadekoBot/App.config
deleted file mode 100644
index 75d0347a..00000000
--- a/NadekoBot/App.config
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/NadekoBot/Classes/BombermanGame.cs b/NadekoBot/Classes/BombermanGame.cs
deleted file mode 100644
index 5b801e30..00000000
--- a/NadekoBot/Classes/BombermanGame.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-namespace NadekoBot.Classes
-{
- class BombermanGame
- {
- public ulong ChannelId { get; internal set; }
- public bool Ended { get; internal set; }
- }
-}
diff --git a/NadekoBot/Classes/DBHandler.cs b/NadekoBot/Classes/DBHandler.cs
deleted file mode 100644
index db8dee81..00000000
--- a/NadekoBot/Classes/DBHandler.cs
+++ /dev/null
@@ -1,164 +0,0 @@
-using NadekoBot.DataModels;
-using SQLite;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Linq.Expressions;
-
-namespace NadekoBot.Classes
-{
- internal class DbHandler
- {
- public static DbHandler Instance { get; } = new DbHandler();
-
- private string FilePath { get; } = "data/nadekobot.sqlite";
-
- public SQLiteConnection Connection { get; set; }
-
- static DbHandler() { }
- public DbHandler()
- {
- Connection = new SQLiteConnection(FilePath);
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.CreateTable();
- Connection.Execute(Queries.TransactionTriggerQuery);
- try
- {
- Connection.Execute(Queries.DeletePlaylistTriggerQuery);
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
- }
-
- internal T FindOne(Expression> p) where T : IDataModel, new()
- {
- return Connection.Table().Where(p).FirstOrDefault();
-
- }
-
- internal IList FindAll(Expression> p) where T : IDataModel, new()
- {
-
- return Connection.Table().Where(p).ToList();
-
- }
-
- internal void DeleteWhere(Expression> p) where T : IDataModel, new()
- {
- var id = Connection.Table().Where(p).FirstOrDefault()?.Id;
- if (id.HasValue)
- Connection.Delete(id);
- }
-
- internal HashSet GetAllRows() where T : IDataModel, new()
- {
- return new HashSet(Connection.Table());
- }
-
- internal CurrencyState GetStateByUserId(long id)
- {
- return Connection.Table().Where(x => x.UserId == id).FirstOrDefault();
- }
-
- internal T Delete(int id) where T : IDataModel, new()
- {
- var found = Connection.Find(id);
- if (found != null)
- Connection.Delete(found.Id);
- return found;
- }
-
- ///
- /// Updates an existing object or creates a new one
- ///
- internal void Save(T o) where T : IDataModel, new()
- {
- var found = Connection.Find(o.Id);
- if (found == null)
- Connection.Insert(o, typeof(T));
- else
- Connection.Update(o, typeof(T));
- }
-
- ///
- /// Updates an existing object or creates a new one
- ///
- internal void SaveAll(IEnumerable ocol) where T : IDataModel, new()
- {
- foreach (var o in ocol)
- Connection.InsertOrReplace(o);
- }
-
- internal T GetRandom(Expression> p) where T : IDataModel, new()
- {
- var r = new Random();
- return Connection.Table().Where(p).ToList().OrderBy(x => r.Next()).FirstOrDefault();
- }
- ///
- ///
- ///
- /// Page number (0+)
- ///
- internal List GetPlaylistData(int num)
- {
- return Connection.Query(
-@"SELECT mp.Name as 'Name',mp.Id as 'Id', mp.CreatorName as 'Creator', Count(*) as 'SongCnt' FROM MusicPlaylist as mp
-INNER JOIN PlaylistSongInfo as psi
-ON mp.Id = psi.PlaylistId
-Group BY mp.Name
-Order By mp.DateAdded desc
-Limit 20 OFFSET ?", num * 20);
-
- }
-
- internal IEnumerable GetTopRichest(int n = 10)
- {
- return Connection.Table().OrderByDescending(cs => cs.Value).Take(n).ToList();
- }
- }
-}
-
-public class PlaylistData
-{
- public string Name { get; set; }
- public int Id { get; set; }
- public string Creator { get; set; }
- public int SongCnt { get; set; }
-}
-
-public static class Queries
-{
- public const string TransactionTriggerQuery = @"
-CREATE TRIGGER IF NOT EXISTS OnTransactionAdded
-AFTER INSERT ON CurrencyTransaction
-BEGIN
-INSERT OR REPLACE INTO CurrencyState (Id, UserId, Value, DateAdded)
- VALUES (COALESCE((SELECT Id from CurrencyState where UserId = NEW.UserId),(SELECT COALESCE(MAX(Id),0)+1 from CurrencyState)),
- NEW.UserId,
- COALESCE((SELECT Value+New.Value FROM CurrencyState Where UserId = NEW.UserId),NEW.Value),
- NEW.DateAdded);
-END
-";
- public const string DeletePlaylistTriggerQuery = @"
-CREATE TRIGGER IF NOT EXISTS music_playlist
-AFTER DELETE ON MusicPlaylist
-FOR EACH ROW
-BEGIN
- DELETE FROM PlaylistSongInfo WHERE PlaylistId = OLD.Id;
-END";
-}
diff --git a/NadekoBot/Classes/Extensions.cs b/NadekoBot/Classes/Extensions.cs
deleted file mode 100644
index 098e4732..00000000
--- a/NadekoBot/Classes/Extensions.cs
+++ /dev/null
@@ -1,378 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Security.Cryptography;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Extensions
-{
- public static class Extensions
- {
- private static Random rng = new Random();
-
- public static string Scramble(this string word)
- {
-
- var letters = word.ToArray();
- var count = 0;
- for (var i = 0; i < letters.Length; i++)
- {
- if (letters[i] == ' ')
- continue;
-
- count++;
- if (count <= letters.Length / 5)
- continue;
-
- if (count % 3 == 0)
- continue;
-
- if (letters[i] != ' ')
- letters[i] = '_';
- }
- return "`" + string.Join(" ", letters) + "`";
- }
- public static string TrimTo(this string str, int num, bool hideDots = false)
- {
- if (num < 0)
- throw new ArgumentOutOfRangeException(nameof(num), "TrimTo argument cannot be less than 0");
- if (num == 0)
- return string.Empty;
- if (num <= 3)
- return string.Concat(str.Select(c => '.'));
- if (str.Length < num)
- return str;
- return string.Concat(str.Take(num - 3)) + (hideDots ? "" : "...");
- }
- ///
- /// Removes trailing S or ES (if specified) on the given string if the num is 1
- ///
- ///
- ///
- ///
- /// String with the correct singular/plural form
- public static string SnPl(this string str, int? num, bool es = false)
- {
- if (str == null)
- throw new ArgumentNullException(nameof(str));
- if (num == null)
- throw new ArgumentNullException(nameof(num));
- return num == 1 ? str.Remove(str.Length - 1, es ? 2 : 1) : str;
- }
-
- ///
- /// Sends a message to the channel from which this command is called.
- ///
- /// EventArg
- /// Message to be sent
- ///
- public static async Task Send(this CommandEventArgs e, string message)
- => await e.Channel.SendMessage(message).ConfigureAwait(false);
-
- ///
- /// Sends a message to the channel from which MessageEventArg came.
- ///
- /// EventArg
- /// Message to be sent
- ///
- public static async Task Send(this MessageEventArgs e, string message)
- {
- if (string.IsNullOrWhiteSpace(message))
- return;
- await e.Channel.SendMessage(message).ConfigureAwait(false);
- }
-
- ///
- /// Sends a message to this channel.
- ///
- ///
- ///
- ///
- public static async Task Send(this Channel c, string message)
- {
- await c.SendMessage(message).ConfigureAwait(false);
- }
-
- ///
- /// Sends a private message to this user.
- ///
- ///
- ///
- ///
- public static async Task Send(this User u, string message)
- {
- await u.SendMessage(message).ConfigureAwait(false);
- }
-
- ///
- /// Replies to a user who invoked this command, message start with that user's mention.
- ///
- ///
- ///
- ///
- public static async Task Reply(this CommandEventArgs e, string message)
- {
- await e.Channel.SendMessage(e.User.Mention + " " + message).ConfigureAwait(false);
- }
-
- ///
- /// Replies to a user who invoked this command, message start with that user's mention.
- ///
- ///
- ///
- ///
- public static async Task Reply(this MessageEventArgs e, string message)
- {
- await e.Channel.SendMessage(e.User.Mention + " " + message).ConfigureAwait(false);
- }
-
- ///
- /// Randomizes element order in a list
- ///
- ///
- ///
- public static IList Shuffle(this IList list)
- {
-
- // Thanks to @Joe4Evr for finding a bug in the old version of the shuffle
- var provider = new RNGCryptoServiceProvider();
- var n = list.Count;
- while (n > 1)
- {
- var box = new byte[(n / Byte.MaxValue) + 1];
- int boxSum;
- do
- {
- provider.GetBytes(box);
- boxSum = box.Sum(b => b);
- }
- while (!(boxSum < n * ((Byte.MaxValue * box.Length) / n)));
- var k = (boxSum % n);
- n--;
- var value = list[k];
- list[k] = list[n];
- list[n] = value;
- }
- return list;
- }
-
- ///
- /// Shortens a string URL
- ///
- ///
- ///
- ///
- public static async Task ShortenUrl(this string str)
- {
- try
- {
- var result = await SearchHelper.ShortenUrl(str).ConfigureAwait(false);
- return result;
- }
- catch (WebException ex)
- {
- throw new InvalidOperationException("You must enable URL shortner in google developers console.", ex);
- }
- }
-
- public static string GetOnPage(this IEnumerable source, int pageIndex, int itemsPerPage = 5)
- {
- var items = source.Skip(pageIndex * itemsPerPage).Take(itemsPerPage);
- if (!items.Any())
- {
- return $"No items on page {pageIndex + 1}.";
- }
- var sb = new StringBuilder($"---page {pageIndex + 1} --\n");
- var itemsDC = items as IEnumerable>>;
- var itemsDS = items as IEnumerable>;
- if (itemsDC != null)
- {
- foreach (var item in itemsDC)
- {
- sb.Append($"{ Format.Code(item.Key)}\n");
- int i = 1;
- var last = item.Value.Last();
- foreach (var value in item.Value)
- {
- if (last != value)
- sb.AppendLine(" `├" + i++ + "─`" + Format.Bold(value));
- else
- sb.AppendLine(" `└" + i++ + "─`" + Format.Bold(value));
- }
-
- }
- }
- else if (itemsDS != null)
- {
- foreach (var item in itemsDS)
- {
- sb.Append($"{ Format.Code(item.Key)}\n");
- sb.AppendLine(" `└─`" + Format.Bold(item.Value));
- }
-
- }
- else
- {
- foreach (var item in items)
- {
- sb.Append($"{ Format.Code(item.ToString())} \n");
- }
- }
-
- return sb.ToString();
- }
- ///
- /// Gets the program runtime
- ///
- ///
- ///
- ///
- public static string GetRuntime(this DiscordClient c) => ".Net Framework 4.5.2";
-
- public static string Matrix(this string s)
- =>
- string.Concat(s.Select(c => c.ToString() + " ̵̢̬̜͉̞̭̖̰͋̉̎ͬ̔̇̌̀".TrimTo(rng.Next(0, 12), true)));
- //.Replace("`", "");
-
- public static void ForEach(this IEnumerable source, Action action)
- {
- foreach (var element in source)
- {
- action(element);
- }
- }
-
- //http://www.dotnetperls.com/levenshtein
- public static int LevenshteinDistance(this string s, string t)
- {
- var n = s.Length;
- var m = t.Length;
- var d = new int[n + 1, m + 1];
-
- // Step 1
- if (n == 0)
- {
- return m;
- }
-
- if (m == 0)
- {
- return n;
- }
-
- // Step 2
- for (var i = 0; i <= n; d[i, 0] = i++)
- {
- }
-
- for (var j = 0; j <= m; d[0, j] = j++)
- {
- }
-
- // Step 3
- for (var i = 1; i <= n; i++)
- {
- //Step 4
- for (var j = 1; j <= m; j++)
- {
- // Step 5
- var cost = (t[j - 1] == s[i - 1]) ? 0 : 1;
-
- // Step 6
- d[i, j] = Math.Min(
- Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1),
- d[i - 1, j - 1] + cost);
- }
- }
- // Step 7
- return d[n, m];
- }
-
- public static int KiB(this int value) => value * 1024;
- public static int KB(this int value) => value * 1000;
-
- public static int MiB(this int value) => value.KiB() * 1024;
- public static int MB(this int value) => value.KB() * 1000;
-
- public static int GiB(this int value) => value.MiB() * 1024;
- public static int GB(this int value) => value.MB() * 1000;
-
- public static ulong KiB(this ulong value) => value * 1024;
- public static ulong KB(this ulong value) => value * 1000;
-
- public static ulong MiB(this ulong value) => value.KiB() * 1024;
- public static ulong MB(this ulong value) => value.KB() * 1000;
-
- public static ulong GiB(this ulong value) => value.MiB() * 1024;
- public static ulong GB(this ulong value) => value.MB() * 1000;
-
- public static Stream ToStream(this Image img, System.Drawing.Imaging.ImageFormat format = null)
- {
- if (format == null)
- format = System.Drawing.Imaging.ImageFormat.Jpeg;
- var stream = new MemoryStream();
- img.Save(stream, format);
- stream.Position = 0;
- return stream;
- }
-
- ///
- /// Merges Images into 1 Image and returns a bitmap.
- ///
- /// The Images you want to merge.
- /// Merged bitmap
- public static Bitmap Merge(this IEnumerable images, int reverseScaleFactor = 1)
- {
- var imageArray = images as Image[] ?? images.ToArray();
- if (!imageArray.Any()) return null;
- var width = imageArray.Sum(i => i.Width);
- var height = imageArray.First().Height;
- var bitmap = new Bitmap(width / reverseScaleFactor, height / reverseScaleFactor);
- var r = new Random();
- var offsetx = 0;
- foreach (var img in imageArray)
- {
- var bm = new Bitmap(img);
- for (var w = 0; w < img.Width; w++)
- {
- for (var h = 0; h < bitmap.Height; h++)
- {
- bitmap.SetPixel(w / reverseScaleFactor + offsetx, h, bm.GetPixel(w, h * reverseScaleFactor));
- }
- }
- offsetx += img.Width / reverseScaleFactor;
- }
- return bitmap;
- }
-
- ///
- /// Merges Images into 1 Image and returns a bitmap asynchronously.
- ///
- /// The Images you want to merge.
- ///
- /// Merged bitmap
- public static async Task MergeAsync(this IEnumerable images, int reverseScaleFactor = 1) =>
- await Task.Run(() => images.Merge(reverseScaleFactor)).ConfigureAwait(false);
-
- public static string Unmention(this string str) => str.Replace("@", "ම");
-
- public static Stream ToStream(this string str)
- {
- var sw = new StreamWriter(new MemoryStream());
- sw.Write(str);
- sw.Flush();
- sw.BaseStream.Position = 0;
- return sw.BaseStream;
- }
-
- public static double UnixTimestamp(this DateTime dt) => dt.ToUniversalTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
-
- }
-}
diff --git a/NadekoBot/Classes/FlowersHandler.cs b/NadekoBot/Classes/FlowersHandler.cs
deleted file mode 100644
index 57191c63..00000000
--- a/NadekoBot/Classes/FlowersHandler.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System.Threading.Tasks;
-
-namespace NadekoBot.Classes
-{
- internal static class FlowersHandler
- {
- public static async Task AddFlowersAsync(Discord.User u, string reason, int amount, bool silent = false)
- {
- if (amount <= 0)
- return;
- await Task.Run(() =>
- {
- DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
- {
- Reason = reason,
- UserId = (long)u.Id,
- Value = amount,
- });
- }).ConfigureAwait(false);
-
- if (silent)
- return;
-
- var flows = amount + " " + NadekoBot.Config.CurrencySign;
-
- await u.SendMessage("👑Congratulations!👑\nYou received: " + flows).ConfigureAwait(false);
- }
-
- public static async Task RemoveFlowers(Discord.User u, string reason, int amount, bool silent=false, string message="👎`Bot owner has taken {0}{1} from you.`")
- {
- if (amount <= 0)
- return false;
- var uid = (long)u.Id;
- var state = DbHandler.Instance.FindOne(cs => cs.UserId == uid);
-
- if (state.Value < amount)
- return false;
-
- DbHandler.Instance.Connection.Insert(new DataModels.CurrencyTransaction
- {
- Reason = reason,
- UserId = (long)u.Id,
- Value = -amount,
- });
-
- if (silent)
- return true;
-
- await u.SendMessage(string.Format(message,amount,NadekoBot.Config.CurrencySign)).ConfigureAwait(false);
- return true;
- }
- }
-}
diff --git a/NadekoBot/Classes/IncidentsHandler.cs b/NadekoBot/Classes/IncidentsHandler.cs
deleted file mode 100644
index 3042f824..00000000
--- a/NadekoBot/Classes/IncidentsHandler.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using NadekoBot.DataModels;
-using System;
-
-namespace NadekoBot.Classes
-{
- internal static class IncidentsHandler
- {
- public static void Add(ulong serverId, ulong channelId, string text)
- {
- var def = Console.ForegroundColor;
- Console.ForegroundColor = ConsoleColor.Red;
- Console.WriteLine($"INCIDENT: {text}");
- Console.ForegroundColor = def;
- var incident = new Incident
- {
- ChannelId = (long)channelId,
- ServerId = (long)serverId,
- Text = text,
- Read = false
- };
-
- DbHandler.Instance.Connection.Insert(incident, typeof(Incident));
- }
- }
-}
diff --git a/NadekoBot/Classes/NadekoStats.cs b/NadekoBot/Classes/NadekoStats.cs
deleted file mode 100644
index 57d730d4..00000000
--- a/NadekoBot/Classes/NadekoStats.cs
+++ /dev/null
@@ -1,288 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Administration.Commands;
-using NadekoBot.Modules.Music;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-#if NADEKO_RELEASE
-using System.IO;
-#endif
-using System.Linq;
-using System.Net.Http;
-using System.Reflection;
-using System.Threading.Tasks;
-using System.Timers;
-
-namespace NadekoBot
-{
- public class NadekoStats
- {
- public static NadekoStats Instance { get; } = new NadekoStats();
-
- public string BotVersion => $"{Assembly.GetExecutingAssembly().GetName().Name} v{Assembly.GetExecutingAssembly().GetName().Version}";
-
- private int commandsRan = 0;
- private string statsCache = "";
- private readonly Stopwatch statsStopwatch = new Stopwatch();
-
- public int ServerCount { get; private set; } = 0;
- public int TextChannelsCount { get; private set; } = 0;
- public int VoiceChannelsCount { get; private set; } = 0;
-
- private readonly Timer commandLogTimer = new Timer() { Interval = 10000 };
- private readonly Timer carbonStatusTimer = new Timer() { Interval = 3600000 };
-
- private static ulong messageCounter = 0;
- public static ulong MessageCounter => messageCounter;
-
- static NadekoStats() { }
-
- private NadekoStats()
- {
- var commandService = NadekoBot.Client.GetService();
-
- statsStopwatch.Start();
-
- commandService.CommandExecuted += StatsCollector_RanCommand;
- commandService.CommandFinished += CommandService_CommandFinished;
- commandService.CommandErrored += CommandService_CommandFinished;
-
- Task.Run(StartCollecting);
-
- commandLogTimer.Start();
-
- ServerCount = NadekoBot.Client.Servers.Count();
- var channels = NadekoBot.Client.Servers.SelectMany(s => s.AllChannels);
- var channelsArray = channels as Channel[] ?? channels.ToArray();
- TextChannelsCount = channelsArray.Count(c => c.Type == ChannelType.Text);
- VoiceChannelsCount = channelsArray.Count() - TextChannelsCount;
-
- NadekoBot.Client.MessageReceived += (s, e) => messageCounter++;
-
- NadekoBot.Client.JoinedServer += (s, e) =>
- {
- try
- {
- ServerCount++;
- TextChannelsCount += e.Server.TextChannels.Count();
- VoiceChannelsCount += e.Server.VoiceChannels.Count();
- //await SendUpdateToCarbon().ConfigureAwait(false);
- }
- catch { }
- };
- NadekoBot.Client.LeftServer += (s, e) =>
- {
- try
- {
- ServerCount--;
- TextChannelsCount -= e.Server.TextChannels.Count();
- VoiceChannelsCount -= e.Server.VoiceChannels.Count();
- //await SendUpdateToCarbon().ConfigureAwait(false);
- }
- catch { }
- };
- NadekoBot.Client.ChannelCreated += (s, e) =>
- {
- try
- {
- if (e.Channel.IsPrivate)
- return;
- if (e.Channel.Type == ChannelType.Text)
- TextChannelsCount++;
- else if (e.Channel.Type == ChannelType.Voice)
- VoiceChannelsCount++;
- }
- catch { }
- };
- NadekoBot.Client.ChannelDestroyed += (s, e) =>
- {
- try
- {
- if (e.Channel.IsPrivate)
- return;
- if (e.Channel.Type == ChannelType.Text)
- TextChannelsCount--;
- else if (e.Channel.Type == ChannelType.Voice)
- VoiceChannelsCount--;
- }
- catch { }
- };
- carbonStatusTimer.Elapsed += async (s, e) => await SendUpdateToCarbon().ConfigureAwait(false);
- carbonStatusTimer.Start();
- }
-
- HttpClient carbonClient = new HttpClient();
- private async Task SendUpdateToCarbon()
- {
- if (string.IsNullOrWhiteSpace(NadekoBot.Creds.CarbonKey))
- return;
- try
- {
- using (var content = new FormUrlEncodedContent(new Dictionary {
- { "servercount", NadekoBot.Client.Servers.Count().ToString() },
- { "key", NadekoBot.Creds.CarbonKey }
- }))
- {
- content.Headers.Clear();
- content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
-
- var res = await carbonClient.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
- };
- }
- catch (Exception ex)
- {
- Console.WriteLine("Failed sending status update to carbon.");
- Console.WriteLine(ex);
- }
- }
-
- public TimeSpan GetUptime() =>
- DateTime.Now - Process.GetCurrentProcess().StartTime;
-
- public string GetUptimeString()
- {
- var time = GetUptime();
- return time.Days + " days, " + time.Hours + " hours, and " + time.Minutes + " minutes.";
- }
-
- public Task LoadStats() =>
- Task.Run(() =>
- {
- var songs = MusicModule.MusicPlayers.Count(mp => mp.Value.CurrentSong != null);
- var sb = new System.Text.StringBuilder();
- sb.AppendLine("`Author: Kwoth` `Library: Discord.Net`");
- sb.AppendLine($"`Bot Version: {BotVersion}`");
- sb.AppendLine($"`Bot id: {NadekoBot.Client.CurrentUser.Id}`");
- sb.Append("`Owners' Ids:` ");
- sb.AppendLine("`" + String.Join(", ", NadekoBot.Creds.OwnerIds) + "`");
- sb.AppendLine($"`Uptime: {GetUptimeString()}`");
- sb.Append($"`Servers: {ServerCount}");
- sb.Append($" | TextChannels: {TextChannelsCount}");
- sb.AppendLine($" | VoiceChannels: {VoiceChannelsCount}`");
- sb.AppendLine($"`Commands Ran this session: {commandsRan}`");
- sb.AppendLine($"`Message queue size: {NadekoBot.Client.MessageQueue.Count}`");
- sb.Append($"`Greeted {ServerGreetCommand.Greeted} times.`");
- sb.AppendLine($" `| Playing {songs} songs, ".SnPl(songs) +
- $"{MusicModule.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count)} queued.`");
- sb.AppendLine($"`Messages: {messageCounter} ({messageCounter / (double)GetUptime().TotalSeconds:F2}/sec)` `Heap: {Heap(false)}`");
- statsCache = sb.ToString();
- });
-
- public string Heap(bool pass = true) => Math.Round((double)GC.GetTotalMemory(pass) / 1.MiB(), 2).ToString();
-
- public async Task GetStats()
- {
- if (statsStopwatch.Elapsed.Seconds < 4 &&
- !string.IsNullOrWhiteSpace(statsCache)) return statsCache;
- await LoadStats().ConfigureAwait(false);
- statsStopwatch.Restart();
- return statsCache;
- }
-
- private async Task StartCollecting()
- {
- var statsSw = new Stopwatch();
- while (true)
- {
- await Task.Delay(new TimeSpan(0, 30, 0)).ConfigureAwait(false);
- statsSw.Start();
- try
- {
- var onlineUsers = await Task.Run(() => NadekoBot.Client.Servers.Sum(x => x.Users.Count())).ConfigureAwait(false);
- var realOnlineUsers = await Task.Run(() => NadekoBot.Client.Servers
- .Sum(x => x.Users.Count(u => u.Status == UserStatus.Online)))
- .ConfigureAwait(false);
- var connectedServers = NadekoBot.Client.Servers.Count();
-
- Classes.DbHandler.Instance.Connection.Insert(new DataModels.Stats
- {
- OnlineUsers = onlineUsers,
- RealOnlineUsers = realOnlineUsers,
- Uptime = GetUptime(),
- ConnectedServers = connectedServers,
- DateAdded = DateTime.Now
- });
-
- statsSw.Stop();
- var clr = Console.ForegroundColor;
- Console.ForegroundColor = ConsoleColor.Blue;
- Console.WriteLine($"--------------\nCollecting stats finished in {statsSw.Elapsed.TotalSeconds}s\n-------------");
- Console.ForegroundColor = clr;
- statsSw.Reset();
- }
- catch
- {
- Console.WriteLine("DB Exception in stats collecting.");
- break;
- }
- }
- }
-
- private static ConcurrentDictionary commandTracker = new ConcurrentDictionary();
-
- private void CommandService_CommandFinished(object sender, CommandEventArgs e)
- {
-
- DateTime dt;
- if (!commandTracker.TryGetValue(e.Message.Id, out dt))
- return;
-#if NADEKO_RELEASE
- try
- {
- if (e is CommandErrorEventArgs)
- {
- var er = e as CommandErrorEventArgs;
- if (er.ErrorType == CommandErrorType.Exception)
- {
- File.AppendAllText("errors.txt", $@"Command: {er.Command}
-{er.Exception}
--------------------------------------
-");
- Console.WriteLine($">>COMMAND ERRORED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
- }
-
- }
- else
- {
- Console.WriteLine($">>COMMAND ENDED after *{(DateTime.UtcNow - dt).TotalSeconds}s*\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
- }
- }
- catch { }
-#endif
- }
-
- private async void StatsCollector_RanCommand(object sender, CommandEventArgs e)
- {
- commandTracker.TryAdd(e.Message.Id, DateTime.UtcNow);
- Console.WriteLine($">>COMMAND STARTED\nCmd: {e.Command.Text}\nMsg: {e.Message.Text}\nUsr: {e.User.Name} [{e.User.Id}]\nSrvr: {e.Server?.Name ?? "PRIVATE"} [{e.Server?.Id}]\n-----");
- commandsRan++;
-#if !NADEKO_RELEASE
- await Task.Run(() =>
- {
- try
- {
- Classes.DbHandler.Instance.Connection.Insert(new DataModels.Command
- {
- ServerId = (long)(e.Server?.Id ?? 0),
- ServerName = e.Server?.Name ?? "--Direct Message--",
- ChannelId = (long)e.Channel.Id,
- ChannelName = e.Channel.IsPrivate ? "--Direct Message" : e.Channel.Name,
- UserId = (long)e.User.Id,
- UserName = e.User.Name,
- CommandName = e.Command.Text,
- DateAdded = DateTime.Now
- });
- }
- catch (Exception ex)
- {
- Console.WriteLine("Probably unimportant error in ran command DB write.");
- Console.WriteLine(ex);
- }
- }).ConfigureAwait(false);
-#endif
- }
- }
-}
diff --git a/NadekoBot/Classes/ObservableConcurrentDictionary.cs b/NadekoBot/Classes/ObservableConcurrentDictionary.cs
deleted file mode 100644
index cd364328..00000000
--- a/NadekoBot/Classes/ObservableConcurrentDictionary.cs
+++ /dev/null
@@ -1,204 +0,0 @@
-//--------------------------------------------------------------------------
-//
-// Copyright (c) Microsoft Corporation. All rights reserved.
-//
-// File: ObservableConcurrentDictionary.cs
-//
-//--------------------------------------------------------------------------
-
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.ComponentModel;
-using System.Diagnostics;
-using System.Threading;
-
-namespace System.Collections.Concurrent
-{
- ///
- /// Provides a thread-safe dictionary for use with data binding.
- ///
- /// Specifies the type of the keys in this collection.
- /// Specifies the type of the values in this collection.
- [DebuggerDisplay("Count={Count}")]
- public class ObservableConcurrentDictionary :
- ICollection>, IDictionary,
- INotifyCollectionChanged, INotifyPropertyChanged
- {
- private readonly SynchronizationContext _context;
- private readonly ConcurrentDictionary _dictionary;
-
- ///
- /// Initializes an instance of the ObservableConcurrentDictionary class.
- ///
- public ObservableConcurrentDictionary()
- {
- _context = AsyncOperationManager.SynchronizationContext;
- _dictionary = new ConcurrentDictionary();
- }
-
- /// Event raised when the collection changes.
- public event NotifyCollectionChangedEventHandler CollectionChanged;
- /// Event raised when a property on the collection changes.
- public event PropertyChangedEventHandler PropertyChanged;
-
- ///
- /// Notifies observers of CollectionChanged or PropertyChanged of an update to the dictionary.
- ///
- private void NotifyObserversOfChange()
- {
- var collectionHandler = CollectionChanged;
- var propertyHandler = PropertyChanged;
- if (collectionHandler != null || propertyHandler != null)
- {
- _context.Post(s =>
- {
- if (collectionHandler != null)
- {
- collectionHandler(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
- }
- if (propertyHandler != null)
- {
- propertyHandler(this, new PropertyChangedEventArgs("Count"));
- propertyHandler(this, new PropertyChangedEventArgs("Keys"));
- propertyHandler(this, new PropertyChangedEventArgs("Values"));
- }
- }, null);
- }
- }
-
- /// Attempts to add an item to the dictionary, notifying observers of any changes.
- /// The item to be added.
- /// Whether the add was successful.
- private bool TryAddWithNotification(KeyValuePair item)
- {
- return TryAddWithNotification(item.Key, item.Value);
- }
-
- /// Attempts to add an item to the dictionary, notifying observers of any changes.
- /// The key of the item to be added.
- /// The value of the item to be added.
- /// Whether the add was successful.
- private bool TryAddWithNotification(TKey key, TValue value)
- {
- bool result = _dictionary.TryAdd(key, value);
- if (result) NotifyObserversOfChange();
- return result;
- }
-
- /// Attempts to remove an item from the dictionary, notifying observers of any changes.
- /// The key of the item to be removed.
- /// The value of the item removed.
- /// Whether the removal was successful.
- private bool TryRemoveWithNotification(TKey key, out TValue value)
- {
- bool result = _dictionary.TryRemove(key, out value);
- if (result) NotifyObserversOfChange();
- return result;
- }
-
- /// Attempts to add or update an item in the dictionary, notifying observers of any changes.
- /// The key of the item to be updated.
- /// The new value to set for the item.
- /// Whether the update was successful.
- private void UpdateWithNotification(TKey key, TValue value)
- {
- _dictionary[key] = value;
- NotifyObserversOfChange();
- }
-
- #region ICollection> Members
- void ICollection>.Add(KeyValuePair item)
- {
- TryAddWithNotification(item);
- }
-
- void ICollection>.Clear()
- {
- ((ICollection>)_dictionary).Clear();
- NotifyObserversOfChange();
- }
-
- bool ICollection>.Contains(KeyValuePair item)
- {
- return ((ICollection>)_dictionary).Contains(item);
- }
-
- void ICollection>.CopyTo(KeyValuePair[] array, int arrayIndex)
- {
- ((ICollection>)_dictionary).CopyTo(array, arrayIndex);
- }
-
- int ICollection>.Count {
- get { return ((ICollection>)_dictionary).Count; }
- }
-
- bool ICollection>.IsReadOnly {
- get { return ((ICollection>)_dictionary).IsReadOnly; }
- }
-
- bool ICollection>.Remove(KeyValuePair item)
- {
- TValue temp;
- return TryRemoveWithNotification(item.Key, out temp);
- }
- #endregion
-
- #region IEnumerable> Members
- IEnumerator> IEnumerable>.GetEnumerator()
- {
- return ((ICollection>)_dictionary).GetEnumerator();
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return ((ICollection>)_dictionary).GetEnumerator();
- }
- #endregion
-
- #region IDictionary Members
- public void Add(TKey key, TValue value)
- {
- TryAddWithNotification(key, value);
- }
-
- public bool ContainsKey(TKey key)
- {
- return _dictionary.ContainsKey(key);
- }
-
- public ICollection Keys {
- get { return _dictionary.Keys; }
- }
-
- public bool Remove(TKey key)
- {
- TValue temp;
- return TryRemoveWithNotification(key, out temp);
- }
-
- public bool TryGetValue(TKey key, out TValue value)
- {
- return _dictionary.TryGetValue(key, out value);
- }
-
- public bool TryAdd(TKey key, TValue value)
- {
- return TryAddWithNotification(key, value);
- }
-
- public ICollection Values {
- get { return _dictionary.Values; }
- }
-
- public TValue this[TKey key] {
- get { return _dictionary[key]; }
- set { UpdateWithNotification(key, value); }
- }
-
- public bool TryRemove(TKey key, out TValue value)
- {
- return TryRemoveWithNotification(key, out value);
- }
- #endregion
- }
-}
\ No newline at end of file
diff --git a/NadekoBot/Classes/SearchHelper.cs b/NadekoBot/Classes/SearchHelper.cs
deleted file mode 100644
index e5bbcc2e..00000000
--- a/NadekoBot/Classes/SearchHelper.cs
+++ /dev/null
@@ -1,402 +0,0 @@
-using NadekoBot.Classes.JSONModels;
-using NadekoBot.Extensions;
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Net.Http;
-using System.Security.Authentication;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using System.Xml.Linq;
-
-namespace NadekoBot.Classes
-{
- public enum RequestHttpMethod
- {
- Get,
- Post
- }
-
- public static class SearchHelper
- {
- private static DateTime lastRefreshed = DateTime.MinValue;
- private static string token { get; set; } = "";
-
- public static async Task GetResponseStreamAsync(string url,
- IEnumerable> headers = null, RequestHttpMethod method = RequestHttpMethod.Get)
- {
- if (string.IsNullOrWhiteSpace(url))
- throw new ArgumentNullException(nameof(url));
- var cl = new HttpClient();
- cl.DefaultRequestHeaders.Clear();
- switch (method)
- {
- case RequestHttpMethod.Get:
- if (headers != null)
- {
- foreach (var header in headers)
- {
- cl.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
- }
- }
- return await cl.GetStreamAsync(url).ConfigureAwait(false);
- case RequestHttpMethod.Post:
- FormUrlEncodedContent formContent = null;
- if (headers != null)
- {
- formContent = new FormUrlEncodedContent(headers);
- }
- var message = await cl.PostAsync(url, formContent).ConfigureAwait(false);
- return await message.Content.ReadAsStreamAsync().ConfigureAwait(false);
- default:
- throw new NotImplementedException("That type of request is unsupported.");
- }
- }
-
- public static async Task GetResponseStringAsync(string url,
- IEnumerable> headers = null,
- RequestHttpMethod method = RequestHttpMethod.Get)
- {
- if (string.IsNullOrWhiteSpace(url))
- throw new ArgumentNullException(nameof(url));
- var cl = new HttpClient();
- cl.DefaultRequestHeaders.Clear();
- switch (method)
- {
- case RequestHttpMethod.Get:
- if (headers != null)
- {
- foreach (var header in headers)
- {
- cl.DefaultRequestHeaders.TryAddWithoutValidation(header.Key, header.Value);
- }
- }
- return await cl.GetStringAsync(url).ConfigureAwait(false);
- case RequestHttpMethod.Post:
- FormUrlEncodedContent formContent = null;
- if (headers != null)
- {
- formContent = new FormUrlEncodedContent(headers);
- }
- var message = await cl.PostAsync(url, formContent).ConfigureAwait(false);
- return await message.Content.ReadAsStringAsync().ConfigureAwait(false);
- default:
- throw new NotImplementedException("That type of request is unsupported.");
- }
- }
-
- public static async Task GetAnimeData(string query)
- {
- if (string.IsNullOrWhiteSpace(query))
- throw new ArgumentNullException(nameof(query));
-
- await RefreshAnilistToken().ConfigureAwait(false);
-
- var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
- var smallContent = "";
- var cl = new RestSharp.RestClient("http://anilist.co/api");
- var rq = new RestSharp.RestRequest("/anime/search/" + Uri.EscapeUriString(query));
- rq.AddParameter("access_token", token);
- smallContent = cl.Execute(rq).Content;
- var smallObj = JArray.Parse(smallContent)[0];
-
- rq = new RestSharp.RestRequest("/anime/" + smallObj["id"]);
- rq.AddParameter("access_token", token);
- var content = cl.Execute(rq).Content;
-
- return await Task.Run(() => JsonConvert.DeserializeObject(content)).ConfigureAwait(false);
- }
-
- public static async Task GetMangaData(string query)
- {
- if (string.IsNullOrWhiteSpace(query))
- throw new ArgumentNullException(nameof(query));
-
- await RefreshAnilistToken().ConfigureAwait(false);
-
- var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query);
- var smallContent = "";
- var cl = new RestSharp.RestClient("http://anilist.co/api");
- var rq = new RestSharp.RestRequest("/manga/search/" + Uri.EscapeUriString(query));
- rq.AddParameter("access_token", token);
- smallContent = cl.Execute(rq).Content;
- var smallObj = JArray.Parse(smallContent)[0];
-
- rq = new RestSharp.RestRequest("/manga/" + smallObj["id"]);
- rq.AddParameter("access_token", token);
- var content = cl.Execute(rq).Content;
-
- return await Task.Run(() => JsonConvert.DeserializeObject(content)).ConfigureAwait(false);
- }
-
- private static async Task RefreshAnilistToken()
- {
- if (DateTime.Now - lastRefreshed > TimeSpan.FromMinutes(29))
- lastRefreshed = DateTime.Now;
- else
- {
- return;
- }
- var headers = new Dictionary {
- {"grant_type", "client_credentials"},
- {"client_id", "kwoth-w0ki9"},
- {"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"},
- };
- var content = await GetResponseStringAsync(
- "http://anilist.co/api/auth/access_token",
- headers,
- RequestHttpMethod.Post).ConfigureAwait(false);
-
- token = JObject.Parse(content)["access_token"].ToString();
- }
-
- public static async Task ValidateQuery(Discord.Channel ch, string query)
- {
- if (!string.IsNullOrEmpty(query.Trim())) return true;
- await ch.Send("Please specify search parameters.").ConfigureAwait(false);
- return false;
- }
-
- public static async Task FindYoutubeUrlByKeywords(string keywords)
- {
- if (string.IsNullOrWhiteSpace(keywords))
- throw new ArgumentNullException(nameof(keywords), "Query not specified.");
- if (keywords.Length > 150)
- throw new ArgumentException("Query is too long.");
-
- //maybe it is already a youtube url, in which case we will just extract the id and prepend it with youtube.com?v=
- var match = new Regex("(?:youtu\\.be\\/|v=)(?[\\da-zA-Z\\-_]*)").Match(keywords);
- if (match.Length > 1)
- {
- return $"https://www.youtube.com/watch?v={match.Groups["id"].Value}";
- }
-
- if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
- throw new InvalidCredentialException("Google API Key is missing.");
-
- var response = await GetResponseStringAsync(
- $"https://www.googleapis.com/youtube/v3/search?" +
- $"part=snippet&maxResults=1" +
- $"&q={Uri.EscapeDataString(keywords)}" +
- $"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
- JObject obj = JObject.Parse(response);
-
- var data = JsonConvert.DeserializeObject(response);
-
- if (data.items.Length > 0)
- {
- var toReturn = "http://www.youtube.com/watch?v=" + data.items[0].id.videoId.ToString();
- return toReturn;
- }
- else
- return null;
- }
-
- public static async Task> GetRelatedVideoIds(string id, int count = 1)
- {
- if (string.IsNullOrWhiteSpace(id))
- throw new ArgumentNullException(nameof(id));
- var match = new Regex("(?:youtu\\.be\\/|v=)(?[\\da-zA-Z\\-_]*)").Match(id);
- if (match.Length > 1)
- {
- id = match.Groups["id"].Value;
- }
- var response = await GetResponseStringAsync(
- $"https://www.googleapis.com/youtube/v3/search?" +
- $"part=snippet&maxResults={count}&type=video" +
- $"&relatedToVideoId={id}" +
- $"&key={NadekoBot.Creds.GoogleAPIKey}").ConfigureAwait(false);
- JObject obj = JObject.Parse(response);
-
- var data = JsonConvert.DeserializeObject(response);
-
- return data.items.Select(v => "http://www.youtube.com/watch?v=" + v.id.videoId);
- }
-
- public static async Task GetPlaylistIdByKeyword(string query)
- {
- if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
- throw new ArgumentNullException(nameof(query));
- var match = new Regex("(?:youtu\\.be\\/|list=)(?[\\da-zA-Z\\-_]*)").Match(query);
- if (match.Length > 1)
- {
- return match.Groups["id"].Value.ToString();
- }
- var link = "https://www.googleapis.com/youtube/v3/search?part=snippet" +
- "&maxResults=1&type=playlist" +
- $"&q={Uri.EscapeDataString(query)}" +
- $"&key={NadekoBot.Creds.GoogleAPIKey}";
-
- var response = await GetResponseStringAsync(link).ConfigureAwait(false);
- var data = JsonConvert.DeserializeObject(response);
- JObject obj = JObject.Parse(response);
-
- return data.items.Length > 0 ? data.items[0].id.playlistId.ToString() : null;
- }
-
- public static async Task> GetVideoIDs(string playlist, int number = 50)
- {
- if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey))
- {
- throw new ArgumentNullException(nameof(playlist));
- }
- if (number < 1)
- throw new ArgumentOutOfRangeException();
-
- string nextPageToken = null;
-
- List toReturn = new List();
-
- do
- {
- var toGet = number > 50 ? 50 : number;
- number -= toGet;
- var link =
- $"https://www.googleapis.com/youtube/v3/playlistItems?part=contentDetails" +
- $"&maxResults={toGet}" +
- $"&playlistId={playlist}" +
- $"&key={NadekoBot.Creds.GoogleAPIKey}";
- if (!string.IsNullOrWhiteSpace(nextPageToken))
- link += $"&pageToken={nextPageToken}";
- var response = await GetResponseStringAsync(link).ConfigureAwait(false);
- var data = await Task.Run(() => JsonConvert.DeserializeObject(response)).ConfigureAwait(false);
- nextPageToken = data.nextPageToken;
- toReturn.AddRange(data.items.Select(i => i.contentDetails.videoId));
- } while (number > 0 && !string.IsNullOrWhiteSpace(nextPageToken));
-
- return toReturn;
- }
-
-
- public static async Task GetDanbooruImageLink(string tag)
- {
- var rng = new Random();
-
- if (tag == "loli") //loli doesn't work for some reason atm
- tag = "flat_chest";
-
- var link = $"http://danbooru.donmai.us/posts?" +
- $"page={rng.Next(0, 15)}";
- if (!string.IsNullOrWhiteSpace(tag))
- link += $"&tags={tag.Replace(" ", "_")}";
-
- var webpage = await GetResponseStringAsync(link).ConfigureAwait(false);
- var matches = Regex.Matches(webpage, "data-large-file-url=\"(?.*?)\"");
-
- if (matches.Count == 0)
- return null;
- return $"http://danbooru.donmai.us" +
- $"{matches[rng.Next(0, matches.Count)].Groups["id"].Value}";
- }
-
- public static async Task GetGelbooruImageLink(string tag)
- {
- var headers = new Dictionary() {
- {"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"},
- {"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" },
- };
- var url =
- $"http://gelbooru.com/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
- var webpage = await GetResponseStringAsync(url, headers).ConfigureAwait(false);
- var matches = Regex.Matches(webpage, "file_url=\"(?.*?)\"");
- if (matches.Count == 0)
- return null;
- var rng = new Random();
- var match = matches[rng.Next(0, matches.Count)];
- return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
- }
-
- public static async Task GetSafebooruImageLink(string tag)
- {
- var rng = new Random();
- var url =
- $"http://safebooru.org/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
- var webpage = await GetResponseStringAsync(url).ConfigureAwait(false);
- var matches = Regex.Matches(webpage, "file_url=\"(?.*?)\"");
- if (matches.Count == 0)
- return null;
- var match = matches[rng.Next(0, matches.Count)];
- return matches[rng.Next(0, matches.Count)].Groups["url"].Value;
- }
-
- public static async Task GetRule34ImageLink(string tag)
- {
- var rng = new Random();
- var url =
- $"http://rule34.xxx/index.php?page=dapi&s=post&q=index&limit=100&tags={tag.Replace(" ", "_")}";
- var webpage = await GetResponseStringAsync(url).ConfigureAwait(false);
- var matches = Regex.Matches(webpage, "file_url=\"(?.*?)\"");
- if (matches.Count == 0)
- return null;
- var match = matches[rng.Next(0, matches.Count)];
- return "http:" + matches[rng.Next(0, matches.Count)].Groups["url"].Value;
- }
-
-
- internal static async Task GetE621ImageLink(string tags)
- {
- try
- {
- var headers = new Dictionary() {
- {"User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1"},
- {"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" },
- };
- var data = await GetResponseStreamAsync(
- "http://e621.net/post/index.xml?tags=" + Uri.EscapeUriString(tags) + "%20order:random&limit=1",
- headers);
- var doc = XDocument.Load(data);
- return doc.Descendants("file_url").FirstOrDefault().Value;
- }
- catch (Exception ex)
- {
- Console.WriteLine("Error in e621 search: \n" + ex);
- return "Error, do you have too many tags?";
- }
- }
-
- public static async Task ShortenUrl(string url)
- {
- if (string.IsNullOrWhiteSpace(NadekoBot.Creds.GoogleAPIKey)) return url;
- try
- {
- var httpWebRequest =
- (HttpWebRequest)WebRequest.Create("https://www.googleapis.com/urlshortener/v1/url?key=" +
- NadekoBot.Creds.GoogleAPIKey);
- httpWebRequest.ContentType = "application/json";
- httpWebRequest.Method = "POST";
-
- using (var streamWriter = new StreamWriter(await httpWebRequest.GetRequestStreamAsync().ConfigureAwait(false)))
- {
- var json = "{\"longUrl\":\"" + Uri.EscapeDataString(url) + "\"}";
- streamWriter.Write(json);
- }
-
- var httpResponse = (await httpWebRequest.GetResponseAsync().ConfigureAwait(false)) as HttpWebResponse;
- var responseStream = httpResponse.GetResponseStream();
- using (var streamReader = new StreamReader(responseStream))
- {
- var responseText = await streamReader.ReadToEndAsync().ConfigureAwait(false);
- return Regex.Match(responseText, @"""id"": ?""(?.+)""").Groups["id"].Value;
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine("Shortening of this url failed: " + url);
- Console.WriteLine(ex.ToString());
- return url;
- }
- }
-
- public static string ShowInPrettyCode(IEnumerable items, Func howToPrint, int cols = 3)
- {
- var i = 0;
- return "```xl\n" + string.Join("\n", items.GroupBy(item => (i++) / cols)
- .Select(ig => string.Concat(ig.Select(el => howToPrint(el)))))
- + $"\n```";
- }
- }
-}
diff --git a/NadekoBot/Classes/ServerSpecificConfig.cs b/NadekoBot/Classes/ServerSpecificConfig.cs
deleted file mode 100644
index 1642f75e..00000000
--- a/NadekoBot/Classes/ServerSpecificConfig.cs
+++ /dev/null
@@ -1,290 +0,0 @@
-using Newtonsoft.Json;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Classes
-{
- internal class SpecificConfigurations
- {
- public static SpecificConfigurations Default { get; } = new SpecificConfigurations();
- public static bool Instantiated { get; private set; }
-
- private const string filePath = "data/ServerSpecificConfigs.json";
-
- static SpecificConfigurations() { }
-
- private SpecificConfigurations()
- {
-
- if (File.Exists(filePath))
- {
- try
- {
- configs = JsonConvert
- .DeserializeObject>(
- File.ReadAllText(filePath), new JsonSerializerSettings()
- {
- Error = (s, e) =>
- {
- if (e.ErrorContext.Member.ToString() == "GenerateCurrencyChannels")
- {
- e.ErrorContext.Handled = true;
- }
- }
- });
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Deserialization failing: {ex}");
- }
- }
- if (configs == null)
- configs = new ConcurrentDictionary();
- Instantiated = true;
- }
-
- private readonly ConcurrentDictionary configs;
-
- public IEnumerable AllConfigs => configs.Values;
-
- public ServerSpecificConfig Of(ulong id) =>
- configs.GetOrAdd(id, _ => new ServerSpecificConfig());
-
- private readonly SemaphoreSlim saveLock = new SemaphoreSlim(1, 1);
-
- public async Task Save()
- {
- await saveLock.WaitAsync();
- try
- {
- await Task.Run(() => File.WriteAllText(filePath, JsonConvert.SerializeObject(configs, Formatting.Indented)));
- }
- finally
- {
- saveLock.Release();
- }
- }
- }
-
- internal class ServerSpecificConfig : INotifyPropertyChanged
- {
- [JsonProperty("VoicePlusTextEnabled")]
- private bool voicePlusTextEnabled;
- [JsonIgnore]
- public bool VoicePlusTextEnabled {
- get { return voicePlusTextEnabled; }
- set {
- voicePlusTextEnabled = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
- [JsonProperty("SendPrivateMessageOnMention")]
- private bool sendPrivateMessageOnMention;
- [JsonIgnore]
- public bool SendPrivateMessageOnMention {
- get { return sendPrivateMessageOnMention; }
- set {
- sendPrivateMessageOnMention = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
-
- [JsonProperty("LogChannel")]
- private ulong? logServerChannel = null;
- [JsonIgnore]
- public ulong? LogServerChannel {
- get { return logServerChannel; }
- set {
- logServerChannel = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
-
- [JsonIgnore]
- private ObservableCollection logserverIgnoreChannels;
- public ObservableCollection LogserverIgnoreChannels {
- get { return logserverIgnoreChannels; }
- set {
- logserverIgnoreChannels = value;
- if (value != null)
- logserverIgnoreChannels.CollectionChanged += (s, e) =>
- {
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- };
- }
- }
-
- [JsonProperty("LogPresenceChannel")]
- private ulong? logPresenceChannel = null;
- [JsonIgnore]
- public ulong? LogPresenceChannel {
- get { return logPresenceChannel; }
- set {
- logPresenceChannel = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
-
- [JsonIgnore]
- private ObservableConcurrentDictionary voiceChannelLog;
- public ObservableConcurrentDictionary VoiceChannelLog {
- get { return voiceChannelLog; }
- set {
- voiceChannelLog = value;
- if (value != null)
- voiceChannelLog.CollectionChanged += (s, e) =>
- {
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- };
- }
- }
-
- [JsonIgnore]
- private ObservableCollection listOfSelfAssignableRoles;
- public ObservableCollection ListOfSelfAssignableRoles {
- get { return listOfSelfAssignableRoles; }
- set {
- listOfSelfAssignableRoles = value;
- if (value != null)
- listOfSelfAssignableRoles.CollectionChanged += (s, e) =>
- {
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- };
- }
- }
-
-
-
- [JsonIgnore]
- private ulong autoAssignedRole = 0;
- public ulong AutoAssignedRole {
- get { return autoAssignedRole; }
- set {
- autoAssignedRole = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
-
- [JsonIgnore]
- private ObservableConcurrentDictionary generateCurrencyChannels;
- public ObservableConcurrentDictionary GenerateCurrencyChannels {
- get { return generateCurrencyChannels; }
- set {
- generateCurrencyChannels = value;
- if (value != null)
- generateCurrencyChannels.CollectionChanged += (s, e) =>
- {
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- };
- }
- }
-
- [JsonIgnore]
- private bool autoDeleteMessagesOnCommand = false;
- public bool AutoDeleteMessagesOnCommand {
- get { return autoDeleteMessagesOnCommand; }
- set {
- autoDeleteMessagesOnCommand = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
-
- [JsonIgnore]
- private bool exclusiveSelfAssignedRoles = false;
- public bool ExclusiveSelfAssignedRoles {
- get { return exclusiveSelfAssignedRoles; }
- set {
- exclusiveSelfAssignedRoles = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
-
-
- [JsonIgnore]
- private ObservableCollection observingStreams;
- public ObservableCollection ObservingStreams {
- get { return observingStreams; }
- set {
- observingStreams = value;
- if (value != null)
- observingStreams.CollectionChanged += (s, e) =>
- {
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- };
- }
- }
-
- [JsonIgnore]
- private float defaultMusicVolume = 1f;
- public float DefaultMusicVolume {
- get { return defaultMusicVolume; }
- set {
- defaultMusicVolume = value;
- if (!SpecificConfigurations.Instantiated) return;
- OnPropertyChanged();
- }
- }
-
- public ServerSpecificConfig()
- {
- ListOfSelfAssignableRoles = new ObservableCollection();
- ObservingStreams = new ObservableCollection();
- GenerateCurrencyChannels = new ObservableConcurrentDictionary();
- VoiceChannelLog = new ObservableConcurrentDictionary();
- LogserverIgnoreChannels = new ObservableCollection();
- }
-
- public event PropertyChangedEventHandler PropertyChanged = async delegate { await SpecificConfigurations.Default.Save().ConfigureAwait(false); };
-
- private void OnPropertyChanged([CallerMemberName] string propertyName = null)
- {
- PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
- }
-
- public class StreamNotificationConfig : IEquatable
- {
- public string Username { get; set; }
- public StreamType Type { get; set; }
- public ulong ServerId { get; set; }
- public ulong ChannelId { get; set; }
- public bool LastStatus { get; set; }
-
- public enum StreamType
- {
- Twitch,
- Beam,
- Hitbox,
- YoutubeGaming
- }
-
- public bool Equals(StreamNotificationConfig other) =>
- this.Username.ToUpperInvariant().Trim() == other.Username.ToUpperInvariant().Trim() &&
- this.Type == other.Type &&
- this.ServerId == other.ServerId;
-
- public override int GetHashCode()
- {
- return (int)ServerId + Username.Length + (int)Type;
- }
- }
-}
diff --git a/NadekoBot/Classes/lib/ScaredFingers.UnitsConversion.dll b/NadekoBot/Classes/lib/ScaredFingers.UnitsConversion.dll
deleted file mode 100644
index 8b121811..00000000
Binary files a/NadekoBot/Classes/lib/ScaredFingers.UnitsConversion.dll and /dev/null differ
diff --git a/NadekoBot/Classes/lib/ScaredFingers.UnitsConversion.pdb b/NadekoBot/Classes/lib/ScaredFingers.UnitsConversion.pdb
deleted file mode 100644
index f63024ad..00000000
Binary files a/NadekoBot/Classes/lib/ScaredFingers.UnitsConversion.pdb and /dev/null differ
diff --git a/NadekoBot/Classes/lib/sqlite3.dll b/NadekoBot/Classes/lib/sqlite3.dll
deleted file mode 100644
index c68c1f14..00000000
Binary files a/NadekoBot/Classes/lib/sqlite3.dll and /dev/null differ
diff --git a/NadekoBot/Modules/Administration/AdministrationModule.cs b/NadekoBot/Modules/Administration/AdministrationModule.cs
deleted file mode 100644
index 24effe3a..00000000
--- a/NadekoBot/Modules/Administration/AdministrationModule.cs
+++ /dev/null
@@ -1,901 +0,0 @@
-using Discord;
-using Discord.Commands;
-using Discord.Modules;
-using NadekoBot.Classes;
-using NadekoBot.DataModels;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Administration.Commands;
-using NadekoBot.Modules.Permissions.Classes;
-using Newtonsoft.Json;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Administration
-{
- internal class AdministrationModule : DiscordModule
- {
- public AdministrationModule()
- {
- commands.Add(new ServerGreetCommand(this));
- commands.Add(new LogCommand(this));
- commands.Add(new MessageRepeater(this));
- commands.Add(new PlayingRotate(this));
- commands.Add(new RatelimitCommand(this));
- commands.Add(new VoicePlusTextCommand(this));
- commands.Add(new CrossServerTextChannel(this));
- commands.Add(new SelfAssignedRolesCommand(this));
- commands.Add(new CustomReactionsCommands(this));
- commands.Add(new AutoAssignRole(this));
- commands.Add(new SelfCommands(this));
- commands.Add(new IncidentsCommands(this));
-
- NadekoBot.Client.GetService().CommandExecuted += DeleteCommandMessage;
- }
-
- private void DeleteCommandMessage(object sender, CommandEventArgs e)
- {
- if (e.Server == null || e.Channel.IsPrivate)
- return;
- var conf = SpecificConfigurations.Default.Of(e.Server.Id);
- if (!conf.AutoDeleteMessagesOnCommand)
- return;
- try
- {
- e.Message.Delete();
- }
- catch { }
- }
-
- public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Administration;
-
- public override void Install(ModuleManager manager)
- {
-
- manager.CreateCommands("", cgb =>
- {
-
- cgb.AddCheck(PermissionChecker.Instance);
-
- var client = manager.Client;
-
- commands.ForEach(cmd => cmd.Init(cgb));
-
- cgb.CreateCommand(Prefix + "delmsgoncmd")
- .Description($"Toggles the automatic deletion of user's successful command message to prevent chat flood. **Server Manager Only.** | `{Prefix}delmsgoncmd`")
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- var conf = SpecificConfigurations.Default.Of(e.Server.Id);
- conf.AutoDeleteMessagesOnCommand = !conf.AutoDeleteMessagesOnCommand;
- await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
- if (conf.AutoDeleteMessagesOnCommand)
- await e.Channel.SendMessage("❗`Now automatically deleting successful command invokations.`");
- else
- await e.Channel.SendMessage("❗`Stopped automatic deletion of successful command invokations.`");
-
- });
-
- cgb.CreateCommand(Prefix + "restart")
- .Description($"Restarts the bot. Might not work. **Bot Owner Only** | `{Prefix}restart`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- await e.Channel.SendMessage("`Restarting in 2 seconds...`");
- await Task.Delay(2000);
- System.Diagnostics.Process.Start(System.Reflection.Assembly.GetExecutingAssembly().Location);
- Environment.Exit(0);
- });
-
- cgb.CreateCommand(Prefix + "setrole").Alias(Prefix + "sr")
- .Description($"Sets a role for a given user. **Needs Manage Roles Permissions.**| `{Prefix}sr @User Guest`")
- .Parameter("user_name", ParameterType.Required)
- .Parameter("role_name", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- var userName = e.GetArg("user_name");
- var roleName = e.GetArg("role_name");
-
- if (string.IsNullOrWhiteSpace(roleName)) return;
-
- if (!e.User.ServerPermissions.ManageRoles)
- {
- await e.Channel.SendMessage("You have insufficient permissions.").ConfigureAwait(false);
- }
-
- var usr = e.Server.FindUsers(userName).FirstOrDefault();
- if (usr == null)
- {
- await e.Channel.SendMessage("You failed to supply a valid username").ConfigureAwait(false);
- return;
- }
-
- var role = e.Server.FindRoles(roleName).FirstOrDefault();
- if (role == null)
- {
- await e.Channel.SendMessage("You failed to supply a valid role").ConfigureAwait(false);
- return;
- }
-
- try
- {
- await usr.AddRoles(role).ConfigureAwait(false);
- await e.Channel.SendMessage($"Successfully added role **{role.Name}** to user **{usr.Name}**").ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- await e.Channel.SendMessage("Failed to add roles. Bot has insufficient permissions.\n").ConfigureAwait(false);
- Console.WriteLine(ex.ToString());
- }
- });
-
- cgb.CreateCommand(Prefix + "removerole").Alias(Prefix + "rr")
- .Description($"Removes a role from a given user. **Needs Manage Roles Permissions.**| `{Prefix}rr @User Admin`")
- .Parameter("user_name", ParameterType.Required)
- .Parameter("role_name", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- var userName = e.GetArg("user_name");
- var roleName = e.GetArg("role_name");
-
- if (string.IsNullOrWhiteSpace(roleName)) return;
-
- var usr = e.Server.FindUsers(userName).FirstOrDefault();
- if (usr == null)
- {
- await e.Channel.SendMessage("You failed to supply a valid username").ConfigureAwait(false);
- return;
- }
-
- var role = e.Server.FindRoles(roleName).FirstOrDefault();
- if (role == null)
- {
- await e.Channel.SendMessage("You failed to supply a valid role").ConfigureAwait(false);
- return;
- }
-
- try
- {
- await usr.RemoveRoles(role).ConfigureAwait(false);
- await e.Channel.SendMessage($"Successfully removed role **{role.Name}** from user **{usr.Name}**").ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("Failed to remove roles. Most likely reason: Insufficient permissions.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "renamerole")
- .Alias(Prefix + "renr")
- .Description($"Renames a role. Roles you are renaming must be lower than bot's highest role. **Manage Roles Permissions.** | `{Prefix}renr \"First role\" SecondRole`")
- .Parameter("r1", ParameterType.Required)
- .Parameter("r2", ParameterType.Required)
- .AddCheck(new SimpleCheckers.ManageRoles())
- .Do(async e =>
- {
- var r1 = e.GetArg("r1").Trim();
- var r2 = e.GetArg("r2").Trim();
-
- var roleToEdit = e.Server.FindRoles(r1).FirstOrDefault();
- if (roleToEdit == null)
- {
- await e.Channel.SendMessage("Can't find that role.").ConfigureAwait(false);
- return;
- }
-
- try
- {
- if (roleToEdit.Position > e.Server.CurrentUser.Roles.Max(r => r.Position))
- {
- await e.Channel.SendMessage("I can't edit roles higher than my highest role.").ConfigureAwait(false);
- return;
- }
- await roleToEdit.Edit(r2);
- await e.Channel.SendMessage("Role renamed.").ConfigureAwait(false);
- }
- catch (Exception)
- {
- await e.Channel.SendMessage("Failed to rename role. Probably insufficient permissions.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "removeallroles").Alias(Prefix + "rar")
- .Description($"Removes all roles from a mentioned user. **Needs Manage Roles Permissions.**| `{Prefix}rar @User`")
- .Parameter("user_name", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- var userName = e.GetArg("user_name");
-
- var usr = e.Server.FindUsers(userName).FirstOrDefault();
- if (usr == null)
- {
- await e.Channel.SendMessage("You failed to supply a valid username").ConfigureAwait(false);
- return;
- }
-
- try
- {
- await usr.RemoveRoles(usr.Roles.ToArray()).ConfigureAwait(false);
- await e.Channel.SendMessage($"Successfully removed **all** roles from user **{usr.Name}**").ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("Failed to remove roles. Most likely reason: Insufficient permissions.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "createrole").Alias(Prefix + "cr")
- .Description($"Creates a role with a given name. **Needs Manage Roles Permissions.**| `{Prefix}cr Awesome Role`")
- .Parameter("role_name", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- if (string.IsNullOrWhiteSpace(e.GetArg("role_name")))
- return;
- try
- {
- var r = await e.Server.CreateRole(e.GetArg("role_name")).ConfigureAwait(false);
- await e.Channel.SendMessage($"Successfully created role **{r.Name}**.").ConfigureAwait(false);
- }
- catch (Exception)
- {
- await e.Channel.SendMessage(":warning: Unspecified error.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "rolecolor").Alias(Prefix + "rc")
- .Parameter("role_name", ParameterType.Required)
- .Parameter("r", ParameterType.Optional)
- .Parameter("g", ParameterType.Optional)
- .Parameter("b", ParameterType.Optional)
- .Description($"Set a role's color to the hex or 0-255 rgb color value provided. **Needs Manage Roles Permissions.** | `{Prefix}rc Admin 255 200 100` or `{Prefix}rc Admin ffba55`")
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageRoles)
- {
- await e.Channel.SendMessage("You don't have permission to use this!").ConfigureAwait(false);
- return;
- }
-
- var args = e.Args.Where(s => s != string.Empty);
-
- if (args.Count() != 2 && args.Count() != 4)
- {
- await e.Channel.SendMessage("The parameters are invalid.").ConfigureAwait(false);
- return;
- }
-
- var role = e.Server.FindRoles(e.Args[0]).FirstOrDefault();
-
- if (role == null)
- {
- await e.Channel.SendMessage("That role does not exist.").ConfigureAwait(false);
- return;
- }
- try
- {
- var rgb = args.Count() == 4;
- var arg1 = e.Args[1].Replace("#", "");
-
- var red = Convert.ToByte(rgb ? int.Parse(arg1) : Convert.ToInt32(arg1.Substring(0, 2), 16));
- var green = Convert.ToByte(rgb ? int.Parse(e.Args[2]) : Convert.ToInt32(arg1.Substring(2, 2), 16));
- var blue = Convert.ToByte(rgb ? int.Parse(e.Args[3]) : Convert.ToInt32(arg1.Substring(4, 2), 16));
-
- await role.Edit(color: new Color(red, green, blue)).ConfigureAwait(false);
- await e.Channel.SendMessage($"Role {role.Name}'s color has been changed.").ConfigureAwait(false);
- }
- catch (Exception)
- {
- await e.Channel.SendMessage("Error occured, most likely invalid parameters or insufficient permissions.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "ban").Alias(Prefix + "b")
- .Parameter("user", ParameterType.Required)
- .Parameter("msg", ParameterType.Unparsed)
- .Description($"Bans a user by id or name with an optional message. **Needs Ban Permissions.**| `{Prefix}b \"@some Guy\" Your behaviour is toxic.`")
- .Do(async e =>
- {
- var msg = e.GetArg("msg");
- var user = e.GetArg("user");
- if (e.User.ServerPermissions.BanMembers)
- {
- var usr = e.Server.FindUsers(user).FirstOrDefault();
- if (usr == null)
- {
- await e.Channel.SendMessage("User not found.").ConfigureAwait(false);
- return;
- }
- if (!string.IsNullOrWhiteSpace(msg))
- {
- await usr.SendMessage($"**You have been BANNED from `{e.Server.Name}` server.**\n" +
- $"Reason: {msg}").ConfigureAwait(false);
- await Task.Delay(2000).ConfigureAwait(false); // temp solution; give time for a message to be send, fu volt
- }
- try
- {
- await e.Server.Ban(usr, 7).ConfigureAwait(false);
-
- await e.Channel.SendMessage("Banned user " + usr.Name + " Id: " + usr.Id).ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
- }
- }
- });
-
- cgb.CreateCommand(Prefix + "softban").Alias(Prefix + "sb")
- .Parameter("user", ParameterType.Required)
- .Parameter("msg", ParameterType.Unparsed)
- .Description($"Bans and then unbans a user by id or name with an optional message. **Needs Ban Permissions.**| `{Prefix}sb \"@some Guy\" Your behaviour is toxic.`")
- .Do(async e =>
- {
- var msg = e.GetArg("msg");
- var user = e.GetArg("user");
- if (e.User.ServerPermissions.BanMembers)
- {
- var usr = e.Server.FindUsers(user).FirstOrDefault();
- if (usr == null)
- {
- await e.Channel.SendMessage("User not found.").ConfigureAwait(false);
- return;
- }
- if (!string.IsNullOrWhiteSpace(msg))
- {
- await usr.SendMessage($"**You have been SOFT-BANNED from `{e.Server.Name}` server.**\n" +
- $"Reason: {msg}").ConfigureAwait(false);
- await Task.Delay(2000).ConfigureAwait(false); // temp solution; give time for a message to be send, fu volt
- }
- try
- {
- await e.Server.Ban(usr, 7).ConfigureAwait(false);
- await e.Server.Unban(usr).ConfigureAwait(false);
-
- await e.Channel.SendMessage("Soft-Banned user " + usr.Name + " Id: " + usr.Id).ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
- }
- }
- });
-
- cgb.CreateCommand(Prefix + "kick").Alias(Prefix + "k")
- .Parameter("user")
- .Parameter("msg", ParameterType.Unparsed)
- .Description($"Kicks a mentioned user. **Needs Kick Permissions.**| `{Prefix}k \"@some Guy\" Your behaviour is toxic.`")
- .Do(async e =>
- {
- var msg = e.GetArg("msg");
- var user = e.GetArg("user");
- if (e.User.ServerPermissions.KickMembers)
- {
- var usr = e.Server.FindUsers(user).FirstOrDefault();
- if (usr == null)
- {
- await e.Channel.SendMessage("User not found.").ConfigureAwait(false);
- return;
- }
- if (!string.IsNullOrWhiteSpace(msg))
- {
- await usr.SendMessage($"**You have been KICKED from `{e.Server.Name}` server.**\n" +
- $"Reason: {msg}").ConfigureAwait(false);
- await Task.Delay(2000).ConfigureAwait(false); // temp solution; give time for a message to be send, fu volt
- }
- try
- {
- await usr.Kick().ConfigureAwait(false);
- await e.Channel.SendMessage("Kicked user " + usr.Name + " Id: " + usr.Id).ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("Error. Most likely I don't have sufficient permissions.").ConfigureAwait(false);
- }
- }
- });
- cgb.CreateCommand(Prefix + "mute")
- .Description($"Mutes mentioned user or users. **Needs Mute Permissions.**| `{Prefix}mute \"@Someguy\"` or `{Prefix}mute \"@Someguy\" \"@Someguy\"`")
- .Parameter("throwaway", ParameterType.Unparsed)
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.MuteMembers)
- {
- await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
- return;
- }
- if (!e.Message.MentionedUsers.Any())
- return;
- try
- {
- foreach (var u in e.Message.MentionedUsers)
- {
- await u.Edit(isMuted: true).ConfigureAwait(false);
- }
- await e.Channel.SendMessage("Mute successful").ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "unmute")
- .Description($"Unmutes mentioned user or users. **Needs Mute Permissions.**| `{Prefix}unmute \"@Someguy\"` or `{Prefix}unmute \"@Someguy\" \"@Someguy\"`")
- .Parameter("throwaway", ParameterType.Unparsed)
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.MuteMembers)
- {
- await e.Channel.SendMessage("You do not have permission to do that.").ConfigureAwait(false);
- return;
- }
- if (!e.Message.MentionedUsers.Any())
- return;
- try
- {
- foreach (var u in e.Message.MentionedUsers)
- {
- await u.Edit(isMuted: false).ConfigureAwait(false);
- }
- await e.Channel.SendMessage("Unmute successful").ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "deafen")
- .Alias(Prefix + "deaf")
- .Description($"Deafens mentioned user or users. **Needs Deafen Permissions.**| `{Prefix}deaf \"@Someguy\"` or `{Prefix}deaf \"@Someguy\" \"@Someguy\"`")
- .Parameter("throwaway", ParameterType.Unparsed)
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.DeafenMembers)
- {
- await e.Channel.SendMessage("You do not have permission to do that.").ConfigureAwait(false);
- return;
- }
- if (!e.Message.MentionedUsers.Any())
- return;
- try
- {
- foreach (var u in e.Message.MentionedUsers)
- {
- await u.Edit(isDeafened: true).ConfigureAwait(false);
- }
- await e.Channel.SendMessage("Deafen successful").ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "undeafen")
- .Alias(Prefix + "undef")
- .Description($"Undeafens mentioned user or users. **Needs Deafen Permissions.** | `{Prefix}undef \"@Someguy\"` or `{Prefix}undef \"@Someguy\" \"@Someguy\"`")
- .Parameter("throwaway", ParameterType.Unparsed)
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.DeafenMembers)
- {
- await e.Channel.SendMessage("You do not have permission to do that.").ConfigureAwait(false);
- return;
- }
- if (!e.Message.MentionedUsers.Any())
- return;
- try
- {
- foreach (var u in e.Message.MentionedUsers)
- {
- await u.Edit(isDeafened: false).ConfigureAwait(false);
- }
- await e.Channel.SendMessage("Undeafen successful").ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("I most likely don't have the permission necessary for that.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "delvoichanl")
- .Alias(Prefix + "dvch")
- .Description($"Deletes a voice channel with a given name. **Needs Manage Channel Permissions.**| `{Prefix}dvch VoiceChannelName`")
- .Parameter("channel_name", ParameterType.Required)
- .Do(async e =>
- {
- try
- {
- if (e.User.ServerPermissions.ManageChannels)
- {
- var ch = e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Voice).FirstOrDefault();
- if (ch == null)
- return;
- await ch.Delete().ConfigureAwait(false);
- await e.Channel.SendMessage($"Removed channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
- }
- }
- catch
- {
- await e.Channel.SendMessage("Insufficient permissions.");
- }
- });
-
- cgb.CreateCommand(Prefix + "creatvoichanl")
- .Alias(Prefix + "cvch")
- .Description($"Creates a new voice channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}cvch VoiceChannelName`")
- .Parameter("channel_name", ParameterType.Required)
- .Do(async e =>
- {
- try
- {
- if (e.User.ServerPermissions.ManageChannels)
- {
- await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Voice).ConfigureAwait(false);
- await e.Channel.SendMessage($"Created voice channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
- }
- }
- catch
- {
- await e.Channel.SendMessage("Insufficient permissions.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "deltxtchanl")
- .Alias(Prefix + "dtch")
- .Description($"Deletes a text channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}dtch TextChannelName`")
- .Parameter("channel_name", ParameterType.Required)
- .Do(async e =>
- {
- try
- {
- if (e.User.ServerPermissions.ManageChannels)
- {
- var channel = e.Server.FindChannels(e.GetArg("channel_name"), ChannelType.Text).FirstOrDefault();
- if (channel == null) return;
- await channel.Delete().ConfigureAwait(false);
- await e.Channel.SendMessage($"Removed text channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
- }
- }
- catch
- {
- await e.Channel.SendMessage("Insufficient permissions.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "creatxtchanl")
- .Alias(Prefix + "ctch")
- .Description($"Creates a new text channel with a given name. **Needs Manage Channel Permissions.** | `{Prefix}ctch TextChannelName`")
- .Parameter("channel_name", ParameterType.Required)
- .Do(async e =>
- {
- try
- {
- if (e.User.ServerPermissions.ManageChannels)
- {
- await e.Server.CreateChannel(e.GetArg("channel_name"), ChannelType.Text).ConfigureAwait(false);
- await e.Channel.SendMessage($"Added text channel **{e.GetArg("channel_name")}**.").ConfigureAwait(false);
- }
- }
- catch
- {
- await e.Channel.SendMessage("Insufficient permissions.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "settopic")
- .Alias(Prefix + "st")
- .Description($"Sets a topic on the current channel. **Needs Manage Channel Permissions.** | `{Prefix}st My new topic`")
- .AddCheck(SimpleCheckers.ManageChannels())
- .Parameter("topic", ParameterType.Unparsed)
- .Do(async e =>
- {
- var topic = e.GetArg("topic")?.Trim() ?? "";
- await e.Channel.Edit(topic: topic).ConfigureAwait(false);
- await e.Channel.SendMessage(":ok: **New channel topic set.**").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "setchanlname")
- .Alias(Prefix + "schn")
- .Description($"Changed the name of the current channel. **Needs Manage Channel Permissions.**| `{Prefix}schn NewName`")
- .AddCheck(SimpleCheckers.ManageChannels())
- .Parameter("name", ParameterType.Unparsed)
- .Do(async e =>
- {
- var name = e.GetArg("name");
- if (string.IsNullOrWhiteSpace(name))
- return;
- await e.Channel.Edit(name: name).ConfigureAwait(false);
- await e.Channel.SendMessage(":ok: **New channel name set.**").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "heap")
- .Description($"Shows allocated memory - **Bot Owner Only!** | `{Prefix}heap`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var heap = await Task.Run(() => NadekoStats.Instance.Heap()).ConfigureAwait(false);
- await e.Channel.SendMessage($"`Heap Size:` {heap}").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "prune")
- .Alias(Prefix + "clr")
- .Description(
- "`.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. **Needs Manage Messages Permissions**" +
- $"| `{Prefix}prune` or `{Prefix}prune 5` or `{Prefix}prune @Someone` or `{Prefix}prune @Someone X`")
- .Parameter("user_or_num", ParameterType.Optional)
- .Parameter("num", ParameterType.Optional)
- .Do(async e =>
- {
- if (string.IsNullOrWhiteSpace(e.GetArg("user_or_num"))) // if nothing is set, clear nadeko's messages, no permissions required
- {
- var msgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User?.Id == e.Server.CurrentUser.Id)?.ToArray();
- if (msgs == null || !msgs.Any())
- return;
- var toDelete = msgs as Message[] ?? msgs.ToArray();
- await e.Channel.DeleteMessages(toDelete).ConfigureAwait(false);
- return;
- }
- if (!e.User.GetPermissions(e.Channel).ManageMessages)
- return;
- else if (!e.Server.CurrentUser.GetPermissions(e.Channel).ManageMessages)
- {
- await e.Channel.SendMessage("💢I don't have the permission to manage messages.");
- return;
- }
- int val;
- if (int.TryParse(e.GetArg("user_or_num"), out val)) // if num is set in the first argument,
- //delete that number of messages.
- {
- if (val <= 0)
- return;
- val++;
- await e.Channel.DeleteMessages((await e.Channel.DownloadMessages(val).ConfigureAwait(false)).ToArray()).ConfigureAwait(false);
- return;
- }
- //else if first argument is user
- var usr = e.Server.FindUsers(e.GetArg("user_or_num")).FirstOrDefault();
- if (usr == null)
- return;
- val = 100;
- if (!int.TryParse(e.GetArg("num"), out val))
- val = 100;
- var mesgs = (await e.Channel.DownloadMessages(100).ConfigureAwait(false)).Where(m => m.User?.Id == usr.Id).Take(val);
- if (mesgs == null || !mesgs.Any())
- return;
- await e.Channel.DeleteMessages(mesgs as Message[] ?? mesgs.ToArray()).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "die")
- .Description($"Shuts the bot down and notifies users about the restart. **Bot Owner Only!** | `{Prefix}die`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- await e.Channel.SendMessage("`Shutting down.`").ConfigureAwait(false);
- await Task.Delay(2000).ConfigureAwait(false);
- Environment.Exit(0);
- });
-
- cgb.CreateCommand(Prefix + "setname")
- .Alias(Prefix + "newnm")
- .Description($"Give the bot a new name. **Bot Owner Only!** | `{Prefix}newnm BotName`")
- .Parameter("new_name", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- if (e.GetArg("new_name") == null) return;
-
- await client.CurrentUser.Edit("", e.GetArg("new_name")).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "newavatar")
- .Alias(Prefix + "setavatar")
- .Description($"Sets a new avatar image for the NadekoBot. Argument is a direct link to an image. **Bot Owner Only!** | `{Prefix}setavatar http://i.imgur.com/xTG3a1I.jpg`")
- .Parameter("img", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- if (string.IsNullOrWhiteSpace(e.GetArg("img")))
- return;
- // Gather user provided URL.
- var avatarAddress = e.GetArg("img");
- var imageStream = await SearchHelper.GetResponseStreamAsync(avatarAddress).ConfigureAwait(false);
- var image = System.Drawing.Image.FromStream(imageStream);
- await client.CurrentUser.Edit("", avatar: image.ToStream()).ConfigureAwait(false);
-
- // Send confirm.
- await e.Channel.SendMessage("New avatar set.").ConfigureAwait(false);
-
- // Save the image to disk.
- image.Save("data/avatar.png", System.Drawing.Imaging.ImageFormat.Png);
- });
-
- cgb.CreateCommand(Prefix + "setgame")
- .Description($"Sets the bots game. **Bot Owner Only!** | `{Prefix}setgame Playing with kwoth`")
- .Parameter("set_game", ParameterType.Unparsed)
- .Do(e =>
- {
- if (!NadekoBot.IsOwner(e.User.Id) || e.GetArg("set_game") == null) return;
-
- client.SetGame(e.GetArg("set_game"));
- });
-
- cgb.CreateCommand(Prefix + "send")
- .Description($"Send a message to someone on a different server through the bot. **Bot Owner Only!** | `{Prefix}send sid|u:uid Hello user!` or `{Prefix}send sid|c:cid Message to channel!` (cid = channel id, sid = server id)")
- .Parameter("ids", ParameterType.Required)
- .Parameter("msg", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var msg = e.GetArg("msg")?.Trim();
-
- if (string.IsNullOrWhiteSpace(msg))
- return;
-
- var ids = e.GetArg("ids").Split('|');
- if (ids.Length != 2)
- return;
- var sid = ulong.Parse(ids[0]);
- var server = NadekoBot.Client.Servers.Where(s => s.Id == sid).FirstOrDefault();
-
- if (server == null)
- return;
-
- if (ids[1].ToUpperInvariant().StartsWith("C:"))
- {
- var cid = ulong.Parse(ids[1].Substring(2));
- var channel = server.TextChannels.Where(c => c.Id == cid).FirstOrDefault();
- if (channel == null)
- {
- return;
- }
- await channel.SendMessage(msg);
- }
- else if (ids[1].ToUpperInvariant().StartsWith("U:"))
- {
- var uid = ulong.Parse(ids[1].Substring(2));
- var user = server.Users.Where(u => u.Id == uid).FirstOrDefault();
- if (user == null)
- {
- return;
- }
- await user.SendMessage(msg);
- }
- else
- {
- await e.Channel.SendMessage("`Invalid format.`");
- }
- });
-
- cgb.CreateCommand(Prefix + "mentionrole")
- .Alias(Prefix + "menro")
- .Description($"Mentions every person from the provided role or roles (separated by a ',') on this server. Requires you to have mention everyone permission. | `{Prefix}menro RoleName`")
- .Parameter("roles", ParameterType.Unparsed)
- .Do(async e =>
- {
- await Task.Run(async () =>
- {
- if (!e.User.ServerPermissions.MentionEveryone) return;
- var arg = e.GetArg("roles").Split(',').Select(r => r.Trim());
- string send = $"--{e.User.Mention} has invoked a mention on the following roles--";
- foreach (var roleStr in arg.Where(str => !string.IsNullOrWhiteSpace(str)))
- {
- var role = e.Server.FindRoles(roleStr).FirstOrDefault();
- if (role == null) continue;
- send += $"\n`{role.Name}`\n";
- send += string.Join(", ", role.Members.Select(r => r.Mention));
- }
-
- while (send.Length > 2000)
- {
- var curstr = send.Substring(0, 2000);
- await
- e.Channel.Send(curstr.Substring(0,
- curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1)).ConfigureAwait(false);
- send = curstr.Substring(curstr.LastIndexOf(", ", StringComparison.Ordinal) + 1) +
- send.Substring(2000);
- }
- await e.Channel.Send(send).ConfigureAwait(false);
- }).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "unstuck")
- .Description($"Clears the message queue. **Bot Owner Only!** | `{Prefix}unstuck`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(e =>
- {
- NadekoBot.Client.MessageQueue.Clear();
- });
-
- cgb.CreateCommand(Prefix + "donators")
- .Description($"List of lovely people who donated to keep this project alive. | `{Prefix}donators`")
- .Do(async e =>
- {
- await Task.Run(async () =>
- {
- var rows = DbHandler.Instance.GetAllRows();
- var donatorsOrdered = rows.OrderByDescending(d => d.Amount);
- string str = $"**Thanks to the people listed below for making this project happen!**\n";
-
- await e.Channel.SendMessage(str + string.Join("⭐", donatorsOrdered.Select(d => d.UserName))).ConfigureAwait(false);
- }).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "donadd")
- .Description($"Add a donator to the database. **Kwoth Only** | `{Prefix}donadd Donate Amount`")
- .Parameter("donator")
- .Parameter("amount")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- await Task.Run(() =>
- {
- var donator = e.Server.FindUsers(e.GetArg("donator")).FirstOrDefault();
- var amount = int.Parse(e.GetArg("amount"));
- if (donator == null) return;
- try
- {
- DbHandler.Instance.Connection.Insert(new Donator
- {
- Amount = amount,
- UserName = donator.Name,
- UserId = (long)donator.Id
- });
- e.Channel.SendMessage("Successfuly added a new donator. 👑").ConfigureAwait(false);
- }
- catch { }
- }).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "announce")
- .Description($"Sends a message to all servers' general channel bot is connected to.**Bot Owner Only!** | `{Prefix}announce Useless spam`")
- .Parameter("msg", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- foreach (var ch in NadekoBot.Client.Servers.Select(s => s.DefaultChannel))
- {
- await ch.SendMessage(e.GetArg("msg")).ConfigureAwait(false);
- }
-
- await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "savechat")
- .Description($"Saves a number of messages to a text file and sends it to you. **Bot Owner Only** | `{Prefix}savechat 150`")
- .Parameter("cnt", ParameterType.Required)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var cntstr = e.GetArg("cnt")?.Trim();
- int cnt;
- if (!int.TryParse(cntstr, out cnt))
- return;
- ulong? lastmsgId = null;
- var sb = new StringBuilder();
- var msgs = new List(cnt);
- while (cnt > 0)
- {
- var dlcnt = cnt < 100 ? cnt : 100;
-
- var dledMsgs = await e.Channel.DownloadMessages(dlcnt, lastmsgId);
- if (!dledMsgs.Any())
- break;
- msgs.AddRange(dledMsgs);
- lastmsgId = msgs[msgs.Count - 1].Id;
- cnt -= 100;
- }
- await e.User.SendFile($"Chatlog-{e.Server.Name}/#{e.Channel.Name}-{DateTime.Now}.txt", JsonConvert.SerializeObject(new { Messages = msgs.Select(s => s.ToString()) }, Formatting.Indented).ToStream()).ConfigureAwait(false);
- });
-
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/AutoAssignRole.cs b/NadekoBot/Modules/Administration/Commands/AutoAssignRole.cs
deleted file mode 100644
index 373840cb..00000000
--- a/NadekoBot/Modules/Administration/Commands/AutoAssignRole.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Linq;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- class AutoAssignRole : DiscordCommand
- {
- public AutoAssignRole(DiscordModule module) : base(module)
- {
- NadekoBot.OnReady += () => NadekoBot.Client.UserJoined += (s, e) =>
- {
- try
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
-
- var role = e.Server.Roles.Where(r => r.Id == config.AutoAssignedRole).FirstOrDefault();
-
- if (role == null)
- return;
-
- e.User.AddRoles(role);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"aar exception. {ex}");
- }
- };
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "autoassignrole")
- .Alias(Module.Prefix + "aar")
- .Description($"Automaticaly assigns a specified role to every user who joins the server. **Needs Manage Roles Permissions.** |`{Prefix}aar` to disable, `{Prefix}aar Role Name` to enable")
- .Parameter("role", ParameterType.Unparsed)
- .AddCheck(new SimpleCheckers.ManageRoles())
- .Do(async e =>
- {
- if (!e.Server.CurrentUser.ServerPermissions.ManageRoles)
- {
- await e.Channel.SendMessage("I do not have the permission to manage roles.").ConfigureAwait(false);
- return;
- }
- var r = e.GetArg("role")?.Trim();
-
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
-
- if (string.IsNullOrWhiteSpace(r)) //if role is not specified, disable
- {
- config.AutoAssignedRole = 0;
-
- await e.Channel.SendMessage("`Auto assign role on user join is now disabled.`").ConfigureAwait(false);
- return;
- }
- var role = e.Server.FindRoles(r).FirstOrDefault();
-
- if (role == null)
- {
- await e.Channel.SendMessage("💢 `Role not found.`").ConfigureAwait(false);
- return;
- }
-
- config.AutoAssignedRole = role.Id;
- await e.Channel.SendMessage("`Auto assigned role is set.`").ConfigureAwait(false);
-
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs b/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs
deleted file mode 100644
index 88f6cd40..00000000
--- a/NadekoBot/Modules/Administration/Commands/CrossServerTextChannel.cs
+++ /dev/null
@@ -1,113 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- class CrossServerTextChannel : DiscordCommand
- {
- public CrossServerTextChannel(DiscordModule module) : base(module)
- {
- NadekoBot.OnReady += () =>
- {
- NadekoBot.Client.MessageReceived += async (s, e) =>
- {
- try
- {
- if (e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
- foreach (var subscriber in Subscribers)
- {
- var set = subscriber.Value;
- if (!set.Contains(e.Channel))
- continue;
- foreach (var chan in set.Except(new[] { e.Channel }))
- {
- await chan.SendMessage(GetText(e.Server, e.Channel, e.User, e.Message)).ConfigureAwait(false);
- }
- }
- }
- catch { }
- };
- NadekoBot.Client.MessageUpdated += async (s, e) =>
- {
- try
- {
- if (e.After?.User?.Id == null || e.After.User.Id == NadekoBot.Client.CurrentUser.Id) return;
- foreach (var subscriber in Subscribers)
- {
- var set = subscriber.Value;
- if (!set.Contains(e.Channel))
- continue;
- foreach (var chan in set.Except(new[] { e.Channel }))
- {
- var msg = chan.Messages
- .FirstOrDefault(m =>
- m.RawText == GetText(e.Server, e.Channel, e.User, e.Before));
- if (msg != default(Message))
- await msg.Edit(GetText(e.Server, e.Channel, e.User, e.After)).ConfigureAwait(false);
- }
- }
-
- }
- catch { }
- };
- };
- }
-
- private string GetText(Server server, Channel channel, User user, Message message) =>
- $"**{server.Name} | {channel.Name}** `{user.Name}`: " + message.RawText;
-
- public static readonly ConcurrentDictionary> Subscribers = new ConcurrentDictionary>();
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "scsc")
- .Description("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.** | `{Prefix}scsc`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var token = new Random().Next();
- var set = new HashSet();
- if (Subscribers.TryAdd(token, set))
- {
- set.Add(e.Channel);
- await e.User.SendMessage("This is your CSC token:" + token.ToString()).ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Module.Prefix + "jcsc")
- .Description($"Joins current channel to an instance of cross server channel using the token. **Needs Manage Server Permissions.**| `{Prefix}jcsc`")
- .Parameter("token")
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- int token;
- if (!int.TryParse(e.GetArg("token"), out token))
- return;
- HashSet set;
- if (!Subscribers.TryGetValue(token, out set))
- return;
- set.Add(e.Channel);
- await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "lcsc")
- .Description($"Leaves Cross server channel instance from this channel. **Needs Manage Server Permissions.**| `{Prefix}lcsc`")
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- foreach (var subscriber in Subscribers)
- {
- subscriber.Value.Remove(e.Channel);
- }
- await e.Channel.SendMessage(":ok:").ConfigureAwait(false);
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/CustomReactionsCommands.cs b/NadekoBot/Modules/Administration/Commands/CustomReactionsCommands.cs
deleted file mode 100644
index 7ed71e8b..00000000
--- a/NadekoBot/Modules/Administration/Commands/CustomReactionsCommands.cs
+++ /dev/null
@@ -1,224 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- class CustomReactionsCommands : DiscordCommand
- {
- public CustomReactionsCommands(DiscordModule module) : base(module)
- {
-
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- var Prefix = Module.Prefix;
-
- cgb.CreateCommand(Prefix + "addcustreact")
- .Alias(Prefix + "acr")
- .Description($"Add a custom reaction. Guide here: **Bot Owner Only!** | `{Prefix}acr \"hello\" Hi there %user%`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Parameter("name", ParameterType.Required)
- .Parameter("message", ParameterType.Unparsed)
- .Do(async e =>
- {
- var name = e.GetArg("name");
- var message = e.GetArg("message")?.Trim();
- if (string.IsNullOrWhiteSpace(message))
- {
- await e.Channel.SendMessage($"Incorrect command usage. See -h {Prefix}acr for correct formatting").ConfigureAwait(false);
- return;
- }
- if (NadekoBot.Config.CustomReactions.ContainsKey(name))
- NadekoBot.Config.CustomReactions[name].Add(message);
- else
- NadekoBot.Config.CustomReactions.Add(name, new System.Collections.Generic.List() { message });
- await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
- await e.Channel.SendMessage($"Added {name} : {message}").ConfigureAwait(false);
-
- });
-
- cgb.CreateCommand(Prefix + "listcustreact")
- .Alias(Prefix + "lcr")
- .Description($"Lists custom reactions (paginated with 30 commands per page). Use 'all' instead of page number to get all custom reactions DM-ed to you. |`{Prefix}lcr 1`")
- .Parameter("num", ParameterType.Required)
- .Do(async e =>
- {
- var numStr = e.GetArg("num");
-
- if (numStr.ToUpperInvariant() == "ALL")
- {
- var fullstr = String.Join("\n", NadekoBot.Config.CustomReactions.Select(kvp => kvp.Key));
- do
- {
- var str = string.Concat(fullstr.Take(1900));
- fullstr = new string(fullstr.Skip(1900).ToArray());
- await e.User.SendMessage("```xl\n" + str + "```");
- } while (fullstr.Length != 0);
- return;
- }
- int num;
- if (!int.TryParse(numStr, out num) || num <= 0) num = 1;
- var cmds = GetCustomsOnPage(num - 1);
- if (!cmds.Any())
- {
- await e.Channel.SendMessage("`There are no custom reactions.`");
- }
- else
- {
- string result = SearchHelper.ShowInPrettyCode(cmds, s => $"{s,-25}"); //People prefer starting with 1
- await e.Channel.SendMessage($"`Showing page {num}:`\n" + result).ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "showcustreact")
- .Alias(Prefix + "scr")
- .Description($"Shows all possible responses from a single custom reaction. |`{Prefix}scr %mention% bb`")
- .Parameter("name", ParameterType.Unparsed)
- .Do(async e =>
- {
- var name = e.GetArg("name")?.Trim();
- if (string.IsNullOrWhiteSpace(name))
- return;
- if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
- {
- await e.Channel.SendMessage("`Can't find that custom reaction.`").ConfigureAwait(false);
- return;
- }
- var items = NadekoBot.Config.CustomReactions[name];
- var message = new StringBuilder($"Responses for {Format.Bold(name)}:\n");
- var last = items.Last();
-
- int i = 1;
- foreach (var reaction in items)
- {
- message.AppendLine($"[{i++}] " + Format.Code(Format.Escape(reaction)));
- }
- await e.Channel.SendMessage(message.ToString());
- });
-
- cgb.CreateCommand(Prefix + "editcustreact")
- .Alias(Prefix + "ecr")
- .Description($"Edits a custom reaction, arguments are custom reactions name, index to change, and a (multiword) message **Bot Owner Only** | `{Prefix}ecr \"%mention% disguise\" 2 Test 123`")
- .Parameter("name", ParameterType.Required)
- .Parameter("index", ParameterType.Required)
- .Parameter("message", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var name = e.GetArg("name")?.Trim();
- if (string.IsNullOrWhiteSpace(name))
- return;
- var indexstr = e.GetArg("index")?.Trim();
- if (string.IsNullOrWhiteSpace(indexstr))
- return;
- var msg = e.GetArg("message")?.Trim();
- if (string.IsNullOrWhiteSpace(msg))
- return;
-
-
-
- if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
- {
- await e.Channel.SendMessage("`Could not find given commandname`").ConfigureAwait(false);
- return;
- }
-
- int index;
- if (!int.TryParse(indexstr, out index) || index < 1 || index > NadekoBot.Config.CustomReactions[name].Count)
- {
- await e.Channel.SendMessage("`Invalid index.`").ConfigureAwait(false);
- return;
- }
- index = index - 1;
- NadekoBot.Config.CustomReactions[name][index] = msg;
-
- await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
- await e.Channel.SendMessage($"Edited response #{index + 1} from `{name}`").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "delcustreact")
- .Alias(Prefix + "dcr")
- .Description($"Deletes a custom reaction with given name (and optional index). **Bot Owner Only.**| `{Prefix}dcr \"Reaction Name\"` or `{Prefix}dcr \"Reaction Name\" 3`")
- .Parameter("name", ParameterType.Required)
- .Parameter("index", ParameterType.Optional)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var name = e.GetArg("name")?.Trim();
- if (string.IsNullOrWhiteSpace(name))
- return;
- if (!NadekoBot.Config.CustomReactions.ContainsKey(name))
- {
- await e.Channel.SendMessage("Could not find given commandname").ConfigureAwait(false);
- return;
- }
- string message = "";
- int index;
- if (int.TryParse(e.GetArg("index")?.Trim() ?? "", out index))
- {
- index = index - 1;
- if (index < 0 || index > NadekoBot.Config.CustomReactions[name].Count)
- {
- await e.Channel.SendMessage("Given index was out of range").ConfigureAwait(false);
- return;
-
- }
- NadekoBot.Config.CustomReactions[name].RemoveAt(index);
- if (!NadekoBot.Config.CustomReactions[name].Any())
- {
- NadekoBot.Config.CustomReactions.Remove(name);
- }
- message = $"Deleted response #{index + 1} from `{name}`";
- }
- else
- {
- NadekoBot.Config.CustomReactions.Remove(name);
- message = $"Deleted custom reaction: `{name}`";
- }
- await Classes.JSONModels.ConfigHandler.SaveConfig().ConfigureAwait(false);
- await e.Channel.SendMessage(message).ConfigureAwait(false);
- });
- }
-
- private readonly int ItemsPerPage = 30;
-
- private IEnumerable GetCustomsOnPage(int page)
- {
- var items = NadekoBot.Config.CustomReactions.Skip(page * ItemsPerPage).Take(ItemsPerPage);
- if (!items.Any())
- {
- return Enumerable.Empty();
- }
- return items.Select(kvp => kvp.Key);
- /*
- var message = new StringBuilder($"--- Custom reactions - page {page + 1} ---\n");
- foreach (var cr in items)
- {
- message.Append($"{Format.Code(cr.Key)}\n");
- int i = 1;
- var last = cr.Value.Last();
- foreach (var reaction in cr.Value)
- {
- if (last != reaction)
- message.AppendLine(" `├" + i++ + "─`" + Format.Bold(reaction));
- else
- message.AppendLine(" `└" + i++ + "─`" + Format.Bold(reaction));
- }
- }
- return message.ToString() + "\n";
- */
- }
- }
-}
-// zeta is a god
-//├
-//─
-//│
-//└
diff --git a/NadekoBot/Modules/Administration/Commands/IncidentsCommands.cs b/NadekoBot/Modules/Administration/Commands/IncidentsCommands.cs
deleted file mode 100644
index ab93693a..00000000
--- a/NadekoBot/Modules/Administration/Commands/IncidentsCommands.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.DataModels;
-using NadekoBot.Modules.Permissions.Classes;
-using System.IO;
-using System.Linq;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- internal class IncidentsCommands : DiscordCommand
- {
- public IncidentsCommands(DiscordModule module) : base(module) { }
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "listincidents")
- .Alias(Prefix + "lin")
- .Description($"List all UNREAD incidents and flags them as read. **Needs Manage Server Permissions.**| `{Prefix}lin`")
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- var sid = (long)e.Server.Id;
- var incs = DbHandler.Instance.FindAll(i => i.ServerId == sid && i.Read == false);
- DbHandler.Instance.Connection.UpdateAll(incs.Select(i => { i.Read = true; return i; }));
-
- await e.User.SendMessage(string.Join("\n----------------------", incs.Select(i => i.Text)));
- });
-
- cgb.CreateCommand(Module.Prefix + "listallincidents")
- .Alias(Prefix + "lain")
- .Description($"Sends you a file containing all incidents and flags them as read. **Needs Manage Server Permissions.**| `{Prefix}lain`")
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- var sid = (long)e.Server.Id;
- var incs = DbHandler.Instance.FindAll(i => i.ServerId == sid);
- DbHandler.Instance.Connection.UpdateAll(incs.Select(i => { i.Read = true; return i; }));
- var data = string.Join("\n----------------------\n", incs.Select(i => i.Text));
- MemoryStream ms = new MemoryStream();
- var sw = new StreamWriter(ms);
- sw.WriteLine(data);
- sw.Flush();
- sw.BaseStream.Position = 0;
- await e.User.SendFile("incidents.txt", sw.BaseStream);
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/LogCommand.cs b/NadekoBot/Modules/Administration/Commands/LogCommand.cs
deleted file mode 100644
index 21973116..00000000
--- a/NadekoBot/Modules/Administration/Commands/LogCommand.cs
+++ /dev/null
@@ -1,489 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- internal class LogCommand : DiscordCommand
- {
- private string prettyCurrentTime => $"【{DateTime.Now:HH:mm:ss}】";
-
- private ConcurrentBag> voicePresenceUpdates = new ConcurrentBag>();
-
- public LogCommand(DiscordModule module) : base(module)
- {
- NadekoBot.OnReady += () =>
- {
- //NadekoBot.Client.MessageReceived += MsgRecivd;
- NadekoBot.Client.MessageDeleted += MsgDltd;
- NadekoBot.Client.MessageUpdated += MsgUpdtd;
- NadekoBot.Client.UserUpdated += UsrUpdtd;
- NadekoBot.Client.UserBanned += UsrBanned;
- NadekoBot.Client.UserLeft += UsrLeft;
- NadekoBot.Client.UserJoined += UsrJoined;
- NadekoBot.Client.UserUnbanned += UsrUnbanned;
- NadekoBot.Client.ChannelCreated += ChannelCreated;
- NadekoBot.Client.ChannelDestroyed += ChannelDestroyed;
- NadekoBot.Client.ChannelUpdated += ChannelUpdated;
-
-
- NadekoBot.Client.MessageReceived += async (s, e) =>
- {
- if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
- return;
- if (!SpecificConfigurations.Default.Of(e.Server.Id).SendPrivateMessageOnMention) return;
- try
- {
- var usr = e.Message.MentionedUsers.FirstOrDefault(u => u != e.User);
- if (usr?.Status != UserStatus.Offline)
- return;
- await e.Channel.SendMessage($"User `{usr.Name}` is offline. PM sent.").ConfigureAwait(false);
- await usr.SendMessage(
- $"User `{e.User.Name}` mentioned you on " +
- $"`{e.Server.Name}` server while you were offline.\n" +
- $"`Message:` {e.Message.Text}").ConfigureAwait(false);
- }
- catch { }
- };
- };
-
- // start the userpresence queue
-
- NadekoBot.OnReady += () =>
- {
- Task.Run(async () =>
- {
- while (true)
- {
- var toSend = new Dictionary();
- //take everything from the queue and merge the messages which are going to the same channel
- KeyValuePair item;
- while (voicePresenceUpdates.TryTake(out item))
- {
- if (toSend.ContainsKey(item.Key))
- {
- toSend[item.Key] = toSend[item.Key] + Environment.NewLine + item.Value;
- }
- else
- {
- toSend.Add(item.Key, item.Value);
- }
- }
- //send merged messages to each channel
- foreach (var k in toSend)
- {
- try { await k.Key.SendMessage(Environment.NewLine + k.Value).ConfigureAwait(false); } catch { }
- }
-
- await Task.Delay(5000);
- }
- });
- };
- }
-
- private async void ChannelUpdated(object sender, ChannelUpdatedEventArgs e)
- {
- try
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- var chId = config.LogServerChannel;
- if (chId == null || config.LogserverIgnoreChannels.Contains(e.After.Id))
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- if (e.Before.Name != e.After.Name)
- await ch.SendMessage($@"`{prettyCurrentTime}` **Channel Name Changed** `#{e.Before.Name}` (*{e.After.Id}*)
- `New:` {e.After.Name}").ConfigureAwait(false);
- else if (e.Before.Topic != e.After.Topic)
- await ch.SendMessage($@"`{prettyCurrentTime}` **Channel Topic Changed** `#{e.After.Name}` (*{e.After.Id}*)
- `Old:` {e.Before.Topic}
- `New:` {e.After.Topic}").ConfigureAwait(false);
- }
- catch { }
- }
-
- private async void ChannelDestroyed(object sender, ChannelEventArgs e)
- {
- try
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- var chId = config.LogServerChannel;
- if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- await ch.SendMessage($"❗`{prettyCurrentTime}`❗`Channel Deleted:` #{e.Channel.Name} (*{e.Channel.Id}*)").ConfigureAwait(false);
- }
- catch { }
- }
-
- private async void ChannelCreated(object sender, ChannelEventArgs e)
- {
- try
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- var chId = config.LogServerChannel;
- if (chId == null || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- await ch.SendMessage($"`{prettyCurrentTime}`🆕`Channel Created:` #{e.Channel.Mention} (*{e.Channel.Id}*)").ConfigureAwait(false);
- }
- catch { }
- }
-
- private async void UsrUnbanned(object sender, UserEventArgs e)
- {
- try
- {
- var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
- if (chId == null)
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- await ch.SendMessage($"`{prettyCurrentTime}`♻`User was unbanned:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
- }
- catch { }
- }
-
- private async void UsrJoined(object sender, UserEventArgs e)
- {
- try
- {
- var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
- if (chId == null)
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- await ch.SendMessage($"`{prettyCurrentTime}`✅`User joined:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
- }
- catch { }
- }
-
- private async void UsrLeft(object sender, UserEventArgs e)
- {
- try
- {
- var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
- if (chId == null)
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- await ch.SendMessage($"`{prettyCurrentTime}`❗`User left:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
- }
- catch { }
- }
-
- private async void UsrBanned(object sender, UserEventArgs e)
- {
- try
- {
- var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
- if (chId == null)
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- await ch.SendMessage($"❗`{prettyCurrentTime}`❌`User banned:` **{e.User.Name}** ({e.User.Id})").ConfigureAwait(false);
- }
- catch { }
- }
-
- // private async void MsgRecivd(object sender, MessageEventArgs e)
- // {
- // try
- // {
- // if (e.Server == null || e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
- // return;
- // var config = SpecificConfigurations.Default.Of(e.Server.Id);
- // var chId = config.LogServerChannel;
- // if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
- // return;
- // Channel ch;
- // if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- // return;
- // if (!string.IsNullOrWhiteSpace(e.Message.Text))
- // {
- // await ch.SendMessage(
- // $@"🕔`{prettyCurrentTime}` **New Message** `#{e.Channel.Name}`
- //👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false);
- // }
- // else
- // {
- // await ch.SendMessage(
- // $@"🕔`{prettyCurrentTime}` **File Uploaded** `#{e.Channel.Name}`
- //👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false);
- // }
-
- // }
- // catch { }
- // }
- private async void MsgDltd(object sender, MessageEventArgs e)
- {
- try
- {
- if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
- return;
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- var chId = config.LogServerChannel;
- if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- if (!string.IsNullOrWhiteSpace(e.Message.Text))
- {
- await ch.SendMessage(
- $@"🕔`{prettyCurrentTime}` **Message** 🚮 `#{e.Channel.Name}`
-👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Text.Unmention()}").ConfigureAwait(false);
- }
- else
- {
- await ch.SendMessage(
- $@"🕔`{prettyCurrentTime}` **File Deleted** `#{e.Channel.Name}`
-👤`{e.User?.ToString() ?? ("NULL")}` {e.Message.Attachments.FirstOrDefault()?.ProxyUrl}").ConfigureAwait(false);
- }
- }
- catch { }
- }
- private async void MsgUpdtd(object sender, MessageUpdatedEventArgs e)
- {
- try
- {
- if (e.Server == null || e.Channel.IsPrivate || e.User?.Id == NadekoBot.Client.CurrentUser.Id)
- return;
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- var chId = config.LogServerChannel;
- if (chId == null || e.Channel.Id == chId || config.LogserverIgnoreChannels.Contains(e.Channel.Id))
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- await ch.SendMessage(
- $@"🕔`{prettyCurrentTime}` **Message** 📝 `#{e.Channel.Name}`
-👤`{e.User?.ToString() ?? ("NULL")}`
- `Old:` {e.Before.Text.Unmention()}
- `New:` {e.After.Text.Unmention()}").ConfigureAwait(false);
- }
- catch { }
- }
- private async void UsrUpdtd(object sender, UserUpdatedEventArgs e)
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- try
- {
- var chId = config.LogPresenceChannel;
- if (chId != null)
- {
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) != null)
- {
- if (e.Before.Status != e.After.Status)
- {
- voicePresenceUpdates.Add(new KeyValuePair(ch, $"`{prettyCurrentTime}`**{e.Before.Name}** is now **{e.After.Status}**."));
- }
- }
- }
- }
- catch { }
-
- try
- {
- ulong notifyChBeforeId;
- ulong notifyChAfterId;
- Channel notifyChBefore = null;
- Channel notifyChAfter = null;
- var beforeVch = e.Before.VoiceChannel;
- var afterVch = e.After.VoiceChannel;
- var notifyLeave = false;
- var notifyJoin = false;
- if ((beforeVch != null || afterVch != null) && (beforeVch != afterVch)) // this means we need to notify for sure.
- {
- if (beforeVch != null && config.VoiceChannelLog.TryGetValue(beforeVch.Id, out notifyChBeforeId) && (notifyChBefore = e.Before.Server.TextChannels.FirstOrDefault(tc => tc.Id == notifyChBeforeId)) != null)
- {
- notifyLeave = true;
- }
- if (afterVch != null && config.VoiceChannelLog.TryGetValue(afterVch.Id, out notifyChAfterId) && (notifyChAfter = e.After.Server.TextChannels.FirstOrDefault(tc => tc.Id == notifyChAfterId)) != null)
- {
- notifyJoin = true;
- }
- if ((notifyLeave && notifyJoin) && (notifyChAfter == notifyChBefore))
- {
- await notifyChAfter.SendMessage($"🎼`{prettyCurrentTime}` {e.Before.Name} moved from **{beforeVch.Mention}** to **{afterVch.Mention}** voice channel.").ConfigureAwait(false);
- }
- else if (notifyJoin)
- {
- await notifyChAfter.SendMessage($"🎼`{prettyCurrentTime}` {e.Before.Name} has joined **{afterVch.Mention}** voice channel.").ConfigureAwait(false);
- }
- else if (notifyLeave)
- {
- await notifyChBefore.SendMessage($"🎼`{prettyCurrentTime}` {e.Before.Name} has left **{beforeVch.Mention}** voice channel.").ConfigureAwait(false);
- }
- }
- }
- catch { }
-
- try
- {
- var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
- if (chId == null)
- return;
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
- string str = $"🕔`{prettyCurrentTime}`";
- if (e.Before.Name != e.After.Name)
- str += $"**Name Changed**👤`{e.Before?.ToString()}`\n\t\t`New:`{e.After.ToString()}`";
- else if (e.Before.Nickname != e.After.Nickname)
- str += $"**Nickname Changed**👤`{e.Before?.ToString()}`\n\t\t`Old:` {e.Before.Nickname}#{e.Before.Discriminator}\n\t\t`New:` {e.After.Nickname}#{e.After.Discriminator}";
- else if (e.Before.AvatarUrl != e.After.AvatarUrl)
- str += $"**Avatar Changed**👤`{e.Before?.ToString()}`\n\t {await e.Before.AvatarUrl.ShortenUrl()} `=>` {await e.After.AvatarUrl.ShortenUrl()}";
- else if (!e.Before.Roles.SequenceEqual(e.After.Roles))
- {
- if (e.Before.Roles.Count() < e.After.Roles.Count())
- {
- var diffRoles = e.After.Roles.Where(r => !e.Before.Roles.Contains(r)).Select(r => "`" + r.Name + "`");
- str += $"**User's Roles changed ⚔➕**👤`{e.Before?.ToString()}`\n\tNow has {string.Join(", ", diffRoles)} role.";
- }
- else if (e.Before.Roles.Count() > e.After.Roles.Count())
- {
- var diffRoles = e.Before.Roles.Where(r => !e.After.Roles.Contains(r)).Select(r => "`" + r.Name + "`");
- str += $"**User's Roles changed ⚔➖**👤`{e.Before?.ToString()}`\n\tNo longer has {string.Join(", ", diffRoles)} role.";
- }
- else
- {
- Console.WriteLine("SEQUENCE NOT EQUAL BUT NO DIFF ROLES - REPORT TO KWOTH on #NADEKOLOG server");
- return;
- }
-
- }
- else
- return;
- await ch.SendMessage(str).ConfigureAwait(false);
- }
- catch { }
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
-
- cgb.CreateCommand(Module.Prefix + "spmom")
- .Description($"Toggles whether mentions of other offline users on your server will send a pm to them. **Needs Manage Server Permissions.**| `{Prefix}spmom`")
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- var specificConfig = SpecificConfigurations.Default.Of(e.Server.Id);
- specificConfig.SendPrivateMessageOnMention =
- !specificConfig.SendPrivateMessageOnMention;
- if (specificConfig.SendPrivateMessageOnMention)
- await e.Channel.SendMessage(":ok: I will send private messages " +
- "to mentioned offline users.").ConfigureAwait(false);
- else
- await e.Channel.SendMessage(":ok: I won't send private messages " +
- "to mentioned offline users anymore.").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "logserver")
- .Description($"Toggles logging in this channel. Logs every message sent/deleted/edited on the server. **Bot Owner Only!** | `{Prefix}logserver`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel;
- if (chId == null)
- {
- SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = e.Channel.Id;
- await e.Channel.SendMessage($"❗**I WILL BEGIN LOGGING SERVER ACTIVITY IN THIS CHANNEL**❗").ConfigureAwait(false);
- return;
- }
- Channel ch;
- if ((ch = e.Server.TextChannels.Where(tc => tc.Id == chId).FirstOrDefault()) == null)
- return;
-
- SpecificConfigurations.Default.Of(e.Server.Id).LogServerChannel = null;
- await e.Channel.SendMessage($"❗**NO LONGER LOGGING IN {ch.Mention} CHANNEL**❗").ConfigureAwait(false);
- });
-
-
- cgb.CreateCommand(Prefix + "logignore")
- .Description($"Toggles whether the {Prefix}logserver command ignores this channel. Useful if you have hidden admin channel and public log channel. **Bot Owner Only!**| `{Prefix}logignore`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- if (config.LogserverIgnoreChannels.Remove(e.Channel.Id))
- {
- await e.Channel.SendMessage($"`{Prefix}logserver will stop ignoring this channel.`");
- }
- else
- {
- config.LogserverIgnoreChannels.Add(e.Channel.Id);
- await e.Channel.SendMessage($"`{Prefix}logserver will ignore this channel.`");
- }
- });
-
- cgb.CreateCommand(Module.Prefix + "userpresence")
- .Description($"Starts logging to this channel when someone from the server goes online/offline/idle. **Needs Manage Server Permissions.**| `{Prefix}userpresence`")
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
- var chId = SpecificConfigurations.Default.Of(e.Server.Id).LogPresenceChannel;
- if (chId == null)
- {
- SpecificConfigurations.Default.Of(e.Server.Id).LogPresenceChannel = e.Channel.Id;
- await e.Channel.SendMessage($"**User presence notifications enabled.**").ConfigureAwait(false);
- return;
- }
- SpecificConfigurations.Default.Of(e.Server.Id).LogPresenceChannel = null;
- await e.Channel.SendMessage($"**User presence notifications disabled.**").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "voicepresence")
- .Description($"Toggles logging to this channel whenever someone joins or leaves a voice channel you are in right now. **Needs Manage Server Permissions.**| `{Prefix}voicerpresence`")
- .Parameter("all", ParameterType.Optional)
- .AddCheck(SimpleCheckers.ManageServer())
- .Do(async e =>
- {
-
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- if (e.GetArg("all")?.ToLower() == "all")
- {
- foreach (var voiceChannel in e.Server.VoiceChannels)
- {
- config.VoiceChannelLog.TryAdd(voiceChannel.Id, e.Channel.Id);
- }
- await e.Channel.SendMessage("Started logging user presence for **ALL** voice channels!").ConfigureAwait(false);
- return;
- }
-
- if (e.User.VoiceChannel == null)
- {
- await e.Channel.SendMessage("💢 You are not in a voice channel right now. If you are, please rejoin it.").ConfigureAwait(false);
- return;
- }
- ulong throwaway;
- if (!config.VoiceChannelLog.TryRemove(e.User.VoiceChannel.Id, out throwaway))
- {
- config.VoiceChannelLog.TryAdd(e.User.VoiceChannel.Id, e.Channel.Id);
- await e.Channel.SendMessage($"`Logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`").ConfigureAwait(false);
- }
- else
- await e.Channel.SendMessage($"`Stopped logging user updates for` {e.User.VoiceChannel.Mention} `voice channel.`").ConfigureAwait(false);
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs b/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs
deleted file mode 100644
index e87f5555..00000000
--- a/NadekoBot/Modules/Administration/Commands/MessageRepeater.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Concurrent;
-using System.Threading.Tasks;
-using System.Timers;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- class MessageRepeater : DiscordCommand
- {
- private readonly ConcurrentDictionary repeaters = new ConcurrentDictionary();
- private class Repeater
- {
- [Newtonsoft.Json.JsonIgnore]
- public Timer MessageTimer { get; set; }
- [Newtonsoft.Json.JsonIgnore]
- public Channel RepeatingChannel { get; set; }
-
- public ulong RepeatingServerId { get; set; }
- public ulong RepeatingChannelId { get; set; }
- public Message lastMessage { get; set; } = null;
- public string RepeatingMessage { get; set; }
- public int Interval { get; set; }
-
- public Repeater Start()
- {
- MessageTimer = new Timer { Interval = Interval };
- MessageTimer.Elapsed += async (s, e) => await Invoke();
- return this;
- }
-
- public async Task Invoke()
- {
- var ch = RepeatingChannel;
- var msg = RepeatingMessage;
- if (ch != null && !string.IsNullOrWhiteSpace(msg))
- {
- try
- {
- if (lastMessage != null)
- await lastMessage.Delete().ConfigureAwait(false);
- }
- catch { }
- try
- {
- lastMessage = await ch.SendMessage(msg).ConfigureAwait(false);
- }
- catch { }
- }
- }
- }
- internal override void Init(CommandGroupBuilder cgb)
- {
-
- cgb.CreateCommand(Module.Prefix + "repeatinvoke")
- .Alias(Module.Prefix + "repinv")
- .Description($"Immediately shows the repeat message and restarts the timer. **Needs Manage Messages Permissions.**| `{Prefix}repinv`")
- .AddCheck(SimpleCheckers.ManageMessages())
- .Do(async e =>
- {
- Repeater rep;
- if (!repeaters.TryGetValue(e.Server, out rep))
- {
- await e.Channel.SendMessage("`No repeating message found on this server.`");
- return;
- }
-
- await rep.Invoke();
- });
-
- cgb.CreateCommand(Module.Prefix + "repeat")
- .Description("Repeat a message every X minutes. If no parameters are specified, " +
- $"repeat is disabled. **Needs Manage Messages Permissions.** |`{Prefix}repeat 5 Hello there`")
- .Parameter("minutes", ParameterType.Optional)
- .Parameter("msg", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.ManageMessages())
- .Do(async e =>
- {
- var minutesStr = e.GetArg("minutes");
- var msg = e.GetArg("msg");
-
- // if both null, disable
- if (string.IsNullOrWhiteSpace(msg) && string.IsNullOrWhiteSpace(minutesStr))
- {
-
- Repeater rep;
- if (!repeaters.TryRemove(e.Server, out rep))
- return;
- rep.MessageTimer.Stop();
- await e.Channel.SendMessage("Repeating disabled").ConfigureAwait(false);
- return;
- }
- int minutes;
- if (!int.TryParse(minutesStr, out minutes) || minutes < 1 || minutes > 1440)
- {
- await e.Channel.SendMessage("Invalid value").ConfigureAwait(false);
- return;
- }
-
- var repeater = repeaters.GetOrAdd(
- e.Server,
- s => new Repeater
- {
- Interval = minutes * 60 * 1000,
- RepeatingChannel = e.Channel,
- RepeatingChannelId = e.Channel.Id,
- RepeatingServerId = e.Server.Id,
- }.Start()
- );
-
- if (!string.IsNullOrWhiteSpace(msg))
- repeater.RepeatingMessage = msg;
-
- repeater.MessageTimer.Stop();
- repeater.MessageTimer.Start();
-
- await e.Channel.SendMessage(String.Format("👌 Repeating `{0}` every " +
- "**{1}** minutes on {2} channel.",
- repeater.RepeatingMessage, minutes, repeater.RepeatingChannel))
- .ConfigureAwait(false);
- });
- }
-
- public MessageRepeater(DiscordModule module) : base(module) { }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/PlayingRotate.cs b/NadekoBot/Modules/Administration/Commands/PlayingRotate.cs
deleted file mode 100644
index 3eff2ff2..00000000
--- a/NadekoBot/Modules/Administration/Commands/PlayingRotate.cs
+++ /dev/null
@@ -1,167 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Classes.JSONModels;
-using NadekoBot.Modules.Music;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading;
-using System.Threading.Tasks;
-using Timer = System.Timers.Timer;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- internal class PlayingRotate : DiscordCommand
- {
- private static readonly Timer timer = new Timer(20000);
-
- public static Dictionary> PlayingPlaceholders { get; } =
- new Dictionary> {
- {"%servers%", () => NadekoBot.Client.Servers.Count().ToString()},
- {"%users%", () => NadekoBot.Client.Servers.SelectMany(s => s.Users).Count().ToString()},
- {"%playing%", () => {
- var cnt = MusicModule.MusicPlayers.Count(kvp => kvp.Value.CurrentSong != null);
- if (cnt != 1) return cnt.ToString();
- try {
- var mp = MusicModule.MusicPlayers.FirstOrDefault();
- return mp.Value.CurrentSong.SongInfo.Title;
- }
- catch {
- return "No songs";
- }
- }
- },
- {"%queued%", () => MusicModule.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
- {"%trivia%", () => Games.Commands.TriviaCommands.RunningTrivias.Count.ToString()}
- };
-
- private readonly SemaphoreSlim playingPlaceholderLock = new SemaphoreSlim(1, 1);
-
- public PlayingRotate(DiscordModule module) : base(module)
- {
- var i = -1;
- timer.Elapsed += async (s, e) =>
- {
- try
- {
- i++;
- var status = "";
- //wtf am i doing, just use a queue ffs
- await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
- try
- {
- if (PlayingPlaceholders.Count == 0
- || NadekoBot.Config.RotatingStatuses.Count == 0
- || i >= NadekoBot.Config.RotatingStatuses.Count)
- {
- i = 0;
- }
- status = NadekoBot.Config.RotatingStatuses[i];
- status = PlayingPlaceholders.Aggregate(status,
- (current, kvp) => current.Replace(kvp.Key, kvp.Value()));
- }
- finally { playingPlaceholderLock.Release(); }
- if (string.IsNullOrWhiteSpace(status))
- return;
- await Task.Run(() => { NadekoBot.Client.SetGame(status); });
- }
- catch { }
- };
- NadekoBot.OnReady += () => timer.Enabled = NadekoBot.Config.IsRotatingStatus;
- }
-
- public Func DoFunc() => async e =>
- {
- await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
- try
- {
- if (timer.Enabled)
- timer.Stop();
- else
- timer.Start();
- NadekoBot.Config.IsRotatingStatus = timer.Enabled;
- await ConfigHandler.SaveConfig().ConfigureAwait(false);
- }
- finally
- {
- playingPlaceholderLock.Release();
- }
- await e.Channel.SendMessage($"❗`Rotating playing status has been {(timer.Enabled ? "enabled" : "disabled")}.`").ConfigureAwait(false);
- };
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "rotateplaying")
- .Alias(Module.Prefix + "ropl")
- .Description($"Toggles rotation of playing status of the dynamic strings you specified earlier. **Bot Owner Only!** | `{Prefix}ropl`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(DoFunc());
-
- cgb.CreateCommand(Module.Prefix + "addplaying")
- .Alias(Module.Prefix + "adpl")
- .Description("Adds a specified string to the list of playing strings to rotate. " +
- "Supported placeholders: " + string.Join(", ", PlayingPlaceholders.Keys) + $" **Bot Owner Only!**| `{Prefix}adpl`")
- .Parameter("text", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var arg = e.GetArg("text");
- if (string.IsNullOrWhiteSpace(arg))
- return;
- await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
- try
- {
- NadekoBot.Config.RotatingStatuses.Add(arg);
- await ConfigHandler.SaveConfig();
- }
- finally
- {
- playingPlaceholderLock.Release();
- }
- await e.Channel.SendMessage("🆗 `Added a new playing string.`").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "listplaying")
- .Alias(Module.Prefix + "lipl")
- .Description($"Lists all playing statuses with their corresponding number. **Bot Owner Only!**| `{Prefix}lipl`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- if (NadekoBot.Config.RotatingStatuses.Count == 0)
- await e.Channel.SendMessage("`There are no playing strings. " +
- "Add some with .addplaying [text] command.`").ConfigureAwait(false);
- var sb = new StringBuilder();
- for (var i = 0; i < NadekoBot.Config.RotatingStatuses.Count; i++)
- {
- sb.AppendLine($"`{i + 1}.` {NadekoBot.Config.RotatingStatuses[i]}");
- }
- await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "removeplaying")
- .Alias(Module.Prefix + "repl", Module.Prefix + "rmpl")
- .Description($"Removes a playing string on a given number. **Bot Owner Only!**| `{Prefix}rmpl`")
- .Parameter("number", ParameterType.Required)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var arg = e.GetArg("number");
- int num;
- string str;
- await playingPlaceholderLock.WaitAsync().ConfigureAwait(false);
- try
- {
- if (!int.TryParse(arg.Trim(), out num) || num <= 0 || num > NadekoBot.Config.RotatingStatuses.Count)
- return;
- str = NadekoBot.Config.RotatingStatuses[num - 1];
- NadekoBot.Config.RotatingStatuses.RemoveAt(num - 1);
- await ConfigHandler.SaveConfig().ConfigureAwait(false);
- }
- finally { playingPlaceholderLock.Release(); }
- await e.Channel.SendMessage($"🆗 `Removed playing string #{num}`({str})").ConfigureAwait(false);
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs b/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs
deleted file mode 100644
index 38c30d07..00000000
--- a/NadekoBot/Modules/Administration/Commands/RatelimitCommand.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Concurrent;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- internal class RatelimitCommand : DiscordCommand
- {
-
- public static ConcurrentDictionary> RatelimitingChannels = new ConcurrentDictionary>();
-
- private static readonly TimeSpan ratelimitTime = new TimeSpan(0, 0, 0, 5);
-
- public RatelimitCommand(DiscordModule module) : base(module)
- {
- NadekoBot.OnReady += () => NadekoBot.Client.MessageReceived += async (s, e) =>
- {
- if (e.Channel.IsPrivate || e.User.Id == NadekoBot.Client.CurrentUser.Id)
- return;
- ConcurrentDictionary userTimePair;
- if (!RatelimitingChannels.TryGetValue(e.Channel.Id, out userTimePair)) return;
- DateTime lastMessageTime;
- if (userTimePair.TryGetValue(e.User.Id, out lastMessageTime))
- {
- if (DateTime.Now - lastMessageTime < ratelimitTime)
- {
- try
- {
- await e.Message.Delete().ConfigureAwait(false);
- }
- catch { }
- return;
- }
- }
- userTimePair.AddOrUpdate(e.User.Id, id => DateTime.Now, (id, dt) => DateTime.Now);
- };
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "slowmode")
- .Description($"Toggles slow mode. When ON, users will be able to send only 1 message every 5 seconds. **Needs Manage Messages Permissions.**| `{Prefix}slowmode`")
- .AddCheck(SimpleCheckers.ManageMessages())
- .Do(async e =>
- {
- ConcurrentDictionary throwaway;
- if (RatelimitingChannels.TryRemove(e.Channel.Id, out throwaway))
- {
- await e.Channel.SendMessage("Slow mode disabled.").ConfigureAwait(false);
- return;
- }
- if (RatelimitingChannels.TryAdd(e.Channel.Id, new ConcurrentDictionary()))
- {
- await e.Channel.SendMessage("Slow mode initiated. " +
- "Users can't send more than 1 message every 5 seconds.")
- .ConfigureAwait(false);
- }
- });
- }
- }
-}
\ No newline at end of file
diff --git a/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs b/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs
deleted file mode 100644
index 8e5e54fb..00000000
--- a/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs
+++ /dev/null
@@ -1,207 +0,0 @@
-using Discord.Commands;
-using Discord.Net;
-using NadekoBot.Classes;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- internal class SelfAssignedRolesCommand : DiscordCommand
- {
- public SelfAssignedRolesCommand(DiscordModule module) : base(module) { }
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "asar")
- .Description("Adds a role, or list of roles separated by whitespace" +
- $"(use quotations for multiword roles) to the list of self-assignable roles. **Needs Manage Roles Permissions.**| `{Prefix}asar Gamer`")
- .Parameter("roles", ParameterType.Multiple)
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- var msg = new StringBuilder();
- foreach (var arg in e.Args)
- {
- var role = e.Server.FindRoles(arg.Trim()).FirstOrDefault();
- if (role == null)
- msg.AppendLine($":anger:Role **{arg}** not found.");
- else
- {
- if (config.ListOfSelfAssignableRoles.Contains(role.Id))
- {
- msg.AppendLine($":anger:Role **{role.Name}** is already in the list.");
- continue;
- }
- config.ListOfSelfAssignableRoles.Add(role.Id);
- msg.AppendLine($":ok:Role **{role.Name}** added to the list.");
- }
- }
- await e.Channel.SendMessage(msg.ToString()).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "rsar")
- .Description($"Removes a specified role from the list of self-assignable roles. | `{Prefix}rsar`")
- .Parameter("role", ParameterType.Unparsed)
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- var roleName = e.GetArg("role")?.Trim();
- if (string.IsNullOrWhiteSpace(roleName))
- return;
- var role = e.Server.FindRoles(roleName).FirstOrDefault();
- if (role == null)
- {
- await e.Channel.SendMessage(":anger:That role does not exist.").ConfigureAwait(false);
- return;
- }
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
- {
- await e.Channel.SendMessage(":anger:That role is not self-assignable.").ConfigureAwait(false);
- return;
- }
- config.ListOfSelfAssignableRoles.Remove(role.Id);
- await e.Channel.SendMessage($":ok:**{role.Name}** has been removed from the list of self-assignable roles").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "lsar")
- .Description($"Lists all self-assignable roles. | `{Prefix}lsar`")
- .Parameter("roles", ParameterType.Multiple)
- .Do(async e =>
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- var msg = new StringBuilder($"There are `{config.ListOfSelfAssignableRoles.Count}` self assignable roles:\n");
- var toRemove = new HashSet();
- foreach (var roleId in config.ListOfSelfAssignableRoles.OrderBy(r => r.ToString()))
- {
- var role = e.Server.GetRole(roleId);
- if (role == null)
- {
- msg.Append($"`{roleId} not found. Cleaned up.`, ");
- toRemove.Add(roleId);
- }
- else
- {
- msg.Append($"**{role.Name}**, ");
- }
- }
- foreach (var id in toRemove)
- {
- config.ListOfSelfAssignableRoles.Remove(id);
- }
- await e.Channel.SendMessage(msg.ToString()).ConfigureAwait(false);
- });
-
-
-
- cgb.CreateCommand(Module.Prefix + "togglexclsar").Alias(Module.Prefix + "tesar")
- .Description($"toggle whether the self-assigned roles should be exclusive | `{Prefix}tesar`")
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- config.ExclusiveSelfAssignedRoles = !config.ExclusiveSelfAssignedRoles;
- string exl = config.ExclusiveSelfAssignedRoles ? "exclusive" : "not exclusive";
- await e.Channel.SendMessage("Self assigned roles are now " + exl);
- });
-
- cgb.CreateCommand(Module.Prefix + "iam")
- .Description("Adds a role to you that you choose. " +
- "Role must be on a list of self-assignable roles." +
- $" | `{Prefix}iam Gamer`")
- .Parameter("role", ParameterType.Unparsed)
- .Do(async e =>
- {
- var roleName = e.GetArg("role")?.Trim();
- if (string.IsNullOrWhiteSpace(roleName))
- return;
- var role = e.Server.FindRoles(roleName).FirstOrDefault();
- if (role == null)
- {
- await e.Channel.SendMessage(":anger:That role does not exist.").ConfigureAwait(false);
- return;
- }
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
- {
- await e.Channel.SendMessage(":anger:That role is not self-assignable.").ConfigureAwait(false);
- return;
- }
- if (e.User.HasRole(role))
- {
- await e.Channel.SendMessage($":anger:You already have {role.Name} role.").ConfigureAwait(false);
- return;
- }
- var sameRoles = e.User.Roles.Where(r => config.ListOfSelfAssignableRoles.Contains(r.Id));
- if (config.ExclusiveSelfAssignedRoles && sameRoles.Any())
- {
- await e.Channel.SendMessage($":anger:You already have {sameRoles.FirstOrDefault().Name} role.").ConfigureAwait(false);
- return;
- }
- try
- {
- await e.User.AddRoles(role).ConfigureAwait(false);
- }
- catch (HttpException ex) when (ex.StatusCode == System.Net.HttpStatusCode.InternalServerError)
- {
- }
- catch (Exception ex)
- {
- await e.Channel.SendMessage($":anger:`I am unable to add that role to you. I can't add roles to owners or other roles higher than my role in the role hierarchy.`").ConfigureAwait(false);
- return;
- }
- var msg = await e.Channel.SendMessage($":ok:You now have {role.Name} role.").ConfigureAwait(false);
- await Task.Delay(3000).ConfigureAwait(false);
- await msg.Delete().ConfigureAwait(false);
- try
- {
- await e.Message.Delete().ConfigureAwait(false);
- }
- catch { }
- });
-
- cgb.CreateCommand(Module.Prefix + "iamnot")
- .Alias(Module.Prefix + "iamn")
- .Description("Removes a role to you that you choose. " +
- "Role must be on a list of self-assignable roles." +
- $" | `{Prefix}iamn Gamer`")
- .Parameter("role", ParameterType.Unparsed)
- .Do(async e =>
- {
- var roleName = e.GetArg("role")?.Trim();
- if (string.IsNullOrWhiteSpace(roleName))
- return;
- var role = e.Server.FindRoles(roleName).FirstOrDefault();
- if (role == null)
- {
- await e.Channel.SendMessage(":anger:That role does not exist.").ConfigureAwait(false);
- return;
- }
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- if (!config.ListOfSelfAssignableRoles.Contains(role.Id))
- {
- await e.Channel.SendMessage(":anger:That role is not self-assignable.").ConfigureAwait(false);
- return;
- }
- if (!e.User.HasRole(role))
- {
- await e.Channel.SendMessage($":anger:You don't have {role.Name} role.").ConfigureAwait(false);
- return;
- }
- await e.User.RemoveRoles(role).ConfigureAwait(false);
- var msg = await e.Channel.SendMessage($":ok:Successfuly removed {role.Name} role from you.").ConfigureAwait(false);
- await Task.Delay(3000).ConfigureAwait(false);
- await msg.Delete().ConfigureAwait(false);
- try
- {
- await e.Message.Delete().ConfigureAwait(false);
- }
- catch { }
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/NadekoBot/Modules/Administration/Commands/SelfCommands.cs
deleted file mode 100644
index f8019ac9..00000000
--- a/NadekoBot/Modules/Administration/Commands/SelfCommands.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Modules.Permissions.Classes;
-using System.Linq;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- class SelfCommands : DiscordCommand
- {
- public SelfCommands(DiscordModule module) : base(module)
- {
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "leave")
- .Description($"Makes Nadeko leave the server. Either name or id required. **Bot Owner Only!**| `{Prefix}leave 123123123331`")
- .Parameter("arg", ParameterType.Required)
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Do(async e =>
- {
- var arg = e.GetArg("arg").Trim();
- var server = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id.ToString() == arg) ??
- NadekoBot.Client.FindServers(arg).FirstOrDefault();
- if (server == null)
- {
- await e.Channel.SendMessage("Cannot find that server").ConfigureAwait(false);
- return;
- }
- if (!server.IsOwner)
- {
- await server.Leave().ConfigureAwait(false);
- }
- else
- {
- await server.Delete().ConfigureAwait(false);
- }
- await NadekoBot.SendMessageToOwner("Left server " + server.Name).ConfigureAwait(false);
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/ServerGreetCommand.cs b/NadekoBot/Modules/Administration/Commands/ServerGreetCommand.cs
deleted file mode 100644
index c4ebf22c..00000000
--- a/NadekoBot/Modules/Administration/Commands/ServerGreetCommand.cs
+++ /dev/null
@@ -1,336 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using System.Collections.Concurrent;
-using System.Linq;
-using System.Threading.Tasks;
-
-/* Voltana's legacy
-public class AsyncLazy : Lazy>
-{
- public AsyncLazy(Func valueFactory) :
- base(() => Task.Factory.StartNew(valueFactory)) { }
-
- public AsyncLazy(Func> taskFactory) :
- base(() => Task.Factory.StartNew(() => taskFactory()).Unwrap()) { }
-
- public TaskAwaiter GetAwaiter() { return Value.GetAwaiter(); }
-}
-*/
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- internal class ServerGreetCommand : DiscordCommand
- {
-
- public static ConcurrentDictionary AnnouncementsDictionary;
-
- public static long Greeted = 0;
-
- public ServerGreetCommand(DiscordModule module) : base(module)
- {
- AnnouncementsDictionary = new ConcurrentDictionary();
-
- //gotta subscribe after ready, to prevent trying to send these before all guilds are initialized
- NadekoBot.OnReady += () =>
- {
- NadekoBot.Client.UserJoined += UserJoined;
- NadekoBot.Client.UserLeft += UserLeft;
- };
-
- var data = Classes.DbHandler.Instance.GetAllRows();
-
- if (!data.Any()) return;
- foreach (var obj in data)
- AnnouncementsDictionary.TryAdd((ulong)obj.ServerId, new AnnounceControls(obj));
- }
-
- private async void UserLeft(object sender, UserEventArgs e)
- {
- try
- {
- if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
- !AnnouncementsDictionary[e.Server.Id].Bye) return;
-
- var controls = AnnouncementsDictionary[e.Server.Id];
- var channel = NadekoBot.Client.GetChannel(controls.ByeChannel);
- var msg = controls.ByeText.Replace("%user%", "**" + e.User.Name + "**").Trim();
- if (string.IsNullOrEmpty(msg))
- return;
-
- if (controls.ByePM)
- {
- Greeted++;
- try
- {
- await e.User.SendMessage($"`Farewell Message From {e.Server?.Name}`\n" + msg).ConfigureAwait(false);
-
- }
- catch { }
- }
- else
- {
- if (channel == null) return;
- Greeted++;
- var toDelete = await channel.SendMessage(msg).ConfigureAwait(false);
- if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages && controls.DeleteGreetMessages)
- {
- await Task.Delay(30000).ConfigureAwait(false); // 5 minutes
- await toDelete.Delete().ConfigureAwait(false);
- }
- }
- }
- catch { }
- }
-
- private async void UserJoined(object sender, Discord.UserEventArgs e)
- {
- try
- {
- if (!AnnouncementsDictionary.ContainsKey(e.Server.Id) ||
- !AnnouncementsDictionary[e.Server.Id].Greet) return;
-
- var controls = AnnouncementsDictionary[e.Server.Id];
- var channel = NadekoBot.Client.GetChannel(controls.GreetChannel);
-
- var msg = controls.GreetText.Replace("%user%", e.User.Mention).Trim();
- if (string.IsNullOrEmpty(msg))
- return;
- if (controls.GreetPM)
- {
- Greeted++;
- await e.User.SendMessage($"`Welcome Message From {e.Server.Name}`\n" + msg).ConfigureAwait(false);
- }
- else
- {
- if (channel == null) return;
- Greeted++;
- var toDelete = await channel.SendMessage(msg).ConfigureAwait(false);
- if (e.Server.CurrentUser.GetPermissions(channel).ManageMessages && controls.DeleteGreetMessages)
- {
- await Task.Delay(30000).ConfigureAwait(false); // 5 minutes
- await toDelete.Delete().ConfigureAwait(false);
- }
- }
- }
- catch { }
- }
-
- public class AnnounceControls
- {
- private DataModels.Announcement _model { get; }
-
- public bool Greet {
- get { return _model.Greet; }
- set { _model.Greet = value; Save(); }
- }
-
- public ulong GreetChannel {
- get { return (ulong)_model.GreetChannelId; }
- set { _model.GreetChannelId = (long)value; Save(); }
- }
-
- public bool GreetPM {
- get { return _model.GreetPM; }
- set { _model.GreetPM = value; Save(); }
- }
-
- public bool ByePM {
- get { return _model.ByePM; }
- set { _model.ByePM = value; Save(); }
- }
-
- public string GreetText {
- get { return _model.GreetText; }
- set { _model.GreetText = value; Save(); }
- }
-
- public bool Bye {
- get { return _model.Bye; }
- set { _model.Bye = value; Save(); }
- }
- public ulong ByeChannel {
- get { return (ulong)_model.ByeChannelId; }
- set { _model.ByeChannelId = (long)value; Save(); }
- }
-
- public string ByeText {
- get { return _model.ByeText; }
- set { _model.ByeText = value; Save(); }
- }
-
- public ulong ServerId {
- get { return (ulong)_model.ServerId; }
- set { _model.ServerId = (long)value; }
- }
-
- public bool DeleteGreetMessages {
- get {
- return _model.DeleteGreetMessages;
- }
- set {
- _model.DeleteGreetMessages = value; Save();
- }
- }
-
- public AnnounceControls(DataModels.Announcement model)
- {
- this._model = model;
- }
-
- public AnnounceControls(ulong serverId)
- {
- this._model = new DataModels.Announcement();
- ServerId = serverId;
- }
-
- internal bool ToggleBye(ulong id)
- {
- if (Bye)
- {
- return Bye = false;
- }
- else
- {
- ByeChannel = id;
- return Bye = true;
- }
- }
-
- internal bool ToggleGreet(ulong id)
- {
- if (Greet)
- {
- return Greet = false;
- }
- else
- {
- GreetChannel = id;
- return Greet = true;
- }
- }
-
- internal bool ToggleDelete() => DeleteGreetMessages = !DeleteGreetMessages;
- internal bool ToggleGreetPM() => GreetPM = !GreetPM;
- internal bool ToggleByePM() => ByePM = !ByePM;
-
- private void Save()
- {
- Classes.DbHandler.Instance.Save(_model);
- }
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "grdel")
- .Description($"Toggles automatic deletion of greet and bye messages. **Needs Manage Server Permissions.**| `{Prefix}grdel`")
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageServer) return;
- var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
-
- if (ann.ToggleDelete())
- await e.Channel.SendMessage("`Automatic deletion of greet and bye messages has been enabled.`").ConfigureAwait(false);
- else
- await e.Channel.SendMessage("`Automatic deletion of greet and bye messages has been disabled.`").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "greet")
- .Description($"Toggles anouncements on the current channel when someone joins the server. **Needs Manage Server Permissions.**| `{Prefix}greet`")
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageServer) return;
- var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
-
- if (ann.ToggleGreet(e.Channel.Id))
- await e.Channel.SendMessage("Greet announcements enabled on this channel.").ConfigureAwait(false);
- else
- await e.Channel.SendMessage("Greet announcements disabled.").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "greetmsg")
- .Description($"Sets a new join announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current greet message. **Needs Manage Server Permissions.**| `{Prefix}greetmsg Welcome, %user%.`")
- .Parameter("msg", ParameterType.Unparsed)
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageServer) return;
- var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
- if (string.IsNullOrWhiteSpace(e.GetArg("msg")))
- {
- await e.Channel.SendMessage("`Current greet message:` " + ann.GreetText);
- return;
- }
-
-
- ann.GreetText = e.GetArg("msg");
- await e.Channel.SendMessage("New greet message set.").ConfigureAwait(false);
- if (!ann.Greet)
- await e.Channel.SendMessage("Enable greet messsages by typing `.greet`").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "bye")
- .Description($"Toggles anouncements on the current channel when someone leaves the server. | `{Prefix}bye`")
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageServer) return;
- var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
-
- if (ann.ToggleBye(e.Channel.Id))
- await e.Channel.SendMessage("Bye announcements enabled on this channel.").ConfigureAwait(false);
- else
- await e.Channel.SendMessage("Bye announcements disabled.").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "byemsg")
- .Description($"Sets a new leave announcement message. Type %user% if you want to mention the new member. Using it with no message will show the current bye message. **Needs Manage Server Permissions.**| `{Prefix}byemsg %user% has left.`")
- .Parameter("msg", ParameterType.Unparsed)
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageServer) return;
- var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
- if (string.IsNullOrWhiteSpace(e.GetArg("msg")))
- {
- await e.Channel.SendMessage("`Current bye message:` " + ann.ByeText);
- return;
- }
-
- ann.ByeText = e.GetArg("msg");
- await e.Channel.SendMessage("New bye message set.").ConfigureAwait(false);
- if (!ann.Bye)
- await e.Channel.SendMessage("Enable bye messsages by typing `.bye`.").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "byepm")
- .Description($"Toggles whether the good bye messages will be sent in a PM or in the text channel. **Needs Manage Server Permissions.**| `{Prefix}byepm`")
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageServer) return;
- var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
-
-
- if (ann.ToggleByePM())
- await e.Channel.SendMessage("Bye messages will be sent in a PM from now on.\n ⚠ Keep in mind this might fail if the user and the bot have no common servers after the user leaves.").ConfigureAwait(false);
- else
- await e.Channel.SendMessage("Bye messages will be sent in a bound channel from now on.").ConfigureAwait(false);
- if (!ann.Bye)
- await e.Channel.SendMessage("Enable bye messsages by typing `.bye`, and set the bye message using `.byemsg`").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "greetpm")
- .Description($"Toggles whether the greet messages will be sent in a PM or in the text channel. **Needs Manage Server Permissions.**| `{Prefix}greetpm`")
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageServer) return;
-
- var ann = AnnouncementsDictionary.GetOrAdd(e.Server.Id, new AnnounceControls(e.Server.Id));
-
- if (ann.ToggleGreetPM())
- await e.Channel.SendMessage("Greet messages will be sent in a PM from now on.").ConfigureAwait(false);
- else
- await e.Channel.SendMessage("Greet messages will be sent in a bound channel from now on.").ConfigureAwait(false);
- if (!ann.Greet)
- await e.Channel.SendMessage("Enable greet messsages by typing `.greet`, and set the greet message using `.greetmsg`").ConfigureAwait(false);
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommand.cs b/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommand.cs
deleted file mode 100644
index af220059..00000000
--- a/NadekoBot/Modules/Administration/Commands/VoicePlusTextCommand.cs
+++ /dev/null
@@ -1,164 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-using ChPermOverride = Discord.ChannelPermissionOverrides;
-
-namespace NadekoBot.Modules.Administration.Commands
-{
- internal class VoicePlusTextCommand : DiscordCommand
- {
- Regex channelNameRegex = new Regex(@"[^a-zA-Z0-9 -]", RegexOptions.Compiled);
- public VoicePlusTextCommand(DiscordModule module) : base(module)
- {
- // changing servers may cause bugs
- NadekoBot.OnReady += () => NadekoBot.Client.UserUpdated += async (sender, e) =>
- {
- try
- {
- if (e.Server == null)
- return;
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- if (e.Before.VoiceChannel == e.After.VoiceChannel) return;
- if (!config.VoicePlusTextEnabled)
- return;
- var serverPerms = e.Server.GetUser(NadekoBot.Client.CurrentUser.Id)?.ServerPermissions;
- if (serverPerms == null)
- return;
- if (!serverPerms.Value.ManageChannels || !serverPerms.Value.ManageRoles)
- {
-
- try
- {
- await e.Server.Owner.SendMessage(
- "I don't have manage server and/or Manage Channels permission," +
- $" so I cannot run voice+text on **{e.Server.Name}** server.").ConfigureAwait(false);
- }
- catch { } // meh
- config.VoicePlusTextEnabled = false;
- return;
- }
-
-
- var beforeVch = e.Before.VoiceChannel;
- if (beforeVch != null)
- {
- var textChannel =
- e.Server.FindChannels(GetChannelName(beforeVch.Name), ChannelType.Text).FirstOrDefault();
- if (textChannel != null)
- await textChannel.AddPermissionsRule(e.Before,
- new ChPermOverride(readMessages: PermValue.Deny,
- sendMessages: PermValue.Deny)).ConfigureAwait(false);
- }
- var afterVch = e.After.VoiceChannel;
- if (afterVch != null && e.Server.AFKChannel != afterVch)
- {
- var textChannel = e.Server.FindChannels(
- GetChannelName(afterVch.Name),
- ChannelType.Text)
- .FirstOrDefault();
- if (textChannel == null)
- {
- textChannel = (await e.Server.CreateChannel(GetChannelName(afterVch.Name), ChannelType.Text).ConfigureAwait(false));
- await textChannel.AddPermissionsRule(e.Server.EveryoneRole,
- new ChPermOverride(readMessages: PermValue.Deny,
- sendMessages: PermValue.Deny)).ConfigureAwait(false);
- }
- await textChannel.AddPermissionsRule(e.After,
- new ChPermOverride(readMessages: PermValue.Allow,
- sendMessages: PermValue.Allow)).ConfigureAwait(false);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine(ex);
- }
- };
- }
-
- private string GetChannelName(string voiceName) =>
- channelNameRegex.Replace(voiceName, "").Trim().Replace(" ", "-").TrimTo(90, true) + "-voice";
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "cleanv+t")
- .Alias(Module.Prefix + "cv+t")
- .Description($"Deletes all text channels ending in `-voice` for which voicechannels are not found. **Use at your own risk. Needs Manage Roles and Manage Channels Permissions.** | `{Prefix}cleanv+t`")
- .AddCheck(SimpleCheckers.CanManageRoles)
- .AddCheck(SimpleCheckers.ManageChannels())
- .Do(async e =>
- {
- if (!e.Server.CurrentUser.ServerPermissions.ManageChannels)
- {
- await e.Channel.SendMessage("`I have insufficient permission to do that.`");
- return;
- }
-
- var allTxtChannels = e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice"));
- var validTxtChannelNames = e.Server.VoiceChannels.Select(c => GetChannelName(c.Name));
-
- var invalidTxtChannels = allTxtChannels.Where(c => !validTxtChannelNames.Contains(c.Name));
-
- foreach (var c in invalidTxtChannels)
- {
- try
- {
- await c.Delete();
- }
- catch { }
- await Task.Delay(500);
- }
-
- await e.Channel.SendMessage("`Done.`");
- });
-
- cgb.CreateCommand(Module.Prefix + "voice+text")
- .Alias(Module.Prefix + "v+t")
- .Description("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. **Needs Manage Roles and Manage Channels Permissions.**| `{Prefix}voice+text`")
- .AddCheck(SimpleCheckers.ManageChannels())
- .AddCheck(SimpleCheckers.CanManageRoles)
- .Do(async e =>
- {
- try
- {
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- if (config.VoicePlusTextEnabled == true)
- {
- config.VoicePlusTextEnabled = false;
- foreach (var textChannel in e.Server.TextChannels.Where(c => c.Name.EndsWith("-voice")))
- {
- try
- {
- await textChannel.Delete().ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage(
- ":anger: Error: Most likely i don't have permissions to do this.")
- .ConfigureAwait(false);
- return;
- }
- }
- await e.Channel.SendMessage("Successfuly removed voice + text feature.").ConfigureAwait(false);
- return;
- }
- config.VoicePlusTextEnabled = true;
- await e.Channel.SendMessage("Successfuly enabled voice + text feature. " +
- "**Make sure the bot has manage roles and manage channels permissions**")
- .ConfigureAwait(false);
-
- }
- catch (Exception ex)
- {
- await e.Channel.SendMessage(ex.ToString()).ConfigureAwait(false);
- }
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs b/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs
deleted file mode 100644
index 1ae491ad..00000000
--- a/NadekoBot/Modules/ClashOfClans/ClashOfClans.cs
+++ /dev/null
@@ -1,176 +0,0 @@
-using Newtonsoft.Json;
-using System;
-using System.Linq;
-using System.Text;
-//using Manatee.Json.Serialization;
-
-namespace NadekoBot.Classes.ClashOfClans
-{
- public enum DestroyStars
- {
- One, Two, Three
- }
- public enum WarState
- {
- Started, Ended, Created
- }
- [System.Serializable]
- internal class Caller
- {
- public string CallUser { get; set; }
-
- public DateTime TimeAdded { get; set; }
-
- public bool BaseDestroyed { get; set; }
-
- public int Stars { get; set; } = 3;
-
- public Caller() { }
-
- public Caller(string callUser, DateTime timeAdded, bool baseDestroyed)
- {
- CallUser = callUser;
- TimeAdded = timeAdded;
- BaseDestroyed = baseDestroyed;
- }
-
- public void ResetTime()
- {
- TimeAdded = DateTime.UtcNow;
- }
-
- public void Destroy()
- {
- BaseDestroyed = true;
- }
- }
-
- internal class ClashWar
- {
- private static TimeSpan callExpire => new TimeSpan(2, 0, 0);
-
- public string EnemyClan { get; set; }
- public int Size { get; set; }
-
- public Caller[] Bases { get; set; }
- public WarState WarState { get; set; } = WarState.Created;
- //public bool Started { get; set; } = false;
- public DateTime StartedAt { get; set; }
- //public bool Ended { get; private set; } = false;
-
- public ulong ServerId { get; set; }
- public ulong ChannelId { get; set; }
-
- [JsonIgnore]
- public Discord.Channel Channel { get; internal set; }
-
- ///
- /// This init is purely for the deserialization
- ///
- public ClashWar() { }
-
- public ClashWar(string enemyClan, int size, ulong serverId, ulong channelId)
- {
- this.EnemyClan = enemyClan;
- this.Size = size;
- this.Bases = new Caller[size];
- this.ServerId = serverId;
- this.ChannelId = channelId;
- this.Channel = NadekoBot.Client.Servers.FirstOrDefault(s => s.Id == serverId)?.TextChannels.FirstOrDefault(c => c.Id == channelId);
- }
-
- internal void End()
- {
- //Ended = true;
- WarState = WarState.Ended;
- }
-
- internal void Call(string u, int baseNumber)
- {
- if (baseNumber < 0 || baseNumber >= Bases.Length)
- throw new ArgumentException("Invalid base number");
- if (Bases[baseNumber] != null)
- throw new ArgumentException("That base is already claimed.");
- for (var i = 0; i < Bases.Length; i++)
- {
- if (Bases[i]?.BaseDestroyed == false && Bases[i]?.CallUser == u)
- throw new ArgumentException($"@{u} You already claimed base #{i + 1}. You can't claim a new one.");
- }
-
- Bases[baseNumber] = new Caller(u.Trim(), DateTime.UtcNow, false);
- }
-
- internal void Start()
- {
- if (WarState == WarState.Started)
- throw new InvalidOperationException("War already started");
- //if (Started)
- // throw new InvalidOperationException();
- //Started = true;
- WarState = WarState.Started;
- StartedAt = DateTime.UtcNow;
- foreach (var b in Bases.Where(b => b != null))
- {
- b.ResetTime();
- }
- }
-
- internal int Uncall(string user)
- {
- user = user.Trim();
- for (var i = 0; i < Bases.Length; i++)
- {
- if (Bases[i]?.CallUser != user) continue;
- Bases[i] = null;
- return i;
- }
- throw new InvalidOperationException("You are not participating in that war.");
- }
-
- public string ShortPrint() =>
- $"`{EnemyClan}` ({Size} v {Size})";
-
- public override string ToString()
- {
- var sb = new StringBuilder();
-
- sb.AppendLine($"🔰**WAR AGAINST `{EnemyClan}` ({Size} v {Size}) INFO:**");
- if (WarState == WarState.Created)
- sb.AppendLine("`not started`");
- for (var i = 0; i < Bases.Length; i++)
- {
- if (Bases[i] == null)
- {
- sb.AppendLine($"`{i + 1}.` ❌*unclaimed*");
- }
- else
- {
- if (Bases[i].BaseDestroyed)
- {
- sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {new string('⭐', Bases[i].Stars)}");
- }
- else
- {
- var left = (WarState == WarState.Started) ? callExpire - (DateTime.UtcNow - Bases[i].TimeAdded) : callExpire;
- sb.AppendLine($"`{i + 1}.` ✅ `{Bases[i].CallUser}` {left.Hours}h {left.Minutes}m {left.Seconds}s left");
- }
- }
-
- }
- return sb.ToString();
- }
-
- internal int FinishClaim(string user, int stars = 3)
- {
- user = user.Trim();
- for (var i = 0; i < Bases.Length; i++)
- {
- if (Bases[i]?.BaseDestroyed != false || Bases[i]?.CallUser != user) continue;
- Bases[i].BaseDestroyed = true;
- Bases[i].Stars = stars;
- return i;
- }
- throw new InvalidOperationException($"@{user} You are either not participating in that war, or you already destroyed a base.");
- }
- }
-}
diff --git a/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs b/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs
deleted file mode 100644
index 07db4f98..00000000
--- a/NadekoBot/Modules/ClashOfClans/ClashOfClansModule.cs
+++ /dev/null
@@ -1,421 +0,0 @@
-using Discord.Commands;
-using Discord.Modules;
-using NadekoBot.Classes.ClashOfClans;
-using NadekoBot.Modules.Permissions.Classes;
-using Newtonsoft.Json;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.ClashOfClans
-{
- internal class ClashOfClansModule : DiscordModule
- {
- public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.ClashOfClans;
-
- public static ConcurrentDictionary> ClashWars { get; set; } = new ConcurrentDictionary>();
-
- private readonly object writeLock = new object();
-
- public ClashOfClansModule()
- {
- NadekoBot.OnReady += () =>
- {
- Task.Run(async () =>
- {
- if (File.Exists("data/clashofclans/wars.json"))
- {
- try
- {
- var content = File.ReadAllText("data/clashofclans/wars.json");
-
- var dict = JsonConvert.DeserializeObject>>(content);
-
- foreach (var cw in dict)
- {
- cw.Value.ForEach(war =>
- {
- war.Channel = NadekoBot.Client.GetServer(war.ServerId)?.GetChannel(war.ChannelId);
- if (war.Channel == null)
- {
- cw.Value.Remove(war);
- }
- }
- );
- }
- //urgh
- ClashWars = new ConcurrentDictionary>(dict);
- }
- catch (Exception e)
- {
- Console.WriteLine("Could not load coc wars: " + e.Message);
- }
-
-
- }
- //Can't this be disabled if the modules is disabled too :)
- var callExpire = new TimeSpan(2, 0, 0);
- var warExpire = new TimeSpan(23, 0, 0);
- while (true)
- {
- try
- {
- var hash = ClashWars.GetHashCode();
- foreach (var cw in ClashWars)
- {
- foreach (var war in cw.Value)
- {
- await CheckWar(callExpire, war);
- }
- List newVal = new List();
- foreach (var w in cw.Value)
- {
- //We add when A: the war is not ended
- if (w.WarState != WarState.Ended)
- {
- //and B: the war has not expired
- if ((w.WarState == WarState.Started && DateTime.UtcNow - w.StartedAt <= warExpire) || w.WarState == WarState.Created)
- {
- newVal.Add(w);
- }
- }
- }
- //var newVal = cw.Value.Where(w => !(w.Ended || DateTime.UtcNow - w.StartedAt >= warExpire)).ToList();
- foreach (var exWar in cw.Value.Except(newVal))
- {
- await exWar.Channel.SendMessage($"War against {exWar.EnemyClan} ({exWar.Size}v{exWar.Size}) has ended");
- }
-
- if (newVal.Count == 0)
- {
- List obj;
- ClashWars.TryRemove(cw.Key, out obj);
- }
- else
- {
- ClashWars.AddOrUpdate(cw.Key, newVal, (x, s) => newVal);
- }
- }
- if (hash != ClashWars.GetHashCode()) //something changed
- {
- Save();
- }
-
-
- }
- catch { }
- await Task.Delay(5000);
- }
- });
- };
- }
-
- private static void Save()
- {
- try
- {
- Directory.CreateDirectory("data/clashofclans");
- File.WriteAllText("data/clashofclans/wars.json", JsonConvert.SerializeObject(ClashWars, Formatting.Indented));
- }
- catch (Exception e)
- {
- Console.WriteLine(e.Message);
- }
- }
-
- private static async Task CheckWar(TimeSpan callExpire, ClashWar war)
- {
- var Bases = war.Bases;
- for (var i = 0; i < Bases.Length; i++)
- {
- if (Bases[i] == null) continue;
- if (!Bases[i].BaseDestroyed && DateTime.UtcNow - Bases[i].TimeAdded >= callExpire)
- {
- await war.Channel.SendMessage($"❗🔰**Claim from @{Bases[i].CallUser} for a war against {war.ShortPrint()} has expired.**").ConfigureAwait(false);
- Bases[i] = null;
- }
- }
- }
-
- #region commands
- public override void Install(ModuleManager manager)
- {
- manager.CreateCommands("", cgb =>
- {
-
- cgb.AddCheck(PermissionChecker.Instance);
-
- cgb.CreateCommand(Prefix + "createwar")
- .Alias(Prefix + "cw")
- .Description($"Creates a new war by specifying a size (>10 and multiple of 5) and enemy clan name. | `{Prefix}cw 15 The Enemy Clan`")
- .Parameter("size")
- .Parameter("enemy_clan", ParameterType.Unparsed)
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageChannels)
- return;
- var enemyClan = e.GetArg("enemy_clan");
- if (string.IsNullOrWhiteSpace(enemyClan))
- {
- return;
- }
- int size;
- if (!int.TryParse(e.GetArg("size"), out size) || size < 10 || size > 50 || size % 5 != 0)
- {
- await e.Channel.SendMessage("💢🔰 Not a Valid war size").ConfigureAwait(false);
- return;
- }
- List wars;
- if (!ClashWars.TryGetValue(e.Server.Id, out wars))
- {
- wars = new List();
- if (!ClashWars.TryAdd(e.Server.Id, wars))
- return;
- }
-
-
- var cw = new ClashWar(enemyClan, size, e.Server.Id, e.Channel.Id);
- //cw.Start();
-
- wars.Add(cw);
- await e.Channel.SendMessage($"❗🔰**CREATED CLAN WAR AGAINST {cw.ShortPrint()}**").ConfigureAwait(false);
- Save();
- //war with the index X started.
- });
-
- cgb.CreateCommand(Prefix + "startwar")
- .Alias(Prefix + "sw")
- .Description($"Starts a war with a given number. | `{Prefix}sw 15`")
- .Parameter("number", ParameterType.Required)
- .Do(async e =>
- {
- var warsInfo = GetInfo(e);
- if (warsInfo == null)
- {
- await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
- return;
- }
- var war = warsInfo.Item1[warsInfo.Item2];
- try
- {
- war.Start();
- await e.Channel.SendMessage($"🔰**STARTED WAR AGAINST {war.ShortPrint()}**").ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage($"🔰**WAR AGAINST {war.ShortPrint()} HAS ALREADY STARTED**").ConfigureAwait(false);
- }
- Save();
- });
-
- cgb.CreateCommand(Prefix + "listwar")
- .Alias(Prefix + "lw")
- .Description($"Shows the active war claims by a number. Shows all wars in a short way if no number is specified. | `{Prefix}lw [war_number] or {Prefix}lw`")
- .Parameter("number", ParameterType.Optional)
- .Do(async e =>
- {
- // if number is null, print all wars in a short way
- if (string.IsNullOrWhiteSpace(e.GetArg("number")))
- {
- //check if there are any wars
- List wars = null;
- ClashWars.TryGetValue(e.Server.Id, out wars);
- if (wars == null || wars.Count == 0)
- {
- await e.Channel.SendMessage("🔰 **No active wars.**").ConfigureAwait(false);
- return;
- }
-
- var sb = new StringBuilder();
- sb.AppendLine("🔰 **LIST OF ACTIVE WARS**");
- sb.AppendLine("**-------------------------**");
- for (var i = 0; i < wars.Count; i++)
- {
- sb.AppendLine($"**#{i + 1}.** `Enemy:` **{wars[i].EnemyClan}**");
- sb.AppendLine($"\t\t`Size:` **{wars[i].Size} v {wars[i].Size}**");
- sb.AppendLine("**-------------------------**");
- }
- await e.Channel.SendMessage(sb.ToString()).ConfigureAwait(false);
- return;
-
- }
- //if number is not null, print the war needed
- var warsInfo = GetInfo(e);
- if (warsInfo == null)
- {
- await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
- return;
- }
- await e.Channel.SendMessage(warsInfo.Item1[warsInfo.Item2].ToString()).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "claim")
- .Alias(Prefix + "call")
- .Alias(Prefix + "c")
- .Description($"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. | `{Prefix}call [war_number] [base_number] [optional_other_name]`")
- .Parameter("number")
- .Parameter("baseNumber")
- .Parameter("other_name", ParameterType.Unparsed)
- .Do(async e =>
- {
- var warsInfo = GetInfo(e);
- if (warsInfo == null || warsInfo.Item1.Count == 0)
- {
- await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
- return;
- }
- int baseNum;
- if (!int.TryParse(e.GetArg("baseNumber"), out baseNum))
- {
- await e.Channel.SendMessage("💢🔰 **Invalid base number.**").ConfigureAwait(false);
- return;
- }
- var usr =
- string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
- e.User.Name :
- e.GetArg("other_name");
- try
- {
- var war = warsInfo.Item1[warsInfo.Item2];
- war.Call(usr, baseNum - 1);
- await e.Channel.SendMessage($"🔰**{usr}** claimed a base #{baseNum} for a war against {war.ShortPrint()}").ConfigureAwait(false);
- Save();
- }
- catch (Exception ex)
- {
- await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "claimfinish")
- .Alias(Prefix + "cf")
- .Alias(Prefix + "cf3")
- .Alias(Prefix + "claimfinish3")
- .Description($"Finish your claim with 3 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
- .Parameter("number", ParameterType.Required)
- .Parameter("other_name", ParameterType.Unparsed)
- .Do(e => FinishClaim(e));
-
- cgb.CreateCommand(Prefix + "claimfinish2")
- .Alias(Prefix + "cf2")
- .Description($"Finish your claim with 2 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
- .Parameter("number", ParameterType.Required)
- .Parameter("other_name", ParameterType.Unparsed)
- .Do(e => FinishClaim(e, 2));
-
- cgb.CreateCommand(Prefix + "claimfinish1")
- .Alias(Prefix + "cf1")
- .Description($"Finish your claim with 1 stars if you destroyed a base. Optional second argument finishes for someone else. | `{Prefix}cf [war_number] [optional_other_name]`")
- .Parameter("number", ParameterType.Required)
- .Parameter("other_name", ParameterType.Unparsed)
- .Do(e => FinishClaim(e, 1));
-
- cgb.CreateCommand(Prefix + "unclaim")
- .Alias(Prefix + "uncall")
- .Alias(Prefix + "uc")
- .Description($"Removes your claim from a certain war. Optional second argument denotes a person in whose place to unclaim | `{Prefix}uc [war_number] [optional_other_name]`")
- .Parameter("number", ParameterType.Required)
- .Parameter("other_name", ParameterType.Unparsed)
- .Do(async e =>
- {
- var warsInfo = GetInfo(e);
- if (warsInfo == null || warsInfo.Item1.Count == 0)
- {
- await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
- return;
- }
- var usr =
- string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
- e.User.Name :
- e.GetArg("other_name");
- try
- {
- var war = warsInfo.Item1[warsInfo.Item2];
- var baseNumber = war.Uncall(usr);
- await e.Channel.SendMessage($"🔰 @{usr} has **UNCLAIMED** a base #{baseNumber + 1} from a war against {war.ShortPrint()}").ConfigureAwait(false);
- Save();
- }
- catch (Exception ex)
- {
- await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand(Prefix + "endwar")
- .Alias(Prefix + "ew")
- .Description($"Ends the war with a given index. | `{Prefix}ew [war_number]`")
- .Parameter("number")
- .Do(async e =>
- {
- var warsInfo = GetInfo(e);
- if (warsInfo == null)
- {
- await e.Channel.SendMessage("💢🔰 That war does not exist.").ConfigureAwait(false);
- return;
- }
- warsInfo.Item1[warsInfo.Item2].End();
- await e.Channel.SendMessage($"❗🔰**War against {warsInfo.Item1[warsInfo.Item2].ShortPrint()} ended.**").ConfigureAwait(false);
-
- var size = warsInfo.Item1[warsInfo.Item2].Size;
- warsInfo.Item1.RemoveAt(warsInfo.Item2);
- Save();
- });
- });
-
- }
- #endregion
-
-
- private async Task FinishClaim(CommandEventArgs e, int stars = 3)
- {
- var warInfo = GetInfo(e);
- if (warInfo == null || warInfo.Item1.Count == 0)
- {
- await e.Channel.SendMessage("💢🔰 **That war does not exist.**").ConfigureAwait(false);
- return;
- }
- var usr =
- string.IsNullOrWhiteSpace(e.GetArg("other_name")) ?
- e.User.Name :
- e.GetArg("other_name");
-
- var war = warInfo.Item1[warInfo.Item2];
- try
- {
- var baseNum = war.FinishClaim(usr, stars);
- await e.Channel.SendMessage($"❗🔰{e.User.Mention} **DESTROYED** a base #{baseNum + 1} in a war against {war.ShortPrint()}").ConfigureAwait(false);
- Save();
- }
- catch (Exception ex)
- {
- await e.Channel.SendMessage($"💢🔰 {ex.Message}").ConfigureAwait(false);
- }
- }
-
- private static Tuple, int> GetInfo(CommandEventArgs e)
- {
- //check if there are any wars
- List wars = null;
- ClashWars.TryGetValue(e.Server.Id, out wars);
- if (wars == null || wars.Count == 0)
- {
- return null;
- }
- // get the number of the war
- int num;
- if (string.IsNullOrWhiteSpace(e.GetArg("number")))
- num = 0;
- else if (!int.TryParse(e.GetArg("number"), out num) || num > wars.Count)
- {
- return null;
- }
- num -= 1;
- //get the actual war
- return new Tuple, int>(wars, num);
- }
- }
-}
diff --git a/NadekoBot/Modules/Conversations/Commands/RipCommand.cs b/NadekoBot/Modules/Conversations/Commands/RipCommand.cs
deleted file mode 100644
index 9c4842bf..00000000
--- a/NadekoBot/Modules/Conversations/Commands/RipCommand.cs
+++ /dev/null
@@ -1,120 +0,0 @@
-using NadekoBot.Classes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Discord.Commands;
-using System.Drawing;
-using System.Drawing.Drawing2D;
-using NadekoBot.Properties;
-using System.IO;
-using System.Drawing.Imaging;
-using NadekoBot.Extensions;
-
-namespace NadekoBot.Modules.Conversations.Commands
-{
- class RipCommand : DiscordCommand
- {
- public RipCommand(DiscordModule module) : base(module)
- {
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand("rip")
- .Description("Shows a grave image of someone with a start year | `@NadekoBot rip @Someone 2000`")
- .Parameter("user", ParameterType.Required)
- .Parameter("year", ParameterType.Optional)
- .Do(async e =>
- {
- if (string.IsNullOrWhiteSpace(e.GetArg("user")))
- return;
- var usr = e.Channel.FindUsers(e.GetArg("user")).FirstOrDefault();
- var text = "";
- Stream file;
- if (usr == null)
- {
- text = e.GetArg("user");
- file = RipName(text, string.IsNullOrWhiteSpace(e.GetArg("year"))
- ? null
- : e.GetArg("year"));
- }
- else
- {
- var avatar = await GetAvatar(usr.AvatarUrl);
- text = usr.Name;
- file = RipUser(text, avatar, string.IsNullOrWhiteSpace(e.GetArg("year"))
- ? null
- : e.GetArg("year"));
- }
- await e.Channel.SendFile("ripzor_m8.png",
- file);
- });
- }
-
-
- ///
- /// Create a RIP image of the given name and avatar, with an optional year
- ///
- ///
- ///
- ///
- ///
- public Stream RipUser(string name, Image avatar, string year = null)
- {
- var bm = Resources.rip;
- int width = 300;
- var fontSize = width / name.Length -2;
- if (fontSize > 20) fontSize = 20;
- var g = Graphics.FromImage(bm);
- Font nameFont = new Font("Comic Sans MS", fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
- SizeF nameSize = g.MeasureString(name, nameFont);
- g.DrawString(name, new Font("Comic Sans MS", fontSize, FontStyle.Bold), Brushes.Black, (bm.Width /2 - 8) - (nameSize.Width /2), 243 - nameSize.Height);
- g.DrawString((year ?? "?") + " - " + DateTime.Now.Year, new Font("Consolas", 12, FontStyle.Bold), Brushes.Black, 80, 240);
-
- g.DrawImage(avatar, 80, 135);
- g.DrawImage((Image)Resources.rose_overlay, 0, 0);
- g.Flush();
- g.Dispose();
-
- return bm.ToStream(ImageFormat.Png);
- }
-
- public Stream RipName(string name, string year = null)
- {
- var bm = Resources.rip;
- int width = 190;
- var offset = name.Length * 5;
- var fontSize = width / name.Length;
- if (fontSize > 20) fontSize = 20;
- var g = Graphics.FromImage(bm);
- Font nameFont = new Font("Comic Sans MS", fontSize, FontStyle.Bold, GraphicsUnit.Pixel);
- SizeF nameSize = g.MeasureString(name, nameFont);
- g.DrawString(name, nameFont, Brushes.Black, (bm.Width / 2) - (nameSize.Width / 2), 200);
- g.DrawString((year ?? "?") + " - " + DateTime.Now.Year, new Font("Consolas", 12, FontStyle.Bold), Brushes.Black, 80, 235);
- g.Flush();
- g.Dispose();
-
- return bm.ToStream(ImageFormat.Png);
- }
-
- public static async Task GetAvatar(string url)
- {
- var stream = await SearchHelper.GetResponseStreamAsync(url);
- Bitmap bmp = new Bitmap(100, 100);
- using (GraphicsPath gp = new GraphicsPath())
- {
- gp.AddEllipse(0, 0, bmp.Width, bmp.Height);
- using (Graphics gr = Graphics.FromImage(bmp))
- {
- gr.SetClip(gp);
- gr.DrawImage(Image.FromStream(stream), Point.Empty);
-
- }
- }
- return bmp;
-
- }
- }
-}
diff --git a/NadekoBot/Modules/Conversations/Conversations.cs b/NadekoBot/Modules/Conversations/Conversations.cs
deleted file mode 100644
index a3611d0e..00000000
--- a/NadekoBot/Modules/Conversations/Conversations.cs
+++ /dev/null
@@ -1,224 +0,0 @@
-using Discord;
-using Discord.Commands;
-using Discord.Modules;
-using NadekoBot.DataModels;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Conversations.Commands;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Conversations
-{
- internal class Conversations : DiscordModule
- {
- private const string firestr = "🔥 ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็ด้้้้้็็็็็้้้้้็็็็็้้้้้้้้็็็็็้้้้้็็็็็้้้้ 🔥";
- public Conversations()
- {
- commands.Add(new RipCommand(this));
- }
-
- public override string Prefix { get; } = String.Format(NadekoBot.Config.CommandPrefixes.Conversations, NadekoBot.Creds.BotId);
-
- public override void Install(ModuleManager manager)
- {
- var rng = new Random();
-
- manager.CreateCommands("", cgb =>
- {
- cgb.AddCheck(PermissionChecker.Instance);
-
- cgb.CreateCommand("..")
- .Description("Adds a new quote with the specified name (single word) and message (no limit). | `.. abc My message`")
- .Parameter("keyword", ParameterType.Required)
- .Parameter("text", ParameterType.Unparsed)
- .Do(async e =>
- {
- var text = e.GetArg("text");
- if (string.IsNullOrWhiteSpace(text))
- return;
- await Task.Run(() =>
- Classes.DbHandler.Instance.Connection.Insert(new DataModels.UserQuote()
- {
- DateAdded = DateTime.Now,
- Keyword = e.GetArg("keyword").ToLowerInvariant(),
- Text = text,
- UserName = e.User.Name,
- })).ConfigureAwait(false);
-
- await e.Channel.SendMessage("`New quote added.`").ConfigureAwait(false);
- });
-
- cgb.CreateCommand("...")
- .Description("Shows a random quote with a specified name. | `... abc`")
- .Parameter("keyword", ParameterType.Required)
- .Do(async e =>
- {
- var keyword = e.GetArg("keyword")?.ToLowerInvariant();
- if (string.IsNullOrWhiteSpace(keyword))
- return;
-
- var quote =
- Classes.DbHandler.Instance.GetRandom(
- uqm => uqm.Keyword == keyword);
-
- if (quote != null)
- await e.Channel.SendMessage($"📣 {quote.Text}").ConfigureAwait(false);
- else
- await e.Channel.SendMessage("💢`No quote found.`").ConfigureAwait(false);
- });
-
- cgb.CreateCommand("..qdel")
- .Alias("..quotedelete")
- .Description("Deletes all quotes with the specified keyword. You have to either be bot owner or the creator of the quote to delete it. | `..qdel abc`")
- .Parameter("quote", ParameterType.Required)
- .Do(async e =>
- {
- var text = e.GetArg("quote")?.Trim();
- if (string.IsNullOrWhiteSpace(text))
- return;
- await Task.Run(() =>
- {
- if (NadekoBot.IsOwner(e.User.Id))
- Classes.DbHandler.Instance.DeleteWhere(uq => uq.Keyword == text);
- else
- Classes.DbHandler.Instance.DeleteWhere(uq => uq.Keyword == text && uq.UserName == e.User.Name);
- }).ConfigureAwait(false);
-
- await e.Channel.SendMessage("`Done.`").ConfigureAwait(false);
- });
- });
-
- manager.CreateCommands(NadekoBot.BotMention, cgb =>
- {
- var client = manager.Client;
-
- cgb.AddCheck(PermissionChecker.Instance);
-
- commands.ForEach(cmd => cmd.Init(cgb));
-
- cgb.CreateCommand("die")
- .Description("Works only for the owner. Shuts the bot down. | `@NadekoBot die`")
- .Do(async e =>
- {
- if (NadekoBot.IsOwner(e.User.Id))
- {
- await e.Channel.SendMessage(e.User.Mention + ", Yes, my love.").ConfigureAwait(false);
- await Task.Delay(5000).ConfigureAwait(false);
- Environment.Exit(0);
- }
- else
- await e.Channel.SendMessage(e.User.Mention + ", No.").ConfigureAwait(false);
- });
-
- var randServerSw = new Stopwatch();
- randServerSw.Start();
-
- cgb.CreateCommand("do you love me")
- .Description("Replies with positive answer only to the bot owner. | `@NadekoBot do you love me`")
- .Do(async e =>
- {
- if (NadekoBot.IsOwner(e.User.Id))
- await e.Channel.SendMessage(e.User.Mention + ", Of course I do, my Master.").ConfigureAwait(false);
- else
- await e.Channel.SendMessage(e.User.Mention + ", Don't be silly.").ConfigureAwait(false);
- });
-
- cgb.CreateCommand("how are you")
- .Alias("how are you?")
- .Description("Replies positive only if bot owner is online. | `@NadekoBot how are you`")
- .Do(async e =>
- {
- if (NadekoBot.IsOwner(e.User.Id))
- {
- await e.Channel.SendMessage(e.User.Mention + " I am great as long as you are here.").ConfigureAwait(false);
- return;
- }
- var kw = e.Server.GetUser(NadekoBot.Creds.OwnerIds[0]);
- if (kw != null && kw.Status == UserStatus.Online)
- {
- await e.Channel.SendMessage(e.User.Mention + " I am great as long as " + kw.Mention + " is with me.").ConfigureAwait(false);
- }
- else
- {
- await e.Channel.SendMessage(e.User.Mention + " I am sad. My Master is not with me.").ConfigureAwait(false);
- }
- });
-
- cgb.CreateCommand("fire")
- .Description("Shows a unicode fire message. Optional parameter [x] tells her how many times to repeat the fire. | `@NadekoBot fire [x]`")
- .Parameter("times", ParameterType.Optional)
- .Do(async e =>
- {
- int count;
- if (string.IsNullOrWhiteSpace(e.Args[0]))
- count = 1;
- else
- int.TryParse(e.Args[0], out count);
- if (count < 1 || count > 12)
- {
- await e.Channel.SendMessage("Number must be between 1 and 12").ConfigureAwait(false);
- return;
- }
-
- var str = new StringBuilder();
- for (var i = 0; i < count; i++)
- {
- str.Append(firestr);
- }
- await e.Channel.SendMessage(str.ToString()).ConfigureAwait(false);
- });
-
- cgb.CreateCommand("dump")
- .Description("Dumps all of the invites it can to dump.txt.** Owner Only.** | `@NadekoBot dump`")
- .Do(async e =>
- {
- if (!NadekoBot.IsOwner(e.User.Id)) return;
- var i = 0;
- var j = 0;
- var invites = "";
- foreach (var s in client.Servers)
- {
- try
- {
- var invite = await s.CreateInvite(0).ConfigureAwait(false);
- invites += invite.Url + "\n";
- i++;
- }
- catch
- {
- j++;
- continue;
- }
- }
- File.WriteAllText("dump.txt", invites);
- await e.Channel.SendMessage($"Got invites for {i} servers and failed to get invites for {j} servers")
- .ConfigureAwait(false);
- });
-
- cgb.CreateCommand("ab")
- .Description("Try to get 'abalabahaha'| `@NadekoBot ab`")
- .Do(async e =>
- {
- string[] strings = { "ba", "la", "ha" };
- var construct = "@a";
- var cnt = rng.Next(4, 7);
- while (cnt-- > 0)
- {
- construct += strings[rng.Next(0, strings.Length)];
- }
- await e.Channel.SendMessage(construct).ConfigureAwait(false);
- });
-
- });
- }
-
-
-
- private static Func SayYes()
- => async e => await e.Channel.SendMessage("Yes. :)").ConfigureAwait(false);
- }
-}
diff --git a/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/NadekoBot/Modules/CustomReactions/CustomReactions.cs
deleted file mode 100644
index b62b2dd7..00000000
--- a/NadekoBot/Modules/CustomReactions/CustomReactions.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-using Discord.Commands;
-using Discord.Modules;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text.RegularExpressions;
-
-namespace NadekoBot.Modules.CustomReactions
-{
- internal class CustomReactionsModule : DiscordModule
- {
- public override string Prefix { get; } = "";
-
- private Random rng = new Random();
-
- private Dictionary> commandFuncs;
-
- public CustomReactionsModule()
- {
- commandFuncs = new Dictionary>
- {
- {new Regex(@"(?:%rng%|%rng:(\d{1,9})-(\d{1,9})%)"), (e,m) => {
- int start, end;
- if (m.Groups[1].Success)
- {
- start = int.Parse(m.Groups[1].Value);
- end = int.Parse(m.Groups[2].Value);
- return rng.Next(start, end).ToString();
- }else return rng.Next().ToString();
- } },
- {new Regex("%mention%"), (e,m) => NadekoBot.BotMention },
- {new Regex("%user%"), (e,m) => e.User.Mention },
- {new Regex("%target%"), (e,m) => e.GetArg("args")?.Trim() ?? "" },
-
- };
- }
-
- public override void Install(ModuleManager manager)
- {
- manager.CreateCommands("", cgb =>
- {
- cgb.AddCheck(PermissionChecker.Instance);
-
- foreach (var command in NadekoBot.Config.CustomReactions)
- {
- var commandName = command.Key.Replace("%mention%", NadekoBot.BotMention);
-
- var c = cgb.CreateCommand(commandName);
- if (commandName.Contains(NadekoBot.BotMention))
- c.Alias(commandName.Replace("<@", "<@!"));
- c.Description($"Custom reaction. | `{command.Key}`")
- .Parameter("args", ParameterType.Unparsed)
- .Do(async e =>
- {
- string str = command.Value[rng.Next(0, command.Value.Count())];
- commandFuncs.Keys.ForEach(key => str = key.Replace(str, m => commandFuncs[key](e, m)));
-
-
- await e.Channel.SendMessage(str).ConfigureAwait(false);
- });
- }
- });
- }
- }
-}
diff --git a/NadekoBot/Modules/DiscordCommand.cs b/NadekoBot/Modules/DiscordCommand.cs
deleted file mode 100644
index 05f9a42a..00000000
--- a/NadekoBot/Modules/DiscordCommand.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Modules;
-
-namespace NadekoBot.Classes
-{
- ///
- /// Base DiscordCommand Class.
- /// Inherit this class to create your own command.
- ///
- public abstract class DiscordCommand
- {
-
- ///
- /// Parent module
- ///
- protected DiscordModule Module { get; }
-
- ///
- /// Parent module's prefix
- ///
- protected string Prefix => Module.Prefix;
-
- ///
- /// Creates a new instance of discord command,
- /// use ": base(module)" in the derived class'
- /// constructor to make sure module is assigned
- ///
- /// Module this command resides in
- protected DiscordCommand(DiscordModule module)
- {
- this.Module = module;
- }
-
- ///
- /// Initializes the CommandBuilder with values using CommandGroupBuilder
- ///
- internal abstract void Init(CommandGroupBuilder cgb);
- }
-}
diff --git a/NadekoBot/Modules/DiscordModule.cs b/NadekoBot/Modules/DiscordModule.cs
deleted file mode 100644
index 5e131233..00000000
--- a/NadekoBot/Modules/DiscordModule.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Discord.Modules;
-using System.Collections.Generic;
-using NadekoBot.Classes;
-
-namespace NadekoBot.Modules {
- public abstract class DiscordModule : IModule {
- protected readonly HashSet commands = new HashSet();
-
- public abstract string Prefix { get; }
-
- public abstract void Install(ModuleManager manager);
- }
-}
diff --git a/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs
deleted file mode 100644
index a908128c..00000000
--- a/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs
+++ /dev/null
@@ -1,295 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Extensions;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Gambling.Commands
-{
- class AnimalRacing : DiscordCommand
- {
- public static ConcurrentDictionary AnimalRaces = new ConcurrentDictionary();
-
- public AnimalRacing(DiscordModule module) : base(module)
- {
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Prefix + "race")
- .Description($"Starts a new animal race. | `{Prefix}race`")
- .Do(e =>
- {
- var ar = new AnimalRace(e.Server.Id, e.Channel);
- if (ar.Fail)
- {
- return;
- }
- });
-
-
- cgb.CreateCommand(Prefix + "joinrace")
- .Alias(Prefix + "jr")
- .Description($"Joins a new race. You can specify an amount of flowers for betting (optional). You will get YourBet*(participants-1) back if you win. | `{Prefix}jr` or `{Prefix}jr 5`")
- .Parameter("amount", ParameterType.Optional)
- .Do(async e =>
- {
-
- int amount;
- if (!int.TryParse(e.GetArg("amount"), out amount) || amount < 0)
- amount = 0;
-
- var userFlowers = GamblingModule.GetUserFlowers(e.User.Id);
-
- if (userFlowers < amount)
- {
- await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
- return;
- }
-
- if (amount > 0)
- await FlowersHandler.RemoveFlowers(e.User, "BetRace", (int)amount, true).ConfigureAwait(false);
-
- AnimalRace ar;
- if (!AnimalRaces.TryGetValue(e.Server.Id, out ar))
- {
- await e.Channel.SendMessage("No race exists on this server");
- return;
- }
- await ar.JoinRace(e.User, amount);
-
- });
- }
-
- public class AnimalRace
- {
-
- private ConcurrentQueue animals = new ConcurrentQueue(NadekoBot.Config.RaceAnimals.Shuffle());
-
- public bool Fail { get; internal set; }
-
- public List participants = new List();
- private ulong serverId;
- private int messagesSinceGameStarted = 0;
-
- public Channel raceChannel { get; set; }
- public bool Started { get; private set; } = false;
-
- public AnimalRace(ulong serverId, Channel ch)
- {
- this.serverId = serverId;
- this.raceChannel = ch;
- if (!AnimalRaces.TryAdd(serverId, this))
- {
- Fail = true;
- return;
- }
- var cancelSource = new CancellationTokenSource();
- var token = cancelSource.Token;
- var fullgame = CheckForFullGameAsync(token);
- Task.Run(async () =>
- {
- try
- {
- await raceChannel.SendMessage($"🏁`Race is starting in 20 seconds or when the room is full. Type {NadekoBot.Config.CommandPrefixes.Gambling}jr to join the race.`");
- var t = await Task.WhenAny(Task.Delay(20000, token), fullgame);
- Started = true;
- cancelSource.Cancel();
- if (t == fullgame)
- {
- await raceChannel.SendMessage("🏁`Race full, starting right now!`");
- }
- else if (participants.Count > 1)
- {
- await raceChannel.SendMessage("🏁`Game starting with " + participants.Count + " participants.`");
- }
- else
- {
- await raceChannel.SendMessage("🏁`Race failed to start since there was not enough participants.`");
- var p = participants.FirstOrDefault();
- if (p != null)
- await FlowersHandler.AddFlowersAsync(p.User, "BetRace", p.AmountBet, true).ConfigureAwait(false);
- End();
- return;
- }
- await Task.Run(StartRace);
- End();
- }
- catch { }
- });
- }
-
- private void End()
- {
- AnimalRace throwaway;
- AnimalRaces.TryRemove(serverId, out throwaway);
- }
-
- private async Task StartRace()
- {
- var rng = new Random();
- Participant winner = null;
- Message msg = null;
- int place = 1;
- try
- {
- NadekoBot.Client.MessageReceived += Client_MessageReceived;
-
- while (!participants.All(p => p.Total >= 60))
- {
- //update the state
- participants.ForEach(p =>
- {
-
- p.Total += 1 + rng.Next(0, 10);
- if (p.Total > 60)
- {
- p.Total = 60;
- if (winner == null)
- {
- winner = p;
- }
- if (p.Place == 0)
- p.Place = place++;
- }
- });
-
-
- //draw the state
-
- var text = $@"|🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🏁🔚|
-{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)
- try { await msg.Delete(); } catch { }
- msg = await raceChannel.SendMessage(text);
- messagesSinceGameStarted = 0;
- }
- else
- await msg.Edit(text);
-
- await Task.Delay(2500);
- }
- }
- finally
- {
- NadekoBot.Client.MessageReceived -= Client_MessageReceived;
- }
-
- if (winner.AmountBet > 0)
- {
- var wonAmount = winner.AmountBet * (participants.Count - 1);
- await FlowersHandler.AddFlowersAsync(winner.User, "Won a Race", wonAmount).ConfigureAwait(false);
- await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race and {wonAmount}{NadekoBot.Config.CurrencySign}!**");
- }
- else
- {
- await raceChannel.SendMessage($"🏁 {winner.User.Mention} as {winner.Animal} **Won the race!**");
- }
-
- }
-
- private void Client_MessageReceived(object sender, MessageEventArgs e)
- {
- if (e.Message.IsAuthor || e.Channel.IsPrivate || e.Channel != raceChannel)
- return;
- messagesSinceGameStarted++;
- }
-
- private async Task CheckForFullGameAsync(CancellationToken cancelToken)
- {
- while (animals.Count > 0)
- {
- await Task.Delay(100, cancelToken);
- }
- }
-
- public async Task JoinRace(User u, int amount = 0)
- {
- var animal = "";
- if (!animals.TryDequeue(out animal))
- {
- await raceChannel.SendMessage($"{u.Mention} `There is no running race on this server.`");
- return false;
- }
- var p = new Participant(u, animal, amount);
- if (participants.Contains(p))
- {
- await raceChannel.SendMessage($"{u.Mention} `You already joined this race.`");
- return false;
- }
- if (Started)
- {
- await raceChannel.SendMessage($"{u.Mention} `Race is already started`");
- return false;
- }
- participants.Add(p);
- await raceChannel.SendMessage($"{u.Mention} **joined the race as a {p.Animal}" + (amount > 0 ? $" and bet {amount} {NadekoBot.Config.CurrencyName.SnPl(amount)}!**" : "**"));
- return true;
- }
- }
-
- public class Participant
- {
- public User User { get; set; }
- public string Animal { get; set; }
- public int AmountBet { get; set; }
-
- public float Coeff { get; set; }
- public int Total { get; set; }
-
- public int Place { get; set; } = 0;
-
- public Participant(User u, string a, int amount)
- {
- this.User = u;
- this.Animal = a;
- this.AmountBet = amount;
- }
-
- public override int GetHashCode()
- {
- return User.GetHashCode();
- }
-
- public override bool Equals(object obj)
- {
- var p = obj as Participant;
- return p == null ?
- false :
- p.User == User;
- }
-
- public override string ToString()
- {
- var str = new string('‣', Total) + Animal;
- if (Place == 0)
- 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`";
- }
-
- }
- }
- }
-}
diff --git a/NadekoBot/Modules/Gambling/DiceRollCommand.cs b/NadekoBot/Modules/Gambling/DiceRollCommand.cs
deleted file mode 100644
index 326d85c4..00000000
--- a/NadekoBot/Modules/Gambling/DiceRollCommand.cs
+++ /dev/null
@@ -1,164 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Extensions;
-using System;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Drawing.Imaging;
-using System.Linq;
-using System.Text.RegularExpressions;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Gambling
-{
- internal class DiceRollCommand : DiscordCommand
- {
-
- public DiceRollCommand(DiscordModule module) : base(module) { }
-
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "roll")
- .Description("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. | `{Prefix}roll` or `{Prefix}roll 7` or `{Prefix}roll 3d5`")
- .Parameter("num", ParameterType.Optional)
- .Do(RollFunc());
-
- cgb.CreateCommand(Module.Prefix + "rolluo")
- .Description("Rolls 0-100. If you supply a number [x] it rolls up to 30 normal dice (unordered)." +
- $" If you split 2 numbers with letter d (xdy) it will roll x dice from 1 to y. | `{Prefix}rolluo` or `{Prefix}rolluo 7` or `{Prefix}rolluo 3d5`")
- .Parameter("num", ParameterType.Optional)
- .Do(RollFunc(false));
-
- cgb.CreateCommand(Module.Prefix + "nroll")
- .Description($"Rolls in a given range. | `{Prefix}nroll 5` (rolls 0-5) or `{Prefix}nroll 5-15`")
- .Parameter("range", ParameterType.Required)
- .Do(NRollFunc());
- }
-
- private Image GetDice(int num) => num != 10
- ? Properties.Resources.ResourceManager.GetObject("_" + num) as Image
- : new[]
- {
- (Properties.Resources.ResourceManager.GetObject("_" + 1) as Image),
- (Properties.Resources.ResourceManager.GetObject("_" + 0) as Image),
- }.Merge();
-
-
- Regex dndRegex = new Regex(@"(?\d+)d(?\d+)", RegexOptions.Compiled);
- private Func RollFunc(bool ordered = true)
- {
- var r = new Random();
- return async e =>
- {
- var arg = e.Args[0]?.Trim();
- if (string.IsNullOrWhiteSpace(arg))
- {
- var gen = r.Next(0, 101);
-
- var num1 = gen / 10;
- var num2 = gen % 10;
-
- var imageStream = new Image[2] { GetDice(num1), GetDice(num2) }.Merge().ToStream(ImageFormat.Png);
-
- await e.Channel.SendFile("dice.png", imageStream).ConfigureAwait(false);
- return;
- }
- Match m;
- if ((m = dndRegex.Match(arg)).Length != 0)
- {
- int n1;
- int n2;
- if (int.TryParse(m.Groups["n1"].ToString(), out n1) &&
- int.TryParse(m.Groups["n2"].ToString(), out n2) &&
- n1 <= 50 && n2 <= 100000 && n1 > 0 && n2 > 0)
- {
- var arr = new int[n1];
- for (int i = 0; i < n1; i++)
- {
- arr[i] = r.Next(1, n2 + 1);
- }
- var elemCnt = 0;
- await e.Channel.SendMessage($"`Rolled {n1} {(n1 == 1 ? "die" : "dice")} 1-{n2}.`\n`Result:` " + string.Join(", ", (ordered ? arr.OrderBy(x => x).AsEnumerable() : arr).Select(x => elemCnt++ % 2 == 0 ? $"**{x}**" : x.ToString()))).ConfigureAwait(false);
- }
- return;
- }
- try
- {
- var num = int.Parse(e.Args[0]);
- if (num < 1) num = 1;
- if (num > 30)
- {
- await e.Channel.SendMessage("You can roll up to 30 dice at a time.").ConfigureAwait(false);
- num = 30;
- }
- var dices = new List(num);
- var values = new List(num);
- for (var i = 0; i < num; i++)
- {
- var randomNumber = r.Next(1, 7);
- var toInsert = dices.Count;
- if (ordered)
- {
- if (randomNumber == 6 || dices.Count == 0)
- toInsert = 0;
- else if (randomNumber != 1)
- for (var j = 0; j < dices.Count; j++)
- {
- if (values[j] < randomNumber)
- {
- toInsert = j;
- break;
- }
- }
- }
- else {
- toInsert = dices.Count;
- }
- dices.Insert(toInsert, GetDice(randomNumber));
- values.Insert(toInsert, randomNumber);
- }
-
- var bitmap = dices.Merge();
- await e.Channel.SendMessage(values.Count + " Dice rolled. Total: **" + values.Sum() + "** Average: **" + (values.Sum() / (1.0f * values.Count)).ToString("N2") + "**").ConfigureAwait(false);
- await e.Channel.SendFile("dice.png", bitmap.ToStream(ImageFormat.Png)).ConfigureAwait(false);
- }
- catch
- {
- await e.Channel.SendMessage("Please enter a number of dice to roll.").ConfigureAwait(false);
- }
- };
- }
-
-
- private Func NRollFunc() =>
- async e =>
- {
- try
- {
- int rolled;
- if (e.GetArg("range").Contains("-"))
- {
- var arr = e.GetArg("range").Split('-')
- .Take(2)
- .Select(int.Parse)
- .ToArray();
- if (arr[0] > arr[1])
- throw new ArgumentException("First argument should be bigger than the second one.");
- rolled = new Random().Next(arr[0], arr[1] + 1);
- }
- else
- {
- rolled = new Random().Next(0, int.Parse(e.GetArg("range")) + 1);
- }
-
- await e.Channel.SendMessage($"{e.User.Mention} rolled **{rolled}**.").ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- await e.Channel.SendMessage($":anger: {ex.Message}").ConfigureAwait(false);
- }
- };
- }
-}
diff --git a/NadekoBot/Modules/Gambling/DrawCommand.cs b/NadekoBot/Modules/Gambling/DrawCommand.cs
deleted file mode 100644
index dbd023e1..00000000
--- a/NadekoBot/Modules/Gambling/DrawCommand.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Gambling.Helpers;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Drawing;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Gambling
-{
- internal class DrawCommand : DiscordCommand
- {
- public DrawCommand(DiscordModule module) : base(module) { }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "draw")
- .Description($"Draws a card from the deck.If you supply number [x], she draws up to 5 cards from the deck. | `{Prefix}draw [x]`")
- .Parameter("count", ParameterType.Optional)
- .Do(DrawCardFunc());
-
- cgb.CreateCommand(Module.Prefix + "shuffle")
- .Alias(Module.Prefix + "sh")
- .Description($"Reshuffles all cards back into the deck.|`{Prefix}shuffle`")
- .Do(ReshuffleTask());
- }
-
- private static readonly ConcurrentDictionary AllDecks = new ConcurrentDictionary();
-
- private static Func ReshuffleTask()
- {
- return async e =>
- {
- AllDecks.AddOrUpdate(e.Server,
- (s) => new Cards(),
- (s, c) =>
- {
- c.Restart();
- return c;
- });
-
- await e.Channel.SendMessage("Deck reshuffled.").ConfigureAwait(false);
- };
- }
-
- private Func DrawCardFunc() => async (e) =>
- {
- var cards = AllDecks.GetOrAdd(e.Server, (s) => new Cards());
-
- try
- {
- var num = 1;
- var isParsed = int.TryParse(e.GetArg("count"), out num);
- if (!isParsed || num < 2)
- {
- var c = cards.DrawACard();
- await e.Channel.SendFile(c.Name + ".jpg", (Properties.Resources.ResourceManager.GetObject(c.Name) as Image).ToStream()).ConfigureAwait(false);
- return;
- }
- if (num > 5)
- num = 5;
-
- var images = new List();
- var cardObjects = new List();
- for (var i = 0; i < num; i++)
- {
- if (cards.CardPool.Count == 0 && i != 0)
- {
- await e.Channel.SendMessage("No more cards in a deck.").ConfigureAwait(false);
- break;
- }
- var currentCard = cards.DrawACard();
- cardObjects.Add(currentCard);
- images.Add(Properties.Resources.ResourceManager.GetObject(currentCard.Name) as Image);
- }
- var bitmap = images.Merge();
- await e.Channel.SendFile(images.Count + " cards.jpg", bitmap.ToStream()).ConfigureAwait(false);
- if (cardObjects.Count == 5)
- {
- await e.Channel.SendMessage($"{e.User.Mention} `{Cards.GetHandValue(cardObjects)}`").ConfigureAwait(false);
- }
- }
- catch (Exception ex)
- {
- Console.WriteLine("Error drawing (a) card(s) " + ex.ToString());
- }
- };
- }
-}
diff --git a/NadekoBot/Modules/Gambling/FlipCoinCommand.cs b/NadekoBot/Modules/Gambling/FlipCoinCommand.cs
deleted file mode 100644
index d0b79919..00000000
--- a/NadekoBot/Modules/Gambling/FlipCoinCommand.cs
+++ /dev/null
@@ -1,112 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Extensions;
-using System;
-using System.Drawing;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Gambling
-{
- internal class FlipCoinCommand : DiscordCommand
- {
-
- public FlipCoinCommand(DiscordModule module) : base(module) { }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "flip")
- .Description($"Flips coin(s) - heads or tails, and shows an image. | `{Prefix}flip` or `{Prefix}flip 3`")
- .Parameter("count", ParameterType.Optional)
- .Do(FlipCoinFunc());
-
- cgb.CreateCommand(Module.Prefix + "betflip")
- .Alias(Prefix+"bf")
- .Description($"Bet to guess will the result be heads or tails. Guessing award you double flowers you've bet. | `{Prefix}bf 5 heads` or `{Prefix}bf 3 t`")
- .Parameter("amount", ParameterType.Required)
- .Parameter("guess", ParameterType.Required)
- .Do(BetFlipCoinFunc());
- }
-
-
-
- private readonly Random rng = new Random();
- public Func BetFlipCoinFunc() => async e =>
- {
-
- var amountstr = e.GetArg("amount").Trim();
-
- var guessStr = e.GetArg("guess").Trim().ToUpperInvariant();
- if (guessStr != "H" && guessStr != "T" && guessStr != "HEADS" && guessStr != "TAILS")
- return;
-
- int amount;
- if (!int.TryParse(amountstr, out amount) || amount < 1)
- return;
-
- var userFlowers = GamblingModule.GetUserFlowers(e.User.Id);
-
- if (userFlowers < amount)
- {
- await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
- return;
- }
-
- await FlowersHandler.RemoveFlowers(e.User, "Betflip Gamble", (int)amount, true).ConfigureAwait(false);
- //heads = true
- //tails = false
-
- var guess = guessStr == "HEADS" || guessStr == "H";
- bool result = false;
- if (rng.Next(0, 2) == 1) {
- await e.Channel.SendFile("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
- result = true;
- }
- else {
- await e.Channel.SendFile("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
- }
-
- string str;
- if (guess == result)
- {
- str = $"{e.User.Mention}`You guessed it!` You won {amount * 2}{NadekoBot.Config.CurrencySign}";
- await FlowersHandler.AddFlowersAsync(e.User, "Betflip Gamble", amount * 2, true).ConfigureAwait(false);
-
- }
- else
- str = $"{e.User.Mention}`More luck next time.`";
-
- await e.Channel.SendMessage(str).ConfigureAwait(false);
- };
-
- public Func FlipCoinFunc() => async e =>
- {
-
- if (e.GetArg("count") == "")
- {
- if (rng.Next(0, 2) == 1)
- await e.Channel.SendFile("heads.png", Properties.Resources.heads.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
- else
- await e.Channel.SendFile("tails.png", Properties.Resources.tails.ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
- }
- else
- {
- int result;
- if (int.TryParse(e.GetArg("count"), out result))
- {
- if (result > 10)
- result = 10;
- var imgs = new Image[result];
- for (var i = 0; i < result; i++)
- {
- imgs[i] = rng.Next(0, 2) == 0 ?
- Properties.Resources.tails :
- Properties.Resources.heads;
- }
- await e.Channel.SendFile($"{result} coins.png", imgs.Merge().ToStream(System.Drawing.Imaging.ImageFormat.Png)).ConfigureAwait(false);
- return;
- }
- await e.Channel.SendMessage("Invalid number").ConfigureAwait(false);
- }
- };
- }
-}
diff --git a/NadekoBot/Modules/Gambling/GamblingModule.cs b/NadekoBot/Modules/Gambling/GamblingModule.cs
deleted file mode 100644
index d7ced224..00000000
--- a/NadekoBot/Modules/Gambling/GamblingModule.cs
+++ /dev/null
@@ -1,214 +0,0 @@
-using Discord;
-using Discord.Commands;
-using Discord.Modules;
-using NadekoBot.Classes;
-using NadekoBot.DataModels;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Gambling.Commands;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Linq;
-using System.Text;
-
-namespace NadekoBot.Modules.Gambling
-{
- internal class GamblingModule : DiscordModule
- {
- public GamblingModule()
- {
- commands.Add(new DrawCommand(this));
- commands.Add(new FlipCoinCommand(this));
- commands.Add(new DiceRollCommand(this));
- commands.Add(new AnimalRacing(this));
- }
-
- public override string Prefix { get; } = NadekoBot.Config.CommandPrefixes.Gambling;
-
- public override void Install(ModuleManager manager)
- {
- manager.CreateCommands("", cgb =>
- {
- cgb.AddCheck(PermissionChecker.Instance);
-
- commands.ForEach(com => com.Init(cgb));
-
- cgb.CreateCommand(Prefix + "raffle")
- .Description($"Prints a name and ID of a random user from the online list from the (optional) role. | `{Prefix}raffle` or `{Prefix}raffle RoleName`")
- .Parameter("role", ParameterType.Optional)
- .Do(async e =>
- {
- var arg = string.IsNullOrWhiteSpace(e.GetArg("role")) ? "@everyone" : e.GetArg("role");
- var role = e.Server.FindRoles(arg).FirstOrDefault();
- if (role == null)
- {
- await e.Channel.SendMessage("💢 Role not found.").ConfigureAwait(false);
- return;
- }
- var members = role.Members.Where(u => u.Status == UserStatus.Online); // only online
- var membersArray = members as User[] ?? members.ToArray();
- var usr = membersArray[new Random().Next(0, membersArray.Length)];
- await e.Channel.SendMessage($"**Raffled user:** {usr.Name} (id: {usr.Id})").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "$$")
- .Description(string.Format("Check how much {0}s a person has. (Defaults to yourself) |`{1}$$` or `{1}$$ @Someone`",
- NadekoBot.Config.CurrencyName, Prefix))
- .Parameter("all", ParameterType.Unparsed)
- .Do(async e =>
- {
- var usr = e.Message.MentionedUsers.FirstOrDefault() ?? e.User;
- var pts = GetUserFlowers(usr.Id);
- var str = $"{usr.Name} has {pts} {NadekoBot.Config.CurrencySign}";
- await e.Channel.SendMessage(str).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "give")
- .Description(string.Format("Give someone a certain amount of {0}s", NadekoBot.Config.CurrencyName)+ $"|`{Prefix}give 1 \"@SomeGuy\"`")
- .Parameter("amount", ParameterType.Required)
- .Parameter("receiver", ParameterType.Unparsed)
- .Do(async e =>
- {
- var amountStr = e.GetArg("amount")?.Trim();
- long amount;
- if (!long.TryParse(amountStr, out amount) || amount <= 0)
- return;
-
- var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
- u.Id != NadekoBot.Client.CurrentUser.Id &&
- u.Id != e.User.Id);
- if (mentionedUser == null)
- return;
-
- var userFlowers = GetUserFlowers(e.User.Id);
-
- if (userFlowers < amount)
- {
- await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
- return;
- }
-
- await FlowersHandler.RemoveFlowers(e.User, "Gift", (int)amount, true).ConfigureAwait(false);
- await FlowersHandler.AddFlowersAsync(mentionedUser, "Gift", (int)amount).ConfigureAwait(false);
-
- await e.Channel.SendMessage($"{e.User.Mention} successfully sent {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!").ConfigureAwait(false);
-
- });
-
- cgb.CreateCommand(Prefix + "award")
- .Description($"Gives someone a certain amount of flowers. **Bot Owner Only!** | `{Prefix}award 100 @person`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Parameter("amount", ParameterType.Required)
- .Parameter("receiver", ParameterType.Unparsed)
- .Do(async e =>
- {
- var amountStr = e.GetArg("amount")?.Trim();
- long amount;
- if (!long.TryParse(amountStr, out amount) || amount < 0)
- return;
-
- var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
- u.Id != NadekoBot.Client.CurrentUser.Id);
- if (mentionedUser == null)
- return;
-
- await FlowersHandler.AddFlowersAsync(mentionedUser, $"Awarded by bot owner. ({e.User.Name}/{e.User.Id})", (int)amount).ConfigureAwait(false);
-
- await e.Channel.SendMessage($"{e.User.Mention} successfully awarded {amount} {NadekoBot.Config.CurrencyName}s to {mentionedUser.Mention}!").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "take")
- .Description($"Takes a certain amount of flowers from someone. **Bot Owner Only!** | `{Prefix}take 1 \"@someguy\"`")
- .AddCheck(SimpleCheckers.OwnerOnly())
- .Parameter("amount", ParameterType.Required)
- .Parameter("rektperson", ParameterType.Unparsed)
- .Do(async e =>
- {
- var amountStr = e.GetArg("amount")?.Trim();
- long amount;
- if (!long.TryParse(amountStr, out amount) || amount < 0)
- return;
-
- var mentionedUser = e.Message.MentionedUsers.FirstOrDefault(u =>
- u.Id != NadekoBot.Client.CurrentUser.Id);
- if (mentionedUser == null)
- return;
-
- await FlowersHandler.RemoveFlowers(mentionedUser, $"Taken by bot owner.({e.User.Name}/{e.User.Id})", (int)amount).ConfigureAwait(false);
-
- await e.Channel.SendMessage($"{e.User.Mention} successfully took {amount} {NadekoBot.Config.CurrencyName}s from {mentionedUser.Mention}!").ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Prefix + "betroll")
- .Alias(Prefix + "br")
- .Description($"Bets a certain amount of {NadekoBot.Config.CurrencyName}s and rolls a dice. Rolling over 66 yields x2 flowers, over 90 - x3 and 100 x10. | `{Prefix}br 5`")
- .Parameter("amount",ParameterType.Required)
- .Do(async e =>
- {
- var amountstr = e.GetArg("amount").Trim();
- int amount;
-
- if (!int.TryParse(amountstr, out amount) || amount < 1)
- return;
-
- var userFlowers = GetUserFlowers(e.User.Id);
-
- if (userFlowers < amount)
- {
- await e.Channel.SendMessage($"{e.User.Mention} You don't have enough {NadekoBot.Config.CurrencyName}s. You only have {userFlowers}{NadekoBot.Config.CurrencySign}.").ConfigureAwait(false);
- return;
- }
-
- await FlowersHandler.RemoveFlowers(e.User, "Betroll Gamble", (int)amount, true).ConfigureAwait(false);
-
- var rng = new Random().Next(0, 101);
- var str = $"{e.User.Mention} `You rolled {rng}.` ";
- if (rng < 67)
- {
- str += "Better luck next time.";
- }
- else if (rng < 90)
- {
- str += $"Congratulations! You won {amount * 2}{NadekoBot.Config.CurrencySign} for rolling above 66";
- await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 2, true).ConfigureAwait(false);
- }
- else if (rng < 100)
- {
- str += $"Congratulations! You won {amount * 3}{NadekoBot.Config.CurrencySign} for rolling above 90.";
- await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 3, true).ConfigureAwait(false);
- }
- else {
- str += $"👑 Congratulations! You won {amount * 10}{NadekoBot.Config.CurrencySign} for rolling **100**. 👑";
- await FlowersHandler.AddFlowersAsync(e.User, "Betroll Gamble", amount * 10, true).ConfigureAwait(false);
- }
-
- await e.Channel.SendMessage(str).ConfigureAwait(false);
-
- });
-
- cgb.CreateCommand(Prefix + "leaderboard")
- .Alias(Prefix + "lb")
- .Description($"Displays bot currency leaderboard | `{Prefix}lb`")
- .Do(async e =>
- {
- var richestTemp = DbHandler.Instance.GetTopRichest();
- var richest = richestTemp as CurrencyState[] ?? richestTemp.ToArray();
- if (richest.Length == 0)
- return;
- await e.Channel.SendMessage(
- richest.Aggregate(new StringBuilder(
- $@"```xl
-┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━┓
-┃ Id ┃ $$$ ┃
-"),
- (cur, cs) => cur.AppendLine(
- $@"┣━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━┫
-┃{(e.Server.Users.Where(u => u.Id == (ulong)cs.UserId).FirstOrDefault()?.Name.TrimTo(18, true) ?? cs.UserId.ToString()),-20} ┃ {cs.Value,5} ┃")
- ).ToString() + "┗━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━┛```").ConfigureAwait(false);
- });
- });
- }
-
- public static long GetUserFlowers(ulong userId) =>
- Classes.DbHandler.Instance.GetStateByUserId((long)userId)?.Value ?? 0;
- }
-}
diff --git a/NadekoBot/Modules/Games/Commands/BetrayGame.cs b/NadekoBot/Modules/Games/Commands/BetrayGame.cs
deleted file mode 100644
index 74b98bf6..00000000
--- a/NadekoBot/Modules/Games/Commands/BetrayGame.cs
+++ /dev/null
@@ -1,129 +0,0 @@
-using Discord.Commands;
-using NadekoBot.Classes;
-using System;
-using System.Collections.Generic;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Games.Commands
-{
- class BetrayGame : DiscordCommand
- {
- public BetrayGame(DiscordModule module) : base(module) { }
-
- private enum Answers
- {
- Cooperate,
- Betray
- }
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "betray")
- .Description("BETRAY GAME. Betray nadeko next turn." +
- "If Nadeko cooperates - you get extra points, nadeko loses a LOT." +
- $"If Nadeko betrays - you both lose some points. | `{Prefix}betray`")
- .Do(async e =>
- {
- await ReceiveAnswer(e, Answers.Betray).ConfigureAwait(false);
- });
-
- cgb.CreateCommand(Module.Prefix + "cooperate")
- .Description("BETRAY GAME. Cooperate with nadeko next turn." +
- "If Nadeko cooperates - you both get bonus points." +
- $"If Nadeko betrays - you lose A LOT, nadeko gets extra. | `{Prefix}cooperater`")
- .Do(async e =>
- {
-
- await ReceiveAnswer(e, Answers.Cooperate).ConfigureAwait(false);
- });
- }
-
- private int userPoints = 0;
-
- private int UserPoints {
- get { return userPoints; }
- set {
- if (value < 0)
- userPoints = 0;
- userPoints = value;
- }
- }
- private int nadekoPoints = 0;
- private int NadekoPoints {
- get { return nadekoPoints; }
- set {
- if (value < 0)
- nadekoPoints = 0;
- nadekoPoints = value;
- }
- }
-
- private int round = 0;
- private Answers NextAnswer = Answers.Cooperate;
- private async Task ReceiveAnswer(CommandEventArgs e, Answers userAnswer)
- {
- var response = userAnswer == Answers.Betray
- ? ":no_entry: `You betrayed nadeko` - you monster."
- : ":ok: `You cooperated with nadeko.` ";
- var currentAnswer = NextAnswer;
- var nadekoResponse = currentAnswer == Answers.Betray
- ? ":no_entry: `aww Nadeko betrayed you` - she is so cute"
- : ":ok: `Nadeko cooperated.`";
- NextAnswer = userAnswer;
- if (userAnswer == Answers.Betray && currentAnswer == Answers.Betray)
- {
- NadekoPoints--;
- UserPoints--;
- }
- else if (userAnswer == Answers.Cooperate && currentAnswer == Answers.Cooperate)
- {
- NadekoPoints += 2;
- UserPoints += 2;
- }
- else if (userAnswer == Answers.Betray && currentAnswer == Answers.Cooperate)
- {
- NadekoPoints -= 3;
- UserPoints += 3;
- }
- else if (userAnswer == Answers.Cooperate && currentAnswer == Answers.Betray)
- {
- NadekoPoints += 3;
- UserPoints -= 3;
- }
-
- await e.Channel.SendMessage($"**ROUND {++round}**\n" +
- $"{response}\n" +
- $"{nadekoResponse}\n" +
- $"--------------------------------\n" +
- $"Nadeko has {NadekoPoints} points." +
- $"You have {UserPoints} points." +
- $"--------------------------------\n")
- .ConfigureAwait(false);
- if (round < 10) return;
- if (nadekoPoints == userPoints)
- await e.Channel.SendMessage("Its a draw").ConfigureAwait(false);
- else if (nadekoPoints > userPoints)
- await e.Channel.SendMessage("Nadeko won.").ConfigureAwait(false);
- else
- await e.Channel.SendMessage("You won.").ConfigureAwait(false);
- nadekoPoints = 0;
- userPoints = 0;
- round = 0;
- }
- }
-
- public class BetraySetting
- {
- private string Story = $"{0} have robbed a bank and got captured by a police." +
- $"Investigators gave you a choice:\n" +
- $"You can either >COOPERATE with your friends and " +
- $"not tell them who's idea it was, OR you can >BETRAY your" +
- $"friends. Depending on their answers your penalty will vary.";
-
- public int DoubleCoop = 1;
- public int DoubleBetray = -1;
- public int BetrayCoop_Betrayer = 3;
- public int BetrayCoop_Cooperater = -3;
-
- public string GetStory(IEnumerable names) => String.Format(Story, string.Join(", ", names));
- }
-}
diff --git a/NadekoBot/Modules/Games/Commands/Bomberman.cs b/NadekoBot/Modules/Games/Commands/Bomberman.cs
deleted file mode 100644
index 4987dd66..00000000
--- a/NadekoBot/Modules/Games/Commands/Bomberman.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using System.Text;
-using System.Timers;
-using static NadekoBot.Modules.Games.Commands.Bomberman;
-
-namespace NadekoBot.Modules.Games.Commands
-{
- class Bomberman : DiscordCommand
- {
- public Field[,] board = new Field[15, 15];
-
- public BombermanPlayer[] players = new BombermanPlayer[4];
-
- public Channel gameChannel = null;
-
- public Message godMsg = null;
-
- public int curI = 5;
- public int curJ = 5;
-
-
- public Bomberman(DiscordModule module) : base(module)
- {
- for (int i = 0; i < 15; i++)
- {
- for (int j = 0; j < 15; j++)
- {
- board[i, j] = new Field();
- }
- }
- NadekoBot.Client.MessageReceived += (s, e) =>
- {
- if (e.Channel != gameChannel ||
- e.User.Id == NadekoBot.Client.CurrentUser.Id)
- return;
-
- if (e.Message.Text == "w")
- {
- board[curI - 1, curJ] = board[curI--, curJ];
- board[curI + 1, curJ].player = null;
- }
- else if (e.Message.Text == "s")
- {
- board[curI + 1, curJ] = board[curI++, curJ];
- board[curI - 1, curJ].player = null;
- }
- else if (e.Message.Text == "a")
- {
- board[curI, curJ - 1] = board[curI, curJ--];
- board[curI, curJ + 1].player = null;
- }
- else if (e.Message.Text == "d")
- {
- board[curI, curJ + 1] = board[curI, curJ++];
- board[curI, curJ - 1].player = null;
- }
-
- e.Message.Delete();
- };
-
- var t = new Timer();
- t.Elapsed += async (s, e) =>
- {
- if (gameChannel == null)
- return;
-
- var boardStr = new StringBuilder();
-
- for (int i = 0; i < 15; i++)
- {
- for (int j = 0; j < 15; j++)
- {
- boardStr.Append(board[i, j].ToString());
- }
- boardStr.AppendLine();
- }
- if (godMsg.Id != 0)
- await godMsg.Edit(boardStr.ToString()).ConfigureAwait(false);
-
- };
- t.Interval = 1000;
- t.Start();
-
- }
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- //cgb.CreateCommand(Module.Prefix + "bomb")
- // .Description("Bomberman start")
- // .Do(async e =>
- // {
- // if (gameChannel != null)
- // return;
- // godMsg = await e.Channel.SendMessage("GAME START IN 1 SECOND....").ConfigureAwait(false);
- // gameChannel = e.Channel;
- // players[0] = new BombermanPlayer
- // {
- // User = e.User,
- // };
-
- // board[5, 5].player = players[0];
- // });
- }
-
- public class BombermanPlayer
- {
- public User User = null;
- public string Icon = "👳";
-
- internal void MoveLeft()
- {
-
- }
- }
- }
-
- internal struct Field
- {
- public BombermanPlayer player;
-
- public override string ToString() => player?.Icon ?? "⬜";
- }
-}
diff --git a/NadekoBot/Modules/Games/Commands/PlantPick.cs b/NadekoBot/Modules/Games/Commands/PlantPick.cs
deleted file mode 100644
index 2752ad1f..00000000
--- a/NadekoBot/Modules/Games/Commands/PlantPick.cs
+++ /dev/null
@@ -1,166 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.Extensions;
-using NadekoBot.Modules.Permissions.Classes;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Security.Cryptography;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Games.Commands
-{
- ///
- /// Flower picking/planting idea is given to me by its
- /// inceptor Violent Crumble from Game Developers League discord server
- /// (he has !cookie and !nom) Thanks a lot Violent!
- /// Check out GDL (its a growing gamedev community):
- /// https://discord.gg/0TYNJfCU4De7YIk8
- ///
- class PlantPick : DiscordCommand
- {
-
- private Random rng;
- public PlantPick(DiscordModule module) : base(module)
- {
- NadekoBot.Client.MessageReceived += PotentialFlowerGeneration;
- rng = new Random();
- }
-
- private static readonly ConcurrentDictionary plantpickCooldowns = new ConcurrentDictionary();
-
- private async void PotentialFlowerGeneration(object sender, Discord.MessageEventArgs e)
- {
- try
- {
- if (e.Server == null || e.Channel.IsPrivate || e.Message.IsAuthor)
- return;
- var config = Classes.SpecificConfigurations.Default.Of(e.Server.Id);
- var now = DateTime.Now;
- int cd;
- DateTime lastSpawned;
- if (config.GenerateCurrencyChannels.TryGetValue(e.Channel.Id, out cd))
- if (!plantpickCooldowns.TryGetValue(e.Channel.Id, out lastSpawned) || (lastSpawned + new TimeSpan(0, cd, 0)) < now)
- {
- var rnd = Math.Abs(rng.Next(0,101));
- if (rnd == 0)
- {
- var msgs = new[] { await e.Channel.SendFile(GetRandomCurrencyImagePath()), await e.Channel.SendMessage($"❗ A random {NadekoBot.Config.CurrencyName} appeared! Pick it up by typing `>pick`") };
- plantedFlowerChannels.AddOrUpdate(e.Channel.Id, msgs, (u, m) => { m.ForEach(async msgToDelete => { try { await msgToDelete.Delete(); } catch { } }); return msgs; });
- plantpickCooldowns.AddOrUpdate(e.Channel.Id, now, (i, d) => now);
- }
- }
- }
- catch { }
- }
- //channelid/messageid pair
- ConcurrentDictionary> plantedFlowerChannels = new ConcurrentDictionary>();
-
- private SemaphoreSlim locker = new SemaphoreSlim(1,1);
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "pick")
- .Description($"Picks a flower planted in this channel. | `{Prefix}pick`")
- .Do(async e =>
- {
- IEnumerable msgs;
-
- await e.Message.Delete().ConfigureAwait(false);
- if (!plantedFlowerChannels.TryRemove(e.Channel.Id, out msgs))
- return;
-
- foreach(var msgToDelete in msgs)
- await msgToDelete.Delete().ConfigureAwait(false);
-
- await FlowersHandler.AddFlowersAsync(e.User, "Picked a flower.", 1, true).ConfigureAwait(false);
- var msg = await e.Channel.SendMessage($"**{e.User.Name}** picked a {NadekoBot.Config.CurrencyName}!").ConfigureAwait(false);
- ThreadPool.QueueUserWorkItem(async (state) =>
- {
- try
- {
- await Task.Delay(10000).ConfigureAwait(false);
- await msg.Delete().ConfigureAwait(false);
- }
- catch { }
- });
- });
-
- cgb.CreateCommand(Module.Prefix + "plant")
- .Description($"Spend a flower to plant it in this channel. (If bot is restarted or crashes, flower will be lost) | `{Prefix}plant`")
- .Do(async e =>
- {
- await locker.WaitAsync().ConfigureAwait(false);
- try
- {
- if (plantedFlowerChannels.ContainsKey(e.Channel.Id))
- {
- await e.Channel.SendMessage($"There is already a {NadekoBot.Config.CurrencyName} in this channel.").ConfigureAwait(false);
- return;
- }
- var removed = await FlowersHandler.RemoveFlowers(e.User, "Planted a flower.", 1, true).ConfigureAwait(false);
- if (!removed)
- {
- await e.Channel.SendMessage($"You don't have any {NadekoBot.Config.CurrencyName}s.").ConfigureAwait(false);
- return;
- }
-
- var file = GetRandomCurrencyImagePath();
- Message msg;
- if (file == null)
- msg = await e.Channel.SendMessage(NadekoBot.Config.CurrencySign).ConfigureAwait(false);
- else
- msg = await e.Channel.SendFile(file).ConfigureAwait(false);
- var vowelFirst = new[] { 'a', 'e', 'i', 'o', 'u' }.Contains(NadekoBot.Config.CurrencyName[0]);
- var msg2 = await e.Channel.SendMessage($"Oh how Nice! **{e.User.Name}** planted {(vowelFirst ? "an" : "a")} {NadekoBot.Config.CurrencyName}. Pick it using {Module.Prefix}pick").ConfigureAwait(false);
- plantedFlowerChannels.TryAdd(e.Channel.Id, new[] { msg, msg2 });
- }
- finally { locker.Release(); }
- });
-
- cgb.CreateCommand(Prefix + "gencurrency")
- .Alias(Prefix + "gc")
- .Description($"Toggles currency generation on this channel. Every posted message will have 2% chance to spawn a {NadekoBot.Config.CurrencyName}. Optional parameter cooldown time in minutes, 5 minutes by default. Requires Manage Messages permission. | `{Prefix}gc` or `{Prefix}gc 60`")
- .AddCheck(SimpleCheckers.ManageMessages())
- .Parameter("cd", ParameterType.Unparsed)
- .Do(async e =>
- {
- var cdStr = e.GetArg("cd");
- int cd = 2;
- if (!int.TryParse(cdStr, out cd) || cd < 0)
- {
- cd = 2;
- }
- var config = SpecificConfigurations.Default.Of(e.Server.Id);
- int throwaway;
- if (config.GenerateCurrencyChannels.TryRemove(e.Channel.Id, out throwaway))
- {
- await e.Channel.SendMessage("`Currency generation disabled on this channel.`").ConfigureAwait(false);
- }
- else
- {
- if (config.GenerateCurrencyChannels.TryAdd(e.Channel.Id, cd))
- await e.Channel.SendMessage($"`Currency generation enabled on this channel. Cooldown is {cd} minutes.`").ConfigureAwait(false);
- }
- });
- }
-
- private string GetRandomCurrencyImagePath() =>
- Directory.GetFiles("data/currency_images").OrderBy(s => rng.Next()).FirstOrDefault();
-
- int GetRandomNumber()
- {
- using (RNGCryptoServiceProvider rg = new RNGCryptoServiceProvider())
- {
- byte[] rno = new byte[4];
- rg.GetBytes(rno);
- int randomvalue = BitConverter.ToInt32(rno, 0);
- return randomvalue;
- }
- }
- }
-}
diff --git a/NadekoBot/Modules/Games/Commands/PollCommand.cs b/NadekoBot/Modules/Games/Commands/PollCommand.cs
deleted file mode 100644
index b7082803..00000000
--- a/NadekoBot/Modules/Games/Commands/PollCommand.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Games.Commands
-{
- internal class PollCommand : DiscordCommand
- {
-
- public static ConcurrentDictionary ActivePolls = new ConcurrentDictionary();
-
- internal override void Init(CommandGroupBuilder cgb)
- {
- cgb.CreateCommand(Module.Prefix + "poll")
- .Description($"Creates a poll, only person who has manage server permission can do it. **Needs Manage Server Permissions**| `{Prefix}poll Question?;Answer1;Answ 2;A_3`")
- .Parameter("allargs", ParameterType.Unparsed)
- .Do(async e =>
- {
- await Task.Run(async () =>
- {
- if (!e.User.ServerPermissions.ManageChannels)
- return;
- if (ActivePolls.ContainsKey(e.Server))
- return;
- var arg = e.GetArg("allargs");
- if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";"))
- return;
- var data = arg.Split(';');
- if (data.Length < 3)
- return;
-
- var poll = new Poll(e, data[0], data.Skip(1));
- if (PollCommand.ActivePolls.TryAdd(e.Server, poll))
- {
- await poll.StartPoll().ConfigureAwait(false);
- }
- }).ConfigureAwait(false);
- });
- cgb.CreateCommand(Module.Prefix + "pollend")
- .Description($"Stops active poll on this server and prints the results in this channel. | `{Prefix}pollend`")
- .Do(async e =>
- {
- if (!e.User.ServerPermissions.ManageChannels)
- return;
- if (!ActivePolls.ContainsKey(e.Server))
- return;
- await ActivePolls[e.Server].StopPoll(e.Channel).ConfigureAwait(false);
- });
- }
-
- public PollCommand(DiscordModule module) : base(module) { }
- }
-
- internal class Poll
- {
- private readonly CommandEventArgs e;
- private readonly string[] answers;
- private ConcurrentDictionary participants = new ConcurrentDictionary();
- private readonly string question;
- private DateTime started;
- private CancellationTokenSource pollCancellationSource = new CancellationTokenSource();
-
- public Poll(CommandEventArgs e, string question, IEnumerable enumerable)
- {
- this.e = e;
- this.question = question;
- this.answers = enumerable as string[] ?? enumerable.ToArray();
- }
-
- public async Task StartPoll()
- {
- started = DateTime.Now;
- NadekoBot.Client.MessageReceived += Vote;
- var msgToSend =
- $"📃**{e.User.Name}** from **{e.Server.Name}** server has created a poll which requires your attention:\n\n" +
- $"**{question}**\n";
- var num = 1;
- msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n");
- msgToSend += "\n**Private Message me with the corresponding number of the answer.**";
- await e.Channel.SendMessage(msgToSend).ConfigureAwait(false);
- }
-
- public async Task StopPoll(Channel ch)
- {
- NadekoBot.Client.MessageReceived -= Vote;
- Poll throwaway;
- PollCommand.ActivePolls.TryRemove(e.Server, out throwaway);
- try
- {
- var results = participants.GroupBy(kvp => kvp.Value)
- .ToDictionary(x => x.Key, x => x.Sum(kvp => 1))
- .OrderBy(kvp => kvp.Value);
-
- var totalVotesCast = results.Sum(kvp => kvp.Value);
- if (totalVotesCast == 0)
- {
- await ch.SendMessage("📄 **No votes have been cast.**").ConfigureAwait(false);
- return;
- }
- var closeMessage = $"--------------**POLL CLOSED**--------------\n" +
- $"📄 , here are the results:\n";
- closeMessage = results.Aggregate(closeMessage, (current, kvp) => current + $"`{kvp.Key}.` **[{answers[kvp.Key - 1]}]**" +
- $" has {kvp.Value} votes." +
- $"({kvp.Value * 1.0f / totalVotesCast * 100}%)\n");
-
- await ch.SendMessage($"📄 **Total votes cast**: {totalVotesCast}\n{closeMessage}").ConfigureAwait(false);
- }
- catch (Exception ex)
- {
- Console.WriteLine($"Error in poll game {ex}");
- }
- }
-
- private async void Vote(object sender, MessageEventArgs e)
- {
- try
- {
- if (!e.Channel.IsPrivate)
- return;
- if (participants.ContainsKey(e.User))
- return;
-
- int vote;
- if (!int.TryParse(e.Message.Text, out vote)) return;
- if (vote < 1 || vote > answers.Length)
- return;
- if (participants.TryAdd(e.User, vote))
- {
- await e.User.SendMessage($"Thanks for voting **{e.User.Name}**.").ConfigureAwait(false);
- }
- }
- catch { }
- }
- }
-}
diff --git a/NadekoBot/Modules/Games/Commands/SpeedTyping.cs b/NadekoBot/Modules/Games/Commands/SpeedTyping.cs
deleted file mode 100644
index 07100820..00000000
--- a/NadekoBot/Modules/Games/Commands/SpeedTyping.cs
+++ /dev/null
@@ -1,195 +0,0 @@
-using Discord;
-using Discord.Commands;
-using NadekoBot.Classes;
-using NadekoBot.DataModels;
-using NadekoBot.Extensions;
-using System;
-using System.Collections.Concurrent;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace NadekoBot.Modules.Games.Commands
-{
-
- public static class SentencesProvider
- {
- internal static string GetRandomSentence()
- {
- var data = DbHandler.Instance.GetAllRows();
- try
- {
- return data.ToList()[new Random().Next(0, data.Count())].Text;
- }
- catch
- {
- return "Failed retrieving data from parse. Owner didn't add any articles to type using `typeadd`.";
- }
- }
- }
-
- public class TypingGame
- {
- public const float WORD_VALUE = 4.5f;
- private readonly Channel channel;
- public string CurrentSentence;
- public bool IsActive;
- private readonly Stopwatch sw;
- private readonly List finishedUserIds;
-
- public TypingGame(Channel channel)
- {
- this.channel = channel;
- IsActive = false;
- sw = new Stopwatch();
- finishedUserIds = new List();
- }
-
- public Channel Channell { get; internal set; }
-
- internal async Task Stop()
- {
- if (!IsActive) return false;
- NadekoBot.Client.MessageReceived -= AnswerReceived;
- finishedUserIds.Clear();
- IsActive = false;
- sw.Stop();
- sw.Reset();
- await channel.Send("Typing contest stopped").ConfigureAwait(false);
- return true;
- }
-
- internal async Task Start()
- {
- while (true)
- {
- if (IsActive) return; // can't start running game
- IsActive = true;
- CurrentSentence = SentencesProvider.GetRandomSentence();
- var i = (int)(CurrentSentence.Length / WORD_VALUE * 1.7f);
- await channel.SendMessage($":clock2: Next contest will last for {i} seconds. Type the bolded text as fast as you can.").ConfigureAwait(false);
-
-
- var msg = await channel.SendMessage("Starting new typing contest in **3**...").ConfigureAwait(false);
- await Task.Delay(1000).ConfigureAwait(false);
- await msg.Edit("Starting new typing contest in **2**...").ConfigureAwait(false);
- await Task.Delay(1000).ConfigureAwait(false);
- await msg.Edit("Starting new typing contest in **1**...").ConfigureAwait(false);
- await Task.Delay(1000).ConfigureAwait(false);
- await msg.Edit($":book:**{CurrentSentence.Replace(" ", " \x200B")}**:book:").ConfigureAwait(false);
- sw.Start();
- HandleAnswers();
-
- while (i > 0)
- {
- await Task.Delay(1000).ConfigureAwait(false);
- i--;
- if (!IsActive)
- return;
- }
-
- await Stop().ConfigureAwait(false);
- }
- }
-
- private void HandleAnswers()
- {
- NadekoBot.Client.MessageReceived += AnswerReceived;
- }
-
- private async void AnswerReceived(object sender, MessageEventArgs e)
- {
- try
- {
- if (e.Channel == null || e.Channel.Id != channel.Id || e.User.Id == NadekoBot.Client.CurrentUser.Id) return;
-
- var guess = e.Message.RawText;
-
- var distance = CurrentSentence.LevenshteinDistance(guess);
- var decision = Judge(distance, guess.Length);
- if (decision && !finishedUserIds.Contains(e.User.Id))
- {
- finishedUserIds.Add(e.User.Id);
- await channel.Send($"{e.User.Mention} finished in **{sw.Elapsed.Seconds}** seconds with { distance } errors, **{ CurrentSentence.Length / WORD_VALUE / sw.Elapsed.Seconds * 60 }** WPM!").ConfigureAwait(false);
- if (finishedUserIds.Count % 2 == 0)
- {
- await e.Channel.SendMessage($":exclamation: `A lot of people finished, here is the text for those still typing:`\n\n:book:**{CurrentSentence}**:book:").ConfigureAwait(false);
- }
- }
- }
- catch { }
- }
-
- private bool Judge(int errors, int textLength) => errors <= textLength / 25;
-
- }
-
- internal class SpeedTyping : DiscordCommand
- {
-
- public static ConcurrentDictionary RunningContests;
-
- public SpeedTyping(DiscordModule module) : base(module)
- {
- RunningContests = new ConcurrentDictionary