├── .editorconfig
├── .github
└── FUNDING.yml
├── .gitignore
├── .run
├── clean-package.run.xml
└── update-license-headers.run.xml
├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
├── java
└── com
│ └── rezzedup
│ └── discordsrv
│ └── staffchat
│ ├── ChatService.java
│ ├── Data.java
│ ├── Debugger.java
│ ├── MessageProcessor.java
│ ├── Permissions.java
│ ├── StaffChatAPI.java
│ ├── StaffChatData.java
│ ├── StaffChatPlugin.java
│ ├── StaffChatProfile.java
│ ├── Updater.java
│ ├── commands
│ ├── ManageStaffChatCommand.java
│ ├── StaffChatCommand.java
│ ├── ToggleStaffChatCommand.java
│ ├── ToggleStaffChatSoundsCommand.java
│ └── package-info.java
│ ├── config
│ ├── Configs.java
│ ├── MessagesConfig.java
│ ├── StaffChatConfig.java
│ └── package-info.java
│ ├── events
│ ├── AutoStaffChatToggleEvent.java
│ ├── ConsoleStaffChatMessageEvent.java
│ ├── DiscordStaffChatMessageEvent.java
│ ├── PlayerStaffChatMessageEvent.java
│ ├── ProfileToggleEvent.java
│ ├── ReceivingStaffChatToggleEvent.java
│ ├── StaffChatMessageEvent.java
│ └── package-info.java
│ ├── listeners
│ ├── DiscordSrvLoadedLaterListener.java
│ ├── DiscordStaffChatListener.java
│ ├── JoinNotificationListener.java
│ ├── PlayerPrefixedMessageListener.java
│ ├── PlayerStaffChatToggleListener.java
│ └── package-info.java
│ ├── package-info.java
│ └── util
│ ├── FileIO.java
│ ├── MappedPlaceholder.java
│ ├── Strings.java
│ └── package-info.java
└── resources
├── messages.config.header.txt
├── plugin.yml
└── staff-chat.config.header.txt
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 2
7 | indent_style = tab
8 | insert_final_newline = true
9 |
10 | [*.yml]
11 | indent_style = space
12 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: RezzedUp
2 | custom: ["https://paypal.me/RezzedUp"]
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # Don't ignore jars in lib/
12 | !lib/*.jar
13 |
14 | # IntelliJ
15 | .idea/
16 | *.iml
17 | *.ipr
18 | out/
19 |
20 | # Maven
21 | target/
22 |
23 | # Eclipse
24 | .settings/
25 | .project
26 | .classpath
27 |
28 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
29 | hs_err_pid*
30 |
31 | # =========================
32 | # Operating System Files
33 | # =========================
34 |
35 | # OSX
36 | # =========================
37 |
38 | .DS_Store
39 | .AppleDouble
40 | .LSOverride
41 |
42 | # Thumbnails
43 | ._*
44 |
45 | # Files that might appear in the root of a volume
46 | .DocumentRevisions-V100
47 | .fseventsd
48 | .Spotlight-V100
49 | .TemporaryItems
50 | .Trashes
51 | .VolumeIcon.icns
52 |
53 | # Directories potentially created on remote AFP share
54 | .AppleDB
55 | .AppleDesktop
56 | Network Trash Folder
57 | Temporary Items
58 | .apdisk
59 |
60 | # Windows
61 | # =========================
62 |
63 | # Windows image file caches
64 | Thumbs.db
65 | ehthumbs.db
66 |
67 | # Folder config file
68 | Desktop.ini
69 |
70 | # Recycle Bin used on file shares
71 | $RECYCLE.BIN/
72 |
73 | # Windows Installer files
74 | *.cab
75 | *.msi
76 | *.msm
77 | *.msp
78 |
79 | # Windows shortcuts
80 | *.lnk
81 |
--------------------------------------------------------------------------------
/.run/clean-package.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/.run/update-license-headers.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017-2022 RezzedUp and Contributors
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 |
2 |
3 | # 
4 |
5 | [](./LICENSE "Project License: MIT")
6 | [](# "Java Version: 11")
7 | [](https://github.com/DiscordSRV/Staff-Chat/releases/latest "Latest Release")
8 | [](https://www.spigotmc.org/resources/discordsrv-staff-chat.44245/ "Spigot Resource Page")
9 | [](https://modrinth.com/plugin/uD7Bzf5q "Modrinth Project Page")
10 |
11 |
12 |
13 | DiscordSRV-Staff-Chat is a staff chat plugin that connects to a Discord channel (via [DiscordSRV](https://github.com/DiscordSRV/DiscordSRV)), allowing in-game staff to communicate with staff on Discord.
14 |
15 | 
16 |
17 | ## Installation
18 |
19 | * Add **DiscordSRV** and **DiscordSRV-Staff-Chat** to your `plugins/` directory.
20 | * Restart the server.
21 | * Add a `staff-chat` channel to **DiscordSRV**'s config.
22 | * Execute: `/discord reload` *or* restart the server again.
23 |
24 | ### Adding a staff-chat channel
25 |
26 | Add a **"staff-chat"** entry to DiscordSRV's config. Note: it's very important that this entry is called `"staff-chat"`.
27 |
28 | ```yaml
29 | # Channel links from game to Discord
30 | # syntax is Channels: {"in-game channel name from Minecraft": "numerical channel ID from Discord", "another in-game channel name from Minecraft": "another numerical channel ID from Discord"}
31 | #
32 | Channels: {"global": "000000000000000000", "staff-chat": "000000000000000000"}
33 | ```
34 |
35 | Replace all those zeros with your staff chat's channel ID.
36 |
37 | 
38 |
39 | ```yaml
40 | Channels: {"global": "000000000000000000", "staff-chat": "337769984539361281"}
41 | ```
42 |
43 |
44 | ## Commands & Permissions
45 |
46 | ### /staffchat
47 |
48 | > 
49 | >
50 | > **Permission:** `staffchat.access`
51 | >
52 | > **Aliases:** `/adminchat`, `/schat`, `/achat`, `/sc`, `/ac`, and `/a`
53 | >
54 | > **Usage:**
55 | > - `/staffchat` - Toggle automatic staff chat.
56 | > - `/staffchat ` - Send a message to the staff chat.
57 |
58 | ### /leavestaffchat
59 |
60 | > 
61 | >
62 | > **Permission:** `staffchat.access`
63 | >
64 | > **Aliases:** `/leaveadminchat`
65 | >
66 | > **Usage:**
67 | > - `/leavestaffchat` - Stop receiving staff chat messages.
68 | > - Useful to avoid leaking staff chat messages if a staff member is filming or streaming.
69 | > - This can be disabled in the config if you don't want staff members to turn off their staff chat.
70 |
71 | ### /joinstaffchat
72 |
73 | > 
74 | >
75 | > **Permission:** `staffchat.access`
76 | >
77 | > **Aliases:** `/joinadminchat`
78 | >
79 | > **Usage:**
80 | > - `/joinstaffchat` - Start receiving staff chat messages again if you previously left.
81 |
82 | ### /togglestaffchatsounds
83 |
84 | > 
85 | >
86 | > **Permission:** `staffchat.access`
87 | >
88 | > **Aliases:** `/toggleadminchatsounds`
89 | >
90 | > **Usage:**
91 | > - `/togglestaffchatsounds` - Mute or unmute staff chat sounds for yourself.
92 |
93 | ### /managestaffchat
94 |
95 | > **Permission:** `staffchat.manage`
96 | >
97 | > **Aliases:** `/discordsrv-staff-chat`, `/discordsrvstaffchat`, `/discordstaffchat`, `/discordadminchat`, `/manageadminchat`
98 | >
99 | > **Usage:**
100 | > - `/managestaffchat` - Display plugin information and command usage.
101 | > - `/managestaffchat reload` - Reload configs.
102 | > - `/managestaffchat debug` - Enable or disable debugging.
103 |
104 | [](https://bstats.org/plugin/bukkit/DiscordSRV-Staff-Chat/11056)
105 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.rezzedup
8 | discordsrv-staff-chat
9 | 1.4.6
10 |
11 | DiscordSRV-Staff-Chat
12 | 2017
13 | https://github.com/DiscordSRV/Staff-Chat
14 | A staff-chat plugin that hooks into DiscordSRV.
15 |
16 |
17 | 11
18 | 11
19 |
20 | yyyy
21 | UTF-8
22 |
23 | com.rezzedup.discordsrv.staffchat.shaded
24 |
25 |
26 | ${project.inceptionYear}-${maven.build.timestamp}
27 | RezzedUp and Contributors
28 | https://github.com/DiscordSRV/Staff-Chat
29 |
30 |
31 |
32 |
33 | spigot-repo
34 | https://hub.spigotmc.org/nexus/content/repositories/snapshots/
35 |
36 |
37 | scarsz-nexus
38 | https://nexus.scarsz.me/content/repositories/public/
39 |
40 |
41 | jitpack.io
42 | https://jitpack.io
43 |
44 |
45 |
46 |
47 |
48 |
49 | org.spigotmc
50 | spigot-api
51 | 1.21.3-R0.1-SNAPSHOT
52 | provided
53 |
54 |
55 |
56 | com.discordsrv
57 | discordsrv
58 | 1.27.0
59 | provided
60 |
61 |
62 |
63 | com.github.placeholderapi
64 | placeholderapi
65 | 2.11.1
66 | provided
67 |
68 |
69 |
70 | community.leaf.configvalues
71 | config-values-bukkit
72 | 0.0.9
73 |
74 |
75 |
76 | community.leaf.eventful
77 | events-bukkit
78 | 0.4.0
79 |
80 |
81 |
82 | community.leaf.tasks
83 | tasks-bukkit
84 | 0.0.2
85 |
86 |
87 |
88 |
89 | com.github.zafarkhaja
90 | java-semver
91 | 0.10.2
92 |
93 |
94 |
95 | org.bstats
96 | bstats-bukkit
97 | 3.0.2
98 |
99 |
100 |
101 | pl.tlinkowski.annotation
102 | pl.tlinkowski.annotation.basic
103 | 0.2.0
104 |
105 |
106 |
107 |
108 |
109 | package
110 | ${project.name}-${project.version}
111 |
112 |
113 |
114 | org.apache.maven.plugins
115 | maven-compiler-plugin
116 | 3.8.1
117 |
118 | ${maven.compiler.source}
119 | ${maven.compiler.target}
120 |
121 |
122 |
123 |
124 | org.apache.maven.plugins
125 | maven-shade-plugin
126 | 3.3.0
127 |
128 | ${project.build.directory}/dependency-reduced-pom.xml
129 |
130 |
131 |
132 | com.github
133 | ${shade.relocation}.com.github
134 |
135 |
136 | community.leaf
137 | ${shade.relocation}.community.leaf
138 |
139 |
140 | com.rezzedup.util
141 | ${shade.relocation}.com.rezzedup.util
142 |
143 |
144 | org.bstats
145 | ${shade.relocation}.org.bstats
146 |
147 |
148 |
149 |
150 |
151 | com.google.code.findbugs:jsr305
152 | org.jetbrains.kotlin:kotlin-annotations-jvm
153 | pl.tlinkowski.annotation:pl.tlinkowski.annotation.basic
154 |
155 |
156 |
157 |
158 |
159 | *:*
160 |
161 | META-INF/**
162 |
163 |
164 |
165 |
166 |
167 |
168 | package
169 |
170 | shade
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 | com.mycila
179 | license-maven-plugin
180 | 4.1
181 |
182 |
183 | ${license.header.year}
184 | ${license.header.owner}
185 | ${license.header.url}
186 |
187 |
188 |
189 | com/mycila/maven/plugin/license/templates/MIT.txt
190 |
191 | *.md
192 | *.txt
193 | *.xml
194 | *.yml
195 | .run/**
196 | examples/**
197 | src/test/resources/**
198 | src/main/resources/**
199 | .editorconfig
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 | test
208 |
209 | check
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 | src/main/resources
219 | true
220 |
221 |
222 |
223 | .
224 |
225 | LICENSE
226 |
227 |
228 |
229 |
230 |
231 |
232 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/ChatService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | public enum ChatService {
26 | MINECRAFT("In-Game"),
27 | DISCORD("Discord");
28 |
29 | private final String prefix;
30 |
31 | ChatService(String prefix) {
32 | this.prefix = prefix;
33 | }
34 |
35 | public String asPrefixInBrackets(String context) {
36 | return "[" + prefix + ": " + context + "]";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/Data.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import com.rezzedup.discordsrv.staffchat.config.StaffChatConfig;
26 | import com.rezzedup.discordsrv.staffchat.events.AutoStaffChatToggleEvent;
27 | import com.rezzedup.discordsrv.staffchat.events.ReceivingStaffChatToggleEvent;
28 | import community.leaf.configvalues.bukkit.YamlValue;
29 | import community.leaf.configvalues.bukkit.data.YamlDataFile;
30 | import community.leaf.configvalues.bukkit.util.Sections;
31 | import community.leaf.tasks.TaskContext;
32 | import org.bukkit.configuration.ConfigurationSection;
33 | import org.bukkit.entity.Player;
34 | import org.bukkit.scheduler.BukkitTask;
35 | import pl.tlinkowski.annotation.basic.NullOr;
36 |
37 | import java.time.Instant;
38 | import java.util.HashMap;
39 | import java.util.Map;
40 | import java.util.Optional;
41 | import java.util.UUID;
42 |
43 | public class Data extends YamlDataFile implements StaffChatData {
44 | private static final String PROFILES_PATH = "staff-chat.profiles";
45 |
46 | private final Map profilesByUuid = new HashMap<>();
47 |
48 | private final StaffChatPlugin plugin;
49 |
50 | private @NullOr TaskContext task = null;
51 |
52 | Data(StaffChatPlugin plugin) {
53 | super(plugin.directory().resolve("data"), "staff-chat.data.yml");
54 | this.plugin = plugin;
55 |
56 | // Load persistent toggles.
57 | if (plugin.config().getOrDefault(StaffChatConfig.PERSIST_TOGGLES)) {
58 | Sections.get(data(), PROFILES_PATH).ifPresent(section ->
59 | {
60 | for (String key : section.getKeys(false)) {
61 | try {
62 | getOrCreateProfile(UUID.fromString(key));
63 | } catch (IllegalArgumentException ignored) {
64 | }
65 | }
66 | });
67 | }
68 |
69 | // Start the save task.
70 | task = plugin.async().every(2).minutes().run(() -> {
71 | if (isUpdated()) {
72 | save();
73 | }
74 | });
75 |
76 | // Update profiles of all online players when reloaded.
77 | reloadsWith(() -> plugin.getServer().getOnlinePlayers().forEach(this::updateProfile));
78 | }
79 |
80 | protected void end() {
81 | if (task != null) {
82 | task.cancel();
83 | }
84 | if (isUpdated()) {
85 | save();
86 | }
87 | }
88 |
89 | @Override
90 | public StaffChatProfile getOrCreateProfile(UUID uuid) {
91 | return profilesByUuid.computeIfAbsent(uuid, k -> new Profile(plugin, this, k));
92 | }
93 |
94 | @Override
95 | public Optional getProfile(UUID uuid) {
96 | return Optional.ofNullable(profilesByUuid.get(uuid));
97 | }
98 |
99 | public void updateProfile(Player player) {
100 | @NullOr Profile profile = profilesByUuid.get(player.getUniqueId());
101 |
102 | if (Permissions.ACCESS.allows(player)) {
103 | // Ensure that this staff member has an active profile.
104 | if (profile == null) {
105 | profile = (Profile) getOrCreateProfile(player);
106 | }
107 |
108 | // If leaving the staff chat is disabled...
109 | if (!plugin.config().getOrDefault(StaffChatConfig.LEAVING_STAFFCHAT_ENABLED)) {
110 | // ... and this staff member previously left the staff chat ...
111 | if (profile.left != null) {
112 | // Bring them back.
113 | profile.receivesStaffChatMessages(true);
114 | }
115 | }
116 | } else {
117 | // Not a staff member but has a loaded profile...
118 | if (profile != null) {
119 | // Notify that they're no longer talking in staff chat.
120 | if (profile.automaticStaffChat()) {
121 | profile.automaticStaffChat(false);
122 | }
123 |
124 | // No longer staff, delete data.
125 | profile.clearStoredProfileData();
126 |
127 | // Remove from the map.
128 | profilesByUuid.remove(player.getUniqueId());
129 | }
130 | }
131 | }
132 |
133 | static class Profile implements StaffChatProfile {
134 | static final YamlValue AUTO_TOGGLE_DATE = YamlValue.ofInstant("toggles.auto").maybe();
135 |
136 | static final YamlValue LEFT_TOGGLE_DATE = YamlValue.ofInstant("toggles.left").maybe();
137 |
138 | static final YamlValue MUTED_SOUNDS_TOGGLE = YamlValue.ofBoolean("toggles.muted-sounds").maybe();
139 |
140 | private final StaffChatPlugin plugin;
141 | private final YamlDataFile yaml;
142 | private final UUID uuid;
143 |
144 | private @NullOr Instant auto;
145 | private @NullOr Instant left;
146 | private boolean mutedSounds = false;
147 |
148 | Profile(StaffChatPlugin plugin, YamlDataFile yaml, UUID uuid) {
149 | this.plugin = plugin;
150 | this.yaml = yaml;
151 | this.uuid = uuid;
152 |
153 | if (plugin.config().getOrDefault(StaffChatConfig.PERSIST_TOGGLES)) {
154 | Sections.get(yaml.data(), path()).ifPresent(section ->
155 | {
156 | auto = AUTO_TOGGLE_DATE.get(section).orElse(null);
157 | left = LEFT_TOGGLE_DATE.get(section).orElse(null);
158 | mutedSounds = MUTED_SOUNDS_TOGGLE.get(section).orElse(false);
159 | });
160 | }
161 | }
162 |
163 | String path() {
164 | return PROFILES_PATH + "." + uuid;
165 | }
166 |
167 | @Override
168 | public UUID uuid() {
169 | return uuid;
170 | }
171 |
172 | @Override
173 | public Optional sinceEnabledAutoChat() {
174 | return Optional.ofNullable(auto);
175 | }
176 |
177 | @Override
178 | public boolean automaticStaffChat() {
179 | return auto != null;
180 | }
181 |
182 | @Override
183 | public void automaticStaffChat(boolean enabled) {
184 | if (plugin.events().call(new AutoStaffChatToggleEvent(this, enabled)).isCancelled()) {
185 | return;
186 | }
187 |
188 | auto = (enabled) ? Instant.now() : null;
189 | updateStoredProfileData();
190 | }
191 |
192 | @Override
193 | public Optional sinceLeftStaffChat() {
194 | return Optional.ofNullable(left);
195 | }
196 |
197 | @Override
198 | public boolean receivesStaffChatMessages() {
199 | // hasn't left the staff chat or leaving is disabled outright
200 | return left == null || !plugin.config().getOrDefault(StaffChatConfig.LEAVING_STAFFCHAT_ENABLED);
201 | }
202 |
203 | @Override
204 | public void receivesStaffChatMessages(boolean enabled) {
205 | if (plugin.events().call(new ReceivingStaffChatToggleEvent(this, enabled)).isCancelled()) {
206 | return;
207 | }
208 |
209 | left = (enabled) ? null : Instant.now();
210 | updateStoredProfileData();
211 | }
212 |
213 | @Override
214 | public boolean receivesStaffChatSounds() {
215 | return !mutedSounds;
216 | }
217 |
218 | @Override
219 | public void receivesStaffChatSounds(boolean enabled) {
220 | mutedSounds = !enabled;
221 | }
222 |
223 | boolean hasDefaultSettings() {
224 | return auto == null && left == null && !mutedSounds;
225 | }
226 |
227 | void clearStoredProfileData() {
228 | if (!plugin.config().getOrDefault(StaffChatConfig.PERSIST_TOGGLES)) {
229 | return;
230 | }
231 |
232 | yaml.data().set(path(), null);
233 | yaml.updated(true);
234 | }
235 |
236 | void updateStoredProfileData() {
237 | if (!plugin.config().getOrDefault(StaffChatConfig.PERSIST_TOGGLES)) {
238 | return;
239 | }
240 |
241 | if (hasDefaultSettings()) {
242 | clearStoredProfileData();
243 | return;
244 | }
245 |
246 | ConfigurationSection section = Sections.getOrCreate(yaml.data(), path());
247 |
248 | AUTO_TOGGLE_DATE.set(section, auto);
249 | LEFT_TOGGLE_DATE.set(section, left);
250 | MUTED_SOUNDS_TOGGLE.set(section, mutedSounds);
251 |
252 | yaml.updated(true);
253 | }
254 | }
255 | }
256 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/Debugger.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import github.scarsz.discordsrv.dependencies.jda.api.entities.Message;
26 | import github.scarsz.discordsrv.dependencies.jda.api.entities.User;
27 | import org.bukkit.entity.Player;
28 | import org.bukkit.event.Event;
29 | import org.bukkit.plugin.Plugin;
30 | import pl.tlinkowski.annotation.basic.NullOr;
31 |
32 | import java.io.IOException;
33 | import java.nio.file.Files;
34 | import java.nio.file.Path;
35 | import java.nio.file.StandardOpenOption;
36 | import java.time.LocalDateTime;
37 | import java.time.temporal.ChronoUnit;
38 | import java.util.function.Supplier;
39 |
40 | public class Debugger {
41 | private static String now() {
42 | return LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS).toString();
43 | }
44 |
45 | private static final DebugLogger DISABLED = message -> {
46 | };
47 |
48 | private final StaffChatPlugin plugin;
49 | private final Path debugToggleFile;
50 | private final Path debugLogFile;
51 |
52 | private boolean isEnabled;
53 |
54 | public Debugger(StaffChatPlugin plugin) {
55 | this.plugin = plugin;
56 | this.debugToggleFile = plugin.directory().resolve("debugging-is-enabled");
57 | this.debugLogFile = plugin.directory().resolve("debug.log");
58 | this.isEnabled = isToggleFilePresent();
59 | }
60 |
61 | private boolean isToggleFilePresent() {
62 | return Files.isRegularFile(debugToggleFile);
63 | }
64 |
65 | public boolean isEnabled() {
66 | return isEnabled;
67 | }
68 |
69 | public void setEnabled(boolean enabled) {
70 | if (this.isEnabled == enabled) {
71 | return;
72 | }
73 |
74 | this.isEnabled = enabled;
75 |
76 | try {
77 | if (enabled) {
78 | printThenWriteToLogFile("========== Starting Debugger ==========");
79 | if (!isToggleFilePresent()) {
80 | Files.createFile(debugToggleFile);
81 | }
82 | } else {
83 | printThenWriteToLogFile("========== Disabled Debugger ==========");
84 | Files.deleteIfExists(debugToggleFile);
85 | }
86 | } catch (IOException e) {
87 | e.printStackTrace();
88 | }
89 | }
90 |
91 | public DebugLogger debug(Class> clazz) {
92 | return (isEnabled) ? message -> record("[" + clazz.getSimpleName() + "] " + message.get()) : DISABLED;
93 | }
94 |
95 | private void record(String message) {
96 | if (isEnabled) {
97 | printThenWriteToLogFile(message);
98 | }
99 | }
100 |
101 | private void printThenWriteToLogFile(String message) {
102 | plugin.getLogger().info("[Debug] " + message);
103 |
104 | try {
105 | if (!Files.isRegularFile(debugLogFile)) {
106 | Files.createFile(debugLogFile);
107 | }
108 | Files.write(debugLogFile, ("[" + now() + "] " + message + "\n").getBytes(), StandardOpenOption.APPEND);
109 | } catch (IOException e) {
110 | e.printStackTrace();
111 | }
112 | }
113 |
114 | public void schedulePluginStatus(Class> clazz, String context) {
115 | if (!isEnabled) {
116 | return;
117 | }
118 |
119 | // Log status directly on the next tick.
120 | plugin.sync().run(() -> logPluginStatus(clazz, context + " (Initial)"));
121 |
122 | // Log status 30 seconds after so that DiscordSRV has a chance to connect.
123 | plugin.sync().delay(30).seconds().run(() -> logPluginStatus(clazz, context + " (30 Seconds)"));
124 | }
125 |
126 | private void logPluginStatus(Class> clazz, String context) {
127 | debug(clazz).recordDebugLogEntry(() ->
128 | {
129 | @NullOr Plugin discordSrv = plugin.getServer().getPluginManager().getPlugin(StaffChatPlugin.DISCORDSRV);
130 | @NullOr Object channel = plugin.getDiscordChannelOrNull();
131 |
132 | boolean isDiscordSrvEnabled = discordSrv != null && discordSrv.isEnabled();
133 | boolean isDiscordSrvHooked = plugin.isDiscordSrvHookEnabled();
134 | boolean isChannelReady = channel != null;
135 |
136 | return "[Status: " + context + "] " +
137 | "Is DiscordSRV installed and enabled? " + isDiscordSrvEnabled + " :: " +
138 | "Is DiscordSRV hooked? " + isDiscordSrvHooked + " :: " +
139 | "Is " + StaffChatPlugin.CHANNEL + " channel ready? " + isChannelReady + " (" + channel + ")";
140 | });
141 | }
142 |
143 | private static String handleContext(@NullOr Object context) {
144 | if (context instanceof Class>) {
145 | return ((Class>) context).getSimpleName();
146 | }
147 | if (context instanceof Event) {
148 | return ((Event) context).getEventName();
149 | }
150 | return String.valueOf(context);
151 | }
152 |
153 | private static String handleException(Throwable exception) {
154 | return exception.getClass().getSimpleName() + ": " + exception.getMessage();
155 | }
156 |
157 | @FunctionalInterface
158 | public interface DebugLogger {
159 | void recordDebugLogEntry(Supplier message);
160 |
161 | default void log(Supplier message) {
162 | recordDebugLogEntry(message);
163 | }
164 |
165 | default void log(@NullOr Object context, Supplier message) {
166 | recordDebugLogEntry(() -> "[" + handleContext(context) + "] " + message.get());
167 | }
168 |
169 | default void log(ChatService source, @NullOr Object context, Supplier message) {
170 | recordDebugLogEntry(() -> source.asPrefixInBrackets(handleContext(context)) + " " + message.get());
171 | }
172 |
173 | default void header(Supplier message) {
174 | recordDebugLogEntry(() -> "---------- " + message.get() + " ----------");
175 | }
176 |
177 | default void logException(Object context, Throwable exception) {
178 | log(context, () -> {
179 | exception.printStackTrace();
180 | return handleException(exception);
181 | });
182 | }
183 |
184 | default T failure(T exception) throws T {
185 | log(() -> handleException(exception));
186 | throw exception;
187 | }
188 |
189 | default T failure(@NullOr Object context, T exception) throws T {
190 | log(context, () -> handleException(exception));
191 | throw exception;
192 | }
193 |
194 | default void logConsoleChatMessage(String message) {
195 | log(ChatService.MINECRAFT, "Message", () ->
196 | "from() message(\"" + message + "\")"
197 | );
198 | }
199 |
200 | default void logPlayerChatMessage(Player author, String message) {
201 | log(ChatService.MINECRAFT, "Message", () ->
202 | "from(" + author.getName() + ") message(\"" + message + "\")"
203 | );
204 | }
205 |
206 | default void logDiscordChatMessage(User author, Message message) {
207 | log(ChatService.DISCORD, "Message", () ->
208 | "from(" + author.getName() + "#" + author.getDiscriminator() + ") message(\"" + message.getContentStripped() + "\")"
209 | );
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/MessageProcessor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import com.rezzedup.discordsrv.staffchat.config.MessagesConfig;
26 | import com.rezzedup.discordsrv.staffchat.events.ConsoleStaffChatMessageEvent;
27 | import com.rezzedup.discordsrv.staffchat.events.DiscordStaffChatMessageEvent;
28 | import com.rezzedup.discordsrv.staffchat.events.PlayerStaffChatMessageEvent;
29 | import com.rezzedup.discordsrv.staffchat.util.MappedPlaceholder;
30 | import com.rezzedup.discordsrv.staffchat.util.Strings;
31 | import community.leaf.configvalues.bukkit.DefaultYamlValue;
32 | import github.scarsz.discordsrv.DiscordSRV;
33 | import github.scarsz.discordsrv.dependencies.emoji.EmojiParser;
34 | import github.scarsz.discordsrv.dependencies.jda.api.entities.Member;
35 | import github.scarsz.discordsrv.dependencies.jda.api.entities.Message;
36 | import github.scarsz.discordsrv.dependencies.jda.api.entities.Role;
37 | import github.scarsz.discordsrv.dependencies.jda.api.entities.TextChannel;
38 | import github.scarsz.discordsrv.dependencies.jda.api.entities.User;
39 | import github.scarsz.discordsrv.util.DiscordUtil;
40 | import me.clip.placeholderapi.PlaceholderAPI;
41 | import net.md_5.bungee.api.ChatColor;
42 | import org.bukkit.entity.Player;
43 | import pl.tlinkowski.annotation.basic.NullOr;
44 |
45 | import java.awt.*;
46 | import java.util.List;
47 | import java.util.Locale;
48 | import java.util.Objects;
49 | import java.util.function.Consumer;
50 |
51 | public class MessageProcessor {
52 | private final StaffChatPlugin plugin;
53 |
54 | MessageProcessor(StaffChatPlugin plugin) {
55 | this.plugin = plugin;
56 | }
57 |
58 | private void sendFormattedChatMessage(@NullOr Object author, DefaultYamlValue format, MappedPlaceholder placeholders) {
59 | // If the value of %message% doesn't exist for some reason, don't announce.
60 | if (Strings.isEmptyOrNull(placeholders.get("message"))) {
61 | return;
62 | }
63 |
64 | String formatted = plugin.messages().getOrDefault(format);
65 |
66 | if (plugin.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
67 | // Update format's PAPI placeholders before inserting the message
68 | // (which *could* contain arbitrary placeholders itself, ah placeholder injection).
69 | @NullOr Player player = (author instanceof Player) ? (Player) author : null;
70 | formatted = PlaceholderAPI.setPlaceholders(player, formatted);
71 | }
72 |
73 | String content = Strings.colorful(placeholders.update(formatted));
74 |
75 | if (author instanceof Player) {
76 | Player player = (Player) author;
77 | StaffChatProfile profile = plugin.data().getOrCreateProfile(player);
78 |
79 | // Author left the staff chat but is sending a message there...
80 | if (!profile.receivesStaffChatMessages()) {
81 | String reminder = Strings.colorful(placeholders.update(
82 | plugin.messages().getOrDefault(MessagesConfig.LEFT_CHAT_NOTIFICATION_REMINDER))
83 | );
84 |
85 | player.sendMessage(content);
86 | player.sendMessage(reminder);
87 |
88 | plugin.config().playNotificationSound(player);
89 | }
90 | }
91 |
92 | plugin.onlineStaffChatParticipants().forEach(staff -> {
93 | staff.sendMessage(content);
94 | plugin.config().playMessageSound(staff);
95 | });
96 |
97 | plugin.getServer().getConsoleSender().sendMessage(content);
98 | }
99 |
100 | private void sendToDiscord(Consumer sender) {
101 | @NullOr TextChannel channel = plugin.getDiscordChannelOrNull();
102 |
103 | if (channel == null) {
104 | plugin.debug(getClass()).log(ChatService.MINECRAFT, "Message", () ->
105 | "Unable to send message to discord: " + StaffChatPlugin.CHANNEL + " => null"
106 | );
107 | return;
108 | }
109 |
110 | plugin.debug(getClass()).log(ChatService.MINECRAFT, "Message", () ->
111 | "Sending message to discord channel: " + StaffChatPlugin.CHANNEL + " => " + channel
112 | );
113 |
114 | sender.accept(channel);
115 | }
116 |
117 | public void processConsoleChat(String message) {
118 | Objects.requireNonNull(message, "message");
119 |
120 | plugin.debug(getClass()).logConsoleChatMessage(message);
121 |
122 | ConsoleStaffChatMessageEvent event =
123 | plugin.events().call(new ConsoleStaffChatMessageEvent(message));
124 |
125 | if (event.isCancelled() || event.getText().isEmpty()) {
126 | plugin.debug(getClass()).log(ChatService.MINECRAFT, event, () -> "Cancelled or text is empty");
127 | return;
128 | }
129 |
130 | MappedPlaceholder placeholders = plugin.messages().placeholders();
131 | placeholders.map("message", "content", "text").to(event::getText);
132 |
133 | sendFormattedChatMessage(null, MessagesConfig.IN_GAME_CONSOLE_FORMAT, placeholders);
134 |
135 | if (plugin.isDiscordSrvHookEnabled()) {
136 | String discordMessage = placeholders.update(
137 | plugin.messages().getOrDefault(MessagesConfig.DISCORD_CONSOLE_FORMAT)
138 | );
139 |
140 | sendToDiscord(channel -> DiscordUtil.queueMessage(channel, discordMessage, true));
141 | } else {
142 | plugin.debug(getClass()).log(ChatService.MINECRAFT, "Message", () ->
143 | "DiscordSRV hook is not enabled, cannot send to discord"
144 | );
145 | }
146 | }
147 |
148 | public void processPlayerChat(Player author, String message) {
149 | Objects.requireNonNull(author, "author");
150 | Objects.requireNonNull(message, "message");
151 |
152 | plugin.debug(getClass()).logPlayerChatMessage(author, message);
153 |
154 | PlayerStaffChatMessageEvent event =
155 | plugin.events().call(new PlayerStaffChatMessageEvent(author, message));
156 |
157 | if (event.isCancelled() || event.getText().isEmpty()) {
158 | plugin.debug(getClass()).log(ChatService.MINECRAFT, event, () -> "Cancelled or text is empty");
159 | return;
160 | }
161 |
162 | MappedPlaceholder placeholders = plugin.messages().placeholders(author);
163 | placeholders.map("message", "content", "text").to(event::getText);
164 |
165 | sendFormattedChatMessage(author, MessagesConfig.IN_GAME_PLAYER_FORMAT, placeholders);
166 |
167 | if (plugin.isDiscordSrvHookEnabled()) {
168 | sendToDiscord(channel -> {
169 | // Send to discord off the main thread (just like DiscordSRV does)
170 | plugin.async().run(() ->
171 | DiscordSRV.getPlugin().processChatMessage(author, message, StaffChatPlugin.CHANNEL, false)
172 | );
173 | });
174 | } else {
175 | plugin.debug(getClass()).log(ChatService.MINECRAFT, "Message", () ->
176 | "DiscordSRV hook is not enabled, cannot send to discord"
177 | );
178 | }
179 | }
180 |
181 | public void processDiscordChat(User author, Message message) {
182 | Objects.requireNonNull(author, "author");
183 | Objects.requireNonNull(message, "message");
184 |
185 | plugin.debug(getClass()).logDiscordChatMessage(author, message);
186 |
187 | DiscordStaffChatMessageEvent event =
188 | plugin.events().call(new DiscordStaffChatMessageEvent(author, message, message.getContentStripped()));
189 |
190 | if (event.isCancelled() || event.getText().isEmpty()) {
191 | plugin.debug(getClass()).log(ChatService.DISCORD, "Message", () -> "Cancelled or text is empty");
192 | return;
193 | }
194 |
195 | // Emoji Unicode -> Alias (library included with DiscordSRV)
196 | String text = EmojiParser.parseToAliases(event.getText());
197 |
198 | MappedPlaceholder placeholders = plugin.messages().placeholders();
199 |
200 | placeholders.map("message", "content", "text").to(() -> text);
201 | placeholders.map("user", "name", "username", "sender").to(author::getName);
202 | placeholders.map("discriminator", "discrim").to(author::getDiscriminator);
203 |
204 | @NullOr Member member = message.getMember();
205 |
206 | if (member != null) {
207 | placeholders.map("nickname", "displayname").to(member::getEffectiveName);
208 |
209 | // Simulate placeholders from DiscordSRV:
210 | // https://github.com/DiscordSRV/DiscordSRV/blob/1d08598206b1af5dcc29e411cead8e152e4c3f94/src/main/java/github/scarsz/discordsrv/listeners/DiscordChatListener.java#L293
211 |
212 | DiscordSRV discordSrv = DiscordSRV.getPlugin();
213 | List selectedRoles = discordSrv.getSelectedRoles(member);
214 | @NullOr Role topRole = (selectedRoles.isEmpty()) ? null : selectedRoles.get(0);
215 |
216 | if (topRole != null) {
217 | placeholders.map("toprole").to(topRole::getName);
218 | placeholders.map("toproleinitial").to(() -> topRole.getName().substring(0, 1));
219 |
220 | placeholders.map("toprolealias").to(() ->
221 | discordSrv.getRoleAliases().getOrDefault(
222 | topRole.getId(),
223 | discordSrv.getRoleAliases().getOrDefault(
224 | topRole.getName().toLowerCase(Locale.ROOT),
225 | topRole.getName()
226 | )
227 | )
228 | );
229 |
230 | placeholders.map("toprolecolor").to(() -> ChatColor.of(new Color(topRole.getColorRaw())));
231 | placeholders.map("allroles").to(() -> DiscordUtil.getFormattedRoles(selectedRoles));
232 | }
233 | }
234 |
235 | sendFormattedChatMessage(author, MessagesConfig.IN_GAME_DISCORD_FORMAT, placeholders);
236 | }
237 | }
238 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/Permissions.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import org.bukkit.permissions.Permissible;
26 |
27 | public enum Permissions {
28 | MANAGE,
29 | ACCESS;
30 |
31 | public static final String PREFIX = "staffchat";
32 |
33 | private final String permission;
34 |
35 | Permissions() {
36 | this.permission = PREFIX + "." + name().toLowerCase();
37 | }
38 |
39 | public String getPermissionNode() {
40 | return this.permission;
41 | }
42 |
43 | public boolean allows(Permissible permissible) {
44 | return permissible.hasPermission(permission);
45 | }
46 |
47 | public boolean denies(Permissible permissible) {
48 | return !allows(permissible);
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/StaffChatAPI.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import github.scarsz.discordsrv.dependencies.jda.api.entities.Message;
26 | import github.scarsz.discordsrv.dependencies.jda.api.entities.TextChannel;
27 | import github.scarsz.discordsrv.dependencies.jda.api.entities.User;
28 | import org.bukkit.Bukkit;
29 | import org.bukkit.entity.Player;
30 | import pl.tlinkowski.annotation.basic.NullOr;
31 |
32 | import java.util.stream.Stream;
33 |
34 | public interface StaffChatAPI {
35 | StaffChatData data();
36 |
37 | boolean isDiscordSrvHookEnabled();
38 |
39 | @NullOr TextChannel getDiscordChannelOrNull();
40 |
41 | void submitMessageFromConsole(String message);
42 |
43 | void submitMessageFromPlayer(Player author, String message);
44 |
45 | void submitMessageFromDiscord(User author, Message message);
46 |
47 | default Stream extends Player> onlineStaffChatParticipants() {
48 | return Bukkit.getOnlinePlayers().stream()
49 | .filter(Permissions.ACCESS::allows)
50 | .filter(data()::isReceivingStaffChatMessages);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/StaffChatData.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import org.bukkit.entity.Player;
26 |
27 | import java.util.Optional;
28 | import java.util.UUID;
29 |
30 | public interface StaffChatData {
31 | StaffChatProfile getOrCreateProfile(UUID uuid);
32 |
33 | Optional getProfile(UUID uuid);
34 |
35 | default StaffChatProfile getOrCreateProfile(Player player) {
36 | return getOrCreateProfile(player.getUniqueId());
37 | }
38 |
39 | default Optional getProfile(Player player) {
40 | // If they're a staff member, then they will always have a profile
41 | // otherwise, return the possibly existing profile for non-staff
42 | return (Permissions.ACCESS.allows(player))
43 | ? Optional.of(getOrCreateProfile(player.getUniqueId()))
44 | : getProfile(player.getUniqueId());
45 | }
46 |
47 | default boolean isAutomaticStaffChatEnabled(Player player) {
48 | return getProfile(player).filter(StaffChatProfile::automaticStaffChat).isPresent();
49 | }
50 |
51 | default boolean isReceivingStaffChatMessages(Player player) {
52 | return getProfile(player).filter(StaffChatProfile::receivesStaffChatMessages).isPresent();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/StaffChatPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import com.github.zafarkhaja.semver.Version;
26 | import com.rezzedup.discordsrv.staffchat.commands.ManageStaffChatCommand;
27 | import com.rezzedup.discordsrv.staffchat.commands.StaffChatCommand;
28 | import com.rezzedup.discordsrv.staffchat.commands.ToggleStaffChatCommand;
29 | import com.rezzedup.discordsrv.staffchat.commands.ToggleStaffChatSoundsCommand;
30 | import com.rezzedup.discordsrv.staffchat.config.MessagesConfig;
31 | import com.rezzedup.discordsrv.staffchat.config.StaffChatConfig;
32 | import com.rezzedup.discordsrv.staffchat.listeners.DiscordSrvLoadedLaterListener;
33 | import com.rezzedup.discordsrv.staffchat.listeners.DiscordStaffChatListener;
34 | import com.rezzedup.discordsrv.staffchat.listeners.JoinNotificationListener;
35 | import com.rezzedup.discordsrv.staffchat.listeners.PlayerPrefixedMessageListener;
36 | import com.rezzedup.discordsrv.staffchat.listeners.PlayerStaffChatToggleListener;
37 | import com.rezzedup.discordsrv.staffchat.util.FileIO;
38 | import community.leaf.configvalues.bukkit.YamlValue;
39 | import community.leaf.configvalues.bukkit.data.YamlDataFile;
40 | import community.leaf.eventful.bukkit.BukkitEventSource;
41 | import community.leaf.tasks.bukkit.BukkitTaskSource;
42 | import github.scarsz.discordsrv.DiscordSRV;
43 | import github.scarsz.discordsrv.dependencies.jda.api.entities.Message;
44 | import github.scarsz.discordsrv.dependencies.jda.api.entities.TextChannel;
45 | import github.scarsz.discordsrv.dependencies.jda.api.entities.User;
46 | import org.bstats.bukkit.Metrics;
47 | import org.bstats.charts.SimplePie;
48 | import org.bukkit.command.CommandExecutor;
49 | import org.bukkit.command.PluginCommand;
50 | import org.bukkit.command.TabCompleter;
51 | import org.bukkit.entity.Player;
52 | import org.bukkit.plugin.Plugin;
53 | import org.bukkit.plugin.java.JavaPlugin;
54 | import pl.tlinkowski.annotation.basic.NullOr;
55 |
56 | import java.nio.file.Files;
57 | import java.nio.file.Path;
58 | import java.util.List;
59 |
60 | public class StaffChatPlugin extends JavaPlugin implements BukkitTaskSource, BukkitEventSource, StaffChatAPI {
61 | // https://bstats.org/plugin/bukkit/DiscordSRV-Staff-Chat/11056
62 | public static final int BSTATS = 11056;
63 |
64 | public static final String CHANNEL = "staff-chat";
65 |
66 | public static final String DISCORDSRV = "DiscordSRV";
67 |
68 | private @NullOr Version version;
69 | private @NullOr Path pluginDirectoryPath;
70 | private @NullOr Path backupsDirectoryPath;
71 | private @NullOr Debugger debugger;
72 | private @NullOr StaffChatConfig config;
73 | private @NullOr MessagesConfig messages;
74 | private @NullOr Data data;
75 | private @NullOr Updater updater;
76 | private @NullOr MessageProcessor processor;
77 | private @NullOr DiscordStaffChatListener discordSrvHook;
78 |
79 | @Override
80 | public void onEnable() {
81 | this.version = Version.valueOf(getDescription().getVersion());
82 |
83 | this.pluginDirectoryPath = getDataFolder().toPath();
84 | this.backupsDirectoryPath = pluginDirectoryPath.resolve("backups");
85 |
86 | this.debugger = new Debugger(this);
87 |
88 | debug(getClass()).header(() -> "Starting Plugin: " + this);
89 | debugger().schedulePluginStatus(getClass(), "Enable");
90 |
91 | this.config = new StaffChatConfig(this);
92 | this.messages = new MessagesConfig(this);
93 |
94 | loadConfigurationFiles();
95 |
96 | this.data = new Data(this);
97 | this.updater = new Updater(this);
98 | this.processor = new MessageProcessor(this);
99 |
100 | events().register(new JoinNotificationListener(this));
101 | events().register(new PlayerPrefixedMessageListener(this));
102 | events().register(new PlayerStaffChatToggleListener(this));
103 |
104 |
105 | command("staffchat", new StaffChatCommand(this));
106 | command("managestaffchat", new ManageStaffChatCommand(this));
107 | command("togglestaffchatsounds", new ToggleStaffChatSoundsCommand(this));
108 |
109 | ToggleStaffChatCommand toggle = new ToggleStaffChatCommand(this);
110 | command("leavestaffchat", toggle);
111 | command("joinstaffchat", toggle);
112 |
113 | @NullOr Plugin discordSrv = getServer().getPluginManager().getPlugin(DISCORDSRV);
114 |
115 | if (discordSrv != null) {
116 | debug(getClass()).log("Enable", () -> "DiscordSRV is enabled");
117 | subscribeToDiscordSrv(discordSrv);
118 | } else {
119 | debug(getClass()).log("Enable", () -> "DiscordSRV is not enabled: continuing without discord support");
120 |
121 | getLogger().warning("DiscordSRV is not currently enabled (messages will NOT be sent to Discord).");
122 | getLogger().warning("Staff chat messages will still work in-game, however.");
123 |
124 | // Subscribe to DiscordSRV later because it somehow hasn't enabled yet.
125 | events().register(new DiscordSrvLoadedLaterListener(this));
126 | }
127 |
128 | startMetrics();
129 |
130 | // Display toggle message so that auto staff-chat users are aware that their chat is private again.
131 | // Useful when hot loading this plugin on a live server.
132 | onlineStaffChatParticipants()
133 | .filter(data()::isAutomaticStaffChatEnabled)
134 | .forEach(messages()::notifyAutoChatEnabled);
135 | }
136 |
137 | @Override
138 | public void onDisable() {
139 | debug(getClass()).log("Disable", () -> "Disabling plugin...");
140 |
141 | data().end();
142 | updater().end();
143 |
144 | // Display toggle message so that auto staff-chat users are aware that their chat is public again.
145 | // Useful when selectively disabling this plugin on a live server.
146 | onlineStaffChatParticipants()
147 | .filter(data()::isAutomaticStaffChatEnabled)
148 | .forEach(messages()::notifyAutoChatDisabled);
149 |
150 | if (isDiscordSrvHookEnabled()) {
151 | debug(getClass()).log("Disable", () -> "Unsubscribing from DiscordSRV API (hook is enabled)");
152 |
153 | try {
154 | DiscordSRV.api.unsubscribe(discordSrvHook);
155 | } catch (RuntimeException ignored) {
156 | } // Don't show a user-facing error if DiscordSRV is already unloaded.
157 | }
158 |
159 | debug(getClass()).header(() -> "Disabled Plugin: " + this);
160 | }
161 |
162 | private T initialized(@NullOr T thing) {
163 | if (thing != null) {
164 | return thing;
165 | }
166 | throw new IllegalStateException("Not initialized yet");
167 | }
168 |
169 | @Override
170 | public Plugin plugin() {
171 | return this;
172 | }
173 |
174 | public Version version() {
175 | return initialized(version);
176 | }
177 |
178 | public Path directory() {
179 | return initialized(pluginDirectoryPath);
180 | }
181 |
182 | public Path backups() {
183 | return initialized(backupsDirectoryPath);
184 | }
185 |
186 | public Debugger debugger() {
187 | return initialized(debugger);
188 | }
189 |
190 | public Debugger.DebugLogger debug(Class> clazz) {
191 | return debugger().debug(clazz);
192 | }
193 |
194 | public StaffChatConfig config() {
195 | return initialized(config);
196 | }
197 |
198 | public MessagesConfig messages() {
199 | return initialized(messages);
200 | }
201 |
202 | @Override
203 | public Data data() {
204 | return initialized(data);
205 | }
206 |
207 | public Updater updater() {
208 | return initialized(updater);
209 | }
210 |
211 | @Override
212 | public boolean isDiscordSrvHookEnabled() {
213 | return discordSrvHook != null;
214 | }
215 |
216 | public void subscribeToDiscordSrv(Plugin plugin) {
217 | debug(getClass()).log("Subscribe", () -> "Subscribing to DiscordSRV: " + plugin);
218 |
219 | if (!DISCORDSRV.equals(plugin.getName()) || !(plugin instanceof DiscordSRV)) {
220 | throw debug(getClass()).failure("Subscribe", new IllegalArgumentException("Not DiscordSRV: " + plugin));
221 | }
222 |
223 | if (isDiscordSrvHookEnabled()) {
224 | throw debug(getClass()).failure("Subscribe", new IllegalStateException(
225 | "Already subscribed to DiscordSRV. Did the server reload? ... If so, don't do that!"
226 | ));
227 | }
228 |
229 | DiscordSRV.api.subscribe(discordSrvHook = new DiscordStaffChatListener(this));
230 |
231 | getLogger().info("Subscribed to DiscordSRV: messages will be sent to Discord");
232 | }
233 |
234 | @Override
235 | public @NullOr TextChannel getDiscordChannelOrNull() {
236 | return (isDiscordSrvHookEnabled())
237 | ? DiscordSRV.getPlugin().getDestinationTextChannelForGameChannelName(CHANNEL)
238 | : null;
239 | }
240 |
241 | private MessageProcessor processor() {
242 | return initialized(processor);
243 | }
244 |
245 | @Override
246 | public void submitMessageFromConsole(String message) {
247 | processor().processConsoleChat(message);
248 | }
249 |
250 | @Override
251 | public void submitMessageFromPlayer(Player author, String message) {
252 | processor().processPlayerChat(author, message);
253 | }
254 |
255 | @Override
256 | public void submitMessageFromDiscord(User author, Message message) {
257 | processor().processDiscordChat(author, message);
258 | }
259 |
260 | //
261 | //
262 | //
263 |
264 | private void loadConfigurationFiles() {
265 | // Explicitly load configs
266 | config().reload();
267 | messages().reload();
268 |
269 | // Upgrade & migrate legacy config if it exists
270 | upgradeLegacyConfig();
271 | }
272 |
273 | private void upgradeLegacyConfig(YamlDataFile file, List> values) {
274 | file.migrateValues(values, getConfig());
275 |
276 | if (file.isNewlyCreated()) {
277 | file.save();
278 | } else {
279 | file.backupThenSave(backups(), "migrated");
280 | }
281 | }
282 |
283 | private void upgradeLegacyConfig() {
284 | Path legacyConfigPath = directory().resolve("config.yml");
285 | if (!Files.isRegularFile(legacyConfigPath)) {
286 | return;
287 | }
288 |
289 | debug(getClass()).log("Upgrade Legacy Config", () ->
290 | "Found legacy config, upgrading it to new configs..."
291 | );
292 |
293 | upgradeLegacyConfig(config(), StaffChatConfig.VALUES);
294 | upgradeLegacyConfig(messages(), MessagesConfig.VALUES);
295 |
296 | try {
297 | FileIO.backup(legacyConfigPath, backups().resolve("config.legacy.yml"));
298 | Files.deleteIfExists(legacyConfigPath);
299 | } catch (Exception e) {
300 | e.printStackTrace();
301 | debug(getClass()).log("Upgrade Legacy Config", () ->
302 | "Failed to backup legacy config: " + e.getMessage()
303 | );
304 | }
305 | }
306 |
307 | private void command(String name, CommandExecutor executor) {
308 | @NullOr PluginCommand command = getCommand(name);
309 |
310 | if (command == null) {
311 | debug(getClass()).log("Command: Setup", () ->
312 | "Unable to register command /" + name + " because it is not defined in plugin.yml"
313 | );
314 | return;
315 | }
316 |
317 | command.setExecutor(executor);
318 | debug(getClass()).log("Command: Setup", () -> "Registered command executor for: /" + name);
319 |
320 | if (executor instanceof TabCompleter) {
321 | command.setTabCompleter((TabCompleter) executor);
322 | debug(getClass()).log("Command: Setup", () -> "Registered tab completer for: /" + name);
323 | }
324 | }
325 |
326 | private void startMetrics() {
327 | if (!config().getOrDefault(StaffChatConfig.METRICS_ENABLED)) {
328 | debug(getClass()).log("Metrics", () -> "Aborting: metrics are disabled in the config");
329 | return;
330 | }
331 |
332 | debug(getClass()).log("Metrics", () -> "Scheduling metrics to start one minute from now");
333 |
334 | // Start a minute later to get the most accurate data.
335 | sync().delay(1).minutes().run(() ->
336 | {
337 | Metrics metrics = new Metrics(this, BSTATS);
338 |
339 | metrics.addCustomChart(new SimplePie(
340 | "hooked_into_discordsrv", () -> String.valueOf(isDiscordSrvHookEnabled())
341 | ));
342 |
343 | metrics.addCustomChart(new SimplePie(
344 | "has_valid_staff-chat_channel", () -> String.valueOf(getDiscordChannelOrNull() != null)
345 | ));
346 |
347 | debug(getClass()).log("Metrics", () -> "Started bStats metrics");
348 | });
349 | }
350 | }
351 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/StaffChatProfile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import org.bukkit.Bukkit;
26 | import org.bukkit.entity.Player;
27 |
28 | import java.time.Instant;
29 | import java.util.Optional;
30 | import java.util.UUID;
31 |
32 | public interface StaffChatProfile {
33 | UUID uuid();
34 |
35 | Optional sinceEnabledAutoChat();
36 |
37 | boolean automaticStaffChat();
38 |
39 | void automaticStaffChat(boolean enabled);
40 |
41 | Optional sinceLeftStaffChat();
42 |
43 | boolean receivesStaffChatMessages();
44 |
45 | void receivesStaffChatMessages(boolean enabled);
46 |
47 | boolean receivesStaffChatSounds();
48 |
49 | void receivesStaffChatSounds(boolean enabled);
50 |
51 | default void toggleAutomaticStaffChat() {
52 | automaticStaffChat(!automaticStaffChat());
53 | }
54 |
55 | default Optional toPlayer() {
56 | return Optional.ofNullable(Bukkit.getPlayer(uuid()));
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/Updater.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat;
24 |
25 | import com.github.zafarkhaja.semver.Version;
26 | import com.google.gson.JsonObject;
27 | import com.google.gson.JsonParser;
28 | import com.rezzedup.discordsrv.staffchat.config.StaffChatConfig;
29 | import community.leaf.tasks.TaskContext;
30 | import net.md_5.bungee.api.ChatColor;
31 | import org.bukkit.command.CommandSender;
32 | import org.bukkit.command.ConsoleCommandSender;
33 | import org.bukkit.entity.Player;
34 | import org.bukkit.scheduler.BukkitTask;
35 | import pl.tlinkowski.annotation.basic.NullOr;
36 |
37 | import java.net.URI;
38 | import java.net.http.HttpClient;
39 | import java.net.http.HttpRequest;
40 | import java.net.http.HttpResponse;
41 | import java.util.Optional;
42 |
43 | public class Updater {
44 | public static final String RESOURCE_PAGE = "https://www.spigotmc.org/resources/44245/";
45 |
46 | public static final URI LATEST_UPDATE_API_ENDPOINT = URI.create("https://api.spiget.org/v2/resources/44245/versions/latest");
47 |
48 | private final StaffChatPlugin plugin;
49 | private final HttpClient client;
50 | private final String userAgent;
51 |
52 | private @NullOr TaskContext task;
53 | private @NullOr Version latestAvailableVersion;
54 |
55 | Updater(StaffChatPlugin plugin) {
56 | this.plugin = plugin;
57 | this.client = HttpClient.newHttpClient();
58 |
59 | this.userAgent =
60 | plugin.getName() + "/" + plugin.version() + " (Minecraft) " +
61 | plugin.getServer().getName() + "/" + plugin.getServer().getVersion();
62 |
63 | plugin.debug(getClass()).log("Init", () -> "User-Agent: " + userAgent);
64 |
65 | reload();
66 | }
67 |
68 | public boolean isRunningUpdateCheckTask() {
69 | return task != null;
70 | }
71 |
72 | public Optional latestAvailableVersion() {
73 | return Optional.ofNullable(latestAvailableVersion);
74 | }
75 |
76 | public Optional latestUpdateVersion() {
77 | return latestAvailableVersion().filter(plugin.version()::lessThan);
78 | }
79 |
80 | public boolean isOutdated() {
81 | return latestUpdateVersion().isPresent();
82 | }
83 |
84 | public void end() {
85 | if (task != null) {
86 | task.cancel();
87 | }
88 | }
89 |
90 | public void reload() {
91 | if (plugin.config().getOrDefault(StaffChatConfig.UPDATE_CHECKER_ENABLED)) {
92 | if (task == null || task.isCancelled()) {
93 | plugin.debug(getClass()).log("Reload", () -> "Update checker enabled: starting task");
94 | this.task = plugin.async().delay(10).ticks().every(7).hours().run(this::checkForUpdates);
95 | } else {
96 | plugin.debug(getClass()).log("Reload", () -> "Update checker enabled: task already running");
97 | }
98 | } else {
99 | latestAvailableVersion = null;
100 |
101 | if (task != null) {
102 | plugin.debug(getClass()).log("Reload", () -> "Update checker disabled: ending previously-enabled task");
103 | task.cancel();
104 | } else {
105 | plugin.debug(getClass()).log("Reload", () -> "Update checker disabled: will not start task");
106 | }
107 | }
108 | }
109 |
110 | private void checkForUpdates() {
111 | HttpRequest request =
112 | HttpRequest.newBuilder(LATEST_UPDATE_API_ENDPOINT)
113 | .setHeader("User-Agent", userAgent)
114 | .build();
115 |
116 | try {
117 | HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString());
118 |
119 | if (response.statusCode() != 200) {
120 | plugin.debug(getClass()).log("Update Check: Failure", () ->
121 | "Cannot check latest version, response status code: " + response.statusCode()
122 | );
123 | return;
124 | }
125 |
126 | JsonObject json = new JsonParser().parse(response.body()).getAsJsonObject();
127 | this.latestAvailableVersion = Version.valueOf(json.get("name").getAsString());
128 |
129 | plugin.debug(getClass()).log("Update Check: Success", () ->
130 | "Found latest available version: " + latestAvailableVersion + " (current: " + plugin.version() + ")"
131 | );
132 |
133 | plugin.sync().run(() -> notifyIfUpdateAvailable(plugin.getServer().getConsoleSender()));
134 | } catch (Exception e) {
135 | plugin.debug(getClass()).logException("Update Check: Failure", e);
136 | }
137 | }
138 |
139 | private void print(String text) {
140 | plugin.getLogger().info(ChatColor.BLUE + text);
141 | }
142 |
143 | public void notifyIfUpdateAvailable(CommandSender sender) {
144 | latestUpdateVersion().ifPresent(version ->
145 | {
146 | if (sender instanceof Player) {
147 | plugin.messages().notifyUpdateAvailable((Player) sender, version);
148 | } else if (sender instanceof ConsoleCommandSender) {
149 | print("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
150 | print("An update is available: " + version + " (current: " + plugin.version() + ")");
151 | print("Get the update @ " + RESOURCE_PAGE);
152 | print("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
153 | }
154 | });
155 | }
156 | }
157 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/commands/ManageStaffChatCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.commands;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
26 | import com.rezzedup.util.constants.Aggregates;
27 | import com.rezzedup.util.constants.MatchRules;
28 | import com.rezzedup.util.constants.annotations.AggregatedResult;
29 | import org.bukkit.command.Command;
30 | import org.bukkit.command.CommandExecutor;
31 | import org.bukkit.command.CommandSender;
32 | import org.bukkit.command.TabCompleter;
33 | import org.bukkit.entity.Player;
34 | import pl.tlinkowski.annotation.basic.NullOr;
35 |
36 | import java.util.ArrayList;
37 | import java.util.List;
38 | import java.util.Locale;
39 | import java.util.Set;
40 | import java.util.stream.Collectors;
41 |
42 | import static com.rezzedup.discordsrv.staffchat.util.Strings.colorful;
43 |
44 | public class ManageStaffChatCommand implements CommandExecutor, TabCompleter {
45 | private static final Set RELOAD_ALIASES = Set.of("reload");
46 | private static final Set DEBUG_ALIASES = Set.of("debug");
47 | private static final Set HELP_ALIASES = Set.of("help", "usage", "?");
48 |
49 | @AggregatedResult
50 | private static final Set ALL_OPTION_ALIASES =
51 | Aggregates.fromThisClass()
52 | .constantsOfType(String.class)
53 | .matching(
54 | MatchRules.of().all("ALIAS").collections(true)
55 | )
56 | .toSet();
57 |
58 | private final StaffChatPlugin plugin;
59 |
60 | public ManageStaffChatCommand(StaffChatPlugin plugin) {
61 | this.plugin = plugin;
62 | }
63 |
64 | @Override
65 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
66 | @NullOr String option = (args.length >= 1) ? args[0].toLowerCase(Locale.ROOT) : null;
67 |
68 | if (option == null || HELP_ALIASES.contains(option)) {
69 | usage(sender, label);
70 | } else if (RELOAD_ALIASES.contains(option)) {
71 | reload(sender);
72 | } else if (DEBUG_ALIASES.contains(option)) {
73 | debug(sender);
74 | } else {
75 | sender.sendMessage(colorful(
76 | "&9&lDiscordSRV-Staff-Chat&f: &7&oUnknown arguments: " + String.join(" ", args)
77 | ));
78 | }
79 |
80 | return true;
81 | }
82 |
83 | @Override
84 | public @NullOr List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
85 | @NullOr List suggestions = null;
86 |
87 | if (args.length <= 0) {
88 | suggestions = new ArrayList<>(ALL_OPTION_ALIASES);
89 | } else if (args.length == 1) {
90 | String last = args[0].toLowerCase(Locale.ROOT);
91 |
92 | suggestions =
93 | ALL_OPTION_ALIASES.stream()
94 | .filter(option -> option.contains(last))
95 | .collect(Collectors.toCollection(ArrayList::new));
96 | }
97 |
98 | if (suggestions != null) {
99 | suggestions.sort(String.CASE_INSENSITIVE_ORDER);
100 | }
101 | return suggestions;
102 | }
103 |
104 | private void usage(CommandSender sender, String label) {
105 | sender.sendMessage(colorful(
106 | "&9DiscordSRV-&lStaff&9-&lChat &fv" + plugin.getDescription().getVersion() + " Usage:"
107 | ));
108 |
109 | sender.sendMessage(colorful("&f- &7/staffchat &9Toggle automatic staff chat"));
110 | sender.sendMessage(colorful("&f- &7/staffchat &9Send a message to staff chat"));
111 | sender.sendMessage(colorful("&f- &7/leavestaffchat &9Leave the staff chat"));
112 | sender.sendMessage(colorful("&f- &7/joinstaffchat &9Rejoin the staff chat"));
113 | sender.sendMessage(colorful("&f- &7/" + label.toLowerCase() + " reload &9Reload configs"));
114 | sender.sendMessage(colorful("&f- &7/" + label.toLowerCase() + " debug &9Toggle debugging"));
115 |
116 | if (plugin.debugger().isEnabled()) {
117 | sender.sendMessage(colorful("&2→ &aDebugging is currently enabled"));
118 | } else {
119 | sender.sendMessage(colorful("&7→ &8Debugging is currently disabled"));
120 | }
121 |
122 | plugin.updater().notifyIfUpdateAvailable(sender);
123 | }
124 |
125 | private void reload(CommandSender sender) {
126 | plugin.debug(getClass()).log("Reload", () -> "Reloading configs and data...");
127 |
128 | plugin.config().reload();
129 | plugin.messages().reload();
130 | plugin.data().reload();
131 | plugin.updater().reload();
132 |
133 | sender.sendMessage(colorful("&9&lDiscordSRV-Staff-Chat&f: Reloaded."));
134 | }
135 |
136 | private void debug(CommandSender sender) {
137 | boolean enabled = !plugin.debugger().isEnabled();
138 | plugin.debugger().setEnabled(enabled);
139 |
140 | if (enabled) {
141 | plugin.debugger().schedulePluginStatus(getClass(), "Debug Toggle");
142 | sender.sendMessage(colorful("&9[Debug] &2→ &aEnabled debugging"));
143 |
144 | if (sender instanceof Player) {
145 | sender.sendMessage(colorful("&9[Debug]&o Sending a test message..."));
146 | plugin.sync().delay(10).ticks().run(() ->
147 | plugin.getServer().dispatchCommand(sender, "staffchat Hello! Just testing things...")
148 | );
149 | }
150 | } else {
151 | sender.sendMessage(colorful("&9[Debug] &4→ &cDisabled debugging"));
152 | }
153 | }
154 | }
155 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/commands/StaffChatCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.commands;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
26 | import org.bukkit.command.Command;
27 | import org.bukkit.command.CommandExecutor;
28 | import org.bukkit.command.CommandSender;
29 | import org.bukkit.command.ConsoleCommandSender;
30 | import org.bukkit.entity.Player;
31 |
32 | public class StaffChatCommand implements CommandExecutor {
33 | private final StaffChatPlugin plugin;
34 |
35 | public StaffChatCommand(StaffChatPlugin plugin) {
36 | this.plugin = plugin;
37 | }
38 |
39 | @Override
40 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
41 | if (args.length <= 0) {
42 | // Show usage to console (only players can enable auto chat)
43 | if (!(sender instanceof Player)) {
44 | return false;
45 | }
46 | plugin.data().getOrCreateProfile((Player) sender).toggleAutomaticStaffChat();
47 | } else {
48 | String message = String.join(" ", args);
49 |
50 | if (sender instanceof Player) {
51 | plugin.submitMessageFromPlayer((Player) sender, message);
52 | } else if (sender instanceof ConsoleCommandSender) {
53 | plugin.submitMessageFromConsole(message);
54 | } else {
55 | sender.sendMessage("Unsupported command sender type: " + sender.getClass().getSimpleName());
56 | }
57 | }
58 |
59 | return true;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/commands/ToggleStaffChatCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.commands;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
26 | import org.bukkit.command.Command;
27 | import org.bukkit.command.CommandExecutor;
28 | import org.bukkit.command.CommandSender;
29 | import org.bukkit.entity.Player;
30 |
31 | public class ToggleStaffChatCommand implements CommandExecutor {
32 | private final StaffChatPlugin plugin;
33 |
34 | public ToggleStaffChatCommand(StaffChatPlugin plugin) {
35 | this.plugin = plugin;
36 | }
37 |
38 | @Override
39 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
40 | if (sender instanceof Player) {
41 | // Either join or leave so...
42 | plugin.data().getOrCreateProfile((Player) sender)
43 | .receivesStaffChatMessages(command.getName().contains("join"));
44 | } else {
45 | sender.sendMessage("Only players may run this command.");
46 | }
47 |
48 | return true;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/commands/ToggleStaffChatSoundsCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.commands;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
26 | import com.rezzedup.discordsrv.staffchat.StaffChatProfile;
27 | import org.bukkit.command.Command;
28 | import org.bukkit.command.CommandExecutor;
29 | import org.bukkit.command.CommandSender;
30 | import org.bukkit.entity.Player;
31 | import org.jetbrains.annotations.NotNull;
32 |
33 | public class ToggleStaffChatSoundsCommand implements CommandExecutor {
34 | private final StaffChatPlugin plugin;
35 |
36 | public ToggleStaffChatSoundsCommand(StaffChatPlugin plugin) {
37 | this.plugin = plugin;
38 | }
39 |
40 | @Override
41 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
42 | if (sender instanceof Player) {
43 | Player player = (Player) sender;
44 | StaffChatProfile profile = plugin.data().getOrCreateProfile(player);
45 | boolean toggle = !profile.receivesStaffChatSounds();
46 | profile.receivesStaffChatSounds(toggle);
47 |
48 | plugin.debug(getClass()).log(() -> String.format(
49 | "Player: %s (%s) has %s receiving staff chat sounds",
50 | player.getName(), profile.uuid(), ((toggle) ? "enabled (unmuted)" : "disabled (muted)")
51 | ));
52 |
53 | if (toggle) {
54 | plugin.messages().notifySoundsUnmuted(player);
55 | } else {
56 | plugin.messages().notifySoundsMuted(player);
57 | }
58 | } else {
59 | sender.sendMessage("Only players may run this command.");
60 | }
61 |
62 | return true;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/commands/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | @NonNullPackage
24 | package com.rezzedup.discordsrv.staffchat.commands;
25 |
26 | import pl.tlinkowski.annotation.basic.NonNullPackage;
27 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/config/Configs.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.config;
24 |
25 | import com.github.zafarkhaja.semver.Version;
26 | import com.rezzedup.util.valuables.Adapter;
27 | import community.leaf.configvalues.bukkit.YamlAccessor;
28 |
29 | import java.nio.file.Path;
30 | import java.util.Optional;
31 | import java.util.logging.Logger;
32 |
33 | public class Configs {
34 | private Configs() {
35 | throw new UnsupportedOperationException();
36 | }
37 |
38 | public static final Version NO_VERSION = Version.forIntegers(0, 0, 0);
39 |
40 | public static YamlAccessor VERSION =
41 | YamlAccessor.of(Adapter.of(
42 | object -> {
43 | try {
44 | return Optional.of(Version.valueOf(String.valueOf(object)));
45 | } catch (RuntimeException e) {
46 | return Optional.empty();
47 | }
48 | },
49 | version -> Optional.of(String.valueOf(version))
50 | ));
51 |
52 | public static void couldNotLoad(Logger logger, Path path) {
53 | logger.warning("Couldn't load configuration: " + path.getFileName());
54 | logger.warning("Default values will be used until the config file is repaired.");
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/config/MessagesConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.config;
24 |
25 | import com.github.zafarkhaja.semver.Version;
26 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
27 | import com.rezzedup.discordsrv.staffchat.Updater;
28 | import com.rezzedup.discordsrv.staffchat.util.MappedPlaceholder;
29 | import com.rezzedup.discordsrv.staffchat.util.Strings;
30 | import com.rezzedup.util.constants.Aggregates;
31 | import com.rezzedup.util.constants.annotations.AggregatedResult;
32 | import community.leaf.configvalues.bukkit.DefaultYamlValue;
33 | import community.leaf.configvalues.bukkit.ExampleYamlValue;
34 | import community.leaf.configvalues.bukkit.YamlValue;
35 | import community.leaf.configvalues.bukkit.data.Load;
36 | import community.leaf.configvalues.bukkit.data.YamlDataFile;
37 | import community.leaf.configvalues.bukkit.migrations.Migration;
38 | import community.leaf.configvalues.bukkit.util.Sections;
39 | import org.bukkit.entity.Player;
40 | import pl.tlinkowski.annotation.basic.NullOr;
41 |
42 | import java.util.List;
43 | import java.util.function.Predicate;
44 |
45 | public class MessagesConfig extends YamlDataFile {
46 | public static final YamlValue VERSION =
47 | YamlValue.of("meta.config-version", Configs.VERSION).maybe();
48 |
49 | public static final DefaultYamlValue PREFIX =
50 | YamlValue.ofString("placeholders.prefix")
51 | .defaults("&d(&5&l&oStaff&d)");
52 |
53 | public static final ExampleYamlValue EXAMPLE_PLACEHOLDER =
54 | YamlValue.ofString("placeholders.example")
55 | .example("Define your own placeholders here!");
56 |
57 | public static final DefaultYamlValue IN_GAME_PLAYER_FORMAT =
58 | YamlValue.ofString("messages.in-game-formats.player")
59 | .migrates(Migration.move("in-game-message-format"))
60 | .defaults("%prefix% %name%&7:&f %message%");
61 |
62 | public static final DefaultYamlValue IN_GAME_DISCORD_FORMAT =
63 | YamlValue.ofString("messages.in-game-formats.discord")
64 | .migrates(Migration.move("discord-message-format"))
65 | .defaults("&9&ldiscord &f→ %prefix% %name%&7:&f %message%");
66 |
67 | public static final DefaultYamlValue IN_GAME_CONSOLE_FORMAT =
68 | YamlValue.ofString("messages.in-game-formats.console")
69 | .defaults("%prefix% [CONSOLE]&7:&f %message%");
70 |
71 | public static final DefaultYamlValue DISCORD_CONSOLE_FORMAT =
72 | YamlValue.ofString("messages.discord-formats.console")
73 | .defaults("**`CONSOLE:`** %message%");
74 |
75 | public static final DefaultYamlValue AUTO_ENABLED_NOTIFICATION =
76 | YamlValue.ofString("notifications.automatic-staff-chat.enabled")
77 | .migrates(Migration.move("enable-staff-chat"))
78 | .defaults("%prefix% &2→&a &nEnabled&a automatic staff chat");
79 |
80 | public static final DefaultYamlValue AUTO_DISABLED_NOTIFICATION =
81 | YamlValue.ofString("notifications.automatic-staff-chat.disabled")
82 | .migrates(Migration.move("disable-staff-chat"))
83 | .defaults("%prefix% &4→&c &nDisabled&c automatic staff chat");
84 |
85 | public static final DefaultYamlValue LEFT_CHAT_NOTIFICATION_SELF =
86 | YamlValue.ofString("notifications.leave.self")
87 | .defaults(
88 | "%prefix% &4→&c You &nleft&c the staff chat&r\n" +
89 | "&8&oYou won't receive any staff chat messages"
90 | );
91 |
92 | public static final DefaultYamlValue LEFT_CHAT_NOTIFICATION_OTHERS =
93 | YamlValue.ofString("notifications.leave.others")
94 | .defaults("%prefix% &4→&c %player% &nleft&c the staff chat");
95 |
96 | public static final DefaultYamlValue LEFT_CHAT_NOTIFICATION_REMINDER =
97 | YamlValue.ofString("notifications.leave.reminder")
98 | .defaults("&8&o(Reminder: you left the staff chat)");
99 |
100 | public static final DefaultYamlValue LEFT_CHAT_DISABLED_ERROR =
101 | YamlValue.ofString("notifications.leave.disabled")
102 | .defaults(
103 | "%prefix% &6→&e You cannot leave the staff chat\n" +
104 | "&8&oLeaving the staff chat is currently disabled"
105 | );
106 |
107 | public static final DefaultYamlValue JOIN_CHAT_NOTIFICATION_SELF =
108 | YamlValue.ofString("notifications.join.self")
109 | .defaults(
110 | "%prefix% &2→&a You &njoined&a the staff chat&r\n" +
111 | "&8&oYou will now receive staff chat messages again"
112 | );
113 |
114 | public static final DefaultYamlValue JOIN_CHAT_NOTIFICATION_OTHERS =
115 | YamlValue.ofString("notifications.join.others")
116 | .defaults("%prefix% &2→&a %player% &njoined&a the staff chat");
117 |
118 | public static final DefaultYamlValue MUTE_SOUNDS_NOTIFICATION =
119 | YamlValue.ofString("notifications.sounds.muted")
120 | .defaults(
121 | "%prefix% &4→&c You have &nmuted&c staff chat sounds"
122 | );
123 |
124 | public static final DefaultYamlValue UNMUTE_SOUNDS_NOTIFICATION =
125 | YamlValue.ofString("notifications.sounds.unmuted")
126 | .defaults(
127 | "%prefix% &2→&a You have &nunmuted&a staff chat sounds"
128 | );
129 |
130 | @AggregatedResult
131 | public static final List> VALUES =
132 | Aggregates.fromThisClass().constantsOfType(YamlValue.type()).toList();
133 |
134 | private final StaffChatPlugin plugin;
135 |
136 | private @NullOr MappedPlaceholder definitions = null;
137 |
138 | public MessagesConfig(StaffChatPlugin plugin) {
139 | super(plugin.directory(), "messages.config.yml", Load.LATER);
140 | this.plugin = plugin;
141 |
142 | reloadsWith(() ->
143 | {
144 | if (isInvalid()) {
145 | Configs.couldNotLoad(plugin.getLogger(), getFilePath());
146 | plugin.debug(getClass()).log("Reload", () -> "Couldn't load: " + getInvalidReason());
147 |
148 | // Add default placeholders
149 | if (definitions == null) {
150 | definitions = new MappedPlaceholder();
151 | definitions.map("prefix").to(PREFIX::getDefaultValue);
152 | }
153 |
154 | return;
155 | }
156 |
157 | Version existing = get(VERSION).orElse(Configs.NO_VERSION);
158 | boolean isOutdated = existing.lessThan(plugin.version());
159 |
160 | if (isOutdated) {
161 | plugin.debug(getClass()).log("Reload", () -> "Updating outdated config: " + existing);
162 | set(VERSION, plugin.version());
163 | }
164 |
165 | headerFromResource("messages.config.header.txt");
166 | defaultValues(VALUES);
167 |
168 | if (isUpdated()) {
169 | plugin.debug(getClass()).log("Reload", () -> "Saving updated config and backing up old config: v" + existing);
170 | backupThenSave(plugin.backups(), "v" + existing);
171 | }
172 |
173 | // Remove old placeholder definitions
174 | definitions = null;
175 |
176 | // Load defined placeholders
177 | Sections.get(data(), "placeholders").ifPresent(section ->
178 | {
179 | definitions = new MappedPlaceholder();
180 |
181 | for (String key : section.getKeys(false)) {
182 | @NullOr String value = section.getString(key);
183 | if (Strings.isEmptyOrNull(value)) {
184 | continue;
185 | }
186 | definitions.map(key).to(() -> value);
187 | }
188 | });
189 | });
190 | }
191 |
192 | public MappedPlaceholder placeholders() {
193 | MappedPlaceholder placeholders = new MappedPlaceholder();
194 | if (definitions != null) {
195 | placeholders.inherit(definitions);
196 | }
197 | return placeholders;
198 | }
199 |
200 | public MappedPlaceholder placeholders(Player player) {
201 | MappedPlaceholder placeholders = placeholders();
202 |
203 | placeholders.map("user", "name", "username", "player", "sender").to(player::getName);
204 | placeholders.map("nickname", "displayname").to(player::getDisplayName);
205 |
206 | return placeholders;
207 | }
208 |
209 | private void sendNotification(Player player, String message) {
210 | player.sendMessage(message);
211 | plugin.config().playNotificationSound(player);
212 | }
213 |
214 | private void sendNotification(Player player, DefaultYamlValue self, @NullOr DefaultYamlValue others) {
215 | MappedPlaceholder placeholders = placeholders(player);
216 | sendNotification(player, Strings.colorful(placeholders.update(getOrDefault(self))));
217 |
218 | if (others == null) {
219 | return;
220 | }
221 |
222 | String notification = Strings.colorful(placeholders.update(getOrDefault(others)));
223 | plugin.getServer().getConsoleSender().sendMessage(notification);
224 |
225 | plugin.onlineStaffChatParticipants()
226 | .filter(Predicate.not(player::equals))
227 | .forEach(staff -> sendNotification(staff, notification));
228 | }
229 |
230 | public void notifyAutoChatEnabled(Player enabler) {
231 | sendNotification(enabler, AUTO_ENABLED_NOTIFICATION, null);
232 | }
233 |
234 | public void notifyAutoChatDisabled(Player disabler) {
235 | sendNotification(disabler, AUTO_DISABLED_NOTIFICATION, null);
236 | }
237 |
238 | public void notifyLeaveChat(Player leaver, boolean notifyOthers) {
239 | @NullOr DefaultYamlValue others = (notifyOthers) ? LEFT_CHAT_NOTIFICATION_OTHERS : null;
240 | sendNotification(leaver, LEFT_CHAT_NOTIFICATION_SELF, others);
241 | }
242 |
243 | public void notifyLeavingChatIsDisabled(Player leaver) {
244 | sendNotification(leaver, LEFT_CHAT_DISABLED_ERROR, null);
245 | }
246 |
247 | public void notifyJoinChat(Player joiner, boolean notifyOthers) {
248 | @NullOr DefaultYamlValue others = (notifyOthers) ? JOIN_CHAT_NOTIFICATION_OTHERS : null;
249 | sendNotification(joiner, JOIN_CHAT_NOTIFICATION_SELF, others);
250 | }
251 |
252 | public void notifySoundsMuted(Player player) {
253 | sendNotification(player, MUTE_SOUNDS_NOTIFICATION, null);
254 | }
255 |
256 | public void notifySoundsUnmuted(Player player) {
257 | sendNotification(player, UNMUTE_SOUNDS_NOTIFICATION, null);
258 | }
259 |
260 | //
261 | // Unconfigurable notifications
262 | //
263 |
264 | public void notifyUpdateAvailable(Player manager, Version version) {
265 | sendNotification(manager, Strings.colorful(
266 | "&9DiscordSRV-&lStaff&9-&lChat&6 →&e Update available: &f" +
267 | version + " &6&o(" + plugin.version() + ")&r\n" + "&9&o&n" + Updater.RESOURCE_PAGE
268 | ));
269 | }
270 | }
271 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/config/StaffChatConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.config;
24 |
25 | import com.github.zafarkhaja.semver.Version;
26 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
27 | import com.rezzedup.discordsrv.staffchat.StaffChatProfile;
28 | import com.rezzedup.util.constants.Aggregates;
29 | import com.rezzedup.util.constants.annotations.AggregatedResult;
30 | import community.leaf.configvalues.bukkit.DefaultYamlValue;
31 | import community.leaf.configvalues.bukkit.YamlValue;
32 | import community.leaf.configvalues.bukkit.data.Load;
33 | import community.leaf.configvalues.bukkit.data.YamlDataFile;
34 | import community.leaf.configvalues.bukkit.migrations.Migration;
35 | import org.bukkit.Sound;
36 | import org.bukkit.entity.Player;
37 |
38 | import java.util.List;
39 |
40 | public class StaffChatConfig extends YamlDataFile {
41 | public static final YamlValue VERSION =
42 | YamlValue.of("meta.config-version", Configs.VERSION).maybe();
43 |
44 | public static final DefaultYamlValue METRICS_ENABLED =
45 | YamlValue.ofBoolean("plugin.metrics")
46 | .migrates(Migration.move("metrics"))
47 | .defaults(true);
48 |
49 | public static final DefaultYamlValue UPDATE_CHECKER_ENABLED =
50 | YamlValue.ofBoolean("plugin.updates.check-for-updates").defaults(true);
51 |
52 | public static final DefaultYamlValue NOTIFY_IF_UPDATE_AVAILABLE =
53 | YamlValue.ofBoolean("plugin.updates.notify-in-game").defaults(true);
54 |
55 | public static final DefaultYamlValue PERSIST_TOGGLES =
56 | YamlValue.ofBoolean("staff-chat.toggles.chat-toggles-persist-after-restart").defaults(true);
57 |
58 | public static final DefaultYamlValue LEAVING_STAFFCHAT_ENABLED =
59 | YamlValue.ofBoolean("staff-chat.toggles.let-staff-members-leave-staffchat").defaults(true);
60 |
61 | public static final DefaultYamlValue NOTIFY_IF_TOGGLE_ENABLED =
62 | YamlValue.ofBoolean("staff-chat.toggles.notify-toggle-status-on-join")
63 | .migrates(Migration.move("notify-staff-chat-enabled-on-join"))
64 | .defaults(true);
65 |
66 | public static final DefaultYamlValue PREFIXED_CHAT_ENABLED =
67 | YamlValue.ofBoolean("staff-chat.prefixed.enable-prefixed-chat-messages")
68 | .migrates(Migration.move("enable-prefixed-chat-messages"))
69 | .defaults(false);
70 |
71 | public static final DefaultYamlValue PREFIXED_CHAT_IDENTIFIER =
72 | YamlValue.ofString("staff-chat.prefixed.prefixed-chat-identifier")
73 | .migrates(Migration.move("prefixed-chat-identifier"))
74 | .defaults("@");
75 |
76 | // Message Sound
77 |
78 | public static final DefaultYamlValue MESSAGE_SOUND_ENABLED =
79 | YamlValue.ofBoolean("sounds.messages.enabled").defaults(true);
80 |
81 | public static final DefaultYamlValue MESSAGE_SOUND_NAME =
82 | YamlValue.ofSound("sounds.messages.name").defaults(Sound.ENTITY_ITEM_PICKUP);
83 |
84 | public static final DefaultYamlValue MESSAGE_SOUND_VOLUME =
85 | YamlValue.ofFloat("sounds.messages.volume").defaults(1.0F);
86 |
87 | public static final DefaultYamlValue MESSAGE_SOUND_PITCH =
88 | YamlValue.ofFloat("sounds.messages.pitch").defaults(0.5F);
89 |
90 | // Notification Sound
91 |
92 | public static final DefaultYamlValue NOTIFICATION_SOUND_ENABLED =
93 | YamlValue.ofBoolean("sounds.notifications.enabled").defaults(true);
94 |
95 | public static final DefaultYamlValue NOTIFICATION_SOUND_NAME =
96 | YamlValue.ofSound("sounds.notifications.name").defaults(Sound.ENTITY_ITEM_PICKUP);
97 |
98 | public static final DefaultYamlValue NOTIFICATION_SOUND_VOLUME =
99 | YamlValue.ofFloat("sounds.notifications.volume").defaults(1.0F);
100 |
101 | public static final DefaultYamlValue NOTIFICATION_SOUND_PITCH =
102 | YamlValue.ofFloat("sounds.notifications.pitch").defaults(0.75F);
103 |
104 | @AggregatedResult
105 | public static final List> VALUES =
106 | Aggregates.fromThisClass().constantsOfType(YamlValue.type()).toList();
107 |
108 | private final StaffChatPlugin plugin;
109 |
110 | public StaffChatConfig(StaffChatPlugin plugin) {
111 | super(plugin.directory(), "staff-chat.config.yml", Load.LATER);
112 | this.plugin = plugin;
113 |
114 | reloadsWith(() ->
115 | {
116 | if (isInvalid()) {
117 | Configs.couldNotLoad(plugin.getLogger(), getFilePath());
118 | plugin.debug(getClass()).log("Reload", () -> "Couldn't load: " + getInvalidReason());
119 | return;
120 | }
121 |
122 | Version existing = get(VERSION).orElse(Configs.NO_VERSION);
123 | boolean isOutdated = existing.isLowerThan(plugin.version());
124 |
125 | if (isOutdated) {
126 | plugin.debug(getClass()).log("Reload", () -> "Updating outdated config: " + existing);
127 | set(VERSION, plugin.version());
128 | }
129 |
130 | headerFromResource("staff-chat.config.header.txt");
131 | defaultValues(VALUES);
132 |
133 | if (isUpdated()) {
134 | plugin.debug(getClass()).log("Reload", () -> "Saving updated config and backing up old config: v" + existing);
135 | backupThenSave(plugin.backups(), "v" + existing);
136 | }
137 | });
138 | }
139 |
140 | private void playSound(
141 | Player player,
142 | DefaultYamlValue enabled,
143 | DefaultYamlValue sound,
144 | DefaultYamlValue volume,
145 | DefaultYamlValue pitch
146 | ) {
147 | if (!getOrDefault(enabled)) {
148 | return;
149 | }
150 |
151 | boolean sounds = plugin.data().getProfile(player)
152 | .map(StaffChatProfile::receivesStaffChatSounds)
153 | .orElse(true);
154 |
155 | if (sounds) {
156 | player.playSound(
157 | player.getLocation().add(0, 0.5, 0),
158 | getOrDefault(sound),
159 | getOrDefault(volume),
160 | getOrDefault(pitch)
161 | );
162 | }
163 | }
164 |
165 | public void playMessageSound(Player player) {
166 | playSound(player, MESSAGE_SOUND_ENABLED, MESSAGE_SOUND_NAME, MESSAGE_SOUND_VOLUME, MESSAGE_SOUND_PITCH);
167 | }
168 |
169 | public void playNotificationSound(Player player) {
170 | playSound(player, NOTIFICATION_SOUND_ENABLED, NOTIFICATION_SOUND_NAME, NOTIFICATION_SOUND_VOLUME, NOTIFICATION_SOUND_PITCH);
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/config/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | @NonNullPackage
24 | package com.rezzedup.discordsrv.staffchat.config;
25 |
26 | import pl.tlinkowski.annotation.basic.NonNullPackage;
27 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/AutoStaffChatToggleEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.events;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatProfile;
26 | import org.bukkit.event.HandlerList;
27 |
28 | public class AutoStaffChatToggleEvent extends ProfileToggleEvent {
29 | public AutoStaffChatToggleEvent(StaffChatProfile profile, boolean toggleState) {
30 | super(profile, toggleState);
31 | }
32 |
33 | public boolean isEnablingAutomaticChat() {
34 | return getToggleState();
35 | }
36 |
37 | //
38 | // - - - HandlerList boilerplate - - -
39 | //
40 |
41 | public static final HandlerList HANDLERS = new HandlerList();
42 |
43 | @Override
44 | public HandlerList getHandlers() {
45 | return HANDLERS;
46 | }
47 |
48 | public static HandlerList getHandlerList() {
49 | return HANDLERS;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/ConsoleStaffChatMessageEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.events;
24 |
25 | import com.rezzedup.discordsrv.staffchat.ChatService;
26 | import org.bukkit.Bukkit;
27 | import org.bukkit.command.ConsoleCommandSender;
28 | import org.bukkit.event.HandlerList;
29 |
30 | @SuppressWarnings("unused")
31 | public class ConsoleStaffChatMessageEvent extends StaffChatMessageEvent {
32 | public ConsoleStaffChatMessageEvent(String text) {
33 | super(Bukkit.getConsoleSender(), text, text);
34 | }
35 |
36 | @Override
37 | public final ChatService getSource() {
38 | return ChatService.MINECRAFT;
39 | }
40 |
41 | @Override
42 | public final ChatService getDestination() {
43 | return ChatService.DISCORD;
44 | }
45 |
46 | //
47 | // - - - HandlerList boilerplate - - -
48 | //
49 |
50 | public static final HandlerList HANDLERS = new HandlerList();
51 |
52 | @Override
53 | public HandlerList getHandlers() {
54 | return HANDLERS;
55 | }
56 |
57 | public static HandlerList getHandlerList() {
58 | return HANDLERS;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/DiscordStaffChatMessageEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.events;
24 |
25 | import com.rezzedup.discordsrv.staffchat.ChatService;
26 | import github.scarsz.discordsrv.dependencies.jda.api.entities.Message;
27 | import github.scarsz.discordsrv.dependencies.jda.api.entities.User;
28 | import org.bukkit.event.HandlerList;
29 |
30 | @SuppressWarnings("unused")
31 | public class DiscordStaffChatMessageEvent extends StaffChatMessageEvent {
32 | public DiscordStaffChatMessageEvent(User author, Message message, String text) {
33 | super(author, message, text);
34 | }
35 |
36 | @Override
37 | public final ChatService getSource() {
38 | return ChatService.DISCORD;
39 | }
40 |
41 | @Override
42 | public final ChatService getDestination() {
43 | return ChatService.MINECRAFT;
44 | }
45 |
46 | //
47 | // - - - HandlerList boilerplate - - -
48 | //
49 |
50 | public static final HandlerList HANDLERS = new HandlerList();
51 |
52 | @Override
53 | public HandlerList getHandlers() {
54 | return HANDLERS;
55 | }
56 |
57 | public static HandlerList getHandlerList() {
58 | return HANDLERS;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/PlayerStaffChatMessageEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.events;
24 |
25 | import com.rezzedup.discordsrv.staffchat.ChatService;
26 | import org.bukkit.entity.Player;
27 | import org.bukkit.event.HandlerList;
28 |
29 | @SuppressWarnings("unused")
30 | public class PlayerStaffChatMessageEvent extends StaffChatMessageEvent {
31 | public PlayerStaffChatMessageEvent(Player author, String text) {
32 | super(author, text, text);
33 | }
34 |
35 | @Override
36 | public final ChatService getSource() {
37 | return ChatService.MINECRAFT;
38 | }
39 |
40 | @Override
41 | public final ChatService getDestination() {
42 | return ChatService.DISCORD;
43 | }
44 |
45 | //
46 | // - - - HandlerList boilerplate - - -
47 | //
48 |
49 | public static final HandlerList HANDLERS = new HandlerList();
50 |
51 | @Override
52 | public HandlerList getHandlers() {
53 | return HANDLERS;
54 | }
55 |
56 | public static HandlerList getHandlerList() {
57 | return HANDLERS;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/ProfileToggleEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.events;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatProfile;
26 | import org.bukkit.event.Cancellable;
27 | import org.bukkit.event.Event;
28 |
29 | import java.util.Objects;
30 |
31 | public abstract class ProfileToggleEvent extends Event implements Cancellable {
32 | private final StaffChatProfile profile;
33 | private final boolean toggleState;
34 |
35 | private boolean isQuiet = false;
36 |
37 | public ProfileToggleEvent(StaffChatProfile profile, boolean toggleState) {
38 | this.profile = Objects.requireNonNull(profile, "profile");
39 | this.toggleState = toggleState;
40 | }
41 |
42 | public StaffChatProfile getProfile() {
43 | return profile;
44 | }
45 |
46 | public boolean getToggleState() {
47 | return toggleState;
48 | }
49 |
50 | public boolean isQuiet() {
51 | return isQuiet;
52 | }
53 |
54 | public void setQuiet(boolean quiet) {
55 | this.isQuiet = quiet;
56 | }
57 |
58 | //
59 | // - - - Cancellable boilerplate - - -
60 | //
61 |
62 | private boolean isCancelled = false;
63 |
64 | @Override
65 | public final boolean isCancelled() {
66 | return isCancelled;
67 | }
68 |
69 | @Override
70 | public final void setCancelled(boolean cancelled) {
71 | isCancelled = cancelled;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/ReceivingStaffChatToggleEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.events;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatProfile;
26 | import org.bukkit.event.HandlerList;
27 |
28 | public class ReceivingStaffChatToggleEvent extends ProfileToggleEvent {
29 | public ReceivingStaffChatToggleEvent(StaffChatProfile profile, boolean toggleState) {
30 | super(profile, toggleState);
31 | }
32 |
33 | public boolean isJoiningStaffChat() {
34 | return getToggleState();
35 | }
36 |
37 | public boolean isLeavingStaffChat() {
38 | return !getToggleState();
39 | }
40 |
41 | //
42 | // - - - HandlerList boilerplate - - -
43 | //
44 |
45 | public static final HandlerList HANDLERS = new HandlerList();
46 |
47 | @Override
48 | public HandlerList getHandlers() {
49 | return HANDLERS;
50 | }
51 |
52 | public static HandlerList getHandlerList() {
53 | return HANDLERS;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/StaffChatMessageEvent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.events;
24 |
25 | import com.rezzedup.discordsrv.staffchat.ChatService;
26 | import org.bukkit.event.Cancellable;
27 | import org.bukkit.event.Event;
28 |
29 | import java.util.Objects;
30 |
31 | public abstract class StaffChatMessageEvent extends Event implements Cancellable {
32 | private final A author;
33 | private final M message;
34 | private String text;
35 |
36 | public StaffChatMessageEvent(A author, M message, String text) {
37 | this.author = Objects.requireNonNull(author, "author");
38 | this.message = Objects.requireNonNull(message, "message");
39 | this.text = Objects.requireNonNull(text, "text");
40 | }
41 |
42 | public abstract ChatService getSource();
43 |
44 | public abstract ChatService getDestination();
45 |
46 | public final A getAuthor() {
47 | return author;
48 | }
49 |
50 | public final M getMessage() {
51 | return message;
52 | }
53 |
54 | public final String getText() {
55 | return text;
56 | }
57 |
58 | public final void setText(String text) {
59 | this.text = Objects.requireNonNull(text, "text");
60 | }
61 |
62 | //
63 | // - - - Cancellable boilerplate - - -
64 | //
65 |
66 | private boolean isCancelled = false;
67 |
68 | @Override
69 | public final boolean isCancelled() {
70 | return isCancelled;
71 | }
72 |
73 | @Override
74 | public final void setCancelled(boolean cancelled) {
75 | isCancelled = cancelled;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/events/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | @NonNullPackage
24 | package com.rezzedup.discordsrv.staffchat.events;
25 |
26 | import pl.tlinkowski.annotation.basic.NonNullPackage;
27 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/listeners/DiscordSrvLoadedLaterListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.listeners;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
26 | import community.leaf.eventful.bukkit.annotations.EventListener;
27 | import org.bukkit.event.Listener;
28 | import org.bukkit.event.server.PluginEnableEvent;
29 |
30 | @SuppressWarnings("unused")
31 | public class DiscordSrvLoadedLaterListener implements Listener {
32 | private final StaffChatPlugin plugin;
33 |
34 | public DiscordSrvLoadedLaterListener(StaffChatPlugin plugin) {
35 | this.plugin = plugin;
36 | }
37 |
38 | @EventListener
39 | public void onPluginEnable(PluginEnableEvent event) {
40 | if (StaffChatPlugin.DISCORDSRV.equals(event.getPlugin().getName())) {
41 | plugin.debug(getClass()).log(event, () -> "DiscordSRV loaded late: " + event.getPlugin());
42 | plugin.debugger().schedulePluginStatus(getClass(), "Loaded Late");
43 | plugin.subscribeToDiscordSrv(event.getPlugin());
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/listeners/DiscordStaffChatListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.listeners;
24 |
25 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
26 | import github.scarsz.discordsrv.api.Subscribe;
27 | import github.scarsz.discordsrv.api.events.DiscordGuildMessagePreProcessEvent;
28 |
29 | @SuppressWarnings("unused")
30 | public class DiscordStaffChatListener {
31 | private final StaffChatPlugin plugin;
32 |
33 | public DiscordStaffChatListener(StaffChatPlugin plugin) {
34 | this.plugin = plugin;
35 | }
36 |
37 | @Subscribe
38 | public void onDiscordChat(DiscordGuildMessagePreProcessEvent event) {
39 | if (event.getChannel().equals(plugin.getDiscordChannelOrNull())) {
40 | event.setCancelled(true); // Cancel this message from getting sent to global chat.
41 |
42 | // Handle this on the main thread next tick.
43 | plugin.sync().run(() -> plugin.submitMessageFromDiscord(event.getAuthor(), event.getMessage()));
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/listeners/JoinNotificationListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.listeners;
24 |
25 | import com.rezzedup.discordsrv.staffchat.Permissions;
26 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
27 | import com.rezzedup.discordsrv.staffchat.config.StaffChatConfig;
28 | import community.leaf.eventful.bukkit.ListenerOrder;
29 | import community.leaf.eventful.bukkit.annotations.EventListener;
30 | import org.bukkit.entity.Player;
31 | import org.bukkit.event.Listener;
32 | import org.bukkit.event.player.PlayerJoinEvent;
33 | import org.bukkit.event.player.PlayerQuitEvent;
34 |
35 | import java.util.ArrayDeque;
36 | import java.util.Deque;
37 |
38 | public class JoinNotificationListener implements Listener {
39 | private final StaffChatPlugin plugin;
40 |
41 | public JoinNotificationListener(StaffChatPlugin plugin) {
42 | this.plugin = plugin;
43 | }
44 |
45 | @EventListener(ListenerOrder.EARLY)
46 | public void onPlayerJoin(PlayerJoinEvent event) {
47 | Player player = event.getPlayer();
48 | plugin.data().updateProfile(player);
49 |
50 | Deque reminders = new ArrayDeque<>();
51 |
52 | if (plugin.config().getOrDefault(StaffChatConfig.NOTIFY_IF_TOGGLE_ENABLED)) {
53 | if (Permissions.ACCESS.allows(player)) {
54 | if (plugin.data().isAutomaticStaffChatEnabled(player)) {
55 | plugin.debug(getClass()).log(event, () ->
56 | "Player " + event.getPlayer().getName() + " joined: " +
57 | "reminding them that they have automatic staff-chat enabled"
58 | );
59 |
60 | reminders.add(() -> plugin.messages().notifyAutoChatEnabled(player));
61 | }
62 |
63 | if (!plugin.data().isReceivingStaffChatMessages(player)) {
64 | plugin.debug(getClass()).log(event, () ->
65 | "Player " + event.getPlayer().getName() + " joined: " +
66 | "reminding them that they previously left the staff-chat"
67 | );
68 |
69 | reminders.add(() -> plugin.messages().notifyLeaveChat(player, false));
70 | }
71 | }
72 | }
73 |
74 | if (plugin.config().getOrDefault(StaffChatConfig.NOTIFY_IF_UPDATE_AVAILABLE)) {
75 | if (Permissions.MANAGE.allows(player)) {
76 | plugin.updater().latestUpdateVersion().ifPresent(version ->
77 | {
78 | plugin.debug(getClass()).log(event, () ->
79 | "Player " + event.getPlayer().getName() + " joined: " +
80 | "notifying them that a new update is available (" + version + ")"
81 | );
82 |
83 | reminders.add(() -> plugin.messages().notifyUpdateAvailable(player, version));
84 | });
85 | }
86 | }
87 |
88 | if (reminders.isEmpty()) {
89 | return;
90 | }
91 |
92 | plugin.sync().delay(10).ticks().every(10).ticks().run(task ->
93 | {
94 | if (reminders.isEmpty()) {
95 | task.cancel();
96 | } else {
97 | reminders.pop().run();
98 | }
99 | });
100 | }
101 |
102 | @EventListener(ListenerOrder.EARLY)
103 | public void onPlayerQuit(PlayerQuitEvent event) {
104 | // Might as well update the profile (cleanup)
105 | plugin.data().updateProfile(event.getPlayer());
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/listeners/PlayerPrefixedMessageListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.listeners;
24 |
25 | import com.rezzedup.discordsrv.staffchat.Permissions;
26 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
27 | import com.rezzedup.discordsrv.staffchat.config.StaffChatConfig;
28 | import com.rezzedup.discordsrv.staffchat.util.Strings;
29 | import community.leaf.eventful.bukkit.CancellationPolicy;
30 | import community.leaf.eventful.bukkit.ListenerOrder;
31 | import community.leaf.eventful.bukkit.annotations.CancelledEvents;
32 | import community.leaf.eventful.bukkit.annotations.EventListener;
33 | import org.bukkit.entity.Player;
34 | import org.bukkit.event.Listener;
35 | import org.bukkit.event.player.AsyncPlayerChatEvent;
36 |
37 | @SuppressWarnings("unused")
38 | public class PlayerPrefixedMessageListener implements Listener {
39 | private final StaffChatPlugin plugin;
40 |
41 | public PlayerPrefixedMessageListener(StaffChatPlugin plugin) {
42 | this.plugin = plugin;
43 | }
44 |
45 | @EventListener(ListenerOrder.EARLY)
46 | @CancelledEvents(CancellationPolicy.REJECT)
47 | public void onPrefixedChatEarly(AsyncPlayerChatEvent event) {
48 | if (!plugin.config().getOrDefault(StaffChatConfig.PREFIXED_CHAT_ENABLED)) {
49 | return;
50 | }
51 |
52 | Player player = event.getPlayer();
53 | if (Permissions.ACCESS.denies(player)) {
54 | return;
55 | }
56 |
57 | String identifier = plugin.config().getOrDefault(StaffChatConfig.PREFIXED_CHAT_IDENTIFIER);
58 | if (Strings.isEmptyOrNull(identifier)) {
59 | plugin.debug(getClass()).log(event, () -> "Early Listener: Prefixed chat is enabled but identifier is undefined");
60 | return;
61 | }
62 |
63 | String message = event.getMessage();
64 | if (!message.startsWith(identifier)) {
65 | return;
66 | }
67 |
68 | plugin.debug(getClass()).log(event, () ->
69 | "Early Listener: Detected prefixed chat from player(" + player.getName() + "): message(\"" + message + "\")"
70 | );
71 |
72 | event.setCancelled(true); // Cancel this message from getting sent to global chat.
73 | // Handle message in a later listener order, allowing other plugins to modify the message.
74 | }
75 |
76 | @EventListener(ListenerOrder.MONITOR)
77 | public void onPrefixedChatMonitor(AsyncPlayerChatEvent event) {
78 | // Event should already be cancelled in the early listener.
79 | if (!event.isCancelled()) {
80 | return;
81 | }
82 |
83 | if (!plugin.config().getOrDefault(StaffChatConfig.PREFIXED_CHAT_ENABLED)) {
84 | return;
85 | }
86 |
87 | Player player = event.getPlayer();
88 | if (Permissions.ACCESS.denies(player)) {
89 | return;
90 | }
91 |
92 | String identifier = plugin.config().getOrDefault(StaffChatConfig.PREFIXED_CHAT_IDENTIFIER);
93 | if (Strings.isEmptyOrNull(identifier)) {
94 | plugin.debug(getClass()).log(event, () -> "Monitor Listener: Prefixed chat is enabled but identifier is undefined");
95 | return;
96 | }
97 |
98 | String message = event.getMessage();
99 | if (!message.startsWith(identifier)) {
100 | return;
101 | }
102 |
103 | String unprefixed = message.substring(identifier.length()).trim();
104 | String submission = (Strings.isEmptyOrNull(unprefixed)) ? message : unprefixed;
105 |
106 | plugin.debug(getClass()).log(event, () ->
107 | "Monitor Listener: Sending prefixed chat from player(" + player.getName() + ") identified " +
108 | "by prefix(\"" + identifier + "\"): message(\"" + submission + "\")"
109 | );
110 |
111 | // Handle this on the main thread next tick.
112 | plugin.sync().run(() -> plugin.submitMessageFromPlayer(player, submission));
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/listeners/PlayerStaffChatToggleListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.listeners;
24 |
25 | import com.rezzedup.discordsrv.staffchat.Permissions;
26 | import com.rezzedup.discordsrv.staffchat.StaffChatPlugin;
27 | import com.rezzedup.discordsrv.staffchat.config.StaffChatConfig;
28 | import com.rezzedup.discordsrv.staffchat.events.AutoStaffChatToggleEvent;
29 | import com.rezzedup.discordsrv.staffchat.events.ReceivingStaffChatToggleEvent;
30 | import community.leaf.eventful.bukkit.CancellationPolicy;
31 | import community.leaf.eventful.bukkit.ListenerOrder;
32 | import community.leaf.eventful.bukkit.annotations.CancelledEvents;
33 | import community.leaf.eventful.bukkit.annotations.EventListener;
34 | import org.bukkit.entity.Player;
35 | import org.bukkit.event.Listener;
36 | import org.bukkit.event.player.AsyncPlayerChatEvent;
37 | import pl.tlinkowski.annotation.basic.NullOr;
38 |
39 | @SuppressWarnings("unused")
40 | public class PlayerStaffChatToggleListener implements Listener {
41 | private final StaffChatPlugin plugin;
42 |
43 | public PlayerStaffChatToggleListener(StaffChatPlugin plugin) {
44 | this.plugin = plugin;
45 | }
46 |
47 | @EventListener(ListenerOrder.FIRST)
48 | public void onAutomaticChatFirst(AsyncPlayerChatEvent event) {
49 | if (plugin.data().isAutomaticStaffChatEnabled(event.getPlayer())) {
50 | event.setCancelled(true); // Cancel this message from getting sent to global chat.
51 | // Handle message in a later listener order, allowing other plugins to modify the message.
52 | }
53 | }
54 |
55 | @EventListener(ListenerOrder.MONITOR)
56 | public void onAutomaticChatMonitor(AsyncPlayerChatEvent event) {
57 | Player player = event.getPlayer();
58 | if (!plugin.data().isAutomaticStaffChatEnabled(player)) {
59 | return;
60 | }
61 |
62 | event.setCancelled(true); // Cancel this message from getting sent to global chat.
63 | // The event could've been uncancelled since cancelling it the first time.
64 |
65 | if (Permissions.ACCESS.allows(player)) {
66 | plugin.debug(getClass()).log(event, () ->
67 | "Player " + player.getName() + " has automatic staff-chat enabled"
68 | );
69 |
70 | // Handle this on the main thread next tick.
71 | plugin.sync().run(() -> plugin.submitMessageFromPlayer(event.getPlayer(), event.getMessage()));
72 | } else {
73 | plugin.debug(getClass()).log(event, () ->
74 | "Player " + player.getName() + " has automatic staff-chat enabled " +
75 | "but they don't have permission to use the staff chat"
76 | );
77 |
78 | // Remove this non-staff profile (but in sync 'cus it calls an event).
79 | plugin.sync().run(() -> {
80 | plugin.data().updateProfile(player);
81 | player.chat(event.getMessage());
82 | });
83 | }
84 | }
85 |
86 | @EventListener(ListenerOrder.LAST)
87 | @CancelledEvents(CancellationPolicy.REJECT)
88 | public void onToggleAutoChat(AutoStaffChatToggleEvent event) {
89 | @NullOr Player player = event.getProfile().toPlayer().orElse(null);
90 |
91 | plugin.debug(getClass()).log(event, () -> {
92 | String name = (player == null) ? "" : player.getName();
93 | String enabled = (event.isEnablingAutomaticChat()) ? "Enabled" : "Disabled";
94 | return enabled + " automatic staff-chat for player: " + name + " (" + event.getProfile().uuid() + ")";
95 | });
96 |
97 | if (player == null || event.isQuiet()) {
98 | return;
99 | }
100 |
101 | if (event.isEnablingAutomaticChat()) {
102 | plugin.messages().notifyAutoChatEnabled(player);
103 | } else {
104 | plugin.messages().notifyAutoChatDisabled(player);
105 | }
106 | }
107 |
108 | @EventListener(ListenerOrder.EARLY)
109 | @CancelledEvents(CancellationPolicy.REJECT)
110 | public void onLeavingStaffChatIsDisabled(ReceivingStaffChatToggleEvent event) {
111 | if (event.isJoiningStaffChat()) {
112 | return;
113 | }
114 | if (plugin.config().getOrDefault(StaffChatConfig.LEAVING_STAFFCHAT_ENABLED)) {
115 | return;
116 | }
117 |
118 | // Leaving is disabled, cancel the event.
119 | event.setCancelled(true);
120 |
121 | @NullOr Player player = event.getProfile().toPlayer().orElse(null);
122 |
123 | plugin.debug(getClass()).log(event, () -> {
124 | String name = (player == null) ? "" : player.getName();
125 | return "Player: " + name + " (" + event.getProfile().uuid() + ") " +
126 | "tried to leave the staff chat, but leaving is disabled in the config";
127 | });
128 |
129 | if (player == null || event.isQuiet()) {
130 | return;
131 | }
132 |
133 | plugin.messages().notifyLeavingChatIsDisabled(player);
134 | }
135 |
136 | @EventListener(ListenerOrder.LAST)
137 | @CancelledEvents(CancellationPolicy.REJECT)
138 | public void onToggleReceivingMessages(ReceivingStaffChatToggleEvent event) {
139 | @NullOr Player player = event.getProfile().toPlayer().orElse(null);
140 |
141 | plugin.debug(getClass()).log(event, () -> {
142 | String name = (player == null) ? "" : player.getName();
143 | String left = (event.isLeavingStaffChat()) ? "left" : "joined";
144 | return "Player: " + name + " (" + event.getProfile().uuid() + ") " + left + " the staff-chat";
145 | });
146 |
147 | if (player == null || event.isQuiet()) {
148 | return;
149 | }
150 |
151 | boolean broadcastToEveryone =
152 | event.getProfile().sinceLeftStaffChat().isPresent() != event.isLeavingStaffChat();
153 |
154 | if (event.isLeavingStaffChat()) {
155 | plugin.messages().notifyLeaveChat(player, broadcastToEveryone);
156 | } else {
157 | plugin.messages().notifyJoinChat(player, broadcastToEveryone);
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/listeners/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | @NonNullPackage
24 | package com.rezzedup.discordsrv.staffchat.listeners;
25 |
26 | import pl.tlinkowski.annotation.basic.NonNullPackage;
27 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | @NonNullPackage
24 | package com.rezzedup.discordsrv.staffchat;
25 |
26 | import pl.tlinkowski.annotation.basic.NonNullPackage;
27 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/util/FileIO.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.util;
24 |
25 | import java.io.IOException;
26 | import java.nio.file.Files;
27 | import java.nio.file.Path;
28 | import java.time.LocalDate;
29 | import java.util.function.Consumer;
30 |
31 | public class FileIO {
32 | private FileIO() {
33 | throw new UnsupportedOperationException();
34 | }
35 |
36 | public static void write(Path filePath, String contents, Consumer super IOException> exceptions) {
37 | try {
38 | Files.writeString(filePath, contents);
39 | } catch (IOException e) {
40 | exceptions.accept(e);
41 | }
42 | }
43 |
44 | public static void backup(Path existingFilePath, Path backupFilePath, Consumer super IOException> exceptions) {
45 | // Nothing to back up.
46 | if (!Files.isRegularFile(existingFilePath)) {
47 | return;
48 | }
49 |
50 | try {
51 | Path backupDirectory = backupFilePath.getParent();
52 | if (!Files.isDirectory(backupDirectory)) {
53 | Files.createDirectories(backupDirectory);
54 | }
55 |
56 | String backupFileName = backupFilePath.getFileName().toString();
57 | int lastDot = backupFileName.lastIndexOf('.');
58 | String name = (lastDot > 0) ? backupFileName.substring(0, lastDot) : "";
59 | String extension = (lastDot > 0) ? backupFileName.substring(lastDot) : "";
60 |
61 | for (int i = 1; ; i++) {
62 | String attemptedName = name + ".backup_" + LocalDate.now() + "_" + i + extension;
63 | Path attemptedBackupFilePath = backupDirectory.resolve(attemptedName);
64 |
65 | if (Files.isRegularFile(attemptedBackupFilePath)) {
66 | continue;
67 | }
68 |
69 | Files.move(existingFilePath, attemptedBackupFilePath);
70 | return;
71 | }
72 | } catch (IOException e) {
73 | exceptions.accept(e);
74 | }
75 | }
76 |
77 | public static void backup(Path existingFilePath, Path backupFilePath) {
78 | backup(existingFilePath, backupFilePath, e -> {
79 | throw new RuntimeException(e);
80 | });
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/util/MappedPlaceholder.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.util;
24 |
25 | import pl.tlinkowski.annotation.basic.NullOr;
26 |
27 | import java.util.HashMap;
28 | import java.util.Locale;
29 | import java.util.Map;
30 | import java.util.Objects;
31 | import java.util.function.Supplier;
32 | import java.util.regex.Pattern;
33 |
34 | public class MappedPlaceholder {
35 | public static Pattern PATTERN = Pattern.compile("%(.+?)%");
36 |
37 | protected final Map> placeholders = new HashMap<>();
38 |
39 | public String get(@NullOr String placeholder) {
40 | if (Strings.isEmptyOrNull(placeholder)) {
41 | return "";
42 | }
43 |
44 | Supplier> supplier = placeholders.get(placeholder.toLowerCase(Locale.ROOT));
45 | if (supplier == null) {
46 | return "";
47 | }
48 |
49 | @NullOr Object result = null;
50 | try {
51 | result = supplier.get();
52 | } catch (Exception e) {
53 | e.printStackTrace();
54 | }
55 |
56 | return (result == null) ? "" : String.valueOf(result);
57 | }
58 |
59 | private static String escape(String literal) {
60 | return literal.replace("\\", "\\\\").replace("$", "\\$");
61 | }
62 |
63 | public String update(String message) {
64 | return PATTERN.matcher(message).replaceAll(mr -> {
65 | String value = get(mr.group(1));
66 | return escape((value.isEmpty()) ? mr.group() : value);
67 | });
68 | }
69 |
70 | public Putter map(String... placeholders) {
71 | Objects.requireNonNull(placeholders, "placeholders");
72 | if (placeholders.length <= 0) {
73 | throw new IllegalArgumentException("Empty placeholders array");
74 | }
75 | return new Putter(placeholders);
76 | }
77 |
78 | public void inherit(MappedPlaceholder from) {
79 | placeholders.putAll(from.placeholders);
80 | }
81 |
82 | public class Putter {
83 | private final String[] aliases;
84 |
85 | private Putter(String[] aliases) {
86 | this.aliases = aliases;
87 | }
88 |
89 | public void to(Supplier> supplier) {
90 | Objects.requireNonNull(supplier, "supplier");
91 |
92 | for (String alias : aliases) {
93 | if (Strings.isEmptyOrNull(alias)) {
94 | continue;
95 | }
96 | placeholders.put(alias.toLowerCase(Locale.ROOT), supplier);
97 | }
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/util/Strings.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | package com.rezzedup.discordsrv.staffchat.util;
24 |
25 | import net.md_5.bungee.api.ChatColor;
26 | import pl.tlinkowski.annotation.basic.NullOr;
27 |
28 | import java.util.HashSet;
29 | import java.util.Set;
30 | import java.util.regex.Matcher;
31 | import java.util.regex.Pattern;
32 |
33 | public class Strings {
34 | private Strings() {
35 | }
36 |
37 | private static final Pattern HASH_HEX_COLOR_PATTERN = Pattern.compile("(?i)&x?#(?[a-f0-9]{6})");
38 |
39 | public static String colorful(@NullOr String text) {
40 | if (isEmptyOrNull(text)) {
41 | return "";
42 | }
43 |
44 | Matcher matcher = HASH_HEX_COLOR_PATTERN.matcher(text);
45 | @NullOr Set replaced = null;
46 |
47 | while (matcher.find()) {
48 | if (replaced == null) {
49 | replaced = new HashSet<>();
50 | }
51 |
52 | String match = matcher.group();
53 | if (replaced.contains(match)) {
54 | continue;
55 | }
56 |
57 | StringBuilder bungeeHexFormat = new StringBuilder("&x");
58 |
59 | for (char c : matcher.group("hex").toCharArray()) {
60 | bungeeHexFormat.append('&').append(c);
61 | }
62 |
63 | text = text.replace(match, bungeeHexFormat.toString());
64 | replaced.add(match);
65 | }
66 |
67 | return ChatColor.translateAlternateColorCodes('&', text);
68 | }
69 |
70 | public static boolean isEmptyOrNull(@NullOr String text) {
71 | return text == null || text.isEmpty();
72 | }
73 |
74 | public static String orEmpty(@NullOr String text) {
75 | return (isEmptyOrNull(text)) ? "" : text;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/com/rezzedup/discordsrv/staffchat/util/package-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * The MIT License
3 | * Copyright © 2017-2024 RezzedUp and Contributors
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
13 | * all 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
21 | * THE SOFTWARE.
22 | */
23 | @NonNullPackage
24 | package com.rezzedup.discordsrv.staffchat.util;
25 |
26 | import pl.tlinkowski.annotation.basic.NonNullPackage;
27 |
--------------------------------------------------------------------------------
/src/main/resources/messages.config.header.txt:
--------------------------------------------------------------------------------
1 |
2 | ${project.name}: Messages Config
3 |
4 | ---
5 |
6 | Supported hex color code formats: &x&R&R&G&G&B&B and RRGGBB
7 |
8 | Player placeholders:
9 | %name%: player's name
10 | %nickname%: player's nickname, if they have one (falls back to regular name)
11 |
12 | Discord placeholders:
13 | %name%: discord user's name
14 | %discriminator%: discord user's discriminator (#0000)
15 | %nickname%: discord user's nickname if they have one (falls back to regular name)
16 | %toprole%: discord user's topmost role
17 | %toproleinitial%: the first character of the discord user's topmost role
18 | %toprolealias%: alias for the discord user's topmost role as defined in DiscordSRV's config
19 | %toprolecolor%: an RGB color code derived from the discord user's topmost role
20 | %allroles%: all the discord user's roles
21 |
22 | You may also use placeholders from PlaceholderAPI if it is installed.
23 |
24 | ---
25 |
--------------------------------------------------------------------------------
/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | name: ${project.name}
2 | version: ${project.version}
3 |
4 | author: RezzedUp
5 | description: Staff chat plugin that hooks into DiscordSRV.
6 | website: https://modrinth.com/plugin/discordsrv-staff-chat
7 |
8 | main: com.rezzedup.discordsrv.staffchat.StaffChatPlugin
9 | api-version: 1.13
10 | load: POSTWORLD
11 | softdepend: [ DiscordSRV, PlaceholderAPI ]
12 |
13 | commands:
14 | staffchat:
15 | aliases: [ adminchat, schat, achat, sc, ac, a ]
16 | description: Toggle or send a message to staff chat.
17 | permission: staffchat.access
18 | usage: |-
19 | / - toggle automatic staff chat
20 | / - send a message to the staff chat
21 | managestaffchat:
22 | aliases: [ discordsrv-staff-chat, discordsrvstaffchat, discordstaffchat, discordadminchat, manageadminchat ]
23 | description: Manage and get information about DiscordSRV-Staff-Chat
24 | permission: staffchat.manage
25 | usage: /
26 | leavestaffchat:
27 | aliases: [ leaveadminchat ]
28 | description: Leave the staff chat (stop receiving messages).
29 | permission: staffchat.access
30 | usage: /
31 | joinstaffchat:
32 | aliases: [ joinadminchat ]
33 | description: Rejoin the staff chat (receive messages again).
34 | permission: staffchat.access
35 | usage: /
36 | togglestaffchatsounds:
37 | aliases: [ toggleadminchatsounds ]
38 | description: Mute or unmute staff chat sounds for yourself.
39 | permission: staffchat.access
40 | usage: /
41 |
42 | permissions:
43 | staffchat.*:
44 | children:
45 | staffchat.manage: true
46 | staffchat.access: true
47 | staffchat.manage:
48 | description: Manage the staff chat plugin in-game (e.g. reloading)
49 | staffchat.access:
50 | descriptions: Send and receive messages via staff chat
51 |
--------------------------------------------------------------------------------
/src/main/resources/staff-chat.config.header.txt:
--------------------------------------------------------------------------------
1 |
2 | ${project.name} v${project.version} by RezzedUp
3 |
4 | ---
5 |
6 | This plugin *requires* DiscordSRV in order to access Discord.
7 | However, it will work just fine in-game regardless if DiscordSRV is installed or not.
8 |
9 | ---
10 |
11 | Installation (Discord Setup):
12 |
13 | - 1) Install this plugin and DiscordSRV
14 | Get DiscordSRV here: https://modrinth.com/plugin/discordsrv
15 |
16 | - 2) Add a "staff-chat" channel to DiscordSRV's config
17 | (in: /plugins/DiscordSRV/config.yml)
18 |
19 | EXAMPLE:
20 | EXAMPLE: # Channel links from game to Discord
21 | EXAMPLE: # Replace the "00000000000" below with your staff channel's ID
22 | EXAMPLE: Channels: {"global": "00000000000", "staff-chat": "00000000000"}
23 | EXAMPLE: # ^ ^
24 | EXAMPLE: # All staff chat messages will be sent to this channel.
25 | EXAMPLE:
26 |
27 | IMPORTANT NOTE:
28 | The channel's name can be anything on Discord (since DiscordSRV uses its channel ID) ...
29 | However, it MUST be called "staff-chat" in the config.
30 | **This is very important!**
31 |
32 | - 3) Run: `/discord reload` or restart the server
33 |
34 | - 4) Give staff ranks permission to use the staff chat: `staffchat.access`
35 |
36 | ---
37 |
38 | This config can be reloaded in-game with: `/managestaffchat reload`
39 | (Be sure to give yourself permission to manage the staff chat with: `staffchat.manage`)
40 |
41 | ---
42 |
43 | Find available sounds here: https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Sound.html
44 |
--------------------------------------------------------------------------------