From 9f96a439fb5b30d3c64ac10d35218e7120decfd7 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sat, 31 Aug 2024 18:20:26 +0200 Subject: [PATCH 01/23] Change config format for Channel Username --- README.md | 6 +++--- core/src/main/resources/config.yml | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 313cb2a..3723f00 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ These are the only official download mirrors. Any downloads besides of these lin > [!TIP] > If needed, you can copy-paste the names of the Channel Points Rewards into a text document for later use. -3. Set your [config.yml](core/src/main/resources/config.yml) up. Adjust the settings and add and setup the actions for rewards, donations... There are two ways to link your Twitch account to the plugin: +3. Set your [config.yml](core/src/main/resources/config.yml) up. Adjust the settings and add and setup the actions for rewards, donations... You will need to link a Twitch account in order to connect use the Twitch API (the linked account **needs to own/moderate all Twitch channels** set in config.yml) There are two ways to link your Twitch account to the plugin: - **Using a key-based authentication** *(recommended)*: You will need a Client ID and Access token. You can get one mannually or through a website as [Twitch Token Generator](https://twitchtokengenerator.com). Make sure to add all the [needed scopes](#twitch-scopes). @@ -30,7 +30,7 @@ These are the only official download mirrors. Any downloads besides of these lin - **Log in through a browser**: You won't need any extra modification in your config.yml file. You will just need to run `/twitch link` in-game and open the provided link. You may need to log in your Twitch account and authorise the app. Once you finish the log in process you can close the browser and your account will be linked. > [!WARNING] -> Currently due to technical limitations **it's only possible to use the browser method if the login link is opened with the same machine the server is being ran on**. You also have to repeat this process each time you start the server or reload the plugin. +> Currently due to API limitations **it's only possible to use the browser method if the login link is opened with the same machine the server is being ran on**. You also have to repeat this process each time you start the server or reload the plugin. 4. Set up permissions for: - linking/reloading (`chatpointsttv.manage`). @@ -45,7 +45,7 @@ These are the only official download mirrors. Any downloads besides of these lin ## **config.yml docs** To reset the original configuration, delete `config.yml` and reload the plugin. The file will regenerate automatically. *Sections with a (\*) are required to be changed in order to the plugin to be used.* -* **Channel Username***: The channel that will be listened for rewards, bits and subs. +* **Channel Username***: The channel(s) that will be listened for rewards, bits and subs. (In case of multiple channels, they muse be added as a list: `["channel_1", "channel_2", "..."]`) * **Custom Client ID**: Client ID used for key-based authorization. Leave commented if it's not being used. * **Custom Access Token**: Access token used for key-based authorization. Leave commented if it's not being used. * **Show Chat**: If enabled, your stream chat will be shown in-game to all players in the server. diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index 05e56aa..a7de77d 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -1,6 +1,7 @@ # This is the configuration file for ChatPointsTTV. For a fresh copy of this file, go to https://github.com/GospelBG/ChatPointsTTV/blob/master/src/main/resources/config.yml # For more information about how to use this file, refer to the config.yml instructions in the README file at https://github.com/GospelBG/ChatPointsTTV/blob/master/README.md +# Username(s) of the streamer's channels. In case of multiple streamers, must be set as a list: ["channel_1", "channel_2", "..."] CHANNEL_USERNAME: {YOUR CHANNEL} # Uncomment the following lines (remove the # symbol at the start of the line) to use a key-based authentication instead of the browser login. From 62ff3d5b6bf8709c9ef173d2f2fe47f4ded2c320 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sat, 31 Aug 2024 18:23:00 +0200 Subject: [PATCH 02/23] Loop event sub with each channel --- .../gosdev/chatpointsttv/ChatPointsTTV.java | 201 +++++++++--------- 1 file changed, 104 insertions(+), 97 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index baeaf61..c253166 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -78,7 +78,6 @@ public class ChatPointsTTV extends JavaPlugin { public Thread linkThread; private String user_id; - private String channel_id; public Logger log = getLogger(); public FileConfiguration config; @@ -314,106 +313,22 @@ public void linkToTwitch(CommandSender p, String token) { } utils.sendMessage(Bukkit.getConsoleSender(), "Logged in as: "+ user.getDisplayName()); - - // Join the twitch chat of this channel and enable stream/follow events - String channel = config.getString("CHANNEL_USERNAME"); - channel_id = getUserId(channel); + + eventHandler = new TwitchEventHandler(); + + // Linked account UserID user_id = new TwitchIdentityProvider(null, null, null).getAdditionalCredentialInformation(oauth).map(OAuth2Credential::getUserId).orElse(null); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening to " + channel + "'s events..."); - client.getChat().joinChannel(channel); - - // Subscribe to events - eventSocket = client.getEventSocket(); - eventManager = client.getEventManager(); - CountDownLatch latch = new CountDownLatch(3); - eventManager.onEvent(EventSocketSubscriptionSuccessEvent.class, e -> latch.countDown()); - eventManager.onEvent(EventSocketSubscriptionFailureEvent.class, e -> latch.countDown()); - - if (Rewards.getRewards(Rewards.rewardType.CHANNEL_POINTS) != null) { - client.getPubSub().listenForChannelPointsRedemptionEvents(null, channel_id); - eventManager.onEvent(RewardRedeemedEvent.class, new Consumer() { - @Override - public void accept(RewardRedeemedEvent e) { - eventHandler.onChannelPointsRedemption(e); - } - }); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for channel point rewards..."); - } - if (Rewards.getRewards(Rewards.rewardType.FOLLOW) != null) { - if (TwitchUtils.getModeratedChannelIDs(oauth.getAccessToken(), user_id).contains(channel_id) || user_id.equals(channel_id)) { // If account is the streamer or a mod (need to have mod permissions on the channel) - eventSocket.register(SubscriptionTypes.CHANNEL_FOLLOW_V2.prepareSubscription(b -> b.moderatorUserId(user_id).broadcasterUserId(channel_id).build(), null)); - eventManager.onEvent(ChannelFollowEvent.class, new Consumer() { - @Override - public void accept(ChannelFollowEvent e) { - try { // May get NullPointerException if event is triggered while still subscribing - eventHandler.onFollow(e); - } catch (NullPointerException ex) {} - } - }); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for follows..."); - } else { - log.warning("Follow events cannot be listened to on unauthorised channels."); + // Join the twitch chat of this channel(s) and enable stream/follow events + if (config.getList("CHANNEL_USERNAME") == null) { + subscribeToEvents(p, config.getString("CHANNEL_USERNAME")); + } else { + for (String channel : config.getStringList("CHANNEL_USERNAME")) { + subscribeToEvents(p, channel); } - } else latch.countDown(); + } - if (Rewards.getRewards(Rewards.rewardType.CHEER) != null) { - eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_MESSAGE.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); - eventManager.onEvent(ChannelChatMessageEvent.class, new Consumer() { - @Override - public void accept(ChannelChatMessageEvent e) { - try { // May get NullPointerException if event is triggered while still subscribing - eventHandler.onCheer(e); - } catch (NullPointerException ex) {} - } - }); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for Cheers..."); - } else latch.countDown(); - - if (Rewards.getRewards(Rewards.rewardType.SUB) != null || Rewards.getRewards(Rewards.rewardType.GIFT) != null) { - eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_NOTIFICATION.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); - eventManager.onEvent(ChannelChatNotificationEvent.class, new Consumer(){ - @Override - public void accept(ChannelChatNotificationEvent e) { - try { // May get NullPointerException if event is triggered while still subscribing - eventHandler.onEvent(e); - } catch (NullPointerException ex) {} - } - }); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for subscriptions and gifts..."); - } else latch.countDown(); - - if (config.getBoolean("SHOW_CHAT")) { - eventManager.onEvent(ChannelMessageEvent.class, event -> { - if (!chatBlacklist.contains(event.getUser().getName())) { - net.md_5.bungee.api.ChatColor mcColor; - try { - mcColor = ColorUtils.getClosestChatColor(new Color(ColorUtils.hexToRgb(event.getMessageEvent().getUserChatColor().get()))); - } catch (Exception e) { - mcColor = net.md_5.bungee.api.ChatColor.RED; - } - BaseComponent[] components = new BaseComponent[] { - new ComponentBuilder(mcColor + event.getMessageEvent().getUserDisplayName().get() + ": ").create()[0], - new ComponentBuilder(event.getMessage()).create()[0] - }; - for (Player player : Bukkit.getOnlinePlayers()) { - if (player.hasPermission(permissions.BROADCAST.permission_id)) { - utils.sendMessage(player, components); - } - } - } - }); - } - eventHandler = new TwitchEventHandler(); - client.getEventManager().getEventHandler(SimpleEventHandler.class).registerListener(eventHandler); utils.sendMessage(p, "Twitch client was started successfully!"); - - try { - latch.await(); - } catch (InterruptedException e1) { - e1.printStackTrace(); - } - accountConnected = true; }); linkThread.start(); @@ -428,7 +343,99 @@ public void uncaughtException(Thread t, Throwable e) { } }); } - + + public void subscribeToEvents(CommandSender p, String channel) { + String channel_id = getUserId(channel); + eventSocket = client.getEventSocket(); + eventManager = client.getEventManager(); + + CountDownLatch latch = new CountDownLatch(3); + eventManager.onEvent(EventSocketSubscriptionSuccessEvent.class, e -> latch.countDown()); + eventManager.onEvent(EventSocketSubscriptionFailureEvent.class, e -> latch.countDown()); + + if (Rewards.getRewards(Rewards.rewardType.CHANNEL_POINTS) != null) { + client.getPubSub().listenForChannelPointsRedemptionEvents(null, channel_id); + eventManager.onEvent(RewardRedeemedEvent.class, new Consumer() { + @Override + public void accept(RewardRedeemedEvent e) { + eventHandler.onChannelPointsRedemption(e); + } + }); + utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s channel point redemptions..."); + } + if (Rewards.getRewards(Rewards.rewardType.FOLLOW) != null) { + if (TwitchUtils.getModeratedChannelIDs(oauth.getAccessToken(), user_id).contains(channel_id) || user_id.equals(channel_id)) { // If account is the streamer or a mod (need to have mod permissions on the channel) + eventSocket.register(SubscriptionTypes.CHANNEL_FOLLOW_V2.prepareSubscription(b -> b.moderatorUserId(user_id).broadcasterUserId(channel_id).build(), null)); + eventManager.onEvent(ChannelFollowEvent.class, new Consumer() { + @Override + public void accept(ChannelFollowEvent e) { + try { // May get NullPointerException if event is triggered while still subscribing + eventHandler.onFollow(e); + } catch (NullPointerException ex) {} + } + }); + utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s follows..."); + } else { + log.warning("Follow events cannot be listened to on unauthorised channels."); + } + } else latch.countDown(); + + if (Rewards.getRewards(Rewards.rewardType.CHEER) != null) { + eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_MESSAGE.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); + eventManager.onEvent(ChannelChatMessageEvent.class, new Consumer() { + @Override + public void accept(ChannelChatMessageEvent e) { + try { // May get NullPointerException if event is triggered while still subscribing + eventHandler.onCheer(e); + } catch (NullPointerException ex) {} + } + }); + utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s Cheers..."); + } else latch.countDown(); + + if (Rewards.getRewards(Rewards.rewardType.SUB) != null || Rewards.getRewards(Rewards.rewardType.GIFT) != null) { + eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_NOTIFICATION.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); + eventManager.onEvent(ChannelChatNotificationEvent.class, new Consumer(){ + @Override + public void accept(ChannelChatNotificationEvent e) { + try { // May get NullPointerException if event is triggered while still subscribing + eventHandler.onEvent(e); + } catch (NullPointerException ex) {} + } + }); + utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s subscriptions and gifts..."); + } else latch.countDown(); + + if (config.getBoolean("SHOW_CHAT")) { + eventManager.onEvent(ChannelMessageEvent.class, event -> { + if (!chatBlacklist.contains(event.getUser().getName())) { + net.md_5.bungee.api.ChatColor mcColor; + try { + mcColor = ColorUtils.getClosestChatColor(new Color(ColorUtils.hexToRgb(event.getMessageEvent().getUserChatColor().get()))); + } catch (Exception e) { + mcColor = net.md_5.bungee.api.ChatColor.RED; + } + BaseComponent[] components = new BaseComponent[] { + new ComponentBuilder(mcColor + event.getMessageEvent().getUserDisplayName().get() + ": ").create()[0], + new ComponentBuilder(event.getMessage()).create()[0] + }; + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.hasPermission(permissions.BROADCAST.permission_id)) { + utils.sendMessage(player, components); + } + } + } + }); + } + client.getEventManager().getEventHandler(SimpleEventHandler.class).registerListener(eventHandler); + utils.sendMessage(Bukkit.getConsoleSender(), "Listening to " + channel + "'s events..."); + client.getChat().joinChannel(channel); + try { + latch.await(); + } catch (InterruptedException e1) { + log.warning("Failed to listen to " + channel + "'s events. Channel may not exist or the linked account may lack permissions."); + } + } public void unlink(CommandSender p) { if (!accountConnected) { p.sendMessage(ChatColor.RED + "There is no connected account."); From dc1709dde8236f4207d0438b7adf0f91ffd7b5c5 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sat, 31 Aug 2024 22:03:41 +0200 Subject: [PATCH 03/23] Reorganize and fix Channel Event Listening --- .../gosdev/chatpointsttv/ChatPointsTTV.java | 165 ++++++++++-------- 1 file changed, 93 insertions(+), 72 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index c253166..f95daf1 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -319,14 +319,97 @@ public void linkToTwitch(CommandSender p, String token) { // Linked account UserID user_id = new TwitchIdentityProvider(null, null, null).getAdditionalCredentialInformation(oauth).map(OAuth2Credential::getUserId).orElse(null); + eventSocket = client.getEventSocket(); + eventManager = client.getEventManager(); + + int channels = getListenedChannels().size(); + int subs = 0; + + if (Rewards.getRewards(Rewards.rewardType.CHANNEL_POINTS) != null) { + eventManager.onEvent(RewardRedeemedEvent.class, new Consumer() { + @Override + public void accept(RewardRedeemedEvent e) { + eventHandler.onChannelPointsRedemption(e); + } + }); + } + if (Rewards.getRewards(Rewards.rewardType.FOLLOW) != null) { + subs++; + eventManager.onEvent(ChannelFollowEvent.class, new Consumer() { + @Override + public void accept(ChannelFollowEvent e) { + try { // May get NullPointerException if event is triggered while still subscribing + eventHandler.onFollow(e); + } catch (NullPointerException ex) {} + } + }); + } + if (Rewards.getRewards(Rewards.rewardType.CHEER) != null) { + subs++; + eventManager.onEvent(ChannelChatMessageEvent.class, new Consumer() { + @Override + public void accept(ChannelChatMessageEvent e) { + try { // May get NullPointerException if event is triggered while still subscribing + eventHandler.onCheer(e); + } catch (NullPointerException ex) {} + } + }); + } + if (Rewards.getRewards(Rewards.rewardType.SUB) != null || Rewards.getRewards(Rewards.rewardType.GIFT) != null) { + subs++; + eventManager.onEvent(ChannelChatNotificationEvent.class, new Consumer(){ + @Override + public void accept(ChannelChatNotificationEvent e) { + try { // May get NullPointerException if event is triggered while still subscribing + eventHandler.onEvent(e); + } catch (NullPointerException ex) {} + } + }); + } + if (config.getBoolean("SHOW_CHAT")) { + eventManager.onEvent(ChannelMessageEvent.class, event -> { + if (!chatBlacklist.contains(event.getUser().getName())) { + net.md_5.bungee.api.ChatColor mcColor; + try { + mcColor = ColorUtils.getClosestChatColor(new Color(ColorUtils.hexToRgb(event.getMessageEvent().getUserChatColor().get()))); + } catch (Exception e) { + mcColor = net.md_5.bungee.api.ChatColor.RED; + } + BaseComponent[] components = new BaseComponent[] { + new ComponentBuilder(mcColor + event.getMessageEvent().getUserDisplayName().get() + ": ").create()[0], + new ComponentBuilder(event.getMessage()).create()[0] + }; + for (Player player : Bukkit.getOnlinePlayers()) { + if (player.hasPermission(permissions.BROADCAST.permission_id)) { + utils.sendMessage(player, components); + } + } + } + }); + } + + CountDownLatch latch = new CountDownLatch(subs * channels); + log.info(String.valueOf(subs * channels)); + + eventManager.onEvent(EventSocketSubscriptionSuccessEvent.class, e -> {latch.countDown(); log.info(e.toString());}); + eventManager.onEvent(EventSocketSubscriptionFailureEvent.class, e -> {latch.countDown(); log.info("sub error");}); + // Join the twitch chat of this channel(s) and enable stream/follow events - if (config.getList("CHANNEL_USERNAME") == null) { - subscribeToEvents(p, config.getString("CHANNEL_USERNAME")); + if (config.getList("CHANNEL_USERNAME") == null) { // If field is not a list (single channel) + subscribeToEvents(p, latch, config.getString("CHANNEL_USERNAME")); } else { for (String channel : config.getStringList("CHANNEL_USERNAME")) { - subscribeToEvents(p, channel); + subscribeToEvents(p, latch, channel); } - } + } + + try { + client.getEventManager().getEventHandler(SimpleEventHandler.class).registerListener(eventHandler); + latch.await(); + } catch (InterruptedException e) { + log.warning("Failed to bind events."); + return; + } utils.sendMessage(p, "Twitch client was started successfully!"); accountConnected = true; @@ -344,97 +427,35 @@ public void uncaughtException(Thread t, Throwable e) { }); } - public void subscribeToEvents(CommandSender p, String channel) { + public void subscribeToEvents(CommandSender p, CountDownLatch latch, String channel) { String channel_id = getUserId(channel); - eventSocket = client.getEventSocket(); - eventManager = client.getEventManager(); - - CountDownLatch latch = new CountDownLatch(3); - eventManager.onEvent(EventSocketSubscriptionSuccessEvent.class, e -> latch.countDown()); - eventManager.onEvent(EventSocketSubscriptionFailureEvent.class, e -> latch.countDown()); if (Rewards.getRewards(Rewards.rewardType.CHANNEL_POINTS) != null) { client.getPubSub().listenForChannelPointsRedemptionEvents(null, channel_id); - eventManager.onEvent(RewardRedeemedEvent.class, new Consumer() { - @Override - public void accept(RewardRedeemedEvent e) { - eventHandler.onChannelPointsRedemption(e); - } - }); utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s channel point redemptions..."); } + if (Rewards.getRewards(Rewards.rewardType.FOLLOW) != null) { if (TwitchUtils.getModeratedChannelIDs(oauth.getAccessToken(), user_id).contains(channel_id) || user_id.equals(channel_id)) { // If account is the streamer or a mod (need to have mod permissions on the channel) eventSocket.register(SubscriptionTypes.CHANNEL_FOLLOW_V2.prepareSubscription(b -> b.moderatorUserId(user_id).broadcasterUserId(channel_id).build(), null)); - eventManager.onEvent(ChannelFollowEvent.class, new Consumer() { - @Override - public void accept(ChannelFollowEvent e) { - try { // May get NullPointerException if event is triggered while still subscribing - eventHandler.onFollow(e); - } catch (NullPointerException ex) {} - } - }); utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s follows..."); } else { log.warning("Follow events cannot be listened to on unauthorised channels."); + latch.countDown(); } - } else latch.countDown(); + } if (Rewards.getRewards(Rewards.rewardType.CHEER) != null) { eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_MESSAGE.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); - eventManager.onEvent(ChannelChatMessageEvent.class, new Consumer() { - @Override - public void accept(ChannelChatMessageEvent e) { - try { // May get NullPointerException if event is triggered while still subscribing - eventHandler.onCheer(e); - } catch (NullPointerException ex) {} - } - }); utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s Cheers..."); - } else latch.countDown(); + } if (Rewards.getRewards(Rewards.rewardType.SUB) != null || Rewards.getRewards(Rewards.rewardType.GIFT) != null) { eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_NOTIFICATION.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); - eventManager.onEvent(ChannelChatNotificationEvent.class, new Consumer(){ - @Override - public void accept(ChannelChatNotificationEvent e) { - try { // May get NullPointerException if event is triggered while still subscribing - eventHandler.onEvent(e); - } catch (NullPointerException ex) {} - } - }); utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s subscriptions and gifts..."); - } else latch.countDown(); - - if (config.getBoolean("SHOW_CHAT")) { - eventManager.onEvent(ChannelMessageEvent.class, event -> { - if (!chatBlacklist.contains(event.getUser().getName())) { - net.md_5.bungee.api.ChatColor mcColor; - try { - mcColor = ColorUtils.getClosestChatColor(new Color(ColorUtils.hexToRgb(event.getMessageEvent().getUserChatColor().get()))); - } catch (Exception e) { - mcColor = net.md_5.bungee.api.ChatColor.RED; - } - BaseComponent[] components = new BaseComponent[] { - new ComponentBuilder(mcColor + event.getMessageEvent().getUserDisplayName().get() + ": ").create()[0], - new ComponentBuilder(event.getMessage()).create()[0] - }; - for (Player player : Bukkit.getOnlinePlayers()) { - if (player.hasPermission(permissions.BROADCAST.permission_id)) { - utils.sendMessage(player, components); - } - } - } - }); } - client.getEventManager().getEventHandler(SimpleEventHandler.class).registerListener(eventHandler); utils.sendMessage(Bukkit.getConsoleSender(), "Listening to " + channel + "'s events..."); - client.getChat().joinChannel(channel); - try { - latch.await(); - } catch (InterruptedException e1) { - log.warning("Failed to listen to " + channel + "'s events. Channel may not exist or the linked account may lack permissions."); - } + client.getChat().joinChannel(channel); } public void unlink(CommandSender p) { if (!accountConnected) { From c1f5030837997ce3807044f8f720ca618a484c38 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sat, 31 Aug 2024 22:44:02 +0200 Subject: [PATCH 04/23] Update status command --- .../java/me/gosdev/chatpointsttv/ChatPointsTTV.java | 12 +++++------- .../me/gosdev/chatpointsttv/CommandController.java | 8 +++++++- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index f95daf1..a4f2fe6 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -146,13 +146,11 @@ public static Map getRedemptionStrings() { public String getConnectedUsername() { return accountConnected ? user.getLogin() : "Not Linked"; } - public String getListenedChannel() { - if (plugin != null) { - return client.getChat().getChannels().iterator().next(); // UNTESTED - } else { - if (plugin.config.getString("TWITCH_CHANNEL_USERNAME") == null | plugin.config.getString("TWITCH_CHANNEL_USERNAME").startsWith("MemorySection[path=")) return null; // Invalid string (probably left default "{YOUR CHANNEL}")) return null; - return plugin.config.getString("TWITCH_CHANNEL_USERNAME"); - } + public List getListenedChannels() { + List channels = new ArrayList<>(); + if (plugin.config.getStringList("CHANNEL_USERNAME") != null) channels = plugin.config.getStringList("CHANNEL_USERNAME"); + else channels.add(plugin.config.getString("CHANNEL_USERNAME")); + return channels; } private static Utils utils; diff --git a/core/src/main/java/me/gosdev/chatpointsttv/CommandController.java b/core/src/main/java/me/gosdev/chatpointsttv/CommandController.java index d63db00..3f30cba 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/CommandController.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/CommandController.java @@ -144,11 +144,17 @@ private void help(CommandSender p) { } private void status(CommandSender p, ChatPointsTTV plugin) { + List channels = plugin.getListenedChannels(); + String strChannels = ""; + for (int i = 0; i < channels.size(); i++) { + strChannels += channels.get(i); + if (i != channels.size() - 1) strChannels += ", "; + } String msg = ( "---------- " + ChatColor.DARK_PURPLE + ChatColor.BOLD + "ChatPointsTTV status" + ChatColor.RESET + " ----------\n" + ChatColor.LIGHT_PURPLE + "Plugin version: " + ChatColor.RESET + "v" +plugin.getDescription().getVersion() + "\n" + ChatColor.LIGHT_PURPLE + "Connected account: " + ChatColor.RESET + plugin.getConnectedUsername() + "\n" + - ChatColor.LIGHT_PURPLE + "Listened channel: " + ChatColor.RESET + plugin.getListenedChannel() + "\n" + + ChatColor.LIGHT_PURPLE + "Listened channels: " + ChatColor.RESET + strChannels + "\n" + "\n" + ChatColor.LIGHT_PURPLE + "Connection status: " + (plugin.isAccountConnected() ? ChatColor.GREEN + "" + ChatColor.BOLD + "ACTIVE" : ChatColor.RED + "" + ChatColor.BOLD + "DISCONNECTED") ); From 31a02f3110aac55e171f1587294eab20a373020f Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sat, 31 Aug 2024 22:44:19 +0200 Subject: [PATCH 05/23] Remove debugging messages --- .../src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index a4f2fe6..b366a19 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -387,10 +387,9 @@ public void accept(ChannelChatNotificationEvent e) { } CountDownLatch latch = new CountDownLatch(subs * channels); - log.info(String.valueOf(subs * channels)); - eventManager.onEvent(EventSocketSubscriptionSuccessEvent.class, e -> {latch.countDown(); log.info(e.toString());}); - eventManager.onEvent(EventSocketSubscriptionFailureEvent.class, e -> {latch.countDown(); log.info("sub error");}); + eventManager.onEvent(EventSocketSubscriptionSuccessEvent.class, e -> latch.countDown()); + eventManager.onEvent(EventSocketSubscriptionFailureEvent.class, e -> latch.countDown()); // Join the twitch chat of this channel(s) and enable stream/follow events if (config.getList("CHANNEL_USERNAME") == null) { // If field is not a list (single channel) From 7887b3a9a0cb879cb113c0c00f11e1caea845c35 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sun, 1 Sep 2024 21:18:25 +0200 Subject: [PATCH 06/23] Streamer-specific events + corrected README --- README.md | 23 ++++++-- .../gosdev/chatpointsttv/Rewards/Reward.java | 15 ++++- .../gosdev/chatpointsttv/Rewards/Rewards.java | 55 +++++++++++++------ .../chatpointsttv/TwitchEventHandler.java | 55 +++++++++++-------- core/src/main/resources/config.yml | 9 ++- 5 files changed, 110 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 3723f00..17a14dd 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ These are the only official download mirrors. Any downloads besides of these lin > [!TIP] > If needed, you can copy-paste the names of the Channel Points Rewards into a text document for later use. -3. Set your [config.yml](core/src/main/resources/config.yml) up. Adjust the settings and add and setup the actions for rewards, donations... You will need to link a Twitch account in order to connect use the Twitch API (the linked account **needs to own/moderate all Twitch channels** set in config.yml) There are two ways to link your Twitch account to the plugin: +3. Set your [config.yml](core/src/main/resources/config.yml) up. Adjust the settings and setup events for rewards, donations... You will need to link a Twitch account in order to connect use the Twitch API (the linked account **needs to own/moderate all Twitch channels** set in config.yml) There are two ways to link your Twitch account to the plugin: - **Using a key-based authentication** *(recommended)*: You will need a Client ID and Access token. You can get one mannually or through a website as [Twitch Token Generator](https://twitchtokengenerator.com). Make sure to add all the [needed scopes](#twitch-scopes). @@ -45,7 +45,7 @@ These are the only official download mirrors. Any downloads besides of these lin ## **config.yml docs** To reset the original configuration, delete `config.yml` and reload the plugin. The file will regenerate automatically. *Sections with a (\*) are required to be changed in order to the plugin to be used.* -* **Channel Username***: The channel(s) that will be listened for rewards, bits and subs. (In case of multiple channels, they muse be added as a list: `["channel_1", "channel_2", "..."]`) +* **Channel Username***: The channel(s) that will be listened for rewards, bits and subs. (In case of multiple channels, they must be added as a list: `["channel_1", "channel_2", "..."]`) * **Custom Client ID**: Client ID used for key-based authorization. Leave commented if it's not being used. * **Custom Access Token**: Access token used for key-based authorization. Leave commented if it's not being used. * **Show Chat**: If enabled, your stream chat will be shown in-game to all players in the server. @@ -110,7 +110,7 @@ Currently, there are 2 types of actions: > Argument names surrounded by <> means that it is a required argument. > Arguments surrounded by [] are optional. -You should set up your events in your config file with this format: +You should set up your events in your config file following this format: ``` TYPE_REWARDS: - KEY: @@ -118,9 +118,24 @@ TYPE_REWARDS: - Action 2 - ... ``` +or +``` +TYPE_REWARDS: + - KEY: + - STREAMER: + - Action 1 + - Action 2 + - ... + + - default: + - Action +``` Whereas `TYPE_REWARDS` is replaces with the appropiate config key that is already on the file, `KEY` with the channel points reward name, subscription tier or minimal amount of bits/subs. > [!IMPORTANT] -> **For follow events this line should be ommited.** See the placeholders on the default [config.yml](core/src/main/resources/config.yml). +> **For follow events you shouldn't add reward keys.** See placeholders on the default [config.yml](core/src/main/resources/config.yml). + +> [!TIP] +> You can now target multiple channels. If you do so, you can target some events to a specific channel following the second format. You can still follow the first example if you don't aim to target specific channels. ## Twitch Scopes The latest version of the plugin needs the following scopes to function propertly: diff --git a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Reward.java b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Reward.java index c918ad8..fcf4e23 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Reward.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Reward.java @@ -2,15 +2,22 @@ import java.util.List; +import me.gosdev.chatpointsttv.ChatPointsTTV; import me.gosdev.chatpointsttv.Rewards.Rewards.rewardType; public class Reward { rewardType type; private String event; private List cmds; + private String channel; + private String channelId; - public Reward (rewardType type, String event, List cmds) { + public Reward (rewardType type, String channel, String event, List cmds) { this.type = type; + this.channel = channel; + + channelId = channel.equals(Rewards.EVERYONE) ? "*" : ChatPointsTTV.getPlugin().getUserId(channel); + this.event = event; this.cmds = cmds; } @@ -24,4 +31,10 @@ public List getCommands() { public rewardType getType() { return type; } + public String getChannel() { + return channel; + } + public String getTargetId() { + return channelId; + } } \ No newline at end of file diff --git a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java index e7e5d9d..ddabf00 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java @@ -2,12 +2,11 @@ import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.Set; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; import me.gosdev.chatpointsttv.ChatPointsTTV; public class Rewards { @@ -19,29 +18,51 @@ public static enum rewardType { GIFT }; + public static final String EVERYONE = "*"; + public static Map> rewards = new HashMap>(); public static ArrayList getRewards(rewardType type) { - if (rewards.get(type) != null) return rewards.get(type); // Give stored dictionary if it was already fetched + //if (rewards.get(type) != null) return rewards.get(type); // Give stored dictionary if it was already fetched + FileConfiguration config = ChatPointsTTV.getPlugin().config; - ConfigurationSection config_value = ChatPointsTTV.getPlugin().config.getConfigurationSection(type.toString().toUpperCase() + "_REWARDS"); + ConfigurationSection config_rewards = config.getConfigurationSection(type.toString().toUpperCase() + "_REWARDS"); ArrayList reward_list = new ArrayList<>(); + if (type == rewardType.FOLLOW) { - List follow_rewards = ChatPointsTTV.getPlugin().config.getStringList(type.toString().toUpperCase() + "_REWARDS"); - if (follow_rewards == null || follow_rewards.isEmpty()) return null; - reward_list.add(new Reward(type, null, follow_rewards)); - } else { - Set keys = config_value.getKeys(false); - if (config_value == null || keys.size() == 0) return null; - Iterator iterator = keys.iterator(); - for (int i = 0; i < keys.size(); i++) { - String key = iterator.next().toString(); - - reward_list.add(new Reward(type, key, config_value.getStringList(key))); + if (config_rewards == null && config.getStringList(type.toString().toUpperCase() + "_REWARDS") != null) { + // Global events + reward_list.add(new Reward(type, EVERYONE, null, config.getStringList(type.toString().toUpperCase() + "_REWARDS"))); + } else { + // Streamer specific events + Set keys = config_rewards.getKeys(false); + for (String channel : keys) { + reward_list.add(new Reward(type, channel.equals("default") ? EVERYONE : channel, null, config_rewards.getStringList(channel))); + } + } + rewards.put(type, reward_list); + return reward_list; + + } else if (config_rewards != null) { + Set keys = config_rewards.getKeys(false); + + for (String key : keys) { + ConfigurationSection channelSection = config_rewards.getConfigurationSection(key); + if (channelSection == null) { + // No channel specified + reward_list.add(new Reward(type, EVERYONE, key, config_rewards.getStringList(key))); + } else { + // Streamer specific event + Set channelKeys = channelSection.getKeys(false); + for (String channel : channelKeys) { + reward_list.add(new Reward(type, channel.equals("default") ? EVERYONE : channel, key, channelSection.getStringList(channel))); + } + } } + rewards.put(type, reward_list); + return reward_list; } - rewards.put(type, reward_list); - return reward_list; + return null; } } diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index 61d5777..39a8125 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -36,10 +36,12 @@ public class TwitchEventHandler { public void onChannelPointsRedemption(RewardRedeemedEvent event) { - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getRedemption().getUser().getDisplayName() + " has redeemed " + event.getRedemption().getReward().getTitle()); + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getRedemption().getUser().getDisplayName() + " has redeemed " + event.getRedemption().getReward().getTitle() + " in " + plugin.getUsername(event.getRedemption().getChannelId())); ChannelPointsRedemption redemption = event.getRedemption(); for (Reward reward : Rewards.getRewards(rewardType.CHANNEL_POINTS)) { if (!reward.getEvent().equalsIgnoreCase(redemption.getReward().getTitle())) continue; + if (!reward.getTargetId().equals(redemption.getChannelId())) continue; + String custom_string = ChatPointsTTV.getRedemptionStrings().get("REDEEMED_STRING"); Events.displayTitle(redemption.getUser().getDisplayName(), custom_string, redemption.getReward().getTitle(), action_color, user_color, rewardBold); for (String cmd : reward.getCommands()) { @@ -54,23 +56,26 @@ public void onChannelPointsRedemption(RewardRedeemedEvent event) { } public void onFollow(ChannelFollowEvent event) { - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getUserName() + " started following you"); + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getUserName() + " started following " + event.getBroadcasterUserName()); String custom_string = ChatPointsTTV.getRedemptionStrings().get("FOLLOWED_STRING"); Events.displayTitle(event.getUserName(), custom_string, "", action_color, user_color, rewardBold); - for (String cmd : Rewards.getRewards(rewardType.FOLLOW).get(0).getCommands()) { - String[] parts = cmd.split(" ", 2); - try { - Events.runAction(parts[0], parts[1], event.getUserName()); - } catch (Exception e) { - plugin.log.warning(e.toString()); - } - + for (Reward reward : Rewards.getRewards(rewardType.FOLLOW)) { + if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; + + for (String cmd : reward.getCommands()) { + String[] parts = cmd.split(" ", 2); + try { + Events.runAction(parts[0], parts[1], event.getUserName()); + } catch (Exception e) { + plugin.log.warning(e.toString()); + } + } } } public void onCheer(ChannelChatMessageEvent event) { if (event.getCheer() == null) return; - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " cheered " + event.getCheer().getBits() + " bits!"); + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " cheered " + event.getCheer().getBits() + " bits to " + event.getBroadcasterUserName() + "!"); String chatter = event.getChatterUserName(); int amount = event.getCheer().getBits(); @@ -80,10 +85,12 @@ public void onCheer(ChannelChatMessageEvent event) { ArrayList rewards = Rewards.getRewards(rewardType.CHEER); Collections.sort(rewards, new RewardComparator()); - for (Reward i : rewards) { - if (amount >= Integer.parseInt(i.getEvent())) { + for (Reward reward : rewards) { + if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; + + if (amount >= Integer.parseInt(reward.getEvent())) { Events.displayTitle(chatter, custom_string, amount + " bits", action_color, user_color, rewardBold); - for (String cmd : i.getCommands()) { + for (String cmd : reward.getCommands()) { String[] parts = cmd.split(" ", 2); try { Events.runAction(parts[0], parts[1], event.getChatterUserName()); @@ -98,7 +105,7 @@ public void onCheer(ChannelChatMessageEvent event) { public void onEvent(ChannelChatNotificationEvent event) { if (listenForGifts && (event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT | event.getNoticeType() == NoticeType.SUB_GIFT)) { - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " gifted a sub!"); + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " gifted a sub for " + event.getBroadcasterUserName() + "'s channel!"); int amount = 1; String chatter = event.getChatterUserName(); @@ -113,10 +120,12 @@ public void onEvent(ChannelChatNotificationEvent event) { ArrayList rewards = Rewards.getRewards(rewardType.GIFT); Collections.sort(rewards, Collections.reverseOrder()); - for (Reward i : rewards) { - if (amount >= Integer.parseInt(i.getEvent())) { + for (Reward reward : rewards) { + if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; + + if (amount >= Integer.parseInt(reward.getEvent())) { Events.displayTitle(chatter, custom_string, amount + " " + tier + " subs", action_color, user_color, rewardBold); - for (String cmd : i.getCommands()) { + for (String cmd : reward.getCommands()) { String[] parts = cmd.split(" ", 2); try { Events.runAction(parts[0], parts[1], event.getChatterUserName()); @@ -147,13 +156,15 @@ public void onEvent(ChannelChatNotificationEvent event) { return; } - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " subscribed with a " + ChatPointsTTV.getUtils().PlanToString(tier) + " sub!"); - for (Reward i : Rewards.getRewards(rewardType.SUB)) { - if (i.getEvent().equals(ChatPointsTTV.getUtils().PlanToConfig(tier))) { + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " subscribed with a " + ChatPointsTTV.getUtils().PlanToString(tier) + " sub to " + event.getBroadcasterUserName() + "!"); + for (Reward reward : Rewards.getRewards(rewardType.SUB)) { + if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; + + if (reward.getEvent().equals(ChatPointsTTV.getUtils().PlanToConfig(tier))) { String custom_string = ChatPointsTTV.getRedemptionStrings().get("SUB_STRING"); Events.displayTitle(event.getChatterUserName(), custom_string, ChatPointsTTV.getUtils().PlanToString(tier), action_color, user_color, rewardBold); - for (String cmd : i.getCommands()) { + for (String cmd : reward.getCommands()) { String[] parts = cmd.split(" ", 2); try { Events.runAction(parts[0], parts[1], event.getChatterUserName()); diff --git a/core/src/main/resources/config.yml b/core/src/main/resources/config.yml index a7de77d..b82bfe2 100644 --- a/core/src/main/resources/config.yml +++ b/core/src/main/resources/config.yml @@ -33,23 +33,26 @@ SHOW_CHAT: true # If your reward contains a text input, you can reference it as: # {TEXT} **ONLY SUPPORTED ON CHANNEL POINTS** +# To add a streamer-specific reward add the actions inside a list named as the desired channel. +# To target all channels use "default" as the list key. + # Leave any reward class empty to disable it. CHANNEL_POINTS_REWARDS: [REWARD NAME]: - {ACTION 1} - {ACTION 2} -# Put the desired action after the colon in the form of a list. You musn't add a "Reward Name". +# Put the desired action after the colon as a list. You musn't add a "Reward Name". FOLLOW_REWARDS: - {ACTION} - {ACTION} -# Follow the same format as the Channel Point Rewards, replacing the name of the reward for the minimum ammount of bits that needs to be cheered. +# Follow the same format as Channel Point Rewards, replacing the name of the reward for the minimum ammount of bits that needs to be cheered. CHEER_REWARDS: [BITS AMOUNT]: - {ACTION} -# Follow the same format as the Channel Point Rewards, replacing the name of the reward for the desired sub tier: TWITCH_PRIME/TIER1/TIER2/TIER3. +# Follow the same format as Channel Point Rewards, replacing the name of the reward for the desired sub tier: TWITCH_PRIME/TIER1/TIER2/TIER3. # Also you can enter an AMOUNT on GIFT_REWARDS to toggle actions with sub gifting SUB_REWARDS: [TWITCH_PRIME]: From 2f76c46a3a499bf707a5ab356b051c04ac559ae9 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:29:09 +0200 Subject: [PATCH 07/23] Check for query failure and throw error --- .../java/me/gosdev/chatpointsttv/ChatPointsTTV.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index b366a19..fd16e4b 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -114,9 +114,19 @@ public static ChatPointsTTV getPlugin() { } public String getUserId(String username) { - UserList resultList = getTwitchClient().getHelix().getUsers(null, null, Arrays.asList(username)).execute(); + UserList resultList = getTwitchClient().getHelix().getUsers(oauth.getAccessToken(), null, Arrays.asList(username)).execute(); + if (resultList.getUsers().isEmpty()) { + throw new NullPointerException("Couldn't fetch user: " + username); + } return resultList.getUsers().get(0).getId(); } + public String getUsername(String userId) { + UserList resultList = client.getHelix().getUsers(oauth.getAccessToken(), Arrays.asList(userId), null).execute(); + if (resultList.getUsers().isEmpty()) { + throw new NullPointerException("Couldn't fetch user ID: " + userId); + } + return resultList.getUsers().get(0).getDisplayName(); + } public static ITwitchClient getTwitchClient() { return client; From 0cf5907d38d0de757ff22faf8e63ec0664f5e139 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Tue, 3 Sep 2024 13:41:22 +0200 Subject: [PATCH 08/23] Remove some log messages --- .../main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index fd16e4b..96bd0b8 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -439,27 +439,23 @@ public void subscribeToEvents(CommandSender p, CountDownLatch latch, String chan if (Rewards.getRewards(Rewards.rewardType.CHANNEL_POINTS) != null) { client.getPubSub().listenForChannelPointsRedemptionEvents(null, channel_id); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s channel point redemptions..."); } if (Rewards.getRewards(Rewards.rewardType.FOLLOW) != null) { if (TwitchUtils.getModeratedChannelIDs(oauth.getAccessToken(), user_id).contains(channel_id) || user_id.equals(channel_id)) { // If account is the streamer or a mod (need to have mod permissions on the channel) eventSocket.register(SubscriptionTypes.CHANNEL_FOLLOW_V2.prepareSubscription(b -> b.moderatorUserId(user_id).broadcasterUserId(channel_id).build(), null)); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s follows..."); } else { - log.warning("Follow events cannot be listened to on unauthorised channels."); + log.warning(channel + ": Follow events cannot be listened to on unauthorised channels."); latch.countDown(); } } if (Rewards.getRewards(Rewards.rewardType.CHEER) != null) { eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_MESSAGE.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s Cheers..."); } if (Rewards.getRewards(Rewards.rewardType.SUB) != null || Rewards.getRewards(Rewards.rewardType.GIFT) != null) { eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_NOTIFICATION.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); - utils.sendMessage(Bukkit.getConsoleSender(), "Listening for " + channel + "'s subscriptions and gifts..."); } utils.sendMessage(Bukkit.getConsoleSender(), "Listening to " + channel + "'s events..."); client.getChat().joinChannel(channel); From 347d39bc6f0bf9d021e32b9355edb73006746749 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sat, 7 Sep 2024 03:46:37 +0200 Subject: [PATCH 09/23] Experimental sub gift events --- .../java/me/gosdev/chatpointsttv/ChatPointsTTV.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index 96bd0b8..dc54a32 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -35,6 +35,7 @@ import com.github.twitch4j.eventsub.events.ChannelChatMessageEvent; import com.github.twitch4j.eventsub.events.ChannelChatNotificationEvent; import com.github.twitch4j.eventsub.events.ChannelFollowEvent; +import com.github.twitch4j.eventsub.events.ChannelSubscriptionGiftEvent; import com.github.twitch4j.eventsub.socket.IEventSubSocket; import com.github.twitch4j.eventsub.socket.events.EventSocketSubscriptionFailureEvent; import com.github.twitch4j.eventsub.socket.events.EventSocketSubscriptionSuccessEvent; @@ -87,6 +88,7 @@ public class ChatPointsTTV extends JavaPlugin { private final static String ClientID = "1peexftcqommf5tf5pt74g7b3gyki3"; public final String scopes = Scopes.join( Scopes.CHANNEL_READ_REDEMPTIONS, + Scopes.CHANNEL_READ_SUBSCRIPTIONS, Scopes.USER_READ_MODERATED_CHANNELS, Scopes.MODERATOR_READ_FOLLOWERS, Scopes.BITS_READ, @@ -373,6 +375,13 @@ public void accept(ChannelChatNotificationEvent e) { } catch (NullPointerException ex) {} } }); + eventManager.onEvent(ChannelSubscriptionGiftEvent.class, new Consumer() { + @Override + public void accept(ChannelSubscriptionGiftEvent e) { + log.info(e.getUserName()); + log.info(e.getTotal() + " subs"); + } + }); } if (config.getBoolean("SHOW_CHAT")) { eventManager.onEvent(ChannelMessageEvent.class, event -> { @@ -456,6 +465,7 @@ public void subscribeToEvents(CommandSender p, CountDownLatch latch, String chan if (Rewards.getRewards(Rewards.rewardType.SUB) != null || Rewards.getRewards(Rewards.rewardType.GIFT) != null) { eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_NOTIFICATION.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); + eventSocket.register(SubscriptionTypes.CHANNEL_SUBSCRIPTION_GIFT.prepareSubscription(b -> b.broadcasterUserId(channel_id).build(), null)); } utils.sendMessage(Bukkit.getConsoleSender(), "Listening to " + channel + "'s events..."); client.getChat().joinChannel(channel); From 53eb3f1bbb33e2de2192335709a5e9e420abbfa7 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sun, 8 Sep 2024 03:34:13 +0200 Subject: [PATCH 10/23] Split channel.chat.notification events into 2 functions --- .../gosdev/chatpointsttv/ChatPointsTTV.java | 14 +-- .../chatpointsttv/TwitchEventHandler.java | 116 ++++++++---------- 2 files changed, 56 insertions(+), 74 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index dc54a32..a7736a9 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -32,10 +32,10 @@ import com.github.twitch4j.TwitchClientBuilder; import com.github.twitch4j.auth.providers.TwitchIdentityProvider; import com.github.twitch4j.chat.events.channel.ChannelMessageEvent; +import com.github.twitch4j.eventsub.domain.chat.NoticeType; import com.github.twitch4j.eventsub.events.ChannelChatMessageEvent; import com.github.twitch4j.eventsub.events.ChannelChatNotificationEvent; import com.github.twitch4j.eventsub.events.ChannelFollowEvent; -import com.github.twitch4j.eventsub.events.ChannelSubscriptionGiftEvent; import com.github.twitch4j.eventsub.socket.IEventSubSocket; import com.github.twitch4j.eventsub.socket.events.EventSocketSubscriptionFailureEvent; import com.github.twitch4j.eventsub.socket.events.EventSocketSubscriptionSuccessEvent; @@ -371,17 +371,12 @@ public void accept(ChannelChatMessageEvent e) { @Override public void accept(ChannelChatNotificationEvent e) { try { // May get NullPointerException if event is triggered while still subscribing - eventHandler.onEvent(e); + if (e.getNoticeType() == NoticeType.SUB || e.getNoticeType() == NoticeType.RESUB) eventHandler.onSub(e); + else if (e.getNoticeType() == NoticeType.SUB_GIFT) eventHandler.onSubGift(e); + else return; } catch (NullPointerException ex) {} } }); - eventManager.onEvent(ChannelSubscriptionGiftEvent.class, new Consumer() { - @Override - public void accept(ChannelSubscriptionGiftEvent e) { - log.info(e.getUserName()); - log.info(e.getTotal() + " subs"); - } - }); } if (config.getBoolean("SHOW_CHAT")) { eventManager.onEvent(ChannelMessageEvent.class, event -> { @@ -465,7 +460,6 @@ public void subscribeToEvents(CommandSender p, CountDownLatch latch, String chan if (Rewards.getRewards(Rewards.rewardType.SUB) != null || Rewards.getRewards(Rewards.rewardType.GIFT) != null) { eventSocket.register(SubscriptionTypes.CHANNEL_CHAT_NOTIFICATION.prepareSubscription(b -> b.broadcasterUserId(channel_id).userId(user_id).build(), null)); - eventSocket.register(SubscriptionTypes.CHANNEL_SUBSCRIPTION_GIFT.prepareSubscription(b -> b.broadcasterUserId(channel_id).build(), null)); } utils.sendMessage(Bukkit.getConsoleSender(), "Listening to " + channel + "'s events..."); client.getChat().joinChannel(channel); diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index 39a8125..9c186f4 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -32,8 +32,6 @@ public class TwitchEventHandler { ChatColor action_color = ChatPointsTTV.getChatColors().get("ACTION_COLOR"); ChatColor user_color = ChatPointsTTV.getChatColors().get("USER_COLOR"); - private Integer ignoreSubs = 0; - public void onChannelPointsRedemption(RewardRedeemedEvent event) { if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getRedemption().getUser().getDisplayName() + " has redeemed " + event.getRedemption().getReward().getTitle() + " in " + plugin.getUsername(event.getRedemption().getChannelId())); @@ -103,77 +101,67 @@ public void onCheer(ChannelChatMessageEvent event) { } } - public void onEvent(ChannelChatNotificationEvent event) { - if (listenForGifts && (event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT | event.getNoticeType() == NoticeType.SUB_GIFT)) { - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " gifted a sub for " + event.getBroadcasterUserName() + "'s channel!"); - - int amount = 1; - String chatter = event.getChatterUserName(); - String tier; - - ignoreSubs += event.getSubGift().getCumulativeTotal(); // Multiple sub gifting triggers both events - amount = event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT ? event.getCommunitySubGift().getCumulativeTotal() : event.getSubGift().getCumulativeTotal(); - tier = event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT ? ChatPointsTTV.getUtils().PlanToString(event.getCommunitySubGift().getSubTier()) : ChatPointsTTV.getUtils().PlanToString(event.getSubGift().getSubTier()); - - - String custom_string = ChatPointsTTV.getRedemptionStrings().get("GIFT_STRING"); - ArrayList rewards = Rewards.getRewards(rewardType.GIFT); - Collections.sort(rewards, Collections.reverseOrder()); - - for (Reward reward : rewards) { - if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; - - if (amount >= Integer.parseInt(reward.getEvent())) { - Events.displayTitle(chatter, custom_string, amount + " " + tier + " subs", action_color, user_color, rewardBold); - for (String cmd : reward.getCommands()) { - String[] parts = cmd.split(" ", 2); - try { - Events.runAction(parts[0], parts[1], event.getChatterUserName()); - } catch (Exception e) { - plugin.log.warning(e.toString()); - } + public void onSub(ChannelChatNotificationEvent event) { + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " has subscribed to " + event.getBroadcasterUserName() + " with a " + event.getSub().getSubTier().toString() + " sub!"); + + SubscriptionPlan tier; + + if (event.getNoticeType() == NoticeType.SUB) { + if (event.getSub().isPrime()) tier = SubscriptionPlan.TWITCH_PRIME; + else tier = event.getSub().getSubTier(); + + } else if (event.getNoticeType() == NoticeType.RESUB) { + if (event.getResub().isPrime()) tier = SubscriptionPlan.TWITCH_PRIME; + else tier = event.getResub().getSubTier(); + + } else { + plugin.log.warning("Couldn't fetch sub type!"); + return; + } + + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " subscribed with a " + ChatPointsTTV.getUtils().PlanToString(tier) + " sub to " + event.getBroadcasterUserName() + "!"); + for (Reward reward : Rewards.getRewards(rewardType.SUB)) { + + if (reward.getEvent().equals(ChatPointsTTV.getUtils().PlanToConfig(tier))) { + String custom_string = ChatPointsTTV.getRedemptionStrings().get("SUB_STRING"); + + Events.displayTitle(event.getChatterUserName(), custom_string, ChatPointsTTV.getUtils().PlanToString(tier), action_color, user_color, rewardBold); + for (String cmd : reward.getCommands()) { + String[] parts = cmd.split(" ", 2); + try { + Events.runAction(parts[0], parts[1], event.getChatterUserName()); + } catch (Exception e) { + plugin.log.warning(e.toString()); } - break; } } - } else if (listenForSubs && (event.getNoticeType() == NoticeType.SUB | event.getNoticeType() == NoticeType.RESUB)) { - SubscriptionPlan tier; - if (ignoreSubs > 0) { - ignoreSubs -= 1; - return; - } + } + } - if (event.getNoticeType() == NoticeType.SUB) { - if (event.getSub().isPrime()) tier = SubscriptionPlan.TWITCH_PRIME; - else tier = event.getSub().getSubTier(); + public void onSubGift(ChannelChatNotificationEvent event) { + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " has gifted " + event.getSubGift().getCumulativeTotal().toString() + " subs in " + event.getBroadcasterUserName() + "'s' channel!"); + + String chatter = event.getChatterUserName(); + Integer amount = event.getSubGift().getCumulativeTotal(); + String tier = ChatPointsTTV.getUtils().PlanToString(event.getSubGift().getSubTier()); // event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT ? ChatPointsTTV.getUtils().PlanToString(event.getCommunitySubGift().getSubTier()) : - } else if (event.getNoticeType() == NoticeType.RESUB) { - if (event.getResub().isPrime()) tier = SubscriptionPlan.TWITCH_PRIME; - else tier = event.getResub().getSubTier(); - } else { - plugin.log.warning("Couldn't fetch sub type!"); - return; - } + String custom_string = ChatPointsTTV.getRedemptionStrings().get("GIFT_STRING"); + ArrayList rewards = Rewards.getRewards(rewardType.GIFT); + Collections.sort(rewards, Collections.reverseOrder()); - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " subscribed with a " + ChatPointsTTV.getUtils().PlanToString(tier) + " sub to " + event.getBroadcasterUserName() + "!"); - for (Reward reward : Rewards.getRewards(rewardType.SUB)) { - if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; - - if (reward.getEvent().equals(ChatPointsTTV.getUtils().PlanToConfig(tier))) { - String custom_string = ChatPointsTTV.getRedemptionStrings().get("SUB_STRING"); - - Events.displayTitle(event.getChatterUserName(), custom_string, ChatPointsTTV.getUtils().PlanToString(tier), action_color, user_color, rewardBold); - for (String cmd : reward.getCommands()) { - String[] parts = cmd.split(" ", 2); - try { - Events.runAction(parts[0], parts[1], event.getChatterUserName()); - } catch (Exception e) { - plugin.log.warning(e.toString()); - } - } + Events.displayTitle(chatter, custom_string, amount + " " + tier + " subs", action_color, user_color, rewardBold); + + for (Reward reward : rewards) { + for (String cmd : reward.getCommands()) { + String[] parts = cmd.split(" ", 2); + try { + Events.runAction(parts[0], parts[1], event.getChatterUserName()); + } catch (Exception e) { + plugin.log.warning(e.toString()); } } + break; } } } From 13fd35e2a473018ab2f257a1fad009e814617e53 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sun, 8 Sep 2024 03:34:30 +0200 Subject: [PATCH 11/23] Fix streamer check --- .../java/me/gosdev/chatpointsttv/TwitchEventHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index 9c186f4..b6326b1 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -58,7 +58,7 @@ public void onFollow(ChannelFollowEvent event) { String custom_string = ChatPointsTTV.getRedemptionStrings().get("FOLLOWED_STRING"); Events.displayTitle(event.getUserName(), custom_string, "", action_color, user_color, rewardBold); for (Reward reward : Rewards.getRewards(rewardType.FOLLOW)) { - if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; + if (!reward.getTargetId().equals(event.getBroadcasterUserId()) && !reward.getTargetId().equals(Rewards.EVERYONE)) continue; for (String cmd : reward.getCommands()) { String[] parts = cmd.split(" ", 2); @@ -84,7 +84,7 @@ public void onCheer(ChannelChatMessageEvent event) { Collections.sort(rewards, new RewardComparator()); for (Reward reward : rewards) { - if (!reward.getTargetId().equals(event.getBroadcasterUserId())) continue; + if (!reward.getTargetId().equals(event.getBroadcasterUserId()) && !reward.getTargetId().equals(Rewards.EVERYONE)) continue; if (amount >= Integer.parseInt(reward.getEvent())) { Events.displayTitle(chatter, custom_string, amount + " bits", action_color, user_color, rewardBold); @@ -121,6 +121,7 @@ public void onSub(ChannelChatNotificationEvent event) { if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " subscribed with a " + ChatPointsTTV.getUtils().PlanToString(tier) + " sub to " + event.getBroadcasterUserName() + "!"); for (Reward reward : Rewards.getRewards(rewardType.SUB)) { + if (!reward.getTargetId().equals(event.getBroadcasterUserId()) && !reward.getTargetId().equals(Rewards.EVERYONE)) continue; if (reward.getEvent().equals(ChatPointsTTV.getUtils().PlanToConfig(tier))) { String custom_string = ChatPointsTTV.getRedemptionStrings().get("SUB_STRING"); @@ -153,6 +154,7 @@ public void onSubGift(ChannelChatNotificationEvent event) { Events.displayTitle(chatter, custom_string, amount + " " + tier + " subs", action_color, user_color, rewardBold); for (Reward reward : rewards) { + if (!reward.getTargetId().equals(event.getBroadcasterUserId()) && !reward.getTargetId().equals(Rewards.EVERYONE)) continue; for (String cmd : reward.getCommands()) { String[] parts = cmd.split(" ", 2); try { From 41a629723bd7c31ccac5f1e821ec13d6938fc4a9 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sun, 15 Sep 2024 15:19:09 +0200 Subject: [PATCH 12/23] Fix Comparator order --- .../java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java index 71e355c..012e548 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java @@ -19,7 +19,7 @@ public int compare(Reward o1, Reward o2) { }); - return Integer.parseInt(o1.getEvent()) - Integer.parseInt(o2.getEvent()); + return Integer.parseInt(o2.getEvent()) - Integer.parseInt(o1.getEvent()); } } From a032d4a2caab1cdd49668fdf3aa58c2e7a2260ad Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:42:41 +0200 Subject: [PATCH 13/23] Add new Scope --- README.md | 4 ++-- .../main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 17a14dd..204bb1e 100644 --- a/README.md +++ b/README.md @@ -144,8 +144,8 @@ The latest version of the plugin needs the following scopes to function propertl * `moderator:read:followers`: Needed to be able to listen for follows. * `bits:read`: Needed to listen for cheers. * `channel:read:subscriptions`: Needed to listen for subscriptions and gifts. -* `user:read:chat`: Needed to use Twitch EventSub API. -* `chat:read`: Needed to show your stream chat in-game. +* `chat:read` and `user:read:chat`: Needed to show your stream chat in-game and use EventSub API. +* `user:bot` and `channel:bot`: Joins a stream chat to listen for subs. ## Permissions - TARGET diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index a7736a9..034e42e 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -94,7 +94,9 @@ public class ChatPointsTTV extends JavaPlugin { Scopes.BITS_READ, Scopes.CHANNEL_READ_SUBSCRIPTIONS, Scopes.USER_READ_CHAT, - Scopes.CHAT_READ + Scopes.CHAT_READ, + Scopes.USER_BOT, + Scopes.CHANNEL_BOT ).replace(":", "%3A"); // Format colon character for browser private OAuth2Credential oauth; @@ -372,8 +374,7 @@ public void accept(ChannelChatMessageEvent e) { public void accept(ChannelChatNotificationEvent e) { try { // May get NullPointerException if event is triggered while still subscribing if (e.getNoticeType() == NoticeType.SUB || e.getNoticeType() == NoticeType.RESUB) eventHandler.onSub(e); - else if (e.getNoticeType() == NoticeType.SUB_GIFT) eventHandler.onSubGift(e); - else return; + else if (e.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT || e.getNoticeType() == NoticeType.SUB_GIFT) eventHandler.onSubGift(e); } catch (NullPointerException ex) {} } }); From bcbf1d8fc095931b3ed928492485550cc31a0a54 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:06:49 +0200 Subject: [PATCH 14/23] Separate sub and subgift functions --- .../chatpointsttv/TwitchEventHandler.java | 47 +++++++++++++------ 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index b6326b1..d275b05 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -32,13 +32,15 @@ public class TwitchEventHandler { ChatColor action_color = ChatPointsTTV.getChatColors().get("ACTION_COLOR"); ChatColor user_color = ChatPointsTTV.getChatColors().get("USER_COLOR"); + private Integer communitySubs = 0; + public void onChannelPointsRedemption(RewardRedeemedEvent event) { if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getRedemption().getUser().getDisplayName() + " has redeemed " + event.getRedemption().getReward().getTitle() + " in " + plugin.getUsername(event.getRedemption().getChannelId())); ChannelPointsRedemption redemption = event.getRedemption(); for (Reward reward : Rewards.getRewards(rewardType.CHANNEL_POINTS)) { if (!reward.getEvent().equalsIgnoreCase(redemption.getReward().getTitle())) continue; - if (!reward.getTargetId().equals(redemption.getChannelId())) continue; + if (!reward.getTargetId().equals(redemption.getChannelId()) && !reward.getTargetId().equals(Rewards.EVERYONE)) continue; String custom_string = ChatPointsTTV.getRedemptionStrings().get("REDEEMED_STRING"); Events.displayTitle(redemption.getUser().getDisplayName(), custom_string, redemption.getReward().getTitle(), action_color, user_color, rewardBold); @@ -66,8 +68,9 @@ public void onFollow(ChannelFollowEvent event) { Events.runAction(parts[0], parts[1], event.getUserName()); } catch (Exception e) { plugin.log.warning(e.toString()); - } - } + } + } + return; } } @@ -101,25 +104,21 @@ public void onCheer(ChannelChatMessageEvent event) { } } - public void onSub(ChannelChatNotificationEvent event) { - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " has subscribed to " + event.getBroadcasterUserName() + " with a " + event.getSub().getSubTier().toString() + " sub!"); - + public void onSub(ChannelChatNotificationEvent event) { SubscriptionPlan tier; if (event.getNoticeType() == NoticeType.SUB) { if (event.getSub().isPrime()) tier = SubscriptionPlan.TWITCH_PRIME; else tier = event.getSub().getSubTier(); - } else if (event.getNoticeType() == NoticeType.RESUB) { if (event.getResub().isPrime()) tier = SubscriptionPlan.TWITCH_PRIME; else tier = event.getResub().getSubTier(); - } else { plugin.log.warning("Couldn't fetch sub type!"); return; } - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " subscribed with a " + ChatPointsTTV.getUtils().PlanToString(tier) + " sub to " + event.getBroadcasterUserName() + "!"); + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " has subscribed to " + event.getBroadcasterUserName() + " with a " + utils.PlanToString(tier) + " sub!"); for (Reward reward : Rewards.getRewards(rewardType.SUB)) { if (!reward.getTargetId().equals(event.getBroadcasterUserId()) && !reward.getTargetId().equals(Rewards.EVERYONE)) continue; @@ -139,17 +138,35 @@ public void onSub(ChannelChatNotificationEvent event) { } } - public void onSubGift(ChannelChatNotificationEvent event) { - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " has gifted " + event.getSubGift().getCumulativeTotal().toString() + " subs in " + event.getBroadcasterUserName() + "'s' channel!"); - + public void onSubGift(ChannelChatNotificationEvent event) { String chatter = event.getChatterUserName(); - Integer amount = event.getSubGift().getCumulativeTotal(); - String tier = ChatPointsTTV.getUtils().PlanToString(event.getSubGift().getSubTier()); // event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT ? ChatPointsTTV.getUtils().PlanToString(event.getCommunitySubGift().getSubTier()) : + Integer amount; + String tier; + + if (event.getNoticeType() == NoticeType.SUB_GIFT) { + amount = 1; // Single sub gift + tier = ChatPointsTTV.getUtils().PlanToString(event.getSubGift().getSubTier()); + + if (communitySubs > 0) { + communitySubs--; + return; + } + } else if (event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT) { + amount = event.getCommunitySubGift().getTotal(); + tier = ChatPointsTTV.getUtils().PlanToString(event.getCommunitySubGift().getSubTier()); + plugin.log.info(amount + " COMMUNITY SUB GIFTS!!!"); + + communitySubs += amount; + } else { + plugin.log.warning("Couldn't fetch gift type!"); + return; + } + if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " has gifted " + amount + " " + tier + " subs in " + event.getBroadcasterUserName() + "'s' channel!"); String custom_string = ChatPointsTTV.getRedemptionStrings().get("GIFT_STRING"); ArrayList rewards = Rewards.getRewards(rewardType.GIFT); - Collections.sort(rewards, Collections.reverseOrder()); + Collections.sort(rewards, new RewardComparator()); Events.displayTitle(chatter, custom_string, amount + " " + tier + " subs", action_color, user_color, rewardBold); From 69ac18f84eb2f78dbedc3f733353629034545923 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:17:51 +0200 Subject: [PATCH 15/23] Prioritize targeted events rather than general & improve sorting --- .../chatpointsttv/Rewards/RewardComparator.java | 12 ++++-------- .../me/gosdev/chatpointsttv/Rewards/Rewards.java | 6 ++++++ .../me/gosdev/chatpointsttv/TwitchEventHandler.java | 6 ------ 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java index 012e548..be9faf5 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java @@ -1,8 +1,6 @@ package me.gosdev.chatpointsttv.Rewards; -import java.util.ArrayList; import java.util.Comparator; -import java.util.List; import me.gosdev.chatpointsttv.Rewards.Rewards.rewardType; @@ -10,14 +8,12 @@ public class RewardComparator implements Comparator { @Override public int compare(Reward o1, Reward o2) { if (o1.getType() != o2.getType()) throw new java.lang.UnsupportedOperationException("Cannot compare " + o1.getType().toString() + " rewards with " + o2.getType().toString()); - if (o1.getType() == rewardType.CHANNEL_POINTS || o1.getType() == rewardType.FOLLOW || o1.getType() == rewardType.SUB) throw new UnsupportedOperationException("Cannot sort " + o1.getType().toString() + " rewards."); - if (o2.getType() == rewardType.CHANNEL_POINTS || o2.getType() == rewardType.FOLLOW || o2.getType() == rewardType.SUB) throw new UnsupportedOperationException("Cannot sort " + o1.getType().toString() + " rewards."); - List amounts = new ArrayList(); - Rewards.getRewards(rewardType.CHEER).forEach((reward) -> { - amounts.add(Integer.parseInt(reward.getEvent())); - }); + if (o1.getChannel().equals(Rewards.EVERYONE) && !o2.getChannel().equals(Rewards.EVERYONE)) return 1; + if (o2.getChannel().equals(Rewards.EVERYONE) && !o1.getChannel().equals(Rewards.EVERYONE)) return -1; + if (o1.getType() == rewardType.CHANNEL_POINTS || o1.getType() == rewardType.FOLLOW || o1.getType() == rewardType.SUB) return 0; + if (o2.getType() == rewardType.CHANNEL_POINTS || o2.getType() == rewardType.FOLLOW || o2.getType() == rewardType.SUB) return 0; return Integer.parseInt(o2.getEvent()) - Integer.parseInt(o1.getEvent()); } diff --git a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java index ddabf00..24b050d 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java @@ -35,11 +35,13 @@ public static ArrayList getRewards(rewardType type) { reward_list.add(new Reward(type, EVERYONE, null, config.getStringList(type.toString().toUpperCase() + "_REWARDS"))); } else { // Streamer specific events + if (config_rewards == null) return null; Set keys = config_rewards.getKeys(false); for (String channel : keys) { reward_list.add(new Reward(type, channel.equals("default") ? EVERYONE : channel, null, config_rewards.getStringList(channel))); } } + reward_list.sort(new RewardComparator()); rewards.put(type, reward_list); return reward_list; @@ -59,7 +61,11 @@ public static ArrayList getRewards(rewardType type) { } } } + reward_list.sort(new RewardComparator()); rewards.put(type, reward_list); + for (Reward reward : reward_list) { + ChatPointsTTV.getPlugin().log.info(reward.getChannel()+": " + reward.getEvent()); + } return reward_list; } diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index d275b05..94f4091 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -9,13 +9,11 @@ import com.github.twitch4j.pubsub.events.RewardRedeemedEvent; import me.gosdev.chatpointsttv.Rewards.Reward; -import me.gosdev.chatpointsttv.Rewards.RewardComparator; import me.gosdev.chatpointsttv.Rewards.Rewards; import me.gosdev.chatpointsttv.Rewards.Rewards.rewardType; import me.gosdev.chatpointsttv.Utils.Utils; import java.util.ArrayList; -import java.util.Collections; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -82,10 +80,7 @@ public void onCheer(ChannelChatMessageEvent event) { int amount = event.getCheer().getBits(); String custom_string = ChatPointsTTV.getRedemptionStrings().get("CHEERED_STRING"); - // Sort rewards by cheer. ArrayList rewards = Rewards.getRewards(rewardType.CHEER); - Collections.sort(rewards, new RewardComparator()); - for (Reward reward : rewards) { if (!reward.getTargetId().equals(event.getBroadcasterUserId()) && !reward.getTargetId().equals(Rewards.EVERYONE)) continue; @@ -166,7 +161,6 @@ public void onSubGift(ChannelChatNotificationEvent event) { String custom_string = ChatPointsTTV.getRedemptionStrings().get("GIFT_STRING"); ArrayList rewards = Rewards.getRewards(rewardType.GIFT); - Collections.sort(rewards, new RewardComparator()); Events.displayTitle(chatter, custom_string, amount + " " + tier + " subs", action_color, user_color, rewardBold); From 450f1e7d7c73df3d89e92e8a4cc582a5105f2726 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:54:27 +0200 Subject: [PATCH 16/23] Return after match event --- .../me/gosdev/chatpointsttv/TwitchEventHandler.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index 94f4091..be14296 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -50,6 +50,7 @@ public void onChannelPointsRedemption(RewardRedeemedEvent event) { plugin.log.warning(e.toString()); } } + return; } } @@ -68,7 +69,7 @@ public void onFollow(ChannelFollowEvent event) { plugin.log.warning(e.toString()); } } - return; + return; } } @@ -89,14 +90,14 @@ public void onCheer(ChannelChatMessageEvent event) { for (String cmd : reward.getCommands()) { String[] parts = cmd.split(" ", 2); try { - Events.runAction(parts[0], parts[1], event.getChatterUserName()); + Events.runAction(parts[0], parts[1], event.getChatterUserName()); } catch (Exception e) { plugin.log.warning(e.toString()); } } - break; + return; } - } + } } public void onSub(ChannelChatNotificationEvent event) { @@ -129,6 +130,7 @@ public void onSub(ChannelChatNotificationEvent event) { plugin.log.warning(e.toString()); } } + return; } } } @@ -174,7 +176,7 @@ public void onSubGift(ChannelChatNotificationEvent event) { plugin.log.warning(e.toString()); } } - break; + return; } } } From 0cc01cee11b90de45b0e8f3311e4d7b43172a541 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Wed, 18 Sep 2024 21:55:19 +0200 Subject: [PATCH 17/23] Remove testing log message --- .../main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java index 24b050d..342028f 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/Rewards.java @@ -63,9 +63,7 @@ public static ArrayList getRewards(rewardType type) { } reward_list.sort(new RewardComparator()); rewards.put(type, reward_list); - for (Reward reward : reward_list) { - ChatPointsTTV.getPlugin().log.info(reward.getChannel()+": " + reward.getEvent()); - } + return reward_list; } From a8578d442fe26c9b5889c75b3fc942060e8178f3 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:53:11 +0200 Subject: [PATCH 18/23] Update project configuration --- dist/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/pom.xml b/dist/pom.xml index e6364d5..183b2e9 100644 --- a/dist/pom.xml +++ b/dist/pom.xml @@ -1,5 +1,5 @@ - + 4.0.0 me.gosdev chatpointsttv-dist From a33b12a98806010a306e51f5aa3c94095ac713eb Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:53:21 +0200 Subject: [PATCH 19/23] Supress NullPointerExceptionWarning --- .../chatpointsttv/TwitchAuth/AuthenticationCallbackRequest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchAuth/AuthenticationCallbackRequest.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchAuth/AuthenticationCallbackRequest.java index 97e1b07..c743041 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchAuth/AuthenticationCallbackRequest.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchAuth/AuthenticationCallbackRequest.java @@ -102,6 +102,7 @@ public void run() { * * @throws IOException */ + @SuppressWarnings("null") private void processRequest() throws IOException { // Get a reference to the socket's input and output streams. @SuppressWarnings("unused") From 0a83ee4bfb04ef7407e79f83b260fdd0c1fe3170 Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:53:40 +0200 Subject: [PATCH 20/23] Prioritized Sorting --- .../chatpointsttv/Rewards/RewardComparator.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java index be9faf5..1b48c56 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/Rewards/RewardComparator.java @@ -2,20 +2,22 @@ import java.util.Comparator; -import me.gosdev.chatpointsttv.Rewards.Rewards.rewardType; - public class RewardComparator implements Comparator { @Override public int compare(Reward o1, Reward o2) { if (o1.getType() != o2.getType()) throw new java.lang.UnsupportedOperationException("Cannot compare " + o1.getType().toString() + " rewards with " + o2.getType().toString()); - if (o1.getChannel().equals(Rewards.EVERYONE) && !o2.getChannel().equals(Rewards.EVERYONE)) return 1; - if (o2.getChannel().equals(Rewards.EVERYONE) && !o1.getChannel().equals(Rewards.EVERYONE)) return -1; + try { + int difference = Integer.parseInt(o2.getEvent()) - Integer.parseInt(o1.getEvent()); - if (o1.getType() == rewardType.CHANNEL_POINTS || o1.getType() == rewardType.FOLLOW || o1.getType() == rewardType.SUB) return 0; - if (o2.getType() == rewardType.CHANNEL_POINTS || o2.getType() == rewardType.FOLLOW || o2.getType() == rewardType.SUB) return 0; + if (difference == 0) throw new NumberFormatException(); // If value matches compare target channel (go straight to catch) + return difference; + } catch (NumberFormatException e) { + if (o1.getChannel().equals(Rewards.EVERYONE) && !o2.getChannel().equals(Rewards.EVERYONE)) return 1; + if (o2.getChannel().equals(Rewards.EVERYONE) && !o1.getChannel().equals(Rewards.EVERYONE)) return -1; + return 0; + } - return Integer.parseInt(o2.getEvent()) - Integer.parseInt(o1.getEvent()); } } From 07413ca24870444e3a3debe3130fe6fc10741cbe Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Fri, 20 Sep 2024 21:05:38 +0200 Subject: [PATCH 21/23] Remove SUB_GIFT type --- .../gosdev/chatpointsttv/ChatPointsTTV.java | 2 +- .../chatpointsttv/TwitchEventHandler.java | 28 +++---------------- 2 files changed, 5 insertions(+), 25 deletions(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index 034e42e..094fc04 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -374,7 +374,7 @@ public void accept(ChannelChatMessageEvent e) { public void accept(ChannelChatNotificationEvent e) { try { // May get NullPointerException if event is triggered while still subscribing if (e.getNoticeType() == NoticeType.SUB || e.getNoticeType() == NoticeType.RESUB) eventHandler.onSub(e); - else if (e.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT || e.getNoticeType() == NoticeType.SUB_GIFT) eventHandler.onSubGift(e); + else if (e.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT) eventHandler.onSubGift(e); } catch (NullPointerException ex) {} } }); diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index be14296..cd4bcfe 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -30,8 +30,6 @@ public class TwitchEventHandler { ChatColor action_color = ChatPointsTTV.getChatColors().get("ACTION_COLOR"); ChatColor user_color = ChatPointsTTV.getChatColors().get("USER_COLOR"); - private Integer communitySubs = 0; - public void onChannelPointsRedemption(RewardRedeemedEvent event) { if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getRedemption().getUser().getDisplayName() + " has redeemed " + event.getRedemption().getReward().getTitle() + " in " + plugin.getUsername(event.getRedemption().getChannelId())); @@ -137,30 +135,12 @@ public void onSub(ChannelChatNotificationEvent event) { public void onSubGift(ChannelChatNotificationEvent event) { String chatter = event.getChatterUserName(); - Integer amount; - String tier; - - if (event.getNoticeType() == NoticeType.SUB_GIFT) { - amount = 1; // Single sub gift - tier = ChatPointsTTV.getUtils().PlanToString(event.getSubGift().getSubTier()); - - if (communitySubs > 0) { - communitySubs--; - return; - } - } else if (event.getNoticeType() == NoticeType.COMMUNITY_SUB_GIFT) { - amount = event.getCommunitySubGift().getTotal(); - tier = ChatPointsTTV.getUtils().PlanToString(event.getCommunitySubGift().getSubTier()); - plugin.log.info(amount + " COMMUNITY SUB GIFTS!!!"); - - communitySubs += amount; - } else { - plugin.log.warning("Couldn't fetch gift type!"); - return; - } + int amount = event.getCommunitySubGift().getTotal(); + String tier = ChatPointsTTV.getUtils().PlanToString(event.getCommunitySubGift().getSubTier()); + + plugin.log.info(amount + " COMMUNITY SUB GIFTS!!!"); if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getChatterUserName() + " has gifted " + amount + " " + tier + " subs in " + event.getBroadcasterUserName() + "'s' channel!"); - String custom_string = ChatPointsTTV.getRedemptionStrings().get("GIFT_STRING"); ArrayList rewards = Rewards.getRewards(rewardType.GIFT); From 8d716ef70f0d93f91a3ab3dce565b66bb8255a4e Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Fri, 20 Sep 2024 22:18:23 +0200 Subject: [PATCH 22/23] Update TwitchEventHandler.java --- .../main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java index cd4bcfe..e692da8 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/TwitchEventHandler.java @@ -31,7 +31,6 @@ public class TwitchEventHandler { ChatColor user_color = ChatPointsTTV.getChatColors().get("USER_COLOR"); public void onChannelPointsRedemption(RewardRedeemedEvent event) { - if (logEvents) utils.sendMessage(Bukkit.getConsoleSender(), event.getRedemption().getUser().getDisplayName() + " has redeemed " + event.getRedemption().getReward().getTitle() + " in " + plugin.getUsername(event.getRedemption().getChannelId())); ChannelPointsRedemption redemption = event.getRedemption(); for (Reward reward : Rewards.getRewards(rewardType.CHANNEL_POINTS)) { From ea34dca62e98b34d6ea43feba1de71695d493cba Mon Sep 17 00:00:00 2001 From: GospelBG <39804434+GospelBG@users.noreply.github.com> Date: Sun, 22 Sep 2024 17:04:31 +0200 Subject: [PATCH 23/23] Unregister events when disabling /twitch reload command would duplicate join messages --- core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java index baeaf61..ef8942d 100644 --- a/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java +++ b/core/src/main/java/me/gosdev/chatpointsttv/ChatPointsTTV.java @@ -22,6 +22,7 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; +import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; @@ -281,6 +282,8 @@ public void onDisable() { Rewards.rewards = new HashMap>(); TwitchEventHandler.rewardBold = null; + + HandlerList.unregisterAll(this); } public void linkToTwitch(CommandSender p, String token) {