├── .github ├── FUNDING.yml └── workflows │ └── codeql-analysis.yml ├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── main ├── java └── nl │ └── corwindev │ └── streamervschat │ ├── command │ ├── DiscordReload.java │ ├── TestCommand.java │ ├── TwitchReload.java │ └── YouTubeReload.java │ ├── commands.java │ ├── discord │ └── DiscordConnectionHelper.java │ ├── main.java │ ├── objects │ ├── JdaFilter.java │ └── UpdateChecker.java │ ├── twitch │ ├── TwitchConnectionHelper.java │ └── TwitchEvents.java │ └── youtube │ └── YouTubeConnectionHelper.java └── resources ├── config.yml └── plugin.yml /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [CorwinDev] 4 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "master" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "master" ] 20 | schedule: 21 | - cron: '31 3 * * 1' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'java' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | 74 | - name: Setup Java JDK 75 | uses: actions/setup-java@v3.4.1 76 | with: 77 | java-version: '11' 78 | distribution: 'adopt' 79 | - name: Run the Maven verify phase 80 | run: mvn --batch-mode --update-snapshots verify 81 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # User-specific stuff 2 | .idea/ 3 | 4 | *.iml 5 | *.ipr 6 | *.iws 7 | 8 | # IntelliJ 9 | out/ 10 | 11 | # Compiled class file 12 | *.class 13 | 14 | # Log file 15 | *.log 16 | 17 | # BlueJ files 18 | *.ctxt 19 | 20 | # Package Files # 21 | *.jar 22 | *.war 23 | *.nar 24 | *.ear 25 | *.zip 26 | *.tar.gz 27 | *.rar 28 | 29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 30 | hs_err_pid* 31 | 32 | *~ 33 | 34 | # temporary files which can be created if a process still has a handle open of a deleted file 35 | .fuse_hidden* 36 | 37 | # KDE directory preferences 38 | .directory 39 | 40 | # Linux trash folder which might appear on any partition or disk 41 | .Trash-* 42 | 43 | # .nfs files are created when an open file is removed but is still being accessed 44 | .nfs* 45 | 46 | # General 47 | .DS_Store 48 | .AppleDouble 49 | .LSOverride 50 | 51 | # Icon must end with two \r 52 | Icon 53 | 54 | # Thumbnails 55 | ._* 56 | 57 | # Files that might appear in the root of a volume 58 | .DocumentRevisions-V100 59 | .fseventsd 60 | .Spotlight-V100 61 | .TemporaryItems 62 | .Trashes 63 | .VolumeIcon.icns 64 | .com.apple.timemachine.donotpresent 65 | 66 | # Directories potentially created on remote AFP share 67 | .AppleDB 68 | .AppleDesktop 69 | Network Trash Folder 70 | Temporary Items 71 | .apdisk 72 | 73 | # Windows thumbnail cache files 74 | Thumbs.db 75 | Thumbs.db:encryptable 76 | ehthumbs.db 77 | ehthumbs_vista.db 78 | 79 | # Dump file 80 | *.stackdump 81 | 82 | # Folder config file 83 | [Dd]esktop.ini 84 | 85 | # Recycle Bin used on file shares 86 | $RECYCLE.BIN/ 87 | 88 | # Windows Installer files 89 | *.cab 90 | *.msi 91 | *.msix 92 | *.msm 93 | *.msp 94 | 95 | # Windows shortcuts 96 | *.lnk 97 | 98 | target/ 99 | 100 | pom.xml.tag 101 | pom.xml.releaseBackup 102 | pom.xml.versionsBackup 103 | pom.xml.next 104 | 105 | release.properties 106 | dependency-reduced-pom.xml 107 | buildNumber.properties 108 | .mvn/timing.properties 109 | .mvn/wrapper/maven-wrapper.jar 110 | .flattened-pom.xml 111 | 112 | # Common working directory 113 | run/ 114 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 CorwinDev 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # StreamerVSChat 2 | StreamerVSChat is a open source project that allows you to play against your followers/subscribers. 3 | ![ThumbNail](https://user-images.githubusercontent.com/88144943/188877177-8514b504-0a9a-4eef-b870-19ea262ad705.png) 4 | 5 | The plugin contains over 30 commands, and is fully customizable. 6 | 7 | You can also add your own commands! 8 | 9 | ## How to use 10 | 1. Download the latest release from [here](https://github.com/CorwinDev/StreamerVSChat/releases) 11 | 2. Upload the file to your plugin folder 12 | 3. Start your server 13 | 4. Edit the config file 14 | 5. Restart/reload your server 15 | 16 | SUPPORT AT [DISCORD](https://discord.gg/KrTfebJhNH) 17 | 18 | ## How to configure 19 | 1. Open the config file 20 | 2. Change the settings
21 | Get your Twitch Client ID [here](https://twitchapps.com/tmi/)
22 | Get your YouTube API Key [here](https://console.developers.google.com/apis/credentials)
23 | Get your Discord Bot Token [here](https://discord.com/developers/applications)
24 | 3. Save the file 25 | 4. Restart/reload your server 26 | 27 | ## How to use the commands 28 | ### We have now ability to make custom commands! 29 | For more information, check out the [wiki](https://github.com/CorwinDev/StreamerVSChat/wiki#custom-commands-setup) 30 | 31 | We have over 20 commands that you can use to control the streamer: 32 | | Command | Description | 33 | | --- | --- | 34 | | !lava | Place lava under the streamer | 35 | | !anvil | Drops an anvil on the streamer | 36 | | !creepscare or !behindyou | Summons sound of creepers | 37 | | !dropall | Drops all items from the streamer | 38 | | !blindness | Gives the streamer blindness | 39 | | !lightning | Summons lightning on the streamer | 40 | | !fire | Sets the streamer on fire | 41 | | !explosion | Summons an explosion on the streamer | 42 | | !rain | Sets weather to rain | 43 | | !witherscare or !wither | Summons sound of wither | 44 | | !creeper | Summons a creeper on the streamer | 45 | | !zombie | Summons a zombie on the streamer | 46 | | !illness or !nausea | Gives streamer illness | 47 | | !slowness | Gives streamer slowness effect | 48 | | !badluck | Gives streamer BadLuck effect | 49 | | !mining or !miningfatique | Gives streamer miningfatigue | 50 | | !hunger | Gives streamer hunger | 51 | | !fly or !levitate | Lets the streamer fly | 52 | | jumpboost | Gives streamer jumpboost effect | 53 | | !feed | Feeds the streamer | 54 | | !heal | Heals the player | 55 | | !randomeffect or !randompoison | Gives streamer random poison | 56 | | !fireball | Shoots fireball at streamer | 57 | | !drop | Drops item in main hand | 58 | | !silverfish | Summons silverfish on streamer | 59 | | !vex | Summons vex on streamer | 60 | | !chicken | Summons chicken on streamer | 61 | | !bee | Summons angry bee on streamer | 62 | | !day | Sets time to day | 63 | | !night | Sets time to night | 64 | | !peaceful | Sets difficulty to peaceful | 65 | | !hard | Sets difficulty to hard | 66 | | !easy | Sets difficulty to easy | 67 | | !rename ~Name~ | Renames the streamer item currently holding| 68 | // All ! above can be replaced with your custom prefix 69 | // More commands coming soon // 70 | 71 | ![BStats](https://bstats.org/signatures/bukkit/StreamerVSChat.svg) 72 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | StreamerVSChat 8 | StreamerVSChat 9 | 2.2 10 | jar 11 | 12 | Streamer vs Chat 13 | 14 | 15 | 1.8 16 | UTF-8 17 | UTF-8 18 | 19 | 20 | 21 | 22 | 23 | maven-compiler-plugin 24 | 3.8.1 25 | 26 | 1.8 27 | 1.8 28 | 29 | 30 | 31 | maven-shade-plugin 32 | 3.2.4 33 | 34 | 35 | 36 | org.bstats 37 | nl.corwindev.streamervschat.main 38 | 39 | 40 | 41 | 42 | nl.corwindev.streamervschat.main 43 | 44 | 45 | 46 | false 47 | 48 | 49 | 50 | package 51 | 52 | shade 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | spigotmc-repo 63 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/ 64 | 65 | 66 | sonatype 67 | https://oss.sonatype.org/content/groups/public/ 68 | 69 | 70 | dv8tion 71 | m2-dv8tion 72 | https://m2.dv8tion.net/releases 73 | 74 | 75 | central 76 | https://repo1.maven.org/maven2 77 | 78 | 79 | 80 | 81 | 82 | org.spigotmc 83 | spigot-api 84 | 1.16.5-R0.1-SNAPSHOT 85 | provided 86 | 87 | 88 | org.apache.logging.log4j 89 | log4j-core 90 | 2.18.0 91 | 92 | 93 | net.dv8tion 94 | JDA 95 | 4.3.0_349 96 | 97 | 98 | club.minnced 99 | opus-java 100 | 101 | 102 | org.slf4j 103 | * 104 | 105 | 106 | 107 | 108 | com.github.twitch4j 109 | twitch4j-chat 110 | 1.11.0 111 | 112 | 113 | club.minnced 114 | opus-java 115 | 116 | 117 | org.slf4j 118 | * 119 | 120 | 121 | commons-lang 122 | * 123 | 124 | 125 | io.github.openfeign 126 | * 127 | 128 | 129 | 130 | 131 | com.google.apis 132 | google-api-services-youtube 133 | v3-rev182-1.22.0 134 | 135 | 136 | org.bstats 137 | bstats-bukkit 138 | 3.0.0 139 | compile 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/command/DiscordReload.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.command; 2 | 3 | import nl.corwindev.streamervschat.discord.DiscordConnectionHelper; 4 | import nl.corwindev.streamervschat.main; 5 | import org.bukkit.ChatColor; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class DiscordReload implements CommandExecutor { 12 | @Override 13 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { 14 | if(!main.plugin.getConfig().getBoolean("discord.enabled")){ 15 | commandSender.sendMessage(ChatColor.RED + "Discord is not enabled."); 16 | return true; 17 | } 18 | DiscordConnectionHelper.reload(); 19 | commandSender.sendMessage(ChatColor.GREEN + "Reloaded Discord connection."); 20 | return true; 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/command/TestCommand.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.command; 2 | 3 | import org.bukkit.ChatColor; 4 | import org.bukkit.command.Command; 5 | import org.bukkit.command.CommandExecutor; 6 | import org.bukkit.command.CommandSender; 7 | import org.jetbrains.annotations.NotNull; 8 | import nl.corwindev.streamervschat.commands; 9 | 10 | import java.util.Arrays; 11 | 12 | public class TestCommand implements CommandExecutor { 13 | @Override 14 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { 15 | if(command.getName().equalsIgnoreCase("testcommand")){ 16 | // Check if args are empty 17 | if(commandSender.hasPermission("nl.corwindev.streamervschat.streamer")){ 18 | if(strings.length == 0){ 19 | commandSender.sendMessage(ChatColor.RED + "Correct usage: /testcommand "); 20 | return false; 21 | } 22 | commands.UserList.add(commandSender.getName()); 23 | if(strings[0].equalsIgnoreCase("rename")){ 24 | System.out.println(Arrays.toString(strings)); 25 | commands.commandList.add(strings[0] + " " + strings[1]); 26 | }else{ 27 | commands.commandList.add(strings[0]); 28 | } 29 | commandSender.sendMessage(ChatColor.GREEN + "Added command: " + strings[0] + " to queue;"); 30 | return true; 31 | } 32 | } 33 | return true; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/command/TwitchReload.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.command; 2 | 3 | import nl.corwindev.streamervschat.main; 4 | import nl.corwindev.streamervschat.twitch.TwitchConnectionHelper; 5 | import org.bukkit.ChatColor; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class TwitchReload implements CommandExecutor { 12 | @Override 13 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { 14 | if(!main.plugin.getConfig().getBoolean("twitch.enabled")){ 15 | commandSender.sendMessage(ChatColor.RED + "Twitch is not enabled."); 16 | return true; 17 | } 18 | TwitchConnectionHelper.reload(); 19 | commandSender.sendMessage(ChatColor.GREEN + "Reloaded Twitch connection."); 20 | return true; 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/command/YouTubeReload.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.command; 2 | 3 | import nl.corwindev.streamervschat.main; 4 | import nl.corwindev.streamervschat.youtube.YouTubeConnectionHelper; 5 | import org.bukkit.ChatColor; 6 | import org.bukkit.command.Command; 7 | import org.bukkit.command.CommandExecutor; 8 | import org.bukkit.command.CommandSender; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class YouTubeReload implements CommandExecutor { 12 | @Override 13 | public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { 14 | if(!main.plugin.getConfig().getBoolean("youtube.enabled")){ 15 | commandSender.sendMessage(ChatColor.RED + "YouTube is not enabled."); 16 | return true; 17 | } 18 | YouTubeConnectionHelper.reload(); 19 | commandSender.sendMessage(ChatColor.GREEN + "Reloaded YouTube connection."); 20 | return true; 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/commands.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat; 2 | 3 | import net.dv8tion.jda.api.entities.User; 4 | import net.md_5.bungee.api.ChatMessageType; 5 | import net.md_5.bungee.api.chat.TextComponent; 6 | import org.bukkit.*; 7 | import org.bukkit.block.Block; 8 | import org.bukkit.block.BlockFace; 9 | import org.bukkit.entity.*; 10 | import org.bukkit.inventory.Inventory; 11 | import org.bukkit.inventory.ItemStack; 12 | import org.bukkit.inventory.meta.ItemMeta; 13 | import org.bukkit.potion.PotionEffect; 14 | import org.bukkit.potion.PotionEffectType; 15 | import org.bukkit.scheduler.BukkitTask; 16 | import org.bukkit.util.Vector; 17 | 18 | import java.util.*; 19 | import java.util.concurrent.ThreadLocalRandom; 20 | 21 | import static nl.corwindev.streamervschat.main.plugin; 22 | 23 | public class commands { 24 | public static List commandList = new ArrayList(); 25 | public static List UserList = new ArrayList(); 26 | public static List cooldowns = new ArrayList(); 27 | 28 | public static void start() { 29 | BukkitTask task = Bukkit.getScheduler().runTaskTimer(plugin, new Runnable() { 30 | @Override 31 | public void run() { 32 | startCommand(); 33 | } 34 | }, plugin.getConfig().getInt("commands.delay") * 20L, plugin.getConfig().getInt("commands.delay") * 20L); 35 | } 36 | public static void startCommand(){ 37 | Random rand = new Random(); 38 | if (commandList.size() == 0) { 39 | return; 40 | } 41 | int randomCommand = rand.nextInt(commandList.size()); 42 | String command = commandList.get(randomCommand); 43 | runCmd(command, UserList.get(randomCommand)); 44 | } 45 | public static void runCmd(String command, String random) { 46 | if (Objects.requireNonNull(plugin.getConfig().getList("blacklist")).contains(command)) { 47 | return; 48 | } 49 | int index = commandList.indexOf(command); 50 | if(plugin.getConfig().getString("cooldowns." + command) != null){ 51 | if(cooldowns.contains(command)){ 52 | commandList.remove(index); 53 | UserList.remove(index); 54 | startCommand(); 55 | return; 56 | }else{ 57 | cooldowns.add(command); 58 | Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { 59 | @Override 60 | public void run() { 61 | cooldowns.remove(command); 62 | } 63 | }, plugin.getConfig().getInt("cooldowns." + command) * 20L); 64 | } 65 | } 66 | if (Objects.equals(command, "lava")) { 67 | commands.lava(); 68 | } else if (Objects.equals(command, "anvil")) { 69 | commands.anvil(); 70 | } else if (Objects.equals(command, "creepscare") || Objects.equals(command, "behindyou")) { 71 | commands.creepsound(); 72 | } else if (Objects.equals(command, "dropall")) { 73 | commands.dropall(); 74 | } else if (Objects.equals(command, "blindness")) { 75 | commands.blindness(); 76 | } else if (Objects.equals(command, "lightning")) { 77 | commands.lightning(); 78 | } else if (Objects.equals(command, "fire")) { 79 | commands.fire(); 80 | } else if (Objects.equals(command, "explosion")) { 81 | commands.explosion(); 82 | } else if (Objects.equals(command, "rain")) { 83 | commands.rain(); 84 | } else if (Objects.equals(command, "hunger")) { 85 | commands.hunger(); 86 | } else if (Objects.equals(command, "witherscare") || Objects.equals(command, "wither")) { 87 | commands.wither(); 88 | } else if (Objects.equals(command, "creeper")) { 89 | commands.creeper(UserList.get(index)); 90 | } else if (Objects.equals(command, "zombie")) { 91 | commands.zombie(UserList.get(index)); 92 | } else if (Objects.equals(command, "illness") || Objects.equals(command, "nausea")) { 93 | commands.nausea(); 94 | } else if (Objects.equals(command, "slowness")) { 95 | commands.slowness(); 96 | } else if (Objects.equals(command, "badluck")) { 97 | commands.badluck(); 98 | } else if (Objects.equals(command, "mining") || Objects.equals(command, "miningfatigue")) { 99 | commands.miningfatigue(); 100 | } else if (Objects.equals(command, "heal")) { 101 | commands.heal(); 102 | } else if (Objects.equals(command, "feed")) { 103 | commands.feed(); 104 | } else if (Objects.equals(command, "jumpboost")) { 105 | commands.jumpboost(); 106 | } else if (Objects.equals(command, "levitate") || Objects.equals(command, "fly")) { 107 | commands.fly(); 108 | } else if (Objects.equals(command, "randomeffect") || Objects.equals(command, "randompoison")) { 109 | commands.randomeffect(); 110 | } else if (Objects.equals(command, "fireball")) { 111 | commands.fireball(); 112 | } else if (Objects.equals(command, "drop")) { 113 | commands.drop(); 114 | } else if (Objects.equals(command, "silverfish")) { 115 | commands.silverfish(UserList.get(index)); 116 | } else if (Objects.equals(command, "vex")) { 117 | commands.vex(UserList.get(index)); 118 | } else if (Objects.equals(command, "chicken")) { 119 | commands.chicken(UserList.get(index)); 120 | } else if (Objects.equals(command, "bee")) { 121 | commands.bee(UserList.get(index)); 122 | }else if(Objects.equals(command, "day")){ 123 | commands.day(); 124 | }else if(Objects.equals(command, "night")) { 125 | commands.night(); 126 | }else if(Objects.equals(command, "peaceful")) { 127 | commands.peaceful(); 128 | }else if(Objects.equals(command, "hard")) { 129 | commands.hard(); 130 | }else if(Objects.equals(command, "easy")) { 131 | commands.easy(); 132 | }else if(command.startsWith("rename")){ 133 | commands.rename(command); 134 | } else { 135 | if(!commands.custom(command, UserList.get(index))){ 136 | commandList.remove(index); 137 | UserList.remove(index); 138 | startCommand(); 139 | return; 140 | } 141 | } 142 | for (Player player : getPlayers()) { 143 | String hotbar = plugin.getConfig().getString("hotbar"); 144 | if(hotbar == null){ 145 | hotbar = "§a§l%user%§r§a has executed the command: §l%command%"; 146 | } 147 | player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(hotbar.replace("%command%", command).replace("%user%", random))); 148 | player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("§a§l" + random + "§r§a has executed the command: §l" + command)); 149 | } 150 | commandList.clear(); 151 | UserList.clear(); 152 | } 153 | 154 | public static String name = "nl.corwindev.streamervschat"; 155 | public static Integer duration = plugin.getConfig().getInt("poison-duration"); 156 | 157 | public static boolean has(Player player, String permission) { 158 | return player == null || player.hasPermission(name + "." + permission) || player.hasPermission(name + ".*"); 159 | } 160 | 161 | public static Collection getPlayers() { 162 | Collection players = new ArrayList<>(); 163 | if (Objects.equals(plugin.getConfig().getString("affected-players"), "all")) { 164 | return (Collection) Bukkit.getOnlinePlayers(); 165 | } else if (Objects.equals(plugin.getConfig().getString("affected-players"), "permission")) { 166 | for (Player player : Bukkit.getOnlinePlayers()) { 167 | if (has(player, "streamer")) { 168 | players.add(player); 169 | } 170 | } 171 | return players; 172 | } else { 173 | return (Collection) Bukkit.getOnlinePlayers(); 174 | } 175 | } 176 | 177 | 178 | public static void lava() { 179 | for (Player player : getPlayers()) { 180 | Block playerBlock = player.getLocation().getBlock(); 181 | Block blockUnder = playerBlock.getRelative(BlockFace.DOWN); 182 | // Set block to lava 183 | blockUnder.setType(org.bukkit.Material.LAVA); 184 | } 185 | } 186 | 187 | public static void anvil() { 188 | for (Player player : getPlayers()) { 189 | FallingBlock anvil = player.getWorld().spawnFallingBlock(player.getLocation().add(0, 16, 0), Bukkit.createBlockData(Material.ANVIL)); 190 | anvil.setGravity(true); 191 | anvil.setHurtEntities(true); 192 | anvil.setFallDistance(20); 193 | anvil.setDropItem(false); 194 | player.getWorld().playSound(player.getLocation(), "minecraft:block.anvil.land", 100, 1); 195 | } 196 | } 197 | 198 | public static void creepsound() { 199 | for (Player player : getPlayers()) { 200 | player.getWorld().playSound(player.getLocation(), "minecraft:entity.creeper.primed", 100, 1); 201 | player.getWorld().playSound(player.getLocation(), "minecraft:entity.creeper.primed", 100, 1); 202 | } 203 | } 204 | 205 | public static void dropall() { 206 | for (Player player : getPlayers()) { 207 | Location loc = player.getLocation().clone(); 208 | Inventory inv = player.getInventory(); 209 | for (ItemStack item : inv.getContents()) { 210 | if (item != null) { 211 | loc.getWorld().dropItemNaturally(loc, item.clone()); 212 | } 213 | } 214 | inv.clear(); 215 | } 216 | } 217 | 218 | public static void blindness() { 219 | for (Player player : getPlayers()) { 220 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.BLINDNESS, duration * 20, 1)); 221 | } 222 | } 223 | 224 | public static void lightning() { 225 | for (Player player : getPlayers()) { 226 | player.getWorld().strikeLightning(player.getLocation()); 227 | } 228 | } 229 | 230 | public static void creeper(String user) { 231 | for (Player player : getPlayers()) { 232 | player.getWorld().spawn(player.getLocation(), org.bukkit.entity.Creeper.class).setCustomName("§c§l" + user); 233 | } 234 | } 235 | 236 | public static void zombie(String user) { 237 | for (Player player : getPlayers()) { 238 | player.getWorld().spawn(player.getLocation(), org.bukkit.entity.Zombie.class).setCustomName("§c§l" + user); 239 | } 240 | } 241 | 242 | public static void fire() { 243 | for (Player player : getPlayers()) { 244 | player.setFireTicks(20 * 10); 245 | } 246 | } 247 | 248 | public static void explosion() { 249 | for (Player player : getPlayers()) { 250 | TNTPrimed tnt = (TNTPrimed) player.getWorld().spawnEntity(player.getLocation(), EntityType.PRIMED_TNT); 251 | tnt.setFuseTicks(40); 252 | } 253 | } 254 | 255 | public static void rain() { 256 | for (Player player : getPlayers()) { 257 | player.getWorld().setStorm(true); 258 | } 259 | } 260 | 261 | public static void wither() { 262 | for (Player player : getPlayers()) { 263 | player.getWorld().playSound(player.getLocation(), "minecraft:entity.wither.spawn", 100, 1); 264 | } 265 | } 266 | 267 | public static void hunger() { 268 | for (Player player : getPlayers()) { 269 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.HUNGER, duration * 20, 1)); 270 | } 271 | } 272 | 273 | public static void badluck() { 274 | for (Player player : getPlayers()) { 275 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.UNLUCK, duration * 20, 1)); 276 | } 277 | } 278 | 279 | public static void nausea() { 280 | for (Player player : getPlayers()) { 281 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.CONFUSION, duration * 20, 1)); 282 | } 283 | } 284 | 285 | public static void slowness() { 286 | for (Player player : getPlayers()) { 287 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.SLOW, duration * 20, 1)); 288 | } 289 | } 290 | 291 | public static void miningfatigue() { 292 | for (Player player : getPlayers()) { 293 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.SLOW_DIGGING, duration * 20, 1)); 294 | } 295 | } 296 | 297 | public static void feed() { 298 | for (Player player : getPlayers()) { 299 | player.setFoodLevel(20); 300 | } 301 | } 302 | 303 | public static void heal() { 304 | //Gives the player regeneration and health boost 2 305 | for (Player player : getPlayers()) { 306 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.REGENERATION, duration * 20, 1)); 307 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.HEALTH_BOOST, duration * 20, 1)); 308 | } 309 | } 310 | 311 | public static void jumpboost() { 312 | for (Player player : getPlayers()) { 313 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.JUMP, duration * 20, 1)); 314 | } 315 | } 316 | 317 | public static void fly() { 318 | for (Player player : getPlayers()) { 319 | player.addPotionEffect(new org.bukkit.potion.PotionEffect(org.bukkit.potion.PotionEffectType.LEVITATION, duration * 20, 1)); 320 | } 321 | } 322 | 323 | public static boolean custom(String command, String user) { 324 | String command1 = plugin.getConfig().getString("customcommands." + command + ".command"); 325 | if (command1 != null) { 326 | Integer cooldown = plugin.getConfig().getInt("customcommands." + command + ".cooldown"); 327 | 328 | if (cooldown != null) { 329 | if (cooldowns.contains(command)) { 330 | return false; 331 | } 332 | cooldowns.add(command); 333 | Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { 334 | @Override 335 | public void run() { 336 | cooldowns.remove(command); 337 | } 338 | }, cooldown * 20); 339 | } 340 | for (Player player : getPlayers()) { 341 | String command2 = command1.replace("%player%", player.getName()); 342 | String command3 = command2.replace("%user%", user); 343 | plugin.getLogger().info(command3); 344 | Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command2); 345 | } 346 | return true; 347 | } 348 | return false; 349 | } 350 | 351 | public static void randomeffect() { 352 | int rnd = ThreadLocalRandom.current().nextInt(PotionEffectType.values().length); 353 | 354 | for (Player player : getPlayers()) { 355 | player.getPlayer().addPotionEffect(new PotionEffect(PotionEffectType.values()[rnd], 200, 1)); 356 | } 357 | } 358 | 359 | public static void fireball() { 360 | for (Player player : getPlayers()) { 361 | // Send fireball to the player 362 | Location location = new Location(player.getWorld(), player.getLocation().getX(), player.getLocation().getY() + 20, player.getLocation().getZ()); 363 | Vector vector = player.getLocation().toVector().subtract(location.toVector()).normalize(); 364 | Fireball fire = (Fireball) location.getWorld().spawn(location, Fireball.class); 365 | fire.setDirection(vector); 366 | } 367 | } 368 | 369 | public static void drop() { 370 | for (Player player : getPlayers()) { 371 | ItemStack hand = player.getInventory().getItemInMainHand(); 372 | player.getInventory().removeItem(hand); 373 | player.getWorld().dropItemNaturally(player.getLocation(), hand); 374 | } 375 | } 376 | 377 | public static void silverfish(String user) { 378 | for (Player player : getPlayers()) { 379 | player.getWorld().spawn(player.getLocation(), org.bukkit.entity.Silverfish.class).setCustomName("§c§l" + user);; 380 | } 381 | } 382 | 383 | public static void vex(String user) { 384 | for (Player player : getPlayers()) { 385 | player.getWorld().spawn(player.getLocation(), org.bukkit.entity.Vex.class).setCustomName("§c§l" + user);; 386 | } 387 | } 388 | 389 | public static void bee(String user) { 390 | for (Player player : getPlayers()) { 391 | // Make bee angry 392 | Bee bee = (Bee) player.getWorld().spawn(player.getLocation(), org.bukkit.entity.Bee.class); 393 | bee.setAnger(1000000); 394 | bee.setCustomName("§c§l" + user); 395 | bee.attack(player); 396 | } 397 | } 398 | 399 | public static void chicken(String user) { 400 | for (Player player : getPlayers()) { 401 | player.getWorld().spawn(player.getLocation(), org.bukkit.entity.Chicken.class).setCustomName("§c§l" + user);; 402 | } 403 | } 404 | 405 | public static void day() { 406 | for (Player player : getPlayers()) { 407 | player.getWorld().setTime(0); 408 | } 409 | } 410 | 411 | public static void night() { 412 | for (Player player : getPlayers()) { 413 | player.getWorld().setTime(14000); 414 | } 415 | } 416 | 417 | public static void peaceful() { 418 | for (Player player : getPlayers()) { 419 | player.getWorld().setDifficulty(Difficulty.PEACEFUL); 420 | } 421 | } 422 | 423 | public static void hard() { 424 | for (Player player : getPlayers()) { 425 | player.getWorld().setDifficulty(Difficulty.HARD); 426 | } 427 | } 428 | 429 | public static void easy() { 430 | for (Player player : getPlayers()) { 431 | player.getWorld().setDifficulty(Difficulty.EASY); 432 | } 433 | } 434 | 435 | public static void rename(String command) { 436 | String name = command.substring(7); 437 | for (Player player : getPlayers()) { 438 | ItemStack hand = player.getInventory().getItemInMainHand(); 439 | ItemMeta meta = hand.getItemMeta(); 440 | assert meta != null; 441 | int rnd = ThreadLocalRandom.current().nextInt(16); 442 | meta.setDisplayName(ChatColor.values()[rnd] + name); 443 | hand.setItemMeta(meta); 444 | } 445 | } 446 | } -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/discord/DiscordConnectionHelper.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.discord; 2 | 3 | import net.dv8tion.jda.api.JDA; 4 | import net.dv8tion.jda.api.JDABuilder; 5 | import net.dv8tion.jda.api.entities.*; 6 | import net.dv8tion.jda.api.events.message.MessageReceivedEvent; 7 | import net.dv8tion.jda.api.hooks.ListenerAdapter; 8 | 9 | import javax.security.auth.login.LoginException; 10 | 11 | import nl.corwindev.streamervschat.main; 12 | 13 | 14 | import nl.corwindev.streamervschat.commands; 15 | 16 | public class DiscordConnectionHelper { 17 | public static JDA api; 18 | 19 | public void main() throws LoginException, InterruptedException { 20 | api = JDABuilder.createDefault(main.plugin.getConfig().getString("discord.token")) 21 | .addEventListeners(new DiscordConnectionHelper.Listeners()) 22 | .setContextEnabled(false) 23 | .build().awaitReady(); 24 | } 25 | 26 | public static boolean isConnected() { 27 | if (api.getStatus() == JDA.Status.CONNECTED) { 28 | return true; 29 | } else { 30 | return false; 31 | } 32 | } 33 | 34 | public class Listeners extends ListenerAdapter { 35 | @Override 36 | public void onMessageReceived(MessageReceivedEvent event) { 37 | // Get the channel the message was sent in 38 | TextChannel channel = event.getTextChannel(); 39 | if (channel.getId().equals(main.plugin.getConfig().getString("discord.channel"))) { 40 | if (event.getAuthor().isBot()) return; 41 | Message message = event.getMessage(); 42 | String content = message.getContentRaw(); 43 | if (content.contains(main.plugin.getConfig().getString("commands.prefix"))) { 44 | commands.UserList.add(event.getAuthor().getName()); 45 | commands.commandList.add(content.replace(main.plugin.getConfig().getString("commands.prefix"), "")); 46 | } 47 | } 48 | } 49 | } 50 | 51 | public static void reload(){ 52 | main.plugin.getLogger().info("[Discord] Reloading..."); 53 | main.plugin.reloadConfig(); 54 | if(api.getStatus() == JDA.Status.CONNECTED){ 55 | api.shutdown(); 56 | } 57 | try { 58 | main.plugin.getLogger().info("[Discord] Logging in..."); 59 | new DiscordConnectionHelper().main(); 60 | } catch (LoginException | InterruptedException e) { 61 | e.printStackTrace(); 62 | } 63 | main.plugin.getLogger().info("[Discord] Reloaded!"); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/main.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat; 2 | 3 | import nl.corwindev.streamervschat.command.DiscordReload; 4 | import nl.corwindev.streamervschat.command.TwitchReload; 5 | import nl.corwindev.streamervschat.command.YouTubeReload; 6 | import nl.corwindev.streamervschat.objects.UpdateChecker; 7 | import nl.corwindev.streamervschat.youtube.YouTubeConnectionHelper; 8 | import org.bstats.charts.DrilldownPie; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.plugin.java.JavaPlugin; 11 | import nl.corwindev.streamervschat.discord.DiscordConnectionHelper; 12 | import nl.corwindev.streamervschat.twitch.TwitchConnectionHelper; 13 | import javax.security.auth.login.LoginException; 14 | import nl.corwindev.streamervschat.objects.JdaFilter; 15 | import nl.corwindev.streamervschat.command.TestCommand; 16 | import org.bstats.bukkit.Metrics; 17 | 18 | import java.util.HashMap; 19 | import java.util.Map; 20 | 21 | public final class main extends JavaPlugin { 22 | // Exports this class to the plugin. 23 | public static main plugin; 24 | private JdaFilter jdaFilter; 25 | 26 | @Override 27 | public void onEnable() { 28 | this.reloadConfig(); 29 | this.saveDefaultConfig(); 30 | plugin = this; 31 | new UpdateChecker(this, 105119).getVersion(version -> { 32 | if (this.getDescription().getVersion().equals(version)) { 33 | getLogger().info("There is not a new update available."); 34 | } else { 35 | getLogger().warning("There is a new update available. Download it here: https://www.spigotmc.org/resources/streamer-vs-chat-1-13-1-19.105119/"); 36 | } 37 | }); 38 | if (!plugin.getConfig().getBoolean("twitch.enabled") && !plugin.getConfig().getBoolean("discord.enabled") && !plugin.getConfig().getBoolean("youtube.enabled")) { 39 | getLogger().info("No services enabled..."); 40 | } 41 | try { 42 | commands.start(); 43 | } catch (Exception e) { 44 | e.printStackTrace(); 45 | } 46 | boolean serverIsLog4jCapable = false; 47 | boolean serverIsLog4j21Capable = false; 48 | try { 49 | serverIsLog4jCapable = Class.forName("org.apache.logging.log4j.core.Logger") != null; 50 | } catch (ClassNotFoundException e) { 51 | getLogger().info("Log4j classes are NOT available, console channel will not be attached"); 52 | } 53 | try { 54 | serverIsLog4j21Capable = Class.forName("org.apache.logging.log4j.core.Filter") != null; 55 | } catch (ClassNotFoundException e) { 56 | getLogger().info("Log4j 2.1 classes are NOT available, JDA messages will NOT be formatted properly"); 57 | } 58 | 59 | // add log4j filter for JDA messages 60 | if (serverIsLog4j21Capable && jdaFilter == null) { 61 | try { 62 | Class jdaFilterClass = Class.forName("nl.corwindev.streamervschat.objects.JdaFilter"); 63 | jdaFilter = (JdaFilter) jdaFilterClass.newInstance(); 64 | ((org.apache.logging.log4j.core.Logger) org.apache.logging.log4j.LogManager.getRootLogger()).addFilter((org.apache.logging.log4j.core.Filter) jdaFilter); 65 | getLogger().info("ConsoleFilter Attached"); 66 | } catch (Exception e) { 67 | e.printStackTrace(); 68 | } 69 | } 70 | if (plugin.getConfig().getBoolean("twitch.enabled")) { 71 | TwitchConnectionHelper.login(); 72 | } 73 | if (plugin.getConfig().getBoolean("discord.enabled")) { 74 | try { 75 | new DiscordConnectionHelper().main(); 76 | } catch (LoginException | InterruptedException e) { 77 | e.printStackTrace(); 78 | } 79 | } 80 | if (plugin.getConfig().getBoolean("youtube.enabled")) { 81 | YouTubeConnectionHelper.main("run"); 82 | } 83 | this.getCommand("testcommand").setExecutor(new TestCommand()); 84 | this.getCommand("youtube-reload").setExecutor(new YouTubeReload()); 85 | this.getCommand("twitch-reload").setExecutor(new TwitchReload()); 86 | this.getCommand("discord-reload").setExecutor(new DiscordReload()); 87 | int pluginId = 16419; 88 | Metrics metrics = new Metrics(this, pluginId); 89 | metrics.addCustomChart(new DrilldownPie("live_platform", () -> { 90 | Map> map = new HashMap<>(); 91 | Boolean YouTubeEnabled = this.getConfig().getBoolean("youtube.enabled"); 92 | Boolean TwitchEnabled = this.getConfig().getBoolean("twitch.enabled"); 93 | Boolean DiscordEnabled = this.getConfig().getBoolean("discord.enabled"); 94 | Map entry = new HashMap<>(); 95 | entry.put("YouTube", YouTubeEnabled ? 1 : 0); 96 | entry.put("Twitch", TwitchEnabled ? 1 : 0); 97 | entry.put("Discord", DiscordEnabled ? 1 : 0); 98 | if(YouTubeEnabled) { 99 | map.put("YouTube", entry); 100 | } 101 | if(TwitchEnabled) { 102 | map.put("Twitch", entry); 103 | } 104 | if(DiscordEnabled) { 105 | map.put("Discord", entry); 106 | } 107 | return map; 108 | })); 109 | } 110 | 111 | @Override 112 | public void onDisable() { 113 | if(DiscordConnectionHelper.api != null) { 114 | if (DiscordConnectionHelper.isConnected()) { 115 | DiscordConnectionHelper.api.shutdown(); 116 | } 117 | } 118 | if (TwitchConnectionHelper.isConnected()) { 119 | TwitchConnectionHelper.getBot().disconnect(); 120 | } 121 | YouTubeConnectionHelper.stop(); 122 | 123 | getLogger().info("Corwin shutting down!"); 124 | 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/objects/JdaFilter.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.objects; 2 | 3 | import org.apache.commons.lang3.exception.ExceptionUtils; 4 | import org.apache.logging.log4j.Level; 5 | import org.apache.logging.log4j.Marker; 6 | import org.apache.logging.log4j.core.Filter; 7 | import org.apache.logging.log4j.core.LogEvent; 8 | import org.apache.logging.log4j.core.Logger; 9 | import org.apache.logging.log4j.message.Message; 10 | import nl.corwindev.streamervschat.main; 11 | 12 | 13 | public class JdaFilter implements Filter { 14 | 15 | public Result check(String loggerName, Level level, String message, Throwable throwable) { 16 | if (loggerName.startsWith("net.dv8tion")) { 17 | 18 | switch (level.name()) { 19 | case "INFO": 20 | main.plugin.getLogger().info("[JDA] " + message); 21 | break; 22 | case "WARN": 23 | if (message.contains("Encountered 429")) { 24 | main.plugin.getLogger().info(message); 25 | break; 26 | } 27 | 28 | main.plugin.getLogger().warning("[JDA] " + message); 29 | break; 30 | case "ERROR": 31 | if (message.contains("Requester timed out while executing a request")) { 32 | main.plugin.getLogger().log(java.util.logging.Level.WARNING,"[JDA] " + message + ". This is either a issue on Discord's end (https://discordstatus.com) or with your server's connection"); 33 | 34 | main.plugin.getLogger().log(java.util.logging.Level.WARNING, ExceptionUtils.getStackTrace(throwable)); 35 | break; 36 | } 37 | 38 | if (throwable != null) { 39 | main.plugin.getLogger().info("[JDA] " + message + "\n" + ExceptionUtils.getStackTrace(throwable)); 40 | } else { 41 | main.plugin.getLogger().info("[JDA] " + message); 42 | } 43 | break; 44 | default: 45 | main.plugin.getLogger().info("[JDA] " + message); 46 | } 47 | }else if(loggerName.startsWith("com.github.twitch4j") || loggerName.startsWith("com.github.philippheuer.events4j")) { 48 | switch (level.name()) { 49 | case "INFO": 50 | main.plugin.getLogger().info("[TWITCH] " + message); 51 | break; 52 | case "WARN": 53 | main.plugin.getLogger().warning("[TWITCH] " + message); 54 | break; 55 | case "ERROR": 56 | if (throwable != null) { 57 | main.plugin.getLogger().info("[TWITCH] " + message + "\n" + ExceptionUtils.getStackTrace(throwable)); 58 | } else { 59 | main.plugin.getLogger().info("[TWITCH] " + message); 60 | } 61 | break; 62 | default: 63 | main.plugin.getLogger().info("[TWITCH] " + message); 64 | } 65 | }else if(loggerName.startsWith("com.google.api")){ 66 | switch (level.name()) { 67 | case "INFO": 68 | main.plugin.getLogger().info("[YOUTUBE] " + message); 69 | break; 70 | case "WARN": 71 | main.plugin.getLogger().warning("[YOUTUBE] " + message); 72 | break; 73 | case "ERROR": 74 | if (throwable != null) { 75 | main.plugin.getLogger().info("[YOUTUBE] " + message + "\n" + ExceptionUtils.getStackTrace(throwable)); 76 | } else { 77 | main.plugin.getLogger().info("[YOUTUBE] " + message); 78 | } 79 | break; 80 | default: 81 | main.plugin.getLogger().info("[YOUTUBE] " + message); 82 | } 83 | }else{ 84 | return Result.NEUTRAL; 85 | } 86 | return Result.DENY; 87 | 88 | } 89 | 90 | @Override 91 | public Result filter(LogEvent logEvent) { 92 | return check( 93 | logEvent.getLoggerName(), 94 | logEvent.getLevel(), 95 | logEvent.getMessage() 96 | .getFormattedMessage(), 97 | logEvent.getThrown()); 98 | } 99 | @Override 100 | public Result filter(Logger logger, Level level, Marker marker, String message, Object... parameters) { 101 | return check( 102 | logger.getName(), 103 | level, 104 | message, 105 | null); 106 | } 107 | 108 | @Override 109 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0) { 110 | return null; 111 | } 112 | 113 | @Override 114 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1) { 115 | return null; 116 | } 117 | 118 | @Override 119 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2) { 120 | return null; 121 | } 122 | 123 | @Override 124 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3) { 125 | return null; 126 | } 127 | 128 | @Override 129 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4) { 130 | return null; 131 | } 132 | 133 | @Override 134 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5) { 135 | return null; 136 | } 137 | 138 | @Override 139 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6) { 140 | return null; 141 | } 142 | 143 | @Override 144 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7) { 145 | return null; 146 | } 147 | 148 | @Override 149 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8) { 150 | return null; 151 | } 152 | 153 | @Override 154 | public Result filter(Logger logger, Level level, Marker marker, String message, Object p0, Object p1, Object p2, Object p3, Object p4, Object p5, Object p6, Object p7, Object p8, Object p9) { 155 | return null; 156 | } 157 | 158 | @Override 159 | public Result filter(Logger logger, Level level, Marker marker, Object message, Throwable throwable) { 160 | return check( 161 | logger.getName(), 162 | level, 163 | message.toString(), 164 | throwable); 165 | } 166 | @Override 167 | public Result filter(Logger logger, Level level, Marker marker, Message message, Throwable throwable) { 168 | return check( 169 | logger.getName(), 170 | level, 171 | message.getFormattedMessage(), 172 | throwable); 173 | } 174 | 175 | @Override 176 | public State getState() { 177 | return null; 178 | } 179 | 180 | @Override 181 | public void initialize() { 182 | 183 | } 184 | 185 | public void start() {} 186 | public void stop() {} 187 | public boolean isStarted() { 188 | return true; 189 | } 190 | public boolean isStopped() { 191 | return false; 192 | } 193 | 194 | @Override 195 | public Result getOnMismatch() { 196 | return Result.NEUTRAL; 197 | } 198 | @Override 199 | public Result getOnMatch() { 200 | return Result.NEUTRAL; 201 | } 202 | } -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/objects/UpdateChecker.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.objects; 2 | 3 | import org.bukkit.Bukkit; 4 | import org.bukkit.plugin.java.JavaPlugin; 5 | 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.net.URL; 9 | import java.util.Scanner; 10 | import java.util.function.Consumer; 11 | 12 | public class UpdateChecker { 13 | 14 | private final JavaPlugin plugin; 15 | private final int resourceId; 16 | 17 | public UpdateChecker(JavaPlugin plugin, int resourceId) { 18 | this.plugin = plugin; 19 | this.resourceId = resourceId; 20 | } 21 | 22 | public void getVersion(final Consumer consumer) { 23 | Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { 24 | try (InputStream inputStream = new URL("https://api.spigotmc.org/legacy/update.php?resource=" + this.resourceId).openStream(); Scanner scanner = new Scanner(inputStream)) { 25 | if (scanner.hasNext()) { 26 | consumer.accept(scanner.next()); 27 | } 28 | } catch (IOException exception) { 29 | plugin.getLogger().info("Unable to check for updates: " + exception.getMessage()); 30 | } 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/twitch/TwitchConnectionHelper.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.twitch; 2 | 3 | 4 | import com.github.philippheuer.credentialmanager.domain.OAuth2Credential; 5 | import com.github.philippheuer.events4j.simple.SimpleEventHandler; 6 | import com.github.twitch4j.chat.TwitchChat; 7 | import com.github.twitch4j.chat.TwitchChatBuilder; 8 | import com.github.twitch4j.chat.enums.TMIConnectionState; 9 | import nl.corwindev.streamervschat.main; 10 | 11 | import java.util.function.Supplier; 12 | 13 | import static nl.corwindev.streamervschat.main.plugin; 14 | 15 | public class TwitchConnectionHelper { 16 | private static Thread botThread = null; 17 | private static TwitchChat twitchClient = null; 18 | 19 | public static TwitchChat getBot() { 20 | return twitchClient; 21 | } 22 | public static boolean login() { 23 | try { 24 | OAuth2Credential credential = new OAuth2Credential("twitch", plugin.getConfig().getString("twitch.token")); 25 | twitchClient = TwitchChatBuilder.builder() 26 | .withChatAccount(credential) 27 | .withDefaultEventHandler(SimpleEventHandler.class) 28 | .build(); 29 | 30 | 31 | botThread = new Thread(() -> { 32 | TwitchEvents bot = new TwitchEvents(twitchClient.getEventManager().getEventHandler(SimpleEventHandler.class)); 33 | twitchClient.joinChannel(plugin.getConfig().getString("twitch.channel")); 34 | twitchClient.connect(); 35 | }); 36 | 37 | botThread.start(); 38 | return true; 39 | 40 | } catch (Exception e) { 41 | // Log logger to console 42 | 43 | plugin.getLogger().warning((Supplier) e); 44 | return false; 45 | } 46 | } 47 | public static boolean isConnected() { 48 | 49 | if (twitchClient != null) { 50 | return twitchClient.getConnectionState().equals(TMIConnectionState.CONNECTED); 51 | } else { 52 | return false; 53 | } 54 | 55 | } 56 | 57 | public static void disconnectBot() { 58 | 59 | twitchClient.disconnect(); 60 | botThread.interrupt(); 61 | 62 | plugin.getLogger().info("Shutted down twitch bot"); 63 | } 64 | 65 | public static void reload(){ 66 | main.plugin.getLogger().info("[Twitch] Reloading..."); 67 | main.plugin.reloadConfig(); 68 | if(isConnected()){ 69 | disconnectBot(); 70 | } 71 | main.plugin.getLogger().info("[Twitch] Reloaded!"); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/twitch/TwitchEvents.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.twitch; 2 | 3 | import com.github.philippheuer.events4j.simple.SimpleEventHandler; 4 | import com.github.twitch4j.chat.events.channel.ChannelMessageEvent; 5 | import nl.corwindev.streamervschat.commands; 6 | import nl.corwindev.streamervschat.main; 7 | 8 | public class TwitchEvents { 9 | 10 | public TwitchEvents(SimpleEventHandler eventHandler) { 11 | 12 | eventHandler.onEvent(ChannelMessageEvent.class, this::onChannelMessage); 13 | } 14 | 15 | private void onChannelMessage(ChannelMessageEvent event) { 16 | System.out.println(event.getUser().getName() + ": " + event.getMessage()); 17 | if (event.getMessage().contains(main.plugin.getConfig().getString("commands.prefix"))) { 18 | commands.UserList.add(event.getUser().getName()); 19 | commands.commandList.add(event.getMessage().replace(main.plugin.getConfig().getString("commands.prefix"), "")); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/main/java/nl/corwindev/streamervschat/youtube/YouTubeConnectionHelper.java: -------------------------------------------------------------------------------- 1 | package nl.corwindev.streamervschat.youtube; 2 | 3 | 4 | import com.google.api.client.http.HttpRequestInitializer; 5 | import com.google.api.client.http.javanet.NetHttpTransport; 6 | import com.google.api.client.json.jackson2.JacksonFactory; 7 | 8 | import com.google.api.client.util.DateTime; 9 | import com.google.api.services.youtube.YouTube; 10 | import com.google.api.services.youtube.model.*; 11 | import nl.corwindev.streamervschat.commands; 12 | import nl.corwindev.streamervschat.main; 13 | 14 | import java.util.*; 15 | 16 | 17 | public class YouTubeConnectionHelper { 18 | private static final String LIVE_CHAT_FIELDS = 19 | "items(authorDetails(channelId,displayName,isChatModerator,isChatOwner,isChatSponsor," 20 | + "profileImageUrl),snippet(displayMessage,superChatDetails,publishedAt))," 21 | + "nextPageToken,pollingIntervalMillis"; 22 | public static boolean started = false; 23 | private static YouTube youtube; 24 | public static void main(String args) { 25 | 26 | // This OAuth 2.0 access scope allows for read-only access to the 27 | // authenticated user's account, but not other types of account access. 28 | 29 | try { 30 | String liveChatId = main.plugin.getConfig().getString("youtube.youtubeId"); 31 | NetHttpTransport transport = new NetHttpTransport.Builder().build(); 32 | JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance(); 33 | HttpRequestInitializer httpRequestInitializer = request -> { 34 | request.setInterceptor(intercepted -> intercepted.getUrl().set("key", main.plugin.getConfig().getString("youtube.apiKey"))); 35 | }; 36 | 37 | youtube = new YouTube.Builder(transport, jsonFactory, httpRequestInitializer) 38 | .setApplicationName("StreamerVsChat") 39 | .build(); 40 | 41 | liveChatId = youtube.videos().list("liveStreamingDetails").setId(liveChatId).execute().getItems().get(0).getLiveStreamingDetails().getActiveLiveChatId(); 42 | listChatMessages(liveChatId, null, main.plugin.getConfig().getInt("commands.delay") * 1000); 43 | } catch (Throwable t) { 44 | main.plugin.getLogger().warning("[YouTube] Error: " + t.getMessage()); 45 | } 46 | } 47 | public static TimerTask tt = null; 48 | /** 49 | * Lists live chat messages, polling at the server supplied interval. Owners and moderators of a 50 | * live chat will poll at a faster rate. 51 | * 52 | * @param liveChatId The live chat id to list messages from. 53 | * @param nextPageToken The page token from the previous request, if any. 54 | * @param delayMs The delay in milliseconds before making the request. 55 | */ 56 | private static void listChatMessages( 57 | final String liveChatId, 58 | final String nextPageToken, 59 | long delayMs) { 60 | Timer pollTimer = new Timer(); 61 | pollTimer.schedule( 62 | new TimerTask() { 63 | @Override 64 | public void run() { 65 | tt = this; 66 | try { 67 | // Get chat messages from YouTube 68 | LiveChatMessageListResponse response = youtube 69 | .liveChatMessages() 70 | .list(liveChatId, "snippet, authorDetails") 71 | .setPageToken(nextPageToken) 72 | .setFields(LIVE_CHAT_FIELDS) 73 | .execute(); 74 | 75 | // Display messages and super chat details 76 | List messages = response.getItems(); 77 | // Skip first run 78 | for (int i = 0; i < messages.size(); i++) { 79 | LiveChatMessage message = messages.get(i); 80 | LiveChatMessageSnippet snippet = message.getSnippet(); 81 | buildOutput( 82 | snippet.getDisplayMessage(), 83 | message.getAuthorDetails(), 84 | snippet.getSuperChatDetails(), 85 | snippet.getPublishedAt()); 86 | } 87 | 88 | // Request the next page of messages 89 | listChatMessages( 90 | liveChatId, 91 | response.getNextPageToken(), 92 | response.getPollingIntervalMillis()); 93 | 94 | } catch (Throwable t) { 95 | main.plugin.getLogger().warning("[YouTube] Error: " + t.getMessage()); 96 | } 97 | } 98 | }, main.plugin.getConfig().getInt("commands.delay") * 1000); 99 | } 100 | 101 | /** 102 | * Formats a chat message for console output. 103 | * 104 | * @param message The display message to output. 105 | * @param author The author of the message. 106 | * @param superChatDetails SuperChat details associated with the message. 107 | * @return A formatted string for console output. 108 | */ 109 | private static String buildOutput( 110 | String message, 111 | LiveChatMessageAuthorDetails author, 112 | LiveChatSuperChatDetails superChatDetails, 113 | DateTime publishedAt) { 114 | // Check if message is older then 5 minutes 115 | if (publishedAt.getValue() < System.currentTimeMillis() - (main.plugin.getConfig().getInt("commands.delay") * 1000 + 1000)) { 116 | return ""; 117 | } 118 | StringBuilder output = new StringBuilder(); 119 | if (superChatDetails != null) { 120 | output.append(superChatDetails.getAmountDisplayString()); 121 | output.append("SUPERCHAT RECEIVED FROM "); 122 | commands.runCmd(message.replace(main.plugin.getConfig().getString("commands.prefix"), ""), author.getDisplayName()); 123 | } 124 | output.append(author.getDisplayName()); 125 | List roles = new ArrayList(); 126 | if (author.getIsChatOwner()) { 127 | roles.add("OWNER"); 128 | } 129 | if (author.getIsChatModerator()) { 130 | roles.add("MODERATOR"); 131 | } 132 | if (author.getIsChatSponsor()) { 133 | roles.add("SPONSOR"); 134 | } 135 | if (roles.size() > 0) { 136 | output.append(" ("); 137 | String delim = ""; 138 | for (String role : roles) { 139 | output.append(delim).append(role); 140 | delim = ", "; 141 | } 142 | output.append(")"); 143 | } 144 | if (message != null && !message.isEmpty()) { 145 | output.append(": "); 146 | output.append(message); 147 | } 148 | if (message.contains(main.plugin.getConfig().getString("commands.prefix"))) { 149 | commands.UserList.add(author.getDisplayName()); 150 | commands.commandList.add(message.replace(main.plugin.getConfig().getString("commands.prefix"), "")); 151 | }else{ 152 | main.plugin.getServer().broadcastMessage(output.toString()); 153 | } 154 | return output.toString(); 155 | } 156 | 157 | public static void reload(){ 158 | main.plugin.getLogger().info("[YouTube] Reloading..."); 159 | main.plugin.reloadConfig(); 160 | if(tt != null){ 161 | tt.cancel(); 162 | } 163 | main("run"); 164 | main.plugin.getLogger().info("[YouTube] Reloaded!"); 165 | } 166 | 167 | public static void stop(){ 168 | main.plugin.getLogger().info("[YouTube] Stopping..."); 169 | if(tt != null){ 170 | tt.cancel(); 171 | } 172 | main.plugin.getLogger().info("[YouTube] Stopped!"); 173 | } 174 | } -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | # Commands Prefix 2 | # Delay between commands 3 | # Its recommended to set this to 10 seconds or higher 4 | 5 | commands: { 6 | prefix: '!', 7 | delay: 30 8 | } 9 | 10 | # Set affected players 11 | # all/permission 12 | # all: All players will be affected 13 | # permission: Only players with the permission (nl.corwindev.streamervschat.streamer) will be affected 14 | affected-players: all 15 | 16 | # Poison effect 17 | # Set the duration of the poison effect 18 | poison-duration: 20 19 | 20 | # Blacklist 21 | # Set the words that will be blacklisted 22 | # If a player says one of these words, he will be denied 23 | blacklist: [] 24 | 25 | # Cooldown 26 | # Set the cooldown for the commands 27 | # If a player uses a command, he will be denied for the set amount of seconds 28 | cooldowns: 29 | dropall: 30 30 | drop: 30 31 | 32 | 33 | # Hotbar message 34 | # Set the message that will be displayed in the hotbar 35 | # %player% will be replaced with the player's name 36 | # %command% will be replaced with the command 37 | hotbar: '§a§l%user%§r§a has executed the command: §l%command%' 38 | 39 | 40 | # Discord Bot 41 | # https://github.com/CorwinDev/StreamerVSChat/wiki#discord-setup 42 | discord: { 43 | enabled: false, 44 | token: 'discord token', 45 | channel: 'channel id' 46 | } 47 | 48 | # Twitch Chat 49 | # https://github.com/CorwinDev/StreamerVSChat/wiki#twitch-setup 50 | twitch: { 51 | enabled: false, 52 | token: 'twitch token', 53 | channel: 'twitch channel' 54 | } 55 | 56 | # Youtube Chat 57 | # https://github.com/CorwinDev/StreamerVSChat/wiki#youtube-setup 58 | youtube: { 59 | enabled: false, 60 | youtubeId: 'youtube id', 61 | apiKey: 'youtube api key' 62 | } 63 | 64 | # Custom Commands 65 | # 66 | # You can add custom commands to the plugin 67 | # You can add as many commands as you want 68 | # Command name without the prefix 69 | # Command: Command that will be executed without the / 70 | # You can use %player% to get the player name 71 | # Example: !test -> /give %player% diamond 1 72 | 73 | customcommands: 74 | 'test': 75 | command: 'give %player% diamond 1' 76 | cooldown: 30 77 | 'test2': 78 | command: 'give %player% diamond 2' -------------------------------------------------------------------------------- /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: StreamerVsChat 2 | version: '2.2' 3 | main: nl.corwindev.streamervschat.main 4 | api-version: 1.13 5 | commands: 6 | testcommand: 7 | description: 'Test the commands' 8 | usage: '/testcommand' 9 | permission: nl.corwindev.streamervschat.streamer 10 | permission-message: 'You do not have permission to use this command' 11 | default: false 12 | permission-default: op 13 | youtube-reload: 14 | description: 'Reload youtube integration' 15 | usage: '/yt-reload' 16 | permission: nl.corwindev.streamervschat.streamer 17 | permission-message: 'You do not have permission to use this command' 18 | default: false 19 | permission-default: op 20 | twitch-reload: 21 | description: 'Reload twitch integration' 22 | usage: '/twitch-reload' 23 | permission: nl.corwindev.streamervschat.streamer 24 | permission-message: 'You do not have permission to use this command' 25 | default: false 26 | permission-default: op 27 | discord-reload: 28 | description: 'Reload Discord integration' 29 | usage: '/discord-reload' 30 | permission: nl.corwindev.streamervschat.streamer 31 | permission-message: 'You do not have permission to use this command' 32 | default: false 33 | permission-default: op 34 | --------------------------------------------------------------------------------