├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── api ├── build.gradle.kts └── src │ └── main │ └── java │ └── at │ └── helpch │ └── chatchat │ └── api │ ├── ChatChatAPI.java │ ├── channel │ ├── Channel.java │ └── ChannelTypeRegistry.java │ ├── event │ ├── ChannelMentionEvent.java │ ├── ChatChatEvent.java │ ├── MentionEvent.java │ ├── PMSendEvent.java │ └── PersonalMentionEvent.java │ ├── exception │ └── ChatChatException.java │ ├── format │ ├── Format.java │ └── PriorityFormat.java │ ├── holder │ ├── FormatsHolder.java │ └── GlobalFormatsHolder.java │ ├── hook │ ├── Hook.java │ ├── HookManager.java │ ├── MuteHook.java │ └── VanishHook.java │ ├── mention │ ├── Mention.java │ ├── MentionManager.java │ └── MentionResult.java │ ├── placeholder │ ├── MiniPlaceholder.java │ └── MiniPlaceholderManager.java │ ├── rule │ ├── Rule.java │ └── RuleManager.java │ ├── user │ ├── ChatUser.java │ ├── User.java │ └── UsersHolder.java │ └── utils │ └── Validators.java ├── build-logic ├── build.gradle.kts └── src │ └── main │ └── kotlin │ ├── chatchat.base-conventions.gradle.kts │ ├── chatchat.parent-conventions.gradle.kts │ └── chatchat.publish-conventions.gradle.kts ├── build.gradle.kts ├── gradle.properties ├── gradle ├── libs.versions.toml └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin ├── build.gradle.kts └── src │ └── main │ ├── java │ └── at │ │ └── helpch │ │ └── chatchat │ │ ├── ChatChatAPIImpl.java │ │ ├── ChatChatPlugin.java │ │ ├── cache │ │ └── ExpiringCache.java │ │ ├── channel │ │ ├── AbstractChannel.java │ │ ├── ChannelTypeRegistryImpl.java │ │ └── ChatChannel.java │ │ ├── command │ │ ├── ChatChatCommand.java │ │ ├── ChatToggleCommand.java │ │ ├── DumpCommand.java │ │ ├── FormatTestCommand.java │ │ ├── IgnoreCommand.java │ │ ├── IgnoreListCommand.java │ │ ├── MainCommand.java │ │ ├── MentionToggleCommand.java │ │ ├── RangedChatCommand.java │ │ ├── ReloadCommand.java │ │ ├── ReplyCommand.java │ │ ├── SocialSpyCommand.java │ │ ├── SwitchChannelCommand.java │ │ ├── UnignoreCommand.java │ │ ├── WhisperCommand.java │ │ └── WhisperToggleCommand.java │ │ ├── config │ │ ├── ConfigFactory.java │ │ ├── ConfigManager.java │ │ ├── DefaultConfigObjects.java │ │ ├── holder │ │ │ ├── AddonsHolder.java │ │ │ ├── ChannelsHolder.java │ │ │ ├── ExtensionsHolder.java │ │ │ ├── FormatsHolderImpl.java │ │ │ ├── GlobalFormatsHolderImpl.java │ │ │ ├── MentionSettingsHolder.java │ │ │ ├── MessagesHolder.java │ │ │ ├── MiniPlaceholdersHolder.java │ │ │ ├── PMSettingsHolder.java │ │ │ └── SettingsHolder.java │ │ └── mapper │ │ │ ├── AddonsMapper.java │ │ │ ├── ChannelMapMapper.java │ │ │ ├── ChannelMapper.java │ │ │ ├── MiniMessageComponentMapper.java │ │ │ ├── MiniPlaceholderMapper.java │ │ │ ├── PriorityFormatMapper.java │ │ │ └── SimpleFormatMapper.java │ │ ├── data │ │ ├── base │ │ │ └── Database.java │ │ └── impl │ │ │ └── gson │ │ │ ├── ChatUserSerializer.java │ │ │ └── GsonDatabase.java │ │ ├── format │ │ ├── ChatFormat.java │ │ ├── DefaultFormatFactory.java │ │ └── SimpleFormat.java │ │ ├── hooks │ │ ├── AbstractInternalHook.java │ │ ├── AbstractInternalMuteHook.java │ │ ├── AbstractInternalVanishHook.java │ │ ├── HookCreator.java │ │ ├── HookManagerImpl.java │ │ ├── dsrv │ │ │ ├── ChatChatDsrvHook.java │ │ │ └── DsrvListener.java │ │ ├── gp │ │ │ └── GriefPreventionSoftMuteHook.java │ │ ├── towny │ │ │ ├── AbstractTownyChannel.java │ │ │ ├── ChatChatTownyHook.java │ │ │ ├── TownyNationChannel.java │ │ │ └── TownyTownChannel.java │ │ └── vanish │ │ │ ├── EssentialsVanishHook.java │ │ │ ├── SuperVanishHook.java │ │ │ └── VanillaVanishHook.java │ │ ├── listener │ │ ├── ChatListener.java │ │ ├── EssentialsVanishListener.java │ │ ├── GriefPreventionSoftMuteListener.java │ │ ├── PlayerListener.java │ │ ├── SuperVanishListener.java │ │ └── VanillaVanishListener.java │ │ ├── mention │ │ ├── ChannelMention.java │ │ ├── MentionManagerImpl.java │ │ ├── MentionResultImpl.java │ │ └── PersonalMention.java │ │ ├── placeholder │ │ ├── MiniPlaceholderContext.java │ │ ├── MiniPlaceholderImpl.java │ │ ├── MiniPlaceholderManagerImpl.java │ │ └── PlaceholderAPIPlaceholders.java │ │ ├── rule │ │ ├── InvalidCharsRule.java │ │ └── RuleManagerImpl.java │ │ ├── user │ │ ├── ChatUserImpl.java │ │ ├── ConsoleUser.java │ │ ├── UserSenderValidator.java │ │ └── UsersHolderImpl.java │ │ └── util │ │ ├── ChannelUtils.java │ │ ├── DumpUtils.java │ │ ├── FormatUtils.java │ │ ├── ItemUtils.java │ │ ├── Kyorifier.java │ │ ├── MentionUtils.java │ │ ├── MessageProcessor.java │ │ ├── MessageUtils.java │ │ ├── PapiTagUtils.java │ │ └── VersionHelper.java │ └── resources │ ├── channels.yml │ ├── extensions.yml │ ├── formats.yml │ ├── messages.yml │ ├── placeholders.yml │ └── settings.yml └── settings.gradle.kts /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = space 7 | indent_size = 4 8 | charset = utf-8 9 | 10 | [*.java] 11 | ij_java_align_multiline_parameters = true 12 | ij_java_blank_lines_after_class_header = 1 # add blank line after class name 13 | ij_java_blank_lines_after_imports = 1 14 | ij_java_blank_lines_after_package = 1 15 | ij_java_blank_lines_around_initializer = 1 16 | ij_java_blank_lines_around_method = 1 17 | ij_java_blank_lines_before_class_end = 1 18 | ij_java_class_count_to_use_import_on_demand = 100 # 100 classes before 'import some.package.*' 19 | ij_java_imports_layout = *,|,java.**,|,$* 20 | ij_java_layout_static_imports_separately = true # place static imports at the end 21 | ij_java_names_count_to_use_import_on_demand = 20 # 20 names before 'static import some.package.Class.*' 22 | 23 | [*.yml] 24 | indent_size = 2 25 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Gradle build 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: [ main ] 7 | pull_request: 8 | branches: [ main ] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | - name: Set up JDK 21 17 | uses: actions/setup-java@v3 18 | with: 19 | java-version: '21' 20 | distribution: 'temurin' 21 | - name: Build with Gradle 22 | uses: gradle/gradle-build-action@v2.4.2 23 | with: 24 | arguments: shadowJar 25 | - name: Upload jarfiles 26 | if: github.event_name != 'pull_request' 27 | uses: actions/upload-artifact@v4 28 | with: 29 | path: plugin/build/libs/*.jar 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .gradle 3 | build 4 | test-module 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 HelpChat 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 | ChatChat Coming Soon 3 | 4 | https://discord.gg/helpchat 5 | 6 | 7 | Build Status 8 | 9 |

10 | 11 | Soon:tm: 12 | -------------------------------------------------------------------------------- /api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar 2 | 3 | plugins { 4 | id("chatchat.base-conventions") 5 | id("chatchat.publish-conventions") 6 | id("com.gradleup.shadow") version "8.3.5" 7 | } 8 | 9 | repositories { 10 | // adventure snapshot repo 11 | maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") 12 | } 13 | 14 | dependencies { 15 | api(libs.adventure.bukkit) 16 | api(libs.adventure.minimessage) 17 | api(libs.adventure.configurate) 18 | 19 | compileOnly(libs.spigot) 20 | } 21 | 22 | tasks { 23 | withType { 24 | listOf( 25 | "net.kyori", 26 | "io.leangen", 27 | ).forEach { relocate(it, "at.helpch.chatchat.libs.$it") } 28 | 29 | archiveFileName.set("ChatChat-API-${project.version}.jar") 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/ChatChatAPI.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api; 2 | 3 | import at.helpch.chatchat.api.channel.ChannelTypeRegistry; 4 | import at.helpch.chatchat.api.hook.HookManager; 5 | import at.helpch.chatchat.api.mention.MentionManager; 6 | import at.helpch.chatchat.api.placeholder.MiniPlaceholderManager; 7 | import at.helpch.chatchat.api.rule.RuleManager; 8 | import at.helpch.chatchat.api.user.UsersHolder; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public interface ChatChatAPI { 12 | 13 | /** 14 | * Get the {@link UsersHolder} 15 | * 16 | * @return The {@link UsersHolder} 17 | */ 18 | @NotNull UsersHolder usersHolder(); 19 | 20 | /** 21 | * Get the {@link HookManager} 22 | * 23 | * @return The {@link HookManager} 24 | */ 25 | @NotNull HookManager hookManager(); 26 | 27 | /** 28 | * Get the {@link ChannelTypeRegistry} 29 | * 30 | * @return The {@link ChannelTypeRegistry} 31 | */ 32 | @NotNull ChannelTypeRegistry channelTypeRegistry(); 33 | 34 | /** 35 | * Get the {@link RuleManager} 36 | * 37 | * @return The {@link RuleManager} 38 | */ 39 | @NotNull RuleManager ruleManager(); 40 | 41 | /** 42 | * Get the {@link MentionManager} 43 | * 44 | * @return The {@link MentionManager} 45 | */ 46 | @NotNull MentionManager mentionsManager(); 47 | 48 | /** 49 | * Get the {@link MiniPlaceholderManager} 50 | * 51 | * @return The {@link MiniPlaceholderManager} 52 | */ 53 | @NotNull MiniPlaceholderManager miniPlaceholdersManager(); 54 | } 55 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/channel/Channel.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.channel; 2 | 3 | import at.helpch.chatchat.api.holder.FormatsHolder; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.api.user.User; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | /** 12 | * Represents a channel. 13 | */ 14 | public interface Channel { 15 | 16 | /** 17 | * Get the name of the channel. 18 | * 19 | * @return The name of the channel. 20 | */ 21 | @NotNull String name(); 22 | 23 | /** 24 | * Get the message prefix of the channel. This prefix can be used at the start of a message to automatically send 25 | * the message in this channel instead of having the {@link User} switch the channel first. 26 | * 27 | * @return The message prefix of the channel. 28 | */ 29 | @NotNull String messagePrefix(); 30 | 31 | /** 32 | * Get the channel prefix of this channel. This is for display purposes. 33 | * 34 | * @return The channel prefix of this channel. 35 | */ 36 | @NotNull String channelPrefix(); 37 | 38 | /** 39 | * Get a list of commands that can be used to switch to this channel. 40 | * 41 | * @return The commands that can be used to switch to this channel. 42 | */ 43 | @NotNull List commandNames(); 44 | 45 | /** 46 | * Get a {@link FormatsHolder} that contains a list of formats that are associated with this channel. The list can 47 | * be empty, but any format in the list will take precedence over global formats. 48 | * 49 | * @return The formats associated with this channel. 50 | */ 51 | @NotNull FormatsHolder formats(); 52 | 53 | /** 54 | * Get the radius of this channel. Radius can be set to -1 to be disabled. 55 | * 56 | * @return The radius of this channel. 57 | */ 58 | int radius(); 59 | 60 | /** 61 | * Get a set of {@link ChatUser}s that can see this channel. 62 | * 63 | * @param source The {@link User} that is requesting the list. 64 | * @return The {@link ChatUser}s that can see this channel. 65 | */ 66 | Set targets(@NotNull final User source); 67 | 68 | /** 69 | * Get a set of {@link ChatUser}s that can send messages in this channel. 70 | * 71 | * @param user The {@link User} that is requesting the list. 72 | * @return The {@link ChatUser}s that can send messages in this channel. 73 | */ 74 | boolean isUsableBy(@NotNull final ChatUser user); 75 | } 76 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/channel/ChannelTypeRegistry.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.channel; 2 | 3 | import at.helpch.chatchat.api.holder.FormatsHolder; 4 | 5 | import java.util.List; 6 | 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | * This class is used to register new channel types. Channels registered here can be used in channels.yml. 11 | */ 12 | public interface ChannelTypeRegistry { 13 | 14 | /** 15 | * Represents a builder for a channel type. 16 | * @param The channel type. 17 | */ 18 | @FunctionalInterface 19 | interface Builder { 20 | @NotNull T build(@NotNull final String name, 21 | @NotNull final String messagePrefix, 22 | @NotNull final List toggleCommands, 23 | @NotNull final String channelPrefix, 24 | @NotNull final FormatsHolder formats, 25 | final int radius); 26 | } 27 | 28 | /** 29 | * Registers a new channel type. 30 | * 31 | * @param name The name of the channel type. 32 | * @param builder The builder for the channel type. 33 | */ 34 | void add(final @NotNull String name, final @NotNull Builder builder); 35 | } 36 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/event/ChannelMentionEvent.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.event; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.api.user.User; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | /** 9 | * Called when a {@link ChatUser} mentions another {@link ChatUser}. 10 | */ 11 | public class ChannelMentionEvent extends MentionEvent { 12 | public ChannelMentionEvent( 13 | final boolean async, 14 | @NotNull final ChatUser user, 15 | @NotNull final User target, 16 | @NotNull final Channel channel, 17 | final boolean playSound 18 | ) { 19 | super(async, user, target, channel, playSound); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/event/ChatChatEvent.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.event; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.format.Format; 5 | import at.helpch.chatchat.api.user.ChatUser; 6 | import at.helpch.chatchat.api.user.User; 7 | import net.kyori.adventure.text.Component; 8 | import org.bukkit.event.Cancellable; 9 | import org.bukkit.event.Event; 10 | import org.bukkit.event.HandlerList; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Set; 14 | 15 | /** 16 | *

17 | * Called whenever a {@link ChatUser} sends a chat message. 18 | *

19 | */ 20 | public class ChatChatEvent extends Event implements Cancellable { 21 | 22 | private static final HandlerList HANDLERS = new HandlerList(); 23 | private boolean cancelled = false; 24 | 25 | private @NotNull final ChatUser user; 26 | private @NotNull Format format; 27 | private @NotNull Component message; 28 | private @NotNull final Channel channel; 29 | private @NotNull final Set recipients; 30 | 31 | public static @NotNull HandlerList getHandlerList() { 32 | return HANDLERS; 33 | } 34 | 35 | public ChatChatEvent( 36 | final boolean async, 37 | @NotNull final ChatUser user, 38 | @NotNull final Format format, 39 | @NotNull final Component message, 40 | @NotNull final Channel channel, 41 | @NotNull Set recipients) { 42 | super(async); 43 | this.user = user; 44 | this.format = format; 45 | this.message = message; 46 | this.channel = channel; 47 | this.recipients = recipients; 48 | } 49 | 50 | @Override 51 | public @NotNull HandlerList getHandlers() { 52 | return HANDLERS; 53 | } 54 | 55 | @Override 56 | public boolean isCancelled() { 57 | return cancelled; 58 | } 59 | 60 | @Override 61 | public void setCancelled(final boolean cancelled) { 62 | this.cancelled = cancelled; 63 | } 64 | 65 | /** 66 | * Get the user that sent the message. 67 | * 68 | * @return The user that sent the message. 69 | */ 70 | public @NotNull ChatUser user() { 71 | return user; 72 | } 73 | 74 | /** 75 | * Get the format that will be used to format the message for the sender and recipients. 76 | * 77 | * @return The format that will be used. 78 | */ 79 | public @NotNull Format format() { 80 | return format; 81 | } 82 | 83 | /** 84 | * Change the format that will be used to format the message for the sender and recipients. 85 | * 86 | * @param format The format that will be used. 87 | */ 88 | public void format(@NotNull final Format format) { 89 | this.format = format; 90 | } 91 | 92 | /** 93 | * Get the message that is being sent. 94 | * 95 | * @return The message that is being sent. 96 | */ 97 | public @NotNull Component message() { 98 | return message; 99 | } 100 | 101 | /** 102 | * Change the message that will be received. 103 | * 104 | * @param message The new message. 105 | */ 106 | public void message(@NotNull final Component message) { 107 | this.message = message; 108 | } 109 | 110 | /** 111 | * Get the channel that the message was sent in. This will not always be the channel that the user is in as the 112 | * message can be sent using a channel prefix. 113 | * 114 | * @return The channel that the message was sent in. 115 | */ 116 | public @NotNull Channel channel() { 117 | return channel; 118 | } 119 | 120 | /** 121 | * Get a mutable set of users that represent the recipients of the message. Updating the {@link Set} will affect the 122 | * recipients that will end up seeing the message. Also, recipients do not have to be part of the 123 | * {@link ChatChatEvent#channel()}. 124 | * 125 | * @return The recipients of the message. 126 | */ 127 | public Set recipients() { 128 | return recipients; 129 | } 130 | 131 | } 132 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/event/MentionEvent.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.event; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.api.user.User; 6 | import org.bukkit.event.Cancellable; 7 | import org.bukkit.event.Event; 8 | import org.bukkit.event.HandlerList; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * Called when a {@link ChatUser} mentions a {@link User}. 13 | */ 14 | public class MentionEvent extends Event implements Cancellable { 15 | 16 | private static final HandlerList HANDLERS = new HandlerList(); 17 | private boolean cancelled = false; 18 | 19 | private @NotNull final ChatUser user; 20 | private @NotNull final User target; 21 | private @NotNull final Channel channel; 22 | private boolean playSound; 23 | 24 | public static @NotNull HandlerList getHandlerList() { 25 | return HANDLERS; 26 | } 27 | 28 | protected MentionEvent( 29 | final boolean async, 30 | @NotNull final ChatUser user, 31 | @NotNull final User target, 32 | @NotNull final Channel channel, 33 | final boolean playSound 34 | ) { 35 | super(async); 36 | this.user = user; 37 | this.target = target; 38 | this.channel = channel; 39 | this.playSound = playSound; 40 | } 41 | 42 | @Override 43 | public @NotNull HandlerList getHandlers() { 44 | return HANDLERS; 45 | } 46 | 47 | @Override 48 | public boolean isCancelled() { 49 | return cancelled; 50 | } 51 | 52 | @Override 53 | public void setCancelled(final boolean cancelled) { 54 | this.cancelled = cancelled; 55 | } 56 | 57 | /** 58 | * Get the user that mentioned the target. 59 | * 60 | * @return The user that mentioned the target. 61 | */ 62 | public @NotNull ChatUser user() { 63 | return user; 64 | } 65 | 66 | /** 67 | * Get the user that was mentioned. 68 | * 69 | * @return The target of the mention. 70 | */ 71 | public @NotNull User target() { 72 | return target; 73 | } 74 | 75 | /** 76 | * Get the channel that the mention was sent in. 77 | * 78 | * @return The channel that the mention was sent in. 79 | */ 80 | public @NotNull Channel channel() { 81 | return channel; 82 | } 83 | 84 | public boolean playSound() { 85 | return playSound; 86 | } 87 | 88 | public void playSound(final boolean playSound) { 89 | this.playSound = playSound; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/event/PersonalMentionEvent.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.event; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * Called when a {@link ChatUser} mentions another {@link ChatUser}. 9 | */ 10 | public class PersonalMentionEvent extends MentionEvent { 11 | 12 | private final ChatUser target; 13 | 14 | public PersonalMentionEvent( 15 | final boolean async, 16 | @NotNull final ChatUser user, 17 | @NotNull final ChatUser target, 18 | @NotNull final Channel channel, 19 | final boolean playSound 20 | ) { 21 | super(async, user, target, channel, playSound); 22 | this.target = target; 23 | } 24 | 25 | /** 26 | * Get the chat user that was mentioned. 27 | * 28 | * @return The target of the mention. 29 | */ 30 | @Override 31 | public @NotNull ChatUser target() { 32 | return target; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/exception/ChatChatException.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.exception; 2 | 3 | public final class ChatChatException extends RuntimeException { 4 | public ChatChatException(String message) { 5 | super(message); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/format/Format.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.format; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.List; 6 | import java.util.Map; 7 | 8 | /** 9 | * This is a simple format. 10 | */ 11 | public interface Format { 12 | 13 | /** 14 | * This method is used to get the name of the format. 15 | * 16 | * @return the name of the format. 17 | */ 18 | @NotNull String name(); 19 | 20 | /** 21 | * This method is used to override the name of the format. A thing to note is that formats are immutable in 22 | * ChatChat so instead of overriding, this will create and return a copy of this format with the new name. 23 | * 24 | * @param name the new name of the format. 25 | * @return a copy of the current format with the new name. 26 | */ 27 | @NotNull Format name(@NotNull final String name); 28 | 29 | /** 30 | * This method is used to get the parts of the format. The parts are made out of a part name and a list of strings. 31 | * ChatChat will just append the parts into one big string. 32 | * 33 | * @return the parts of the format. 34 | */ 35 | @NotNull Map> parts(); 36 | 37 | /** 38 | * This method is used to override the parts of the format. A thing to note is that formats are immutable in 39 | * ChatChat so instead of overriding, this will create and return a copy of this format with the new parts. 40 | * 41 | * @param parts the new parts of the format. 42 | * @return a copy of the current format with the new parts. 43 | */ 44 | @NotNull Format parts(@NotNull final Map> parts); 45 | } 46 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/format/PriorityFormat.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.format; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | /** 6 | * Represents a basic {@link Format} that has a priority. These are usually used for player formats. 7 | */ 8 | public interface PriorityFormat extends Format { 9 | 10 | /** 11 | * Get the priority of the format. 12 | * 13 | * @return the priority of the format. 14 | */ 15 | int priority(); 16 | 17 | /** 18 | * Set the priority of the format. A thing to note is that formats are immutable in ChatChat so instead of 19 | * changing the priority, this will create and return a copy of this format with the new priority. 20 | * 21 | * @param priority the new priority of the format. 22 | * @return a copy of this format with the new priority. 23 | */ 24 | @NotNull PriorityFormat priority(final int priority); 25 | 26 | } 27 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/holder/FormatsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.holder; 2 | 3 | import at.helpch.chatchat.api.format.PriorityFormat; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Map; 7 | 8 | /** 9 | * This is used to store a list of @link PriorityFormat}s. 10 | */ 11 | public interface FormatsHolder { 12 | 13 | /** 14 | * A map of all formats. The map should be of type Name to Format. 15 | * 16 | * @return The map of formats. 17 | */ 18 | @NotNull Map formats(); 19 | } 20 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/holder/GlobalFormatsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.holder; 2 | 3 | import at.helpch.chatchat.api.format.Format; 4 | import at.helpch.chatchat.api.format.PriorityFormat; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | /** 8 | * This is used to store the name of the default format, a {@link Format} that is used 9 | * for console, and a list of {@link PriorityFormat}s. 10 | */ 11 | public interface GlobalFormatsHolder extends FormatsHolder { 12 | 13 | /** 14 | * Get the name of the default format. The default is a format that everyone has access to and is what will be used 15 | * if the user does not have access to any other format. 16 | * 17 | * @return The name of the default format. 18 | */ 19 | @NotNull String defaultFormat(); 20 | 21 | /** 22 | * Get the console format. This is the format that is used for console output. Console needs a special format 23 | * because spigot does not support Components so not all MiniMessage features can be used. 24 | * 25 | * @return The console format. 26 | */ 27 | @NotNull Format consoleFormat(); 28 | } 29 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/hook/Hook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.hook; 2 | 3 | import org.bukkit.plugin.Plugin; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * A hook to interface with another plugin. 8 | */ 9 | public interface Hook { 10 | 11 | /** 12 | * The plugin that registered the hook. 13 | * 14 | * @return the plugin that registered the hook 15 | */ 16 | @NotNull Plugin plugin(); 17 | 18 | /** 19 | * @return true if ChatChat should register the hook, false otherwise. 20 | */ 21 | boolean register(); 22 | 23 | /** 24 | * The hook name should follow this regex pattern: [a-zA-Z0-9_]+ 25 | * 26 | * @return the name of the hook. this will be used as an identifier, so if there will be multiple hooks with the 27 | * same name, only one of them will be registered. 28 | */ 29 | @NotNull String name(); 30 | 31 | /** 32 | * Enable the hook. 33 | */ 34 | default void enable() {} 35 | 36 | /** 37 | * Disable the hook. 38 | */ 39 | default void disable() {} 40 | } 41 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/hook/HookManager.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.hook; 2 | 3 | import at.helpch.chatchat.api.ChatChatAPI; 4 | 5 | import java.util.Set; 6 | import java.util.function.Function; 7 | 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * A manager for hooks. This class is used to add and register new hooks. 12 | */ 13 | public interface HookManager { 14 | 15 | /** 16 | * Adds and registers a new {@link Hook} with the manager. 17 | *
18 | * Registration will fail if the hook name is invalid (Check {@link Hook#name()} for valid hook name), if a hook 19 | * with the same name is already registered, if the hook throws an unhandled exception during registration or if the 20 | * hook returns false from {@link Hook#register()}. 21 | * 22 | * @param constructor A method, lambda or a constructor that takes in a {@link ChatChatAPI} parameter and returns 23 | * a {@link Hook}. 24 | * 25 | * @return False if the registration failed, true otherwise. 26 | */ 27 | boolean addHook(@NotNull final Function constructor); 28 | 29 | /** 30 | * Get all basic hooks. 31 | * 32 | * @return An unmodifiable {@link Set} of all registered basic {@link Hook}s. 33 | */ 34 | // TODO: 8/29/22 create a BasicHook 35 | @NotNull Set hooks(); 36 | 37 | /** 38 | * Get all vanish hooks. 39 | * 40 | * @return An unmodifiable {@link Set} of all registered {@link VanishHook}s. 41 | */ 42 | @NotNull Set vanishHooks(); 43 | } 44 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/hook/MuteHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.hook; 2 | 3 | import at.helpch.chatchat.api.user.ChatUser; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * A hook that lets other plugins add their own mute integration with chat chat. 8 | */ 9 | public abstract class MuteHook implements Hook { 10 | /** 11 | * Determines if a user is muted. 12 | * @param user instance of a user to check if they are muted. 13 | * @return true if they are muted. 14 | */ 15 | public abstract boolean isMuted(@NotNull ChatUser user); 16 | } 17 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/hook/VanishHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.hook; 2 | 3 | import at.helpch.chatchat.api.user.ChatUser; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * A hook that lets other plugins add their own vanish integration with ChatChat. ChatChat has vanish support in tab 8 | * completion, private messaging and mentions. 9 | */ 10 | public abstract class VanishHook implements Hook { 11 | /** 12 | * Determines if a user can see another user. 13 | * @param user user for which to check if it can see the target. 14 | * @param target the target for which to check if its visible to the user. 15 | * @return true if the user can see the target, false otherwise. 16 | */ 17 | public abstract boolean canSee(@NotNull final ChatUser user, @NotNull final ChatUser target); 18 | } 19 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/mention/Mention.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.mention; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.user.User; 5 | import net.kyori.adventure.text.Component; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | public interface Mention { 10 | /** 11 | * Process the message and replace all mentions of the target by the sender here. The returned mention result should 12 | * contain the processed message, a boolean that represents if the target was mentioned at all or not and a boolean 13 | * that represents if the target should hear a sound when they'll receive the message. 14 | * 15 | * @param async true if call was done async, false otherwise 16 | * @param sender the sender of the message 17 | * @param target the target of the message 18 | * @param channel the channel the message was sent in 19 | * @param message the message to process mentions in 20 | * @param data additional data that can be used to process the message 21 | * @return a mention result 22 | */ 23 | @NotNull MentionResult processMention( 24 | boolean async, 25 | @NotNull User sender, 26 | @NotNull User target, 27 | @NotNull Channel channel, 28 | @NotNull Component message, 29 | @Nullable Object data 30 | ); 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/mention/MentionManager.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.mention; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Set; 6 | 7 | /** 8 | * A manager for mentions. This class is used to add and register new mention types. 9 | */ 10 | public interface MentionManager { 11 | 12 | /** 13 | * Adds and registers a new {@link Mention} with the manager. 14 | * 15 | * @param mention The mention to register. 16 | * 17 | */ 18 | void addMention(@NotNull final Mention mention); 19 | 20 | /** 21 | * Get all mentions. 22 | * 23 | * @return An unmodifiable {@link Set} of all registered basic {@link Mention}s. 24 | */ 25 | @NotNull Set mentions(); 26 | } 27 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/mention/MentionResult.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.mention; 2 | 3 | import net.kyori.adventure.text.Component; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | /** 7 | * Represents a {@link Mention} result. 8 | */ 9 | public interface MentionResult { 10 | 11 | /** 12 | * Get the original message with the mentions processed. 13 | * 14 | * @return The processed message. 15 | */ 16 | @NotNull Component message(); 17 | 18 | /** 19 | * This tells you if the target was mentioned during the mention processing or not. 20 | * 21 | * @return true if the target was mentioned, false otherwise. 22 | */ 23 | boolean mentioned(); 24 | 25 | /** 26 | * This decides if the target will hear a sound when they'll receive the message or not. 27 | * 28 | * @return true if the target should hear a sound, false otherwise. 29 | */ 30 | boolean playSound(); 31 | } 32 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/placeholder/MiniPlaceholder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.placeholder; 2 | 3 | import at.helpch.chatchat.api.user.ChatUser; 4 | import at.helpch.chatchat.api.user.User; 5 | import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.Optional; 9 | 10 | /** 11 | * Represents a placeholder that can be used in MiniMessage. 12 | */ 13 | public interface MiniPlaceholder { 14 | 15 | /** 16 | * Compiles the placeholder to a {@link TagResolver}. 17 | * @param context The context in which the placeholder is used. 18 | * @return The compiled placeholder. 19 | */ 20 | @NotNull TagResolver toTagResolver(final @NotNull Context context); 21 | 22 | public interface Context { 23 | 24 | /** 25 | * The response is going to be true only and only if the placeholder is used in a user generated message such as 26 | * a message sent in chat. If the placeholder is used in a format, or system message, the response is going to 27 | * be false. 28 | * @return Whether the placeholder is used in user sent message or in a format. 29 | */ 30 | boolean inMessage(); 31 | 32 | /** 33 | * The sender of the message is going to be empty if {@link Context#inMessage()} returns false. 34 | * @return the sender of the message 35 | */ 36 | @NotNull Optional sender(); 37 | 38 | /** 39 | * The recipient can be a user that receives a system message or a player that receives a message from another 40 | * user. 41 | * The recipient is going to be empty if the message is not sent to a specific user. 42 | * @return The recipient of the message. 43 | */ 44 | @NotNull Optional recipient(); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/placeholder/MiniPlaceholderManager.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.placeholder; 2 | 3 | import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Set; 7 | 8 | /** 9 | * A manager for . This class is used to add and register new mention types. 10 | */ 11 | public interface MiniPlaceholderManager { 12 | /** 13 | * Adds and registers a new {@link MiniPlaceholder} with the manager. 14 | * 15 | * @param placeholder the placeholder to register 16 | */ 17 | void addPlaceholder(@NotNull MiniPlaceholder placeholder); 18 | 19 | /** 20 | * Compiles all {@link MiniPlaceholder}s into a single {@link TagResolver}. 21 | * 22 | * @param context The context in which the placeholder is used. 23 | * @return the compiled tags 24 | */ 25 | @NotNull TagResolver compileTags(@NotNull MiniPlaceholder.Context context); 26 | 27 | /** 28 | * Get all placeholders. 29 | * 30 | * @return An unmodifiable {@link Set} of all registered {@link MiniPlaceholder}s. 31 | */ 32 | @NotNull Set<@NotNull MiniPlaceholder> placeholders(); 33 | 34 | /** 35 | * Clears all placeholders. 36 | */ 37 | public void clear(); 38 | } 39 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/rule/Rule.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.rule; 2 | 3 | import at.helpch.chatchat.api.user.User; 4 | 5 | import java.util.Optional; 6 | 7 | import at.helpch.chatchat.api.user.ChatUser; 8 | import net.kyori.adventure.text.Component; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | /** 12 | * A hook to interface with another plugin. 13 | */ 14 | public interface Rule { 15 | /** 16 | * This method is called when a {@link ChatUser} sends a public message. The rule should check if the message is 17 | * allowed or not. If the message is not allowed, the message event will be cancelled and the user will be notified 18 | * either with the message given by {@link #publicDeniedMessage()} or the invalid-message from ChatChat. 19 | * 20 | * @param sender The sender of the message. 21 | * @param message The message the user sent. 22 | * 23 | * @return true if the message sent by the player is allowed, false otherwise. 24 | */ 25 | boolean isAllowedPublic(@NotNull ChatUser sender, @NotNull String message); 26 | 27 | /** 28 | * This method is called when a {@link ChatUser} sends a private message. The rule should check if the message is 29 | * allowed or not. If the message is not allowed, the message event will be cancelled and the user will be notified 30 | * either with the message given by {@link #privateDeniedMessage()} or the invalid-message from ChatChat. 31 | * 32 | * @param sender The sender of the message. 33 | * @param recipient The recipient of the message. 34 | * @param message The message the user sent. 35 | * 36 | * @return true if the message sent by the player is allowed, false otherwise. 37 | */ 38 | boolean isAllowedPrivate(@NotNull ChatUser sender, @NotNull User recipient, @NotNull String message); 39 | 40 | /** 41 | * @return the message that should be sent to the player if the public message they sent did not respect this rule. 42 | */ 43 | @NotNull default Optional<@NotNull Component> publicDeniedMessage() { 44 | return Optional.empty(); 45 | } 46 | 47 | /** 48 | * @return the message that should be sent to the player if the private message they sent did not respect this rule. 49 | */ 50 | @NotNull default Optional<@NotNull Component> privateDeniedMessage() { 51 | return Optional.empty(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/rule/RuleManager.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.rule; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Set; 6 | 7 | /** 8 | * A manager for rules. This class is used to add and register new rules. 9 | */ 10 | public interface RuleManager { 11 | /** 12 | * Adds and registers a new {@link Rule} with the manager. The rule will only apply to public messages. 13 | * 14 | * @param rule The rule to add. 15 | */ 16 | void addPublicChatRule(@NotNull final Rule rule); 17 | 18 | /** 19 | * Adds and registers a new {@link Rule} with the manager. The rule will only apply to private messages. 20 | * 21 | * @param rule The rule to add. 22 | */ 23 | void addPrivateChatRule(@NotNull final Rule rule); 24 | 25 | /** 26 | * Get all public chat rules. 27 | * 28 | * @return An unmodifiable {@link Set} of all registered public chat {@link Rule}s. 29 | */ 30 | @NotNull Set publicChatRules(); 31 | 32 | /** 33 | * Get all private chat rules. 34 | * 35 | * @return An unmodifiable {@link Set} of all registered private chat {@link Rule}s. 36 | */ 37 | @NotNull Set privateChatRules(); 38 | } 39 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/user/ChatUser.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.user; 2 | 3 | import org.bukkit.entity.Player; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.jetbrains.annotations.Nullable; 6 | 7 | import java.util.Optional; 8 | 9 | /** 10 | * Represents a chat user that is backed by a {@link Player}. 11 | */ 12 | public interface ChatUser extends User { 13 | 14 | /** 15 | * Gets the player that this user is backed by. 16 | * 17 | * @return The player that this user is backed by. 18 | */ 19 | @NotNull Optional player(); 20 | 21 | /** 22 | * Gets the user that this user has last sent a private message to. 23 | * 24 | * @return The last messaged user. 25 | */ 26 | @NotNull Optional lastMessagedUser(); 27 | 28 | /** 29 | * Change the user that this user has last sent a private message to. 30 | * 31 | * @param user The new last messaged user. 32 | */ 33 | void lastMessagedUser(@Nullable final ChatUser user); 34 | 35 | /** 36 | * Checks if the user has their private messages enabled. 37 | * 38 | * @return True if the user has their private messages enabled, false otherwise. 39 | */ 40 | boolean privateMessages(); 41 | 42 | /** 43 | * Changes the state of the user's private messages. 44 | * 45 | * @param enable True to enable private messages, false to disable. 46 | */ 47 | void privateMessages(final boolean enable); 48 | 49 | /** 50 | * Checks if the user has their personal mentions enabled. If they are enabled, other users will be able to directly 51 | * mention them in chat without the need of the override permission. 52 | * 53 | * @return True if the user has their personal mentions enabled, false otherwise. 54 | */ 55 | boolean personalMentions(); 56 | 57 | /** 58 | * Changes the state of the user's personal mentions. 59 | * 60 | * @param receivesPersonalMentions True to enable personal mentions, false to disable. 61 | */ 62 | void personalMentions(final boolean receivesPersonalMentions); 63 | 64 | /** 65 | * Checks if the user has their channel mentions enabled. If they are enabled, other users will be able to channel 66 | * mention them in chat without the need of the override permission. 67 | * 68 | * @return True if the user has their channel mentions enabled, false otherwise. 69 | */ 70 | boolean channelMentions(); 71 | 72 | /** 73 | * Changes the state of the user's channel mentions. 74 | * 75 | * @param receivesChannelMentions True to enable channel mentions, false to disable. 76 | */ 77 | void channelMentions(final boolean receivesChannelMentions); 78 | 79 | /** 80 | * Checks if the user has social spy enabled. If it is enabled, they will see all the private messages other users 81 | * are sending. 82 | * 83 | * @return True if the user has social spy enabled, false otherwise. 84 | */ 85 | boolean socialSpy(); 86 | 87 | /** 88 | * Changes the state of the user's social spy. 89 | * 90 | * @param enable True to enable social spy, false to disable. 91 | */ 92 | void socialSpy(final boolean enable); 93 | 94 | /** 95 | * Checks if the user has ranged chat enabled. 96 | * If it is enabled, they will only see messages from players within a certain range. 97 | * Only applies to the players that have bypass ChannelUtils.BYPASS_RADIUS_CHANNEL_PERMISSION. 98 | * 99 | * @return True if the user has ranged chat enabled, false otherwise. 100 | */ 101 | boolean rangedChat(); 102 | 103 | /** 104 | * Changes the state of the user's ranged chat. 105 | * 106 | * @param enable True to enable ranged chat, false to disable. 107 | */ 108 | void rangedChat(final boolean enable); 109 | } 110 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/user/User.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.user; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.format.Format; 5 | import net.kyori.adventure.audience.ForwardingAudience; 6 | import net.kyori.adventure.identity.Identified; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.Set; 10 | import java.util.UUID; 11 | 12 | /** 13 | * Represents a simple user. 14 | */ 15 | public interface User extends ForwardingAudience.Single, Identified { 16 | 17 | /** 18 | * Get the channel that the user is in. 19 | * 20 | * @return The channel that the user is in. 21 | */ 22 | @NotNull Channel channel(); 23 | 24 | /** 25 | * Change the user's channel. 26 | * 27 | * @param channel The channel to change to. 28 | */ 29 | void channel(@NotNull final Channel channel); 30 | 31 | /** 32 | * Get the user's chat format. 33 | * 34 | * @return The user's chat format. 35 | * {@code @WARNING} This is currently not used by ChatChat at all! 36 | */ 37 | @NotNull Format format(); 38 | 39 | /** 40 | * Change the user's chat format. 41 | * 42 | * @param format The new chat format. 43 | */ 44 | void format(@NotNull final Format format); 45 | 46 | /** 47 | * Get the user's unique identifier. 48 | * 49 | * @return The user's unique identifier. 50 | */ 51 | @NotNull UUID uuid(); 52 | 53 | /** 54 | * Check if the user has a permission. 55 | * 56 | * @param node The permission to check. 57 | * @return True if the user has the permission, false otherwise. 58 | */ 59 | boolean hasPermission(@NotNull final String node); 60 | 61 | /** 62 | * Checks to see if the user can see another {@link User}. 63 | * 64 | * @param target The target to check if the user can see. 65 | * @return True if the user can see the target, false otherwise. 66 | */ 67 | boolean canSee(@NotNull final User target); 68 | 69 | /** 70 | * Get a set of users that this user has ignored. 71 | * 72 | * @return The ignored users. 73 | */ 74 | @NotNull Set ignoredUsers(); 75 | 76 | /** 77 | * Replace the ignored users with a new set. 78 | * 79 | * @param users The new ignored users. 80 | */ 81 | void ignoredUsers(@NotNull final Set users); 82 | 83 | /** 84 | * Ignore a user. 85 | * 86 | * @param user The user to ignore. 87 | */ 88 | void ignoreUser(@NotNull final User user); 89 | 90 | /** 91 | * Unignore a user. 92 | * 93 | * @param user The user to unignore. 94 | */ 95 | void unignoreUser(@NotNull final User user); 96 | 97 | /** 98 | * Checks if the user has their chat enabled or not. 99 | * 100 | * @return True if the user has their chat enabled, false otherwise. 101 | */ 102 | boolean chatEnabled(); 103 | 104 | /** 105 | * Changes the state of the user's chat. 106 | * 107 | * @param toggle True to enable chat, false to disable. 108 | */ 109 | void chatState(boolean toggle); 110 | } 111 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/user/UsersHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.user; 2 | 3 | import java.util.Collection; 4 | import java.util.UUID; 5 | 6 | import org.bukkit.command.CommandSender; 7 | import org.bukkit.entity.Player; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | * This class holds all the users that are connected to the server. 12 | */ 13 | public interface UsersHolder { 14 | /** 15 | * Gets the user with the given UUID. This will first attempt to get the user from the cache, and if it is not found, 16 | * it will attempt to get the user from the database. If the user is not found in the database, it will create a new 17 | * user and add it to the cache. 18 | * 19 | * @param uuid The UUID of the user. 20 | * @return The user with the given UUID. 21 | */ 22 | @NotNull User getUser(@NotNull UUID uuid); 23 | /** 24 | * Gets the user backed by the specified {@link CommandSender}. This will first attempt to get the user from the 25 | * cache, and if it is not found, it will attempt to get the user from the database. If the user is not found in the 26 | * database, it will create a new user and add it to the cache. 27 | * 28 | * @param user The {@link CommandSender} backing the user. 29 | * @return The user backed by the specified {@link CommandSender}. 30 | */ 31 | @NotNull User getUser(@NotNull CommandSender user); 32 | 33 | /** 34 | * Attempts to remove an {@link User} from the cache and save them to the database. This will do nothing if the user 35 | * is not cached. 36 | * 37 | * @param uuid The UUID of the user to remove. 38 | */ 39 | void removeUser(@NotNull UUID uuid); 40 | 41 | /** 42 | * Attempts to remove an {@link User} from the cache and save them to the database. This will do nothing if the user 43 | * is not cached. 44 | * 45 | * @param user The {@link CommandSender} backing the user to remove. 46 | */ 47 | void removeUser(@NotNull Player user); 48 | 49 | /** 50 | * Gets all the users that are cached. 51 | * 52 | * @return A mutable {@link Collection} of the users that are cached. 53 | */ 54 | @NotNull Collection users(); 55 | } 56 | -------------------------------------------------------------------------------- /api/src/main/java/at/helpch/chatchat/api/utils/Validators.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.api.utils; 2 | 3 | import at.helpch.chatchat.api.hook.Hook; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.regex.Pattern; 7 | 8 | public final class Validators { 9 | 10 | private final static Pattern HOOK_NAME_PATTERN = Pattern.compile("(?\\w+)"); 11 | 12 | private Validators() { 13 | throw new AssertionError("Util classes are not to be instantiated!"); 14 | } 15 | 16 | /** 17 | * Checks if the given string is a valid {@link Hook} name. 18 | * 19 | * @param name the name to check 20 | * @return true if and only if the name is valid, false otherwise 21 | */ 22 | public static boolean isValidHookName(@NotNull final String name) { 23 | final var matcher = HOOK_NAME_PATTERN.matcher(name); 24 | if (!matcher.matches()) { 25 | return false; 26 | } 27 | 28 | final var hookName = matcher.group("name"); 29 | 30 | return hookName != null; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /build-logic/build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `kotlin-dsl` 3 | } 4 | 5 | repositories { 6 | gradlePluginPortal() 7 | } 8 | -------------------------------------------------------------------------------- /build-logic/src/main/kotlin/chatchat.base-conventions.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | maven("https://repo.papermc.io/repository/maven-public/") 8 | } 9 | 10 | java { 11 | sourceCompatibility = JavaVersion.VERSION_21 12 | targetCompatibility = JavaVersion.VERSION_21 13 | withSourcesJar() 14 | withJavadocJar() 15 | } 16 | 17 | dependencies { 18 | compileOnly("org.jetbrains:annotations:23.0.0") 19 | } 20 | 21 | tasks { 22 | withType { 23 | options.encoding = "UTF-8" 24 | options.compilerArgs.add("-parameters") 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /build-logic/src/main/kotlin/chatchat.parent-conventions.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | } 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | java { 10 | sourceCompatibility = JavaVersion.VERSION_21 11 | targetCompatibility = JavaVersion.VERSION_21 12 | } 13 | -------------------------------------------------------------------------------- /build-logic/src/main/kotlin/chatchat.publish-conventions.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | `java-library` 3 | `maven-publish` 4 | } 5 | 6 | publishing { 7 | repositories { 8 | maven { 9 | name = "helpchat" 10 | url = uri("https://repo.helpch.at/snapshots") 11 | credentials { 12 | username = System.getenv("REPO_USER") 13 | password = System.getenv("REPO_PASS") 14 | } 15 | authentication { 16 | create("basic") 17 | } 18 | } 19 | } 20 | publications { 21 | create("maven") { 22 | from(components["java"]) 23 | 24 | pom { 25 | name.set("chat-chat") 26 | description.set("TODO") // Add description 27 | url.set("https://github.com/HelpChat/ChatChat/") 28 | 29 | licenses { 30 | license { 31 | name.set("MIT License") 32 | url.set("http://www.opensource.org/licenses/mit-license.php") 33 | } 34 | } 35 | 36 | developers { 37 | // add devs 38 | } 39 | 40 | // Change later 41 | scm { 42 | connection.set("scm:git:git://github.com/HelpChat/ChatChat.git") 43 | developerConnection.set("scm:git:ssh://github.com:HelpChat/ChatChat.git") 44 | url.set("https://github.com/HelpChat/ChatChat") 45 | } 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | plugins { 2 | id("chatchat.parent-conventions") 3 | } 4 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group = at.helpch 2 | version = 1.0.0-SNAPSHOT 3 | -------------------------------------------------------------------------------- /gradle/libs.versions.toml: -------------------------------------------------------------------------------- 1 | [versions] 2 | # Minecraft 3 | spigot = "1.21.4-R0.1-SNAPSHOT" 4 | 5 | # Adventure 6 | minimessage = "4.16.0" 7 | adventure-platform = "4.3.4" 8 | 9 | # Other 10 | configurate = "4.1.2" 11 | cmds = "2.0.0-SNAPSHOT" 12 | papi = "2.11.6" 13 | towny = "0.98.1.3" 14 | discordsrv = "1.25.1" 15 | supervanish = "6.2.17" 16 | bstats = "3.0.0" 17 | essentials = "2.19.4" 18 | griefprevention = "16.18.1" 19 | 20 | [libraries] 21 | # Minecraft 22 | spigot = { module = "org.spigotmc:spigot-api", version.ref = "spigot" } 23 | 24 | # Adventure 25 | adventure-bukkit = { module = "net.kyori:adventure-platform-bukkit", version.ref = "adventure-platform" } 26 | adventure-configurate = { module = "net.kyori:adventure-serializer-configurate4", version.ref = "adventure-platform" } 27 | adventure-minimessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "minimessage" } 28 | 29 | # Other 30 | configurate = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate" } 31 | triumph-cmds = { module = "dev.triumphteam:triumph-cmd-bukkit", version.ref = "cmds" } 32 | papi = { module = "me.clip:placeholderapi", version.ref = "papi" } 33 | towny = { module = "com.palmergames.bukkit.towny:towny", version.ref = "towny" } 34 | discordsrv = { module = "com.discordsrv:discordsrv", version.ref = "discordsrv" } 35 | supervanish = { module = "com.github.LeonMangler:SuperVanish", version.ref = "supervanish" } 36 | bstats = { module = "org.bstats:bstats-bukkit", version.ref = "bstats" } 37 | essentials = { module = "net.essentialsx:EssentialsX", version.ref="essentials" } 38 | griefprevention = { module = "com.github.TechFortress:GriefPrevention", version.ref = "griefprevention"} 39 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/HelpChat/ChatChat/1f3963f46265dbf37041a282107d644717bb1730/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | @rem SPDX-License-Identifier: Apache-2.0 17 | @rem 18 | 19 | @if "%DEBUG%"=="" @echo off 20 | @rem ########################################################################## 21 | @rem 22 | @rem Gradle startup script for Windows 23 | @rem 24 | @rem ########################################################################## 25 | 26 | @rem Set local scope for the variables with windows NT shell 27 | if "%OS%"=="Windows_NT" setlocal 28 | 29 | set DIRNAME=%~dp0 30 | if "%DIRNAME%"=="" set DIRNAME=. 31 | @rem This is normally unused 32 | set APP_BASE_NAME=%~n0 33 | set APP_HOME=%DIRNAME% 34 | 35 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 36 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 37 | 38 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 39 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 40 | 41 | @rem Find java.exe 42 | if defined JAVA_HOME goto findJavaFromJavaHome 43 | 44 | set JAVA_EXE=java.exe 45 | %JAVA_EXE% -version >NUL 2>&1 46 | if %ERRORLEVEL% equ 0 goto execute 47 | 48 | echo. 1>&2 49 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 50 | echo. 1>&2 51 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 52 | echo location of your Java installation. 1>&2 53 | 54 | goto fail 55 | 56 | :findJavaFromJavaHome 57 | set JAVA_HOME=%JAVA_HOME:"=% 58 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 59 | 60 | if exist "%JAVA_EXE%" goto execute 61 | 62 | echo. 1>&2 63 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 64 | echo. 1>&2 65 | echo Please set the JAVA_HOME variable in your environment to match the 1>&2 66 | echo location of your Java installation. 1>&2 67 | 68 | goto fail 69 | 70 | :execute 71 | @rem Setup the command line 72 | 73 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 74 | 75 | 76 | @rem Execute Gradle 77 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 78 | 79 | :end 80 | @rem End local scope for the variables with windows NT shell 81 | if %ERRORLEVEL% equ 0 goto mainEnd 82 | 83 | :fail 84 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 85 | rem the _cmd.exe /c_ return code! 86 | set EXIT_CODE=%ERRORLEVEL% 87 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 88 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 89 | exit /b %EXIT_CODE% 90 | 91 | :mainEnd 92 | if "%OS%"=="Windows_NT" endlocal 93 | 94 | :omega 95 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/ChatChatAPIImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat; 2 | 3 | import at.helpch.chatchat.api.ChatChatAPI; 4 | import at.helpch.chatchat.channel.ChannelTypeRegistryImpl; 5 | import at.helpch.chatchat.hooks.HookManagerImpl; 6 | import at.helpch.chatchat.mention.MentionManagerImpl; 7 | import at.helpch.chatchat.placeholder.MiniPlaceholderManagerImpl; 8 | import at.helpch.chatchat.rule.RuleManagerImpl; 9 | import at.helpch.chatchat.user.UsersHolderImpl; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | public class ChatChatAPIImpl implements ChatChatAPI { 13 | 14 | private final ChatChatPlugin plugin; 15 | 16 | public ChatChatAPIImpl(ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | public @NotNull UsersHolderImpl usersHolder() { 21 | return plugin.usersHolder(); 22 | } 23 | 24 | public @NotNull HookManagerImpl hookManager() { 25 | return plugin.hookManager(); 26 | } 27 | 28 | public @NotNull ChannelTypeRegistryImpl channelTypeRegistry() { 29 | return plugin.channelTypeRegistry(); 30 | } 31 | 32 | public @NotNull RuleManagerImpl ruleManager() { 33 | return plugin.ruleManager(); 34 | } 35 | 36 | public @NotNull MentionManagerImpl mentionsManager() { 37 | return plugin.mentionsManager(); 38 | } 39 | 40 | public @NotNull MiniPlaceholderManagerImpl miniPlaceholdersManager() { 41 | return plugin.miniPlaceholdersManager(); 42 | } 43 | 44 | public @NotNull ChatChatPlugin plugin() { 45 | return plugin; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/cache/ExpiringCache.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.cache; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | 5 | import java.util.Optional; 6 | import java.util.concurrent.TimeUnit; 7 | 8 | /** 9 | * An expiring cache. 10 | * 11 | * @param the cached type 12 | * @author Initially written by lucko for 13 | * LuckPerms. 14 | */ 15 | public class ExpiringCache { 16 | private final long durationNanos; 17 | 18 | private volatile T value; 19 | 20 | // when to expire. 0 means "not yet initialized". 21 | private volatile long expirationNanos; 22 | 23 | /** 24 | * Creates a new expiring cache. The cache will expire after the specified duration. 25 | *
26 | * Use a negative duration to disable expiration. 27 | * 28 | * @param duration amount of time to keep the cached value in the cache 29 | * @param unit the {@link TimeUnit} of the duration 30 | */ 31 | public ExpiringCache(long duration, TimeUnit unit) { 32 | this.durationNanos = unit.toNanos(duration); 33 | } 34 | 35 | public void put(T put) { 36 | final long now = System.nanoTime(); 37 | 38 | synchronized (this) { 39 | // set the value 40 | if (put == null) { 41 | this.invalidate(); 42 | return; 43 | } 44 | 45 | value = put; 46 | // reset expiration timer 47 | final var nanos = now + this.durationNanos; 48 | 49 | // In the very unlikely event that nanos is <= 0, set it to 1; 50 | // This can happen if duration <= -now. 51 | this.expirationNanos = nanos <= 0 ? 1 : nanos; 52 | } 53 | } 54 | 55 | public @NotNull Optional get() { 56 | long nanos = this.expirationNanos; 57 | long now = System.nanoTime(); 58 | 59 | // If value has not been initialized or cache is expiring and value has expired. 60 | if (nanos == 0 || (now - nanos >= 0 && durationNanos >= 0)) { 61 | synchronized (this) { 62 | if (nanos == this.expirationNanos) { // recheck for lost race 63 | return Optional.empty(); 64 | } 65 | } 66 | } 67 | return Optional.ofNullable(this.value); 68 | } 69 | 70 | public void invalidate() { 71 | this.expirationNanos = 0; 72 | } 73 | 74 | public boolean isPermanent() { 75 | return this.durationNanos < 0; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/channel/AbstractChannel.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.channel; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.holder.FormatsHolder; 5 | import at.helpch.chatchat.api.user.ChatUser; 6 | import at.helpch.chatchat.util.ChannelUtils; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.List; 10 | 11 | public abstract class AbstractChannel implements Channel { 12 | 13 | private final String name; 14 | 15 | private final String messagePrefix; 16 | 17 | private final List toggleCommands; 18 | 19 | private final String channelPrefix; 20 | 21 | private final FormatsHolder formats; 22 | 23 | private final int radius; 24 | 25 | protected AbstractChannel( 26 | @NotNull final String name, 27 | @NotNull final String messagePrefix, 28 | @NotNull final List toggleCommands, 29 | @NotNull final String channelPrefix, 30 | @NotNull final FormatsHolder formats, 31 | final int radius 32 | ) { 33 | this.name = name; 34 | this.messagePrefix = messagePrefix; 35 | this.toggleCommands = toggleCommands; 36 | this.channelPrefix = channelPrefix; 37 | this.formats = formats; 38 | this.radius = radius; 39 | } 40 | 41 | @Override 42 | public @NotNull String name() { 43 | return name; 44 | } 45 | 46 | @Override 47 | public @NotNull String messagePrefix() { 48 | return messagePrefix; 49 | } 50 | 51 | @Override 52 | public @NotNull String channelPrefix() { 53 | return channelPrefix; 54 | } 55 | 56 | @Override 57 | public @NotNull List commandNames() { 58 | return toggleCommands; 59 | } 60 | 61 | @Override 62 | public @NotNull FormatsHolder formats() { 63 | return formats; 64 | } 65 | 66 | @Override 67 | public int radius() { 68 | return radius; 69 | } 70 | 71 | @Override 72 | public boolean isUsableBy(@NotNull final ChatUser user) { 73 | if (ChatChannel.defaultChannel().equals(this)) { 74 | return true; 75 | } 76 | 77 | return user.hasPermission(ChannelUtils.USE_CHANNEL_PERMISSION + name()); 78 | } 79 | 80 | @Override 81 | public boolean equals(Object o) { 82 | if (this == o) return true; 83 | if (o == null || getClass() != o.getClass()) return false; 84 | AbstractChannel that = (AbstractChannel) o; 85 | return name.equals(that.name()) && 86 | messagePrefix.equals(that.messagePrefix()) && 87 | toggleCommands.equals(that.commandNames()) && 88 | channelPrefix.equals(that.channelPrefix()) && 89 | radius == that.radius(); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/channel/ChannelTypeRegistryImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.channel; 2 | 3 | import at.helpch.chatchat.api.channel.ChannelTypeRegistry; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.Collections; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | public final class ChannelTypeRegistryImpl implements ChannelTypeRegistry { 11 | 12 | private final Map> builders = new HashMap<>(); 13 | 14 | { 15 | add("default", ChatChannel::new); 16 | } 17 | 18 | public void add(final @NotNull String name, final @NotNull Builder builder) { 19 | final String lowercase = name.toLowerCase(); 20 | if (builders.containsKey(lowercase)) { 21 | throw new IllegalStateException("Attempted to register duplicate channel type " + name); 22 | } 23 | builders.put(lowercase, builder); 24 | } 25 | 26 | public @NotNull Map> builders() { 27 | return Collections.unmodifiableMap(builders); 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/channel/ChatChannel.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.channel; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.channel.Channel; 5 | import at.helpch.chatchat.api.holder.FormatsHolder; 6 | import at.helpch.chatchat.api.user.ChatUser; 7 | import at.helpch.chatchat.api.user.User; 8 | import at.helpch.chatchat.command.IgnoreCommand; 9 | import at.helpch.chatchat.config.DefaultConfigObjects; 10 | import at.helpch.chatchat.util.ChannelUtils; 11 | import org.jetbrains.annotations.NotNull; 12 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 13 | 14 | import java.util.List; 15 | import java.util.Set; 16 | import java.util.function.Predicate; 17 | import java.util.stream.Collectors; 18 | 19 | @ConfigSerializable 20 | public final class ChatChannel extends AbstractChannel { 21 | 22 | private static Channel defaultChannel = DefaultConfigObjects.createDefaultChannel(); 23 | 24 | public ChatChannel( 25 | @NotNull final String name, 26 | @NotNull final String messagePrefix, 27 | @NotNull final List toggleCommands, 28 | @NotNull final String channelPrefix, 29 | @NotNull final FormatsHolder formats, 30 | final int radius 31 | ) { 32 | super(name, messagePrefix, toggleCommands, channelPrefix, formats, radius); 33 | } 34 | 35 | public static @NotNull Channel defaultChannel() { 36 | return defaultChannel; 37 | } 38 | 39 | public static void defaultChannel(@NotNull final Channel toSet) { 40 | defaultChannel = toSet; 41 | } 42 | 43 | private final ChatChatPlugin plugin = ChatChatPlugin.getPlugin(ChatChatPlugin.class); 44 | 45 | @Override 46 | public String toString() { 47 | return "ChatChannel{" + 48 | "name=" + name() + 49 | ", messagePrefix='" + messagePrefix() + '\'' + 50 | ", toggleCommands='" + commandNames() + '\'' + 51 | ", channelPrefix='" + channelPrefix() + '\'' + 52 | ", radius='" + radius() + 53 | '}'; 54 | } 55 | 56 | @Override 57 | public Set targets(final @NotNull User source) { 58 | 59 | final Predicate filterIgnores = user -> user instanceof ChatUser && 60 | (!user.ignoredUsers().contains(source.uuid()) || source.hasPermission(IgnoreCommand.IGNORE_BYPASS_PERMISSION)); 61 | 62 | if (ChatChannel.defaultChannel().equals(this)) { 63 | return plugin.usersHolder().users().stream() 64 | .filter(User::chatEnabled) // Make sure the user has their chat enabled 65 | .filter(filterIgnores) 66 | .filter(user -> ChannelUtils.isTargetWithinRadius(source, user, radius())) 67 | .collect(Collectors.toSet()); 68 | } 69 | 70 | return plugin.usersHolder().users().stream().filter(user -> 71 | user.hasPermission(ChannelUtils.SEE_CHANNEL_PERMISSION + name())) 72 | .filter(User::chatEnabled) // Make sure the user has their chat enabled 73 | .filter(filterIgnores) 74 | .filter(user -> ChannelUtils.isTargetWithinRadius(source, user, radius())) 75 | .collect(Collectors.toSet()); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/ChatChatCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import dev.triumphteam.cmd.core.BaseCommand; 4 | import dev.triumphteam.cmd.core.annotation.Command; 5 | 6 | @Command("chatchat") 7 | public abstract class ChatChatCommand extends BaseCommand { 8 | } 9 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/ChatToggleCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | 10 | @Command("togglechat") 11 | public class ChatToggleCommand extends BaseCommand { 12 | 13 | private static final String CHAT_TOGGLE_PERMISSION = "chatchat.togglechat"; 14 | private final ChatChatPlugin plugin; 15 | 16 | public ChatToggleCommand(final ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @Default 21 | @Permission(CHAT_TOGGLE_PERMISSION) 22 | public void toggleChat(final ChatUser sender) { 23 | sender.chatState(!sender.chatEnabled()); 24 | 25 | final var messageHolder = plugin.configManager().messages(); 26 | final var message = sender.chatEnabled() ? 27 | messageHolder.chatEnabledSuccessfully() : 28 | messageHolder.chatDisabledSuccessfully(); 29 | 30 | sender.sendMessage(message); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/DumpCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.User; 5 | import at.helpch.chatchat.util.DumpUtils; 6 | import dev.triumphteam.cmd.core.annotation.Optional; 7 | import dev.triumphteam.cmd.core.annotation.SubCommand; 8 | import dev.triumphteam.cmd.core.annotation.Suggestion; 9 | import net.kyori.adventure.text.Component; 10 | import net.kyori.adventure.text.TextReplacementConfig; 11 | import net.kyori.adventure.text.event.ClickEvent; 12 | import org.jetbrains.annotations.NotNull; 13 | 14 | public class DumpCommand extends ChatChatCommand { 15 | 16 | private static final String DUMP_PERMISSION = "chatchat.dump"; 17 | private static final TextReplacementConfig.Builder DUMP_REPLACEMENT_BUILDER = TextReplacementConfig.builder() 18 | .match(""); 19 | 20 | private final ChatChatPlugin plugin; 21 | 22 | public DumpCommand(@NotNull final ChatChatPlugin plugin) { 23 | this.plugin = plugin; 24 | } 25 | 26 | @SubCommand("dump") 27 | public void dump(final User user, final @Suggestion("files") @Optional String file) { 28 | if (!user.hasPermission(DUMP_PERMISSION)) { 29 | user.sendMessage(plugin.configManager().messages().noPermission()); 30 | return; 31 | } 32 | 33 | final var dump = file != null 34 | ? DumpUtils.createDump(plugin, file) 35 | : DumpUtils.createDump(plugin, null); 36 | 37 | if (dump.isEmpty()) { 38 | user.sendMessage(plugin.configManager().messages().dumpFailed()); 39 | return; 40 | } 41 | 42 | DumpUtils.postDump(dump.get()).whenComplete((url, throwable) -> { 43 | if (throwable != null) { 44 | user.sendMessage(plugin.configManager().messages().dumpFailed()); 45 | throwable.printStackTrace(); 46 | return; 47 | } 48 | 49 | final var clickableUrl = Component.text(url) 50 | .clickEvent(ClickEvent.openUrl(url)); 51 | 52 | user.sendMessage(plugin.configManager().messages().dumpSuccess() 53 | .replaceText(DUMP_REPLACEMENT_BUILDER.replacement(clickableUrl).build())); 54 | }); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/FormatTestCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.format.PriorityFormat; 5 | import at.helpch.chatchat.api.user.ChatUser; 6 | import at.helpch.chatchat.placeholder.MiniPlaceholderContext; 7 | import at.helpch.chatchat.user.ConsoleUser; 8 | import at.helpch.chatchat.util.FormatUtils; 9 | import at.helpch.chatchat.util.MessageProcessor; 10 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 11 | import dev.triumphteam.cmd.core.annotation.Join; 12 | import dev.triumphteam.cmd.core.annotation.SubCommand; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | public class FormatTestCommand extends ChatChatCommand { 16 | 17 | private static final String FORMAT_TEST_PERMISSION = "chatchat.test.format"; 18 | 19 | private final ChatChatPlugin plugin; 20 | 21 | public FormatTestCommand(@NotNull final ChatChatPlugin plugin) { 22 | this.plugin = plugin; 23 | } 24 | 25 | @SubCommand("test") 26 | @Permission(FORMAT_TEST_PERMISSION) 27 | public void testFormat( 28 | @NotNull final ChatUser sender, 29 | @NotNull final PriorityFormat format, 30 | @Join @NotNull final String message 31 | ) { 32 | var player = sender.player(); 33 | if (player.isEmpty()) { 34 | sender.sendMessage(plugin.configManager().messages().genericError()); 35 | return; 36 | } 37 | 38 | if (message.isBlank()) { 39 | sender.sendMessage(plugin.configManager().messages().emptyMessage()); 40 | return; 41 | } 42 | 43 | sender.sendMessage( 44 | FormatUtils.parseFormat( 45 | format, 46 | player.get(), 47 | player.get(), 48 | MessageProcessor.processMessage(plugin, sender, ConsoleUser.INSTANCE, message), 49 | plugin.miniPlaceholdersManager().compileTags(MiniPlaceholderContext.builder().inMessage(false).sender(sender).recipient(sender).build()) 50 | ) 51 | ); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/IgnoreCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | 10 | @Command("ignore") 11 | public class IgnoreCommand extends BaseCommand { 12 | 13 | private final ChatChatPlugin plugin; 14 | private final static String IGNORE_PERMISSION = "chatchat.ignore"; 15 | public static final String IGNORE_BYPASS_PERMISSION = IGNORE_PERMISSION + ".bypass"; 16 | 17 | public IgnoreCommand(final ChatChatPlugin plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | @Permission(IGNORE_PERMISSION) 22 | @Default 23 | public void ignore(ChatUser sender, ChatUser target) { 24 | if (sender.uuid().equals(target.uuid())) { 25 | sender.sendMessage(plugin.configManager().messages().cantIgnoreYourself()); 26 | return; 27 | } 28 | 29 | var targetPlayer = target.player(); 30 | if (targetPlayer.isEmpty()) { 31 | sender.sendMessage(plugin.configManager().messages().userOffline()); 32 | return; 33 | } 34 | 35 | if (sender.ignoredUsers().contains(target.uuid())) { 36 | sender.sendMessage(plugin.configManager().messages().alreadyIgnored() 37 | .replaceText(builder -> builder.matchLiteral("").replacement(targetPlayer.get().getDisplayName()))); 38 | return; 39 | } 40 | 41 | sender.ignoreUser(target); 42 | sender.sendMessage(plugin.configManager().messages().ignoredPlayer() 43 | .replaceText(builder -> builder.matchLiteral("").replacement(targetPlayer.get().getDisplayName()))); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/IgnoreListCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | import org.bukkit.Bukkit; 10 | import org.bukkit.OfflinePlayer; 11 | 12 | import java.util.stream.Collectors; 13 | 14 | @Command("ignorelist") 15 | public class IgnoreListCommand extends BaseCommand { 16 | private final ChatChatPlugin plugin; 17 | private final static String IGNORELIST_PERMISSION = "chatchat.ignorelist"; 18 | 19 | public IgnoreListCommand(final ChatChatPlugin plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | @Default 24 | @Permission(IGNORELIST_PERMISSION) 25 | public void ignore(ChatUser sender) { 26 | if (sender.ignoredUsers().isEmpty()) { 27 | sender.sendMessage(plugin.configManager().messages().notIgnoringAnyone()); 28 | return; 29 | } 30 | 31 | String ignoredPlayers = sender.ignoredUsers() 32 | .stream() 33 | .map(Bukkit::getOfflinePlayer) 34 | .map(OfflinePlayer::getName) 35 | .collect(Collectors.joining(", ")); 36 | 37 | sender.sendMessage(plugin.configManager().messages().ignoredPlayersList() 38 | .replaceText(builder -> builder.matchLiteral("").replacement(ignoredPlayers))); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/MainCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.User; 5 | import at.helpch.chatchat.util.MessageUtils; 6 | import dev.triumphteam.cmd.core.annotation.Default; 7 | import net.kyori.adventure.text.Component; 8 | import org.bukkit.plugin.java.JavaPlugin; 9 | 10 | public final class MainCommand extends ChatChatCommand { 11 | 12 | private static final JavaPlugin PLUGIN = JavaPlugin.getProvidingPlugin(ChatChatPlugin.class); 13 | private static final Component TEXT = MessageUtils.parseToMiniMessage( 14 | "A Chat Plugin by <#3dbbe4>Help<#f3af4b>Chat
Version: " + PLUGIN.getDescription().getVersion()); 15 | 16 | @Default 17 | public void defaultCommand(final User sender) { 18 | sender.sendMessage(TEXT); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/MentionToggleCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.util.MentionUtils; 6 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 7 | import dev.triumphteam.cmd.core.BaseCommand; 8 | import dev.triumphteam.cmd.core.annotation.Command; 9 | import dev.triumphteam.cmd.core.annotation.SubCommand; 10 | 11 | @Command(value = "togglemention", alias = "toggleping") 12 | public class MentionToggleCommand extends BaseCommand { 13 | 14 | private final ChatChatPlugin plugin; 15 | 16 | public MentionToggleCommand(final ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @SubCommand("personal") 21 | @Permission(MentionUtils.MENTION_PERSONAL_BLOCK_PERMISSION) 22 | public void togglePersonal(final ChatUser sender) { 23 | sender.personalMentions(!sender.personalMentions()); 24 | 25 | final var messageHolder = plugin.configManager().messages(); 26 | final var message = sender.personalMentions() ? 27 | messageHolder.personalMentionsEnabled() : 28 | messageHolder.personalMentionsDisabled(); 29 | 30 | sender.sendMessage(message); 31 | } 32 | 33 | @SubCommand("channel") 34 | @Permission(MentionUtils.MENTION_CHANNEL_BLOCK_PERMISSION) 35 | public void toggleChannel(final ChatUser sender) { 36 | sender.channelMentions(!sender.channelMentions()); 37 | 38 | final var messageHolder = plugin.configManager().messages(); 39 | final var message = sender.channelMentions() ? 40 | messageHolder.channelMentionsEnabled() : 41 | messageHolder.channelMentionsDisabled(); 42 | 43 | sender.sendMessage(message); 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/RangedChatCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | 10 | @Command("rangedchat") 11 | public class RangedChatCommand extends BaseCommand { 12 | 13 | private static final String CHAT_TOGGLE_PERMISSION = "chatchat.rangedchat"; 14 | private final ChatChatPlugin plugin; 15 | 16 | public RangedChatCommand(final ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @Default 21 | @Permission(CHAT_TOGGLE_PERMISSION) 22 | public void toggleRangedChat(final ChatUser sender) { 23 | sender.rangedChat(!sender.rangedChat()); 24 | 25 | final var messageHolder = plugin.configManager().messages(); 26 | final var message = sender.rangedChat() ? 27 | messageHolder.rangedChatEnabledSuccessfully() : 28 | messageHolder.rangedChatDisabledSuccessfully(); 29 | 30 | sender.sendMessage(message); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/ReloadCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.User; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.annotation.SubCommand; 7 | import net.kyori.adventure.text.Component; 8 | import net.kyori.adventure.text.format.NamedTextColor; 9 | import net.kyori.adventure.text.format.TextColor; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import static net.kyori.adventure.text.Component.text; 13 | 14 | public final class ReloadCommand extends ChatChatCommand { 15 | 16 | private static final String ADMIN_PERMISSION = "chatchat.admin"; 17 | private final ChatChatPlugin plugin; 18 | 19 | public ReloadCommand(@NotNull final ChatChatPlugin plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | @SubCommand("reload") 24 | @Permission(ADMIN_PERMISSION) 25 | public void reloadCommand(final User sender) { 26 | plugin.configManager().reload(); 27 | 28 | final int formats = plugin.configManager().formats().formats().size(); 29 | final int channels = plugin.configManager().channels().channels().size(); 30 | final int channelFormats = plugin.configManager().channels().channels().values().stream() 31 | .mapToInt(channel -> channel.formats().formats().size()) 32 | .sum(); 33 | 34 | sender.sendMessage(text("Chat", TextColor.fromCSSHexString("#40c9ff")) 35 | .append(text("Chat", TextColor.fromCSSHexString("#e81cff"))) 36 | .append(text(" Reloaded Successfully!", NamedTextColor.GREEN)) 37 | .append(Component.newline()) 38 | .append(text(formats, NamedTextColor.WHITE)) 39 | .append(text((formats == 1 ? " format" : " formats") + " loaded!", NamedTextColor.GREEN)) 40 | .append(Component.newline()) 41 | .append(text(channels, NamedTextColor.WHITE)) 42 | .append(text((channels == 1 ? " channel" : " channels") + " loaded!", NamedTextColor.GREEN)) 43 | .append(Component.newline()) 44 | .append(text(channelFormats, NamedTextColor.WHITE)) 45 | .append(text((channelFormats == 1 ? " channel format" : " channel formats") + " loaded!", NamedTextColor.GREEN)) 46 | ); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/ReplyCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | import dev.triumphteam.cmd.core.annotation.Join; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | @Command(value = "reply", alias = "r") 13 | public final class ReplyCommand extends BaseCommand { 14 | 15 | private static final String MESSAGE_PERMISSION = "chatchat.pm"; 16 | private final ChatChatPlugin plugin; 17 | private final WhisperCommand whisperCommand; 18 | 19 | public ReplyCommand(@NotNull final ChatChatPlugin plugin, @NotNull final WhisperCommand whisperCommand) { 20 | this.plugin = plugin; 21 | this.whisperCommand = whisperCommand; 22 | } 23 | 24 | @Default 25 | @Permission(MESSAGE_PERMISSION) 26 | public void reply(final ChatUser user, @Join final String message) { 27 | if (!plugin.configManager().settings().privateMessagesSettings().enabled()) { 28 | user.sendMessage(plugin.configManager().messages().unknownCommand()); 29 | return; 30 | } 31 | 32 | final var lastMessaged = user.lastMessagedUser(); 33 | 34 | if (lastMessaged.isEmpty()) { 35 | user.sendMessage(plugin.configManager().messages().noReplies()); 36 | return; 37 | } 38 | 39 | whisperCommand.whisperCommand(user, lastMessaged.get(), message); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/SocialSpyCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | import dev.triumphteam.cmd.core.annotation.Optional; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | @Command(value = "socialspy", alias = {"sspy", "pmspy", "spy"}) 13 | public final class SocialSpyCommand extends BaseCommand { 14 | private static final String MESSAGE_PERMISSION = "chatchat.socialspy"; 15 | private final ChatChatPlugin plugin; 16 | 17 | public SocialSpyCommand(@NotNull final ChatChatPlugin plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | @Default 22 | @Permission(MESSAGE_PERMISSION) 23 | public void socialSpy(final ChatUser user, @Optional final String toggle) { 24 | final boolean newState = toggle == null ? 25 | !user.socialSpy() : 26 | toggle.equals("true") || toggle.equals("yes") || toggle.equals("on") || toggle.equals("enable"); 27 | 28 | user.socialSpy(newState); 29 | final var messages = plugin.configManager().messages(); 30 | user.sendMessage(newState ? messages.socialSpyEnabled() : messages.socialSpyDisabled()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/SwitchChannelCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.hooks.towny.AbstractTownyChannel; 6 | import at.helpch.chatchat.util.MessageProcessor; 7 | import com.palmergames.bukkit.towny.TownyUniverse; 8 | import com.palmergames.bukkit.towny.object.Resident; 9 | import dev.triumphteam.cmd.core.BaseCommand; 10 | import dev.triumphteam.cmd.core.annotation.Default; 11 | import dev.triumphteam.cmd.core.annotation.Join; 12 | import dev.triumphteam.cmd.core.annotation.Optional; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.List; 16 | 17 | public final class SwitchChannelCommand extends BaseCommand { 18 | 19 | private final ChatChatPlugin plugin; 20 | private final String command; 21 | 22 | public SwitchChannelCommand(@NotNull final ChatChatPlugin plugin, @NotNull final String command, 23 | @NotNull final List aliases) { 24 | super(command, aliases); 25 | this.plugin = plugin; 26 | this.command = command; 27 | } 28 | 29 | @Default 30 | public void switchChannel(final ChatUser user, @Join @Optional @NotNull final String message) { 31 | final var channels = plugin.configManager().channels().channels(); 32 | final var channel = channels.values() 33 | .stream() 34 | .filter(value -> value.commandNames().contains(command)) 35 | .findAny() 36 | .get(); // this should probably only ever throw if the person has changed command names without 37 | // restarting 38 | 39 | if (channel instanceof AbstractTownyChannel) { 40 | final var town = TownyUniverse.getInstance().getResidentOpt(user.uuid()) 41 | .map(Resident::getTownOrNull); 42 | if (town.isEmpty() || town.get().isRuined()) { // the API will still see a player in that town if it is ruined 43 | user.sendMessage(plugin.configManager().messages().userNotInTown()); 44 | return; 45 | } 46 | } 47 | 48 | if (!channel.isUsableBy(user)) { 49 | user.sendMessage(plugin.configManager().messages().channelNoPermission()); 50 | return; 51 | } 52 | 53 | if (message.isEmpty()) { 54 | user.channel(channel); 55 | user.sendMessage(plugin.configManager().messages().channelSwitched() 56 | .replaceText(builder -> builder.matchLiteral("").replacement(channel.name()))); 57 | return; 58 | } 59 | 60 | MessageProcessor.process(plugin, user, channel, message, false); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/UnignoreCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | 10 | @Command("unignore") 11 | public class UnignoreCommand extends BaseCommand { 12 | 13 | private final ChatChatPlugin plugin; 14 | private final static String IGNORE_PERMISSION = "chatchat.ignore"; 15 | 16 | public UnignoreCommand(final ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @Permission(IGNORE_PERMISSION) 21 | @Default 22 | public void unignore(ChatUser sender, ChatUser target) { 23 | var targetPlayer = target.player(); 24 | if (targetPlayer.isEmpty()) { 25 | sender.sendMessage(plugin.configManager().messages().userOffline()); 26 | return; 27 | } 28 | 29 | if (!sender.ignoredUsers().contains(target.uuid())) { 30 | sender.sendMessage(plugin.configManager().messages().notIgnored() 31 | .replaceText(builder -> builder.matchLiteral("").replacement(targetPlayer.get().getDisplayName()))); 32 | return; 33 | } 34 | 35 | sender.unignoreUser(target); 36 | sender.sendMessage(plugin.configManager().messages().unignoredPlayer() 37 | .replaceText(builder -> builder.matchLiteral("").replacement(targetPlayer.get().getDisplayName()))); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/command/WhisperToggleCommand.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.command; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import dev.triumphteam.cmd.bukkit.annotation.Permission; 6 | import dev.triumphteam.cmd.core.BaseCommand; 7 | import dev.triumphteam.cmd.core.annotation.Command; 8 | import dev.triumphteam.cmd.core.annotation.Default; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | @Command(value = "togglemsg", alias = { "toggledms", "togglepms" }) 12 | public class WhisperToggleCommand extends BaseCommand { 13 | 14 | private static final String MESSAGE_TOGGLE_PERMISSION = "chatchat.pm.toggle"; 15 | 16 | private final ChatChatPlugin plugin; 17 | 18 | public WhisperToggleCommand(@NotNull final ChatChatPlugin plugin) { 19 | this.plugin = plugin; 20 | } 21 | 22 | @Default 23 | @Permission(MESSAGE_TOGGLE_PERMISSION) 24 | public void whisperToggleCommand(final ChatUser user) { 25 | user.privateMessages(!user.privateMessages()); 26 | 27 | if (user.privateMessages()) { 28 | user.sendMessage(plugin.configManager().messages().privateMessagesEnabled()); 29 | return; 30 | } 31 | 32 | user.sendMessage(plugin.configManager().messages().privateMessagesDisabled()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/ConfigManager.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.holder.GlobalFormatsHolder; 5 | import at.helpch.chatchat.channel.ChatChannel; 6 | import at.helpch.chatchat.config.holder.ChannelsHolder; 7 | import at.helpch.chatchat.config.holder.ExtensionsHolder; 8 | import at.helpch.chatchat.config.holder.MessagesHolder; 9 | import at.helpch.chatchat.config.holder.MiniPlaceholdersHolder; 10 | import at.helpch.chatchat.config.holder.SettingsHolder; 11 | import at.helpch.chatchat.format.ChatFormat; 12 | import at.helpch.chatchat.format.DefaultFormatFactory; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.nio.file.Path; 16 | 17 | public final class ConfigManager { 18 | 19 | private @NotNull final ChatChatPlugin plugin; 20 | private ChannelsHolder channels; 21 | private GlobalFormatsHolder formats; 22 | private SettingsHolder settings; 23 | private MessagesHolder messages; 24 | private ExtensionsHolder extensions; 25 | private MiniPlaceholdersHolder miniPlaceholders; 26 | private final ConfigFactory factory; 27 | 28 | public ConfigManager(final @NotNull ChatChatPlugin plugin, @NotNull final Path dataFolder) { 29 | this.plugin = plugin; 30 | this.factory = new ConfigFactory(dataFolder, plugin); 31 | } 32 | 33 | public void reload() { 34 | messages = null; 35 | channels = null; 36 | formats = null; 37 | settings = null; 38 | extensions = null; 39 | miniPlaceholders = null; 40 | 41 | messages(); 42 | extensions(); 43 | plugin.getLogger().info("Whenever making changes to extensions.yml, restart the server to make sure all changes are applied."); 44 | 45 | channels(); 46 | final var defaultChannel = channels.channels().get(channels.defaultChannel()); 47 | if (defaultChannel instanceof ChatChannel) { 48 | ChatChannel.defaultChannel(defaultChannel); 49 | } else { 50 | plugin.getLogger().warning( 51 | "Could not find a channel named " + channels.defaultChannel() + "." + System.lineSeparator() + 52 | "Using an internal channel as the default channel." 53 | ); 54 | ChatChannel.defaultChannel(DefaultConfigObjects.createDefaultChannel()); 55 | } 56 | plugin.usersHolder().users().forEach(user -> user.channel(channels().channels().getOrDefault(user.channel().name(), ChatChannel.defaultChannel()))); 57 | 58 | settings(); 59 | 60 | formats(); 61 | final var defaultFormat = formats.formats().get(formats.defaultFormat()); 62 | if (defaultFormat instanceof ChatFormat) { 63 | ChatFormat.defaultFormat(defaultFormat); 64 | } else { 65 | ChatFormat.defaultFormat(DefaultFormatFactory.createDefaultFormat()); 66 | plugin.getLogger().warning( 67 | "Could not find a format named " + formats.defaultFormat() + "." + System.lineSeparator() + 68 | "Using an internal format as the default format." 69 | ); 70 | } 71 | 72 | miniPlaceholders(); 73 | plugin.miniPlaceholdersManager().clear(); 74 | miniPlaceholders.placeholders().forEach(placeholder -> plugin.miniPlaceholdersManager().addPlaceholder(placeholder)); 75 | } 76 | 77 | public @NotNull ChannelsHolder channels() { 78 | if (channels == null) { 79 | this.channels = factory.channels(); 80 | } 81 | return this.channels; 82 | } 83 | 84 | public @NotNull SettingsHolder settings() { 85 | if (settings == null) { 86 | this.settings = factory.settings(); 87 | } 88 | return this.settings; 89 | } 90 | 91 | public @NotNull GlobalFormatsHolder formats() { 92 | if (formats == null) { 93 | this.formats = factory.formats(); 94 | } 95 | return this.formats; 96 | } 97 | 98 | public @NotNull MessagesHolder messages() { 99 | if (messages == null) { 100 | this.messages = factory.messages(); 101 | } 102 | return this.messages; 103 | } 104 | 105 | public @NotNull ExtensionsHolder extensions() { 106 | if (extensions == null) { 107 | this.extensions = factory.extensions(); 108 | } 109 | return this.extensions; 110 | } 111 | 112 | public @NotNull MiniPlaceholdersHolder miniPlaceholders() { 113 | if (miniPlaceholders == null) { 114 | this.miniPlaceholders = factory.miniPlaceholders(); 115 | } 116 | return this.miniPlaceholders; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/AddonsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 4 | 5 | @SuppressWarnings("FieldMayBeFinal") 6 | @ConfigSerializable 7 | public class AddonsHolder { 8 | 9 | // DeluxeChat features 10 | private boolean DELUXECHAT_INVERSE_PRIORITIES = false; 11 | private boolean DELUXECHAT_UNICODE_PERMISSION_PUBLIC_CHAT = true; 12 | private boolean DELUXECHAT_UNICODE_PERMISSION_PRIVATE_CHAT = true; 13 | 14 | // Towny features 15 | private boolean TOWNY_CHANNELS = false; 16 | 17 | // DiscordSRV features 18 | private boolean DISCORDSRV_CHANNELS_BRIDGING = false; 19 | 20 | // Essentials features 21 | private boolean ESSENTIALS_VANISH = false; 22 | 23 | // SuperVanish features 24 | private boolean SUPERVANISH_VANISH = false; 25 | 26 | // GriefPrevention features 27 | private boolean GRIEFPREVENTION_SOFT_MUTE = true; 28 | 29 | public boolean deluxeChatInversePriorities() { 30 | return DELUXECHAT_INVERSE_PRIORITIES; 31 | } 32 | 33 | public void deluxeChatInversePriorities(final boolean value) { 34 | DELUXECHAT_INVERSE_PRIORITIES = value; 35 | } 36 | 37 | public boolean deluxeChatUnicodePermissionPublicChat() { 38 | return DELUXECHAT_UNICODE_PERMISSION_PUBLIC_CHAT; 39 | } 40 | 41 | public void deluxeChatUnicodePermissionPublicChat(final boolean value) { 42 | DELUXECHAT_UNICODE_PERMISSION_PUBLIC_CHAT = value; 43 | } 44 | 45 | public boolean deluxeChatUnicodePermissionPrivateChat() { 46 | return DELUXECHAT_UNICODE_PERMISSION_PRIVATE_CHAT; 47 | } 48 | 49 | public void deluxeChatUnicodePermissionPrivateChat(final boolean value) { 50 | DELUXECHAT_UNICODE_PERMISSION_PRIVATE_CHAT = value; 51 | } 52 | 53 | public boolean townyChannels() { 54 | return TOWNY_CHANNELS; 55 | } 56 | 57 | public void townyChannels(final boolean value) { 58 | TOWNY_CHANNELS = value; 59 | } 60 | 61 | public boolean discordSrvChannelsBridging() { 62 | return DISCORDSRV_CHANNELS_BRIDGING; 63 | } 64 | 65 | public void discordSrvChannelsBridging(final boolean value) { 66 | DISCORDSRV_CHANNELS_BRIDGING = value; 67 | } 68 | 69 | public boolean essentialsVanish() { 70 | return ESSENTIALS_VANISH; 71 | } 72 | 73 | public void essentialsVanish(final boolean value) { 74 | ESSENTIALS_VANISH = value; 75 | } 76 | 77 | public boolean superVanishVanish() { 78 | return SUPERVANISH_VANISH; 79 | } 80 | 81 | public void superVanishVanish(final boolean value) { 82 | SUPERVANISH_VANISH = value; 83 | } 84 | 85 | public boolean griefPreventionSoftMute() { 86 | return GRIEFPREVENTION_SOFT_MUTE; 87 | } 88 | 89 | public void griefPreventionSoftMute(final boolean value) { 90 | GRIEFPREVENTION_SOFT_MUTE = value; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/ChannelsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.config.DefaultConfigObjects; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 7 | 8 | import java.util.Map; 9 | 10 | // configurate requires non-final fields 11 | @SuppressWarnings("FieldMayBeFinal") 12 | @ConfigSerializable 13 | public final class ChannelsHolder { 14 | 15 | private String defaultChannel = "default"; 16 | 17 | private Map channels = Map.of( 18 | "staff", DefaultConfigObjects.createStaffChannel(), 19 | defaultChannel, DefaultConfigObjects.createDefaultChannel()); 20 | 21 | public @NotNull String defaultChannel() { 22 | return defaultChannel; 23 | } 24 | 25 | public @NotNull Map channels() { 26 | return Map.copyOf(channels); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/ExtensionsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 5 | 6 | @SuppressWarnings("FieldMayBeFinal") 7 | @ConfigSerializable 8 | public class ExtensionsHolder { 9 | 10 | private AddonsHolder addons = new AddonsHolder(); 11 | 12 | public @NotNull AddonsHolder addons() { 13 | return addons; 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/FormatsHolderImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import at.helpch.chatchat.api.format.PriorityFormat; 4 | import at.helpch.chatchat.api.holder.FormatsHolder; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 7 | 8 | import java.util.Map; 9 | 10 | // configurate requires non-final fields 11 | @SuppressWarnings("FieldMayBeFinal") 12 | @ConfigSerializable 13 | public class FormatsHolderImpl implements FormatsHolder { 14 | 15 | public FormatsHolderImpl() { 16 | } 17 | 18 | public FormatsHolderImpl(Map formats) { 19 | this.formats = formats; 20 | } 21 | 22 | private Map formats = Map.of(); 23 | 24 | public @NotNull Map formats() { 25 | return Map.copyOf(formats); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/GlobalFormatsHolderImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import at.helpch.chatchat.api.format.Format; 4 | import at.helpch.chatchat.api.format.PriorityFormat; 5 | import at.helpch.chatchat.api.holder.GlobalFormatsHolder; 6 | import at.helpch.chatchat.config.DefaultConfigObjects; 7 | import at.helpch.chatchat.format.SimpleFormat; 8 | import org.jetbrains.annotations.NotNull; 9 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 10 | 11 | import java.util.Map; 12 | 13 | // configurate requires non-final fields 14 | @SuppressWarnings("FieldMayBeFinal") 15 | @ConfigSerializable 16 | public final class GlobalFormatsHolderImpl implements GlobalFormatsHolder { 17 | 18 | private String defaultFormat = "default"; 19 | 20 | private SimpleFormat consoleFormat = DefaultConfigObjects.createDefaultConsoleFormat(); 21 | 22 | private Map formats = Map.of( 23 | "other", DefaultConfigObjects.createOtherFormat(), 24 | defaultFormat, DefaultConfigObjects.createDefaultFormat()); 25 | 26 | public @NotNull String defaultFormat() { 27 | return defaultFormat; 28 | } 29 | 30 | public @NotNull Format consoleFormat() { 31 | return consoleFormat; 32 | } 33 | 34 | public @NotNull Map formats() { 35 | return formats; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/MentionSettingsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import at.helpch.chatchat.api.format.Format; 4 | import at.helpch.chatchat.config.DefaultConfigObjects; 5 | import at.helpch.chatchat.format.SimpleFormat; 6 | import net.kyori.adventure.sound.Sound; 7 | import org.jetbrains.annotations.NotNull; 8 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 9 | 10 | // configurate requires non-final fields 11 | @SuppressWarnings("FieldMayBeFinal") 12 | @ConfigSerializable 13 | public final class MentionSettingsHolder { 14 | 15 | private String prefix = "@"; 16 | private Sound sound = DefaultConfigObjects.createMentionSound(); 17 | private boolean privateMessage = true; 18 | private SimpleFormat personalFormat = DefaultConfigObjects.createPersonalMentionFormat(); 19 | private SimpleFormat channelFormat = DefaultConfigObjects.createChannelMentionFormat(); 20 | 21 | public @NotNull String prefix() { 22 | return prefix; 23 | } 24 | 25 | public @NotNull Sound sound() { 26 | return sound; 27 | } 28 | 29 | public boolean privateMessage() { 30 | return privateMessage; 31 | } 32 | 33 | public @NotNull Format personalFormat() { 34 | return personalFormat; 35 | } 36 | 37 | public @NotNull Format channelFormat() { 38 | return channelFormat; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/MiniPlaceholdersHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import at.helpch.chatchat.placeholder.MiniPlaceholderImpl; 4 | import com.google.common.collect.ImmutableSet; 5 | import org.jetbrains.annotations.NotNull; 6 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 7 | 8 | import java.util.Set; 9 | 10 | // configurate requires non-final fields 11 | @SuppressWarnings("FieldMayBeFinal") 12 | @ConfigSerializable 13 | public class MiniPlaceholdersHolder { 14 | 15 | private Set placeholders = ImmutableSet.of(); 16 | 17 | public @NotNull Set placeholders() { 18 | return placeholders; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/PMSettingsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import at.helpch.chatchat.api.format.Format; 4 | import at.helpch.chatchat.config.DefaultConfigObjects; 5 | import at.helpch.chatchat.format.SimpleFormat; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 8 | 9 | // configurate requires non-final fields 10 | @SuppressWarnings("FieldMayBeFinal") 11 | @ConfigSerializable 12 | public final class PMSettingsHolder { 13 | 14 | private boolean enabled = true; 15 | 16 | private PMFormats formats = new PMFormats(); 17 | 18 | public boolean enabled() { 19 | return enabled; 20 | } 21 | 22 | public PMFormats formats() { 23 | return formats; 24 | } 25 | 26 | // configurate requires non-final fields 27 | @SuppressWarnings("FieldMayBeFinal") 28 | @ConfigSerializable 29 | public static final class PMFormats { 30 | private SimpleFormat senderFormat = DefaultConfigObjects.createPrivateMessageSenderFormat(); 31 | private SimpleFormat recipientFormat = DefaultConfigObjects.createPrivateMessageRecipientFormat(); 32 | private SimpleFormat socialSpyFormat = DefaultConfigObjects.createPrivateMessageSocialSpyFormat(); 33 | 34 | public @NotNull Format senderFormat() { 35 | return senderFormat; 36 | } 37 | 38 | public @NotNull Format recipientFormat() { 39 | return recipientFormat; 40 | } 41 | 42 | public @NotNull Format socialSpyFormat() { 43 | return socialSpyFormat; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/holder/SettingsHolder.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.holder; 2 | 3 | import org.jetbrains.annotations.NotNull; 4 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 5 | 6 | // configurate requires non-final fields 7 | @SuppressWarnings({"FieldMayBeFinal", "FieldCanBeLocal"}) 8 | @ConfigSerializable 9 | public final class SettingsHolder { 10 | 11 | private PMSettingsHolder privateMessages = new PMSettingsHolder(); 12 | 13 | private String itemFormat = "[ x ]"; 14 | private String itemFormatInfo = " x "; 15 | private MentionSettingsHolder mentions = new MentionSettingsHolder(); 16 | private long lastMessagedCacheDuration = 300; 17 | 18 | public @NotNull PMSettingsHolder privateMessagesSettings() { 19 | return privateMessages; 20 | } 21 | 22 | public @NotNull String itemFormat() { 23 | return itemFormat; 24 | } 25 | 26 | public @NotNull String itemFormatInfo() { 27 | return itemFormatInfo; 28 | } 29 | 30 | public @NotNull MentionSettingsHolder mentions() { 31 | return mentions; 32 | } 33 | 34 | public long lastMessagedCacheDuration() { 35 | return lastMessagedCacheDuration; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/mapper/AddonsMapper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.mapper; 2 | 3 | import at.helpch.chatchat.config.holder.AddonsHolder; 4 | import org.checkerframework.checker.nullness.qual.Nullable; 5 | import org.spongepowered.configurate.ConfigurationNode; 6 | import org.spongepowered.configurate.serialize.SerializationException; 7 | import org.spongepowered.configurate.serialize.TypeSerializer; 8 | 9 | import java.lang.reflect.Type; 10 | 11 | public class AddonsMapper implements TypeSerializer { 12 | 13 | private static final Object[] DELUXECHAT_INVERSE_PRIORITIES = new Object[] {"deluxechat", "inverse_priorities"}; 14 | private static final Object[] DELUXECHAT_UNICODE_PERMISSION_PUBLIC_CHAT = new Object[] {"deluxechat", "unicode_permission", "public_chat"}; 15 | private static final Object[] DELUXECHAT_UNICODE_PERMISSION_PRIVATE_CHAT = new Object[] {"deluxechat", "unicode_permission", "private_chat"}; 16 | 17 | private static final Object[] TOWNY_CHANNELS = new Object[] {"towny", "channels"}; 18 | 19 | private static final Object[] DISCORDSRV_CHANNELS_BRIDGING = new Object[] {"discordsrv", "channels_bridging"}; 20 | 21 | private static final Object[] ESSENTIALS_VANISH = new Object[] {"essentials", "vanish"}; 22 | 23 | private static final Object[] SUPERVANISH_VANISH = new Object[] {"supervanish", "vanish"}; 24 | 25 | private static final Object[] GRIEFPREVENTION_SOFT_MUTE = new Object[] {"griefprevention", "soft_mute"}; 26 | 27 | @Override 28 | public AddonsHolder deserialize(final Type type, final ConfigurationNode node) throws SerializationException { 29 | final AddonsHolder holder = new AddonsHolder(); 30 | 31 | holder.deluxeChatInversePriorities(node.node(DELUXECHAT_INVERSE_PRIORITIES).getBoolean(true)); 32 | holder.deluxeChatUnicodePermissionPublicChat(node.node(DELUXECHAT_UNICODE_PERMISSION_PUBLIC_CHAT).getBoolean(true)); 33 | holder.deluxeChatUnicodePermissionPrivateChat(node.node(DELUXECHAT_UNICODE_PERMISSION_PRIVATE_CHAT).getBoolean(true)); 34 | 35 | holder.townyChannels(node.node(TOWNY_CHANNELS).getBoolean(false)); 36 | 37 | holder.discordSrvChannelsBridging(node.node(DISCORDSRV_CHANNELS_BRIDGING).getBoolean(false)); 38 | 39 | holder.essentialsVanish(node.node(ESSENTIALS_VANISH).getBoolean(true)); 40 | 41 | holder.superVanishVanish(node.node(SUPERVANISH_VANISH).getBoolean(false)); 42 | 43 | holder.griefPreventionSoftMute(node.node(GRIEFPREVENTION_SOFT_MUTE).getBoolean(false)); 44 | 45 | return holder; 46 | } 47 | 48 | @Override 49 | public void serialize(final Type type, final @Nullable AddonsHolder obj, final ConfigurationNode target) throws SerializationException { 50 | if (obj == null) { 51 | return; 52 | } 53 | 54 | target.node(DELUXECHAT_INVERSE_PRIORITIES).set(obj.deluxeChatInversePriorities()); 55 | target.node(DELUXECHAT_UNICODE_PERMISSION_PUBLIC_CHAT).set(obj.deluxeChatUnicodePermissionPublicChat()); 56 | target.node(DELUXECHAT_UNICODE_PERMISSION_PRIVATE_CHAT).set(obj.deluxeChatUnicodePermissionPrivateChat()); 57 | 58 | target.node(TOWNY_CHANNELS).set(obj.townyChannels()); 59 | 60 | target.node(DISCORDSRV_CHANNELS_BRIDGING).set(obj.discordSrvChannelsBridging()); 61 | 62 | target.node(ESSENTIALS_VANISH).set(obj.essentialsVanish()); 63 | 64 | target.node(SUPERVANISH_VANISH).set(obj.superVanishVanish()); 65 | 66 | target.node(GRIEFPREVENTION_SOFT_MUTE).set(obj.griefPreventionSoftMute()); 67 | } 68 | 69 | } 70 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/mapper/ChannelMapMapper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.mapper; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.channel.Channel; 5 | import org.checkerframework.checker.nullness.qual.Nullable; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.spongepowered.configurate.ConfigurationNode; 8 | import org.spongepowered.configurate.serialize.SerializationException; 9 | import org.spongepowered.configurate.serialize.TypeSerializer; 10 | 11 | import java.lang.reflect.Type; 12 | import java.util.Collections; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | 16 | /** 17 | * A mapper for the channel map, ignoring invalid channels instead of failing entirely. 18 | */ 19 | public class ChannelMapMapper implements TypeSerializer> { 20 | 21 | private final ChannelMapper channelMapper; 22 | 23 | private final ChatChatPlugin plugin; 24 | 25 | public ChannelMapMapper(@NotNull final ChatChatPlugin plugin) { 26 | this.plugin = plugin; 27 | this.channelMapper = new ChannelMapper(plugin.channelTypeRegistry()); 28 | } 29 | 30 | @Override 31 | public Map deserialize(final Type type, final ConfigurationNode node) { 32 | final Map out = new HashMap<>(); 33 | 34 | if (!node.isMap()) return out; 35 | 36 | for (Map.Entry ent : node.childrenMap().entrySet()) { 37 | Channel parsed; 38 | try { 39 | parsed = channelMapper.deserialize(Channel.class, ent.getValue()); 40 | } catch (SerializationException ex) { 41 | plugin.getLogger().warning(ex.getMessage()); 42 | continue; 43 | } 44 | out.put(ent.getKey().toString(), parsed); 45 | } 46 | return out; 47 | } 48 | 49 | @Override 50 | public void serialize(final Type type, @Nullable final Map obj, final ConfigurationNode node) throws SerializationException { 51 | if (obj == null || obj.isEmpty()) { 52 | node.set(Collections.emptyMap()); 53 | return; 54 | } 55 | obj.forEach((k, v) -> { 56 | try { 57 | channelMapper.serialize(Channel.class, v, node.node(k)); 58 | } catch (SerializationException ignored) {} 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/mapper/ChannelMapper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.mapper; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.format.PriorityFormat; 5 | import at.helpch.chatchat.channel.ChannelTypeRegistryImpl; 6 | import at.helpch.chatchat.config.holder.FormatsHolderImpl; 7 | import io.leangen.geantyref.TypeToken; 8 | import org.jetbrains.annotations.Nullable; 9 | import org.spongepowered.configurate.ConfigurationNode; 10 | import org.spongepowered.configurate.serialize.SerializationException; 11 | import org.spongepowered.configurate.serialize.TypeSerializer; 12 | 13 | import java.lang.reflect.Type; 14 | import java.util.Arrays; 15 | import java.util.Map; 16 | 17 | public final class ChannelMapper implements TypeSerializer { 18 | 19 | private static final String TOGGLE_COMMAND = "toggle-command"; 20 | private static final String MESSAGE_PREFIX = "message-prefix"; 21 | private static final String CHANNEL_PREFIX = "channel-prefix"; 22 | private static final String FORMATS = "formats"; 23 | private static final String RADIUS = "radius"; 24 | private static final String TYPE = "type"; 25 | private static final TypeToken> FORMATS_MAP_TYPE = new TypeToken<>() {}; 26 | 27 | private final ChannelTypeRegistryImpl registry; 28 | 29 | public ChannelMapper(final ChannelTypeRegistryImpl registry) { 30 | this.registry = registry; 31 | } 32 | 33 | private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException { 34 | if (!source.hasChild(path)) { 35 | throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node"); 36 | } 37 | return source.node(path); 38 | } 39 | 40 | @Override 41 | public Channel deserialize(Type type, ConfigurationNode node) throws SerializationException { 42 | final var keyNode = node.key(); 43 | if (keyNode == null) { 44 | throw new SerializationException("A config key cannot be null!"); 45 | } 46 | final var key = keyNode.toString(); 47 | 48 | final var commandName = nonVirtualNode(node, TOGGLE_COMMAND).getList(String.class); 49 | if (commandName == null) { 50 | throw new SerializationException("Command name for " + key + " cannot be null!"); 51 | } 52 | 53 | final var messagePrefix = node.node(MESSAGE_PREFIX).getString(""); 54 | final var channelPrefix = node.node(CHANNEL_PREFIX).getString(""); 55 | final var formatsMap = node.node(FORMATS).get(FORMATS_MAP_TYPE, Map.of()); 56 | final var formats = new FormatsHolderImpl(formatsMap); 57 | final var radius = node.node(RADIUS).getInt(-1); 58 | 59 | final var channelType = node.node(TYPE).getString("default").toLowerCase(); 60 | 61 | final var builder = registry.builders().get(channelType); 62 | if (builder == null) { 63 | throw new SerializationException("Channel " + key + " has unknown channel type " + channelType + ", " + 64 | "ignoring."); 65 | } 66 | return builder.build(key, messagePrefix, commandName, channelPrefix, formats, radius); 67 | } 68 | 69 | @Override 70 | public void serialize(Type type, @Nullable Channel channel, ConfigurationNode target) throws SerializationException { 71 | if (channel == null) { 72 | target.raw(null); 73 | return; 74 | } 75 | 76 | target.node(TOGGLE_COMMAND).set(channel.commandNames()); 77 | target.node(MESSAGE_PREFIX).set(channel.messagePrefix()); 78 | target.node(CHANNEL_PREFIX).set(channel.channelPrefix()); 79 | target.node(FORMATS).set(channel.formats().formats()); 80 | target.node(RADIUS).set(channel.radius()); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/mapper/MiniMessageComponentMapper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.mapper; 2 | 3 | import net.kyori.adventure.text.Component; 4 | import net.kyori.adventure.text.minimessage.MiniMessage; 5 | import org.jetbrains.annotations.Nullable; 6 | import org.spongepowered.configurate.ConfigurationNode; 7 | import org.spongepowered.configurate.serialize.SerializationException; 8 | import org.spongepowered.configurate.serialize.TypeSerializer; 9 | 10 | import java.lang.reflect.Type; 11 | 12 | public final class MiniMessageComponentMapper implements TypeSerializer { 13 | 14 | private final MiniMessage miniMessage = MiniMessage.miniMessage(); 15 | 16 | @Override 17 | public Component deserialize(Type type, ConfigurationNode node) throws SerializationException { 18 | final var key = node.key(); 19 | if (key == null) { 20 | throw new SerializationException("A config key cannot be null! " + node.path()); 21 | } 22 | 23 | final var value = node.getString(); 24 | if (value == null) { 25 | throw new SerializationException("No value was given to " + key); 26 | } 27 | 28 | return miniMessage.deserialize(value); 29 | } 30 | 31 | @Override 32 | public void serialize(Type type, @Nullable Component component, ConfigurationNode target) throws SerializationException { 33 | if (component == null) { 34 | target.raw(null); 35 | return; 36 | } 37 | 38 | target.set(miniMessage.serialize(component)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/mapper/MiniPlaceholderMapper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.mapper; 2 | 3 | import at.helpch.chatchat.placeholder.MiniPlaceholderImpl; 4 | import net.kyori.adventure.text.minimessage.internal.TagInternals; 5 | import org.jetbrains.annotations.Nullable; 6 | import org.spongepowered.configurate.ConfigurationNode; 7 | import org.spongepowered.configurate.serialize.SerializationException; 8 | import org.spongepowered.configurate.serialize.TypeSerializer; 9 | 10 | import java.lang.reflect.Type; 11 | import java.util.Arrays; 12 | 13 | public class MiniPlaceholderMapper implements TypeSerializer { 14 | 15 | private static final String NAME = "name"; 16 | private static final String REQUIRES_RECIPIENT = "requires-recipient"; 17 | private static final String PARSE_MINI = "parse-mini"; 18 | private static final String PARSE_PAPI = "parse-papi"; 19 | private static final String CLOSING = "closing"; 20 | private static final String MESSAGE = "message"; 21 | 22 | private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException { 23 | if (!source.hasChild(path)) { 24 | throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node"); 25 | } 26 | return source.node(path); 27 | } 28 | 29 | @Override 30 | public MiniPlaceholderImpl deserialize(Type type, ConfigurationNode node) throws SerializationException { 31 | final var name = nonVirtualNode(node, NAME).getString(); 32 | if (name == null) { 33 | throw new SerializationException("Placeholder name missing!"); 34 | } 35 | 36 | try { 37 | TagInternals.assertValidTagName(name); 38 | } catch (final IllegalArgumentException ignored) { 39 | throw new SerializationException("Found invalid placeholder name in placeholders.yml: " + name + 40 | " - This placeholder will not be loaded."); 41 | } 42 | 43 | final var requiresRecipient = nonVirtualNode(node, REQUIRES_RECIPIENT).getBoolean(false); 44 | final var parseMini = nonVirtualNode(node, PARSE_MINI).getBoolean(false); 45 | final var parsePapi = nonVirtualNode(node, PARSE_PAPI).getBoolean(true); 46 | final var closing = nonVirtualNode(node, CLOSING).getBoolean(true); 47 | final var message = nonVirtualNode(node, MESSAGE).getString(""); 48 | 49 | return new MiniPlaceholderImpl(name, requiresRecipient, parseMini, parsePapi, closing, message); 50 | } 51 | 52 | @Override 53 | public void serialize(Type type, @Nullable MiniPlaceholderImpl placeholder, ConfigurationNode target) throws SerializationException { 54 | if (placeholder == null) { 55 | target.raw(null); 56 | return; 57 | } 58 | 59 | target.node(NAME).set(placeholder.name()); 60 | target.node(REQUIRES_RECIPIENT).set(placeholder.requiresRecipient()); 61 | target.node(PARSE_MINI).set(placeholder.parseMini()); 62 | target.node(PARSE_PAPI).set(placeholder.parsePapi()); 63 | target.node(CLOSING).set(placeholder.closing()); 64 | target.node(MESSAGE).set(placeholder.message()); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/mapper/PriorityFormatMapper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.mapper; 2 | 3 | import at.helpch.chatchat.api.format.PriorityFormat; 4 | import at.helpch.chatchat.format.ChatFormat; 5 | import io.leangen.geantyref.TypeToken; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.spongepowered.configurate.ConfigurationNode; 8 | import org.spongepowered.configurate.serialize.SerializationException; 9 | import org.spongepowered.configurate.serialize.TypeSerializer; 10 | 11 | import java.lang.reflect.Type; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | public final class PriorityFormatMapper implements TypeSerializer { 17 | 18 | private static final TypeToken>> mapTypeToken = new TypeToken<>() {}; 19 | private static final String PRIORITY = "priority"; 20 | private static final String PARTS = "parts"; 21 | 22 | private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException { 23 | if (!source.hasChild(path)) { 24 | throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node"); 25 | } 26 | return source.node(path); 27 | } 28 | 29 | @Override 30 | public PriorityFormat deserialize(Type type, ConfigurationNode node) throws SerializationException { 31 | final var keyNode = node.key(); 32 | if (keyNode == null) { 33 | throw new SerializationException("A config key cannot be null!"); 34 | } 35 | final var key = keyNode.toString(); 36 | 37 | final var priority = nonVirtualNode(node, PRIORITY).getInt(); 38 | 39 | final var parts = nonVirtualNode(node, PARTS).get(mapTypeToken); 40 | if (parts == null) { 41 | throw new SerializationException("Parts list of node: " + key + " cannot be null!"); 42 | } 43 | 44 | return new ChatFormat(key, priority, parts); 45 | } 46 | 47 | @Override 48 | public void serialize(Type type, @Nullable PriorityFormat format, ConfigurationNode target) throws SerializationException { 49 | if (format == null) { 50 | target.raw(null); 51 | return; 52 | } 53 | 54 | target.node(PRIORITY).set(format.priority()); 55 | target.node(PARTS).set(format.parts()); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/config/mapper/SimpleFormatMapper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.config.mapper; 2 | 3 | import at.helpch.chatchat.api.format.Format; 4 | import at.helpch.chatchat.format.SimpleFormat; 5 | import io.leangen.geantyref.TypeToken; 6 | import org.jetbrains.annotations.Nullable; 7 | import org.spongepowered.configurate.ConfigurationNode; 8 | import org.spongepowered.configurate.serialize.SerializationException; 9 | import org.spongepowered.configurate.serialize.TypeSerializer; 10 | 11 | import java.lang.reflect.Type; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | public final class SimpleFormatMapper implements TypeSerializer { 17 | 18 | private static final TypeToken>> mapTypeToken = new TypeToken<>() {}; 19 | private static final String PARTS = "parts"; 20 | 21 | private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException { 22 | if (!source.hasChild(path)) { 23 | throw new SerializationException("Required field " + Arrays.toString(path) + " was not present in node"); 24 | } 25 | return source.node(path); 26 | } 27 | 28 | @Override 29 | public Format deserialize(Type type, ConfigurationNode node) throws SerializationException { 30 | final var keyNode = node.key(); 31 | if (keyNode == null) { 32 | throw new SerializationException("A config key cannot be null!"); 33 | } 34 | final var key = keyNode.toString(); 35 | 36 | final var parts = nonVirtualNode(node, PARTS).get(mapTypeToken); 37 | if (parts == null) { 38 | throw new SerializationException("Parts list of node: " + key + " cannot be null!"); 39 | } 40 | 41 | return new SimpleFormat(key, parts); 42 | } 43 | 44 | @Override 45 | public void serialize(Type type, @Nullable Format format, ConfigurationNode target) throws SerializationException { 46 | if (format == null) { 47 | target.raw(null); 48 | return; 49 | } 50 | 51 | target.node(PARTS).set(format.parts()); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/data/base/Database.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.data.base; 2 | 3 | import at.helpch.chatchat.api.user.ChatUser; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.UUID; 7 | 8 | public interface Database { 9 | public @NotNull ChatUser loadChatUser(@NotNull final UUID uuid); 10 | public void saveChatUser(@NotNull final ChatUser chatUser); 11 | } 12 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/format/ChatFormat.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.format; 2 | 3 | import at.helpch.chatchat.api.format.PriorityFormat; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 6 | 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | @ConfigSerializable 12 | public final class ChatFormat implements PriorityFormat { 13 | 14 | private static PriorityFormat defaultFormat = DefaultFormatFactory.createDefaultFormat(); 15 | private final String name; 16 | private final int priority; 17 | private final Map> parts; 18 | 19 | public ChatFormat(@NotNull final String name, final int priority, @NotNull final Map> parts) { 20 | this.name = name; 21 | this.priority = priority; 22 | this.parts = Collections.unmodifiableMap(parts); 23 | } 24 | 25 | @Override 26 | public int priority() { 27 | return priority; 28 | } 29 | 30 | @Override 31 | public @NotNull ChatFormat priority(final int priority) { 32 | return new ChatFormat(name, priority, parts); 33 | } 34 | 35 | @Override 36 | public @NotNull Map> parts() { 37 | return parts; 38 | } 39 | 40 | @Override 41 | public @NotNull ChatFormat parts(@NotNull final Map> parts) { 42 | return new ChatFormat(name, priority, parts); 43 | } 44 | 45 | public @NotNull String name() { 46 | return name; 47 | } 48 | 49 | public @NotNull ChatFormat name(@NotNull final String name) { 50 | return new ChatFormat(name, priority, parts); 51 | } 52 | 53 | public static @NotNull PriorityFormat defaultFormat() { 54 | return defaultFormat; 55 | } 56 | 57 | public static void defaultFormat(@NotNull final PriorityFormat format) { 58 | defaultFormat = format; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return "ChatFormat{" + 64 | "name=" + name + 65 | ", priority=" + priority + 66 | ", parts=" + parts + 67 | '}'; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/format/DefaultFormatFactory.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.format; 2 | 3 | import at.helpch.chatchat.api.format.PriorityFormat; 4 | import org.jetbrains.annotations.NotNull; 5 | 6 | import java.util.LinkedHashMap; 7 | import java.util.List; 8 | 9 | public final class DefaultFormatFactory { 10 | 11 | /* 12 | This is only used as an internal format to send when a user: 13 | A - doesn't have any format permissions 14 | B - The default-format config option isn't set correctly 15 | */ 16 | public static @NotNull PriorityFormat createDefaultFormat() { 17 | final LinkedHashMap> map = new LinkedHashMap<>(); 18 | 19 | map.put("prefix", List.of("[ChatChat] ")); 20 | map.put("name", List.of("%player_name%")); 21 | map.put("message", List.of(" » ")); 22 | 23 | return new ChatFormat("default", 2, map); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/format/SimpleFormat.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.format; 2 | 3 | import at.helpch.chatchat.api.format.Format; 4 | import org.jetbrains.annotations.NotNull; 5 | import org.spongepowered.configurate.objectmapping.ConfigSerializable; 6 | 7 | import java.util.Collections; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | @ConfigSerializable 12 | public final class SimpleFormat implements Format { 13 | 14 | private final String name; 15 | private final Map> parts; 16 | 17 | public SimpleFormat(@NotNull final String name, @NotNull final Map> parts) { 18 | this.name = name; 19 | this.parts = Collections.unmodifiableMap(parts); 20 | } 21 | 22 | @Override 23 | public @NotNull String name() { 24 | return name; 25 | } 26 | 27 | @Override 28 | public @NotNull SimpleFormat name(@NotNull String name) { 29 | return new SimpleFormat(name, parts); 30 | } 31 | 32 | @Override 33 | public @NotNull Map> parts() { 34 | return parts; 35 | } 36 | 37 | @Override 38 | public @NotNull SimpleFormat parts(@NotNull final Map> parts) { 39 | return new SimpleFormat(name, parts); 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | return "SimpleFormat{" + 45 | "name=" + name + 46 | ", parts=" + parts + 47 | '}'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/AbstractInternalHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.hook.Hook; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public abstract class AbstractInternalHook implements Hook { 8 | 9 | private final ChatChatPlugin plugin; 10 | 11 | public AbstractInternalHook(@NotNull final ChatChatPlugin plugin) { 12 | this.plugin = plugin; 13 | } 14 | 15 | @Override 16 | public @NotNull ChatChatPlugin plugin() { 17 | return plugin; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/AbstractInternalMuteHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks; 2 | 3 | 4 | import at.helpch.chatchat.ChatChatPlugin; 5 | import at.helpch.chatchat.api.hook.MuteHook; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public abstract class AbstractInternalMuteHook extends MuteHook { 9 | 10 | private final ChatChatPlugin plugin; 11 | 12 | public AbstractInternalMuteHook(@NotNull final ChatChatPlugin plugin) { 13 | this.plugin = plugin; 14 | } 15 | 16 | @Override 17 | public @NotNull ChatChatPlugin plugin() { 18 | return plugin; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/AbstractInternalVanishHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.hook.VanishHook; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public abstract class AbstractInternalVanishHook extends VanishHook { 8 | 9 | private final ChatChatPlugin plugin; 10 | 11 | public AbstractInternalVanishHook(@NotNull final ChatChatPlugin plugin) { 12 | this.plugin = plugin; 13 | } 14 | 15 | @Override 16 | public @NotNull ChatChatPlugin plugin() { 17 | return plugin; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/HookCreator.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.ChatChatAPI; 5 | import at.helpch.chatchat.hooks.dsrv.ChatChatDsrvHook; 6 | import at.helpch.chatchat.hooks.gp.GriefPreventionSoftMuteHook; 7 | import at.helpch.chatchat.hooks.towny.ChatChatTownyHook; 8 | import at.helpch.chatchat.hooks.vanish.EssentialsVanishHook; 9 | import at.helpch.chatchat.hooks.vanish.SuperVanishHook; 10 | import at.helpch.chatchat.hooks.vanish.VanillaVanishHook; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | final class HookCreator { 14 | 15 | private final ChatChatPlugin plugin; 16 | 17 | public HookCreator(@NotNull final ChatChatPlugin plugin) { 18 | this.plugin = plugin; 19 | } 20 | 21 | public @NotNull ChatChatDsrvHook createDsrvHook(@NotNull final ChatChatAPI ignoredApi) { 22 | return new ChatChatDsrvHook(plugin); 23 | } 24 | 25 | public @NotNull ChatChatTownyHook chatChatTownyHook(@NotNull final ChatChatAPI ignoredApi) { 26 | return new ChatChatTownyHook(plugin); 27 | } 28 | 29 | public @NotNull EssentialsVanishHook essentialsVanishHook(@NotNull final ChatChatAPI ignoredApi) { 30 | return new EssentialsVanishHook(plugin); 31 | } 32 | 33 | public @NotNull SuperVanishHook superVanishHook(@NotNull final ChatChatAPI ignoredApi) { 34 | return new SuperVanishHook(plugin); 35 | } 36 | 37 | public @NotNull VanillaVanishHook vanillaVanishHook(@NotNull final ChatChatAPI ignoredApi) { 38 | return new VanillaVanishHook(plugin); 39 | } 40 | 41 | public @NotNull GriefPreventionSoftMuteHook griefPreventionSoftMuteHook(@NotNull final ChatChatAPI ignoredApi) { 42 | return new GriefPreventionSoftMuteHook(plugin); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/dsrv/ChatChatDsrvHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.dsrv; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.hooks.AbstractInternalHook; 5 | import github.scarsz.discordsrv.DiscordSRV; 6 | import org.bukkit.Bukkit; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | public final class ChatChatDsrvHook extends AbstractInternalHook { 10 | 11 | private static final String DISCORD_SRV = "DiscordSRV"; 12 | 13 | private final ChatChatPlugin plugin; 14 | 15 | public ChatChatDsrvHook(@NotNull final ChatChatPlugin plugin) { 16 | super(plugin); 17 | this.plugin = plugin; 18 | } 19 | 20 | @Override 21 | public boolean register() { 22 | return plugin.configManager().extensions().addons().discordSrvChannelsBridging() && 23 | Bukkit.getPluginManager().isPluginEnabled(DISCORD_SRV); 24 | } 25 | 26 | @Override 27 | public @NotNull String name() { 28 | return DISCORD_SRV + "Hook"; 29 | } 30 | 31 | @Override 32 | public void enable() { 33 | final var hook = new DsrvListener(plugin); 34 | DiscordSRV.getPlugin().getPluginHooks().add(hook); 35 | Bukkit.getPluginManager().registerEvents(hook, plugin); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/dsrv/DsrvListener.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.dsrv; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.event.ChatChatEvent; 5 | import at.helpch.chatchat.user.ConsoleUser; 6 | import github.scarsz.discordsrv.DiscordSRV; 7 | import github.scarsz.discordsrv.dependencies.kyori.adventure.text.Component; 8 | import github.scarsz.discordsrv.hooks.chat.ChatHook; 9 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; 10 | import org.bukkit.event.EventHandler; 11 | import org.bukkit.event.EventPriority; 12 | import org.bukkit.plugin.Plugin; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | public final class DsrvListener implements ChatHook { 16 | 17 | private final ChatChatPlugin plugin; 18 | 19 | public DsrvListener(@NotNull final ChatChatPlugin plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | @Override 24 | public Plugin getPlugin() { 25 | return plugin; 26 | } 27 | 28 | @Override 29 | public void broadcastMessageToChannel(final String channelName, final Component component) { 30 | final var channel = plugin.configManager().channels().channels().get(channelName); 31 | if (channel == null) { 32 | plugin.getLogger().info("Couldn't find channel " + channelName); 33 | return; 34 | } 35 | // gotta love shading 36 | final var message = GsonComponentSerializer.gson().deserialize( 37 | github.scarsz.discordsrv.dependencies.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().serialize(component) 38 | ); 39 | for (final var target : channel.targets(ConsoleUser.INSTANCE)) { 40 | target.sendMessage(message); 41 | } 42 | } 43 | 44 | @EventHandler(priority = EventPriority.MONITOR) 45 | public void onChat(ChatChatEvent event) { 46 | var player = event.user().player(); 47 | if (player.isEmpty()) { 48 | return; 49 | } 50 | 51 | final var message = github.scarsz.discordsrv.dependencies.kyori.adventure.text.serializer.gson.GsonComponentSerializer.gson().deserialize( 52 | GsonComponentSerializer.gson().serialize(event.message()) 53 | ); 54 | DiscordSRV.getPlugin().processChatMessage(player.get(), message, event.channel().name(), event.isCancelled()); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/gp/GriefPreventionSoftMuteHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.gp; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.hooks.AbstractInternalHook; 5 | import at.helpch.chatchat.listener.GriefPreventionSoftMuteListener; 6 | import org.bukkit.Bukkit; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | /** 10 | *

11 | * Mute Hook that uses Grief Prevention's implementation of a soft mute. 12 | *

13 | */ 14 | public class GriefPreventionSoftMuteHook extends AbstractInternalHook { 15 | 16 | private static final String GRIEF_PREVENTION = "GriefPrevention"; 17 | 18 | private final ChatChatPlugin plugin; 19 | 20 | public GriefPreventionSoftMuteHook(final @NotNull ChatChatPlugin plugin) { 21 | super(plugin); 22 | this.plugin = plugin; 23 | } 24 | 25 | @Override 26 | public boolean register() { 27 | return plugin.configManager().extensions().addons().griefPreventionSoftMute() && 28 | Bukkit.getPluginManager().isPluginEnabled(GRIEF_PREVENTION); 29 | } 30 | 31 | @Override 32 | public @NotNull String name() { 33 | return GRIEF_PREVENTION + "Hook"; 34 | } 35 | 36 | @Override 37 | public void enable() { 38 | plugin.getServer().getPluginManager().registerEvents(new GriefPreventionSoftMuteListener(), plugin); 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/towny/AbstractTownyChannel.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.towny; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.holder.FormatsHolder; 5 | import at.helpch.chatchat.api.user.ChatUser; 6 | import at.helpch.chatchat.api.user.User; 7 | import at.helpch.chatchat.channel.AbstractChannel; 8 | import at.helpch.chatchat.util.ChannelUtils; 9 | import com.palmergames.bukkit.towny.TownyUniverse; 10 | import com.palmergames.bukkit.towny.object.Resident; 11 | import com.palmergames.bukkit.towny.object.ResidentList; 12 | import org.bukkit.Bukkit; 13 | import org.jetbrains.annotations.NotNull; 14 | import org.jetbrains.annotations.Nullable; 15 | 16 | import java.util.List; 17 | import java.util.Optional; 18 | import java.util.Set; 19 | import java.util.UUID; 20 | import java.util.function.Predicate; 21 | import java.util.stream.Collectors; 22 | 23 | public abstract class AbstractTownyChannel extends AbstractChannel { 24 | protected AbstractTownyChannel(@NotNull final String name, 25 | @NotNull final String messagePrefix, 26 | @NotNull final List toggleCommands, 27 | @NotNull final String channelPrefix, 28 | @NotNull final FormatsHolder formats, 29 | final int radius) { 30 | super(name, messagePrefix, toggleCommands, channelPrefix, formats, radius); 31 | if (Bukkit.getPluginManager().getPlugin("Towny") == null) { 32 | throw new RuntimeException("Attempting to use a Towny channel but Towny is not installed."); 33 | }} 34 | 35 | private Optional residentList(@NotNull final UUID uuid) { 36 | return TownyUniverse.getInstance().getResidentOpt(uuid).map(this::residentList); 37 | } 38 | 39 | @Override 40 | public boolean isUsableBy(@NotNull final ChatUser user) { 41 | return super.isUsableBy(user) && residentList(user.uuid()).isPresent(); 42 | } 43 | 44 | protected abstract @Nullable ResidentList residentList(@NotNull final Resident resident); 45 | 46 | private final ChatChatPlugin plugin = ChatChatPlugin.getPlugin(ChatChatPlugin.class); 47 | 48 | @Override 49 | public Set targets(final @NotNull User source) { 50 | return residentList(source.uuid()).map(residentList -> residentList.getResidents().stream() 51 | .filter(Predicate.not(Resident::isNPC)) 52 | .filter(Resident::isOnline) 53 | .map(Resident::getUUID) 54 | .map(plugin.usersHolder()::getUser) 55 | .filter(User::chatEnabled) // Make sure the user has their chat enabled 56 | .filter(target -> ChannelUtils.isTargetWithinRadius(source, target, radius())) 57 | .collect(Collectors.toSet())).orElseGet(Set::of); 58 | 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/towny/ChatChatTownyHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.towny; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.hooks.AbstractInternalHook; 5 | import org.bukkit.Bukkit; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | public class ChatChatTownyHook extends AbstractInternalHook { 9 | 10 | private static final String TOWNY = "Towny"; 11 | 12 | private final ChatChatPlugin plugin; 13 | 14 | public ChatChatTownyHook(@NotNull final ChatChatPlugin plugin) { 15 | super(plugin); 16 | this.plugin = plugin; 17 | } 18 | 19 | @Override 20 | public boolean register() { 21 | return plugin.configManager().extensions().addons().townyChannels() && 22 | Bukkit.getPluginManager().isPluginEnabled(TOWNY); 23 | } 24 | 25 | @Override 26 | public @NotNull String name() { 27 | return TOWNY + "Hook"; 28 | } 29 | 30 | @Override 31 | public void enable() { 32 | plugin.channelTypeRegistry().add("TOWNY_TOWN", TownyTownChannel::new); 33 | plugin.channelTypeRegistry().add("TOWNY_NATION", TownyNationChannel::new); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/towny/TownyNationChannel.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.towny; 2 | 3 | import at.helpch.chatchat.api.holder.FormatsHolder; 4 | import com.palmergames.bukkit.towny.object.Resident; 5 | import com.palmergames.bukkit.towny.object.ResidentList; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.List; 10 | 11 | public final class TownyNationChannel extends AbstractTownyChannel { 12 | 13 | public TownyNationChannel(@NotNull final String name, 14 | @NotNull final String messagePrefix, 15 | @NotNull final List toggleCommands, 16 | @NotNull final String channelPrefix, 17 | @NotNull final FormatsHolder formats, 18 | final int radius) { 19 | super(name, messagePrefix, toggleCommands, channelPrefix, formats, radius); 20 | } 21 | 22 | @Override 23 | protected @Nullable ResidentList residentList(@NotNull final Resident resident) { 24 | return resident.getNationOrNull(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/towny/TownyTownChannel.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.towny; 2 | 3 | import at.helpch.chatchat.api.holder.FormatsHolder; 4 | import com.palmergames.bukkit.towny.object.Resident; 5 | import com.palmergames.bukkit.towny.object.ResidentList; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.List; 10 | 11 | public final class TownyTownChannel extends AbstractTownyChannel { 12 | 13 | public TownyTownChannel(@NotNull final String name, 14 | @NotNull final String messagePrefix, 15 | @NotNull final List toggleCommands, 16 | @NotNull final String channelPrefix, 17 | @NotNull final FormatsHolder formats, 18 | final int radius) { 19 | super(name, messagePrefix, toggleCommands, channelPrefix, formats, radius); 20 | } 21 | 22 | @Override 23 | protected @Nullable ResidentList residentList(@NotNull final Resident resident) { 24 | return resident.getTownOrNull(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/vanish/EssentialsVanishHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.vanish; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.hooks.AbstractInternalVanishHook; 6 | import at.helpch.chatchat.listener.EssentialsVanishListener; 7 | import org.bukkit.Bukkit; 8 | import org.jetbrains.annotations.NotNull; 9 | 10 | /** 11 | *

12 | * Vanish Hook that uses Essentials' implementation of player hiding 13 | * {@link net.ess3.api.IUser#setVanished(boolean) IUser#setVanished} to check if player is vanished. 14 | *

15 | *

16 | * Some plugins that this is known to work with: EssentialsX 17 | *

18 | */ 19 | public class EssentialsVanishHook extends AbstractInternalVanishHook { 20 | 21 | private static final String ESSENTIALS = "Essentials"; 22 | 23 | private final ChatChatPlugin plugin; 24 | 25 | public EssentialsVanishHook(@NotNull final ChatChatPlugin plugin) { 26 | super(plugin); 27 | this.plugin = plugin; 28 | } 29 | 30 | @Override 31 | public boolean register() { 32 | return plugin.configManager().extensions().addons().essentialsVanish() && 33 | Bukkit.getPluginManager().isPluginEnabled(ESSENTIALS); 34 | } 35 | 36 | @Override 37 | public @NotNull String name() { 38 | return ESSENTIALS + "Hook"; 39 | } 40 | 41 | @Override 42 | public void enable() { 43 | plugin.getServer().getPluginManager().registerEvents(new EssentialsVanishListener(plugin), plugin); 44 | } 45 | 46 | @Override 47 | public boolean canSee(@NotNull final ChatUser user, @NotNull final ChatUser target) { 48 | return user.player() 49 | .map(player -> target.player().map(player::canSee).orElse(true)) 50 | .orElse(true); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/vanish/SuperVanishHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.vanish; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.hooks.AbstractInternalVanishHook; 6 | import at.helpch.chatchat.listener.SuperVanishListener; 7 | import de.myzelyam.api.vanish.VanishAPI; 8 | import org.bukkit.Bukkit; 9 | import org.bukkit.entity.Player; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | /** 13 | *

14 | * Vanish Hook that uses SuperVanish's implementation of player hiding 15 | * {@link VanishAPI#canSee(Player, Player)} VanishAPI#canSee} to check if player is vanished. 16 | *

17 | *

18 | * Some plugins that this is known to work with: SuperVanish, PremiumVanish. 19 | *

20 | */ 21 | public class SuperVanishHook extends AbstractInternalVanishHook { 22 | 23 | private static final String SUPER_VANISH = "SuperVanish"; 24 | private static final String PREMIUM_VANISH = "PremiumVanish"; 25 | 26 | private final ChatChatPlugin plugin; 27 | 28 | public SuperVanishHook(@NotNull final ChatChatPlugin plugin) { 29 | super(plugin); 30 | this.plugin = plugin; 31 | } 32 | 33 | @Override 34 | public boolean register() { 35 | return plugin.configManager().extensions().addons().superVanishVanish() && 36 | (Bukkit.getPluginManager().isPluginEnabled(SUPER_VANISH) || Bukkit.getPluginManager().isPluginEnabled(PREMIUM_VANISH)); 37 | } 38 | 39 | @Override 40 | public @NotNull String name() { 41 | return (Bukkit.getPluginManager().isPluginEnabled(PREMIUM_VANISH) ? PREMIUM_VANISH : SUPER_VANISH) + "Hook"; 42 | } 43 | 44 | @Override 45 | public void enable() { 46 | plugin.getServer().getPluginManager().registerEvents(new SuperVanishListener(plugin), plugin); 47 | } 48 | 49 | @Override 50 | public boolean canSee(@NotNull final ChatUser user, @NotNull final ChatUser target) { 51 | return user.player() 52 | .map(player -> target.player().map(targetPlayer -> VanishAPI.canSee(player, targetPlayer)) 53 | .orElse(true)) 54 | .orElse(true); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/hooks/vanish/VanillaVanishHook.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.hooks.vanish; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.hooks.AbstractInternalVanishHook; 6 | import at.helpch.chatchat.listener.VanillaVanishListener; 7 | import at.helpch.chatchat.util.VersionHelper; 8 | import org.bukkit.entity.Player; 9 | import org.bukkit.plugin.Plugin; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | /** 13 | *

14 | * Vanish Hook that uses spigot's default implementation of player hiding 15 | * {@link org.bukkit.entity.Player#hidePlayer(Plugin, Player) Player#hidePlayer} to check if player is vanished. 16 | *

17 | *

18 | * Some plugins that this is known to work with: EssentialsX. 19 | *

20 | */ 21 | public class VanillaVanishHook extends AbstractInternalVanishHook { 22 | 23 | private final ChatChatPlugin plugin; 24 | 25 | public VanillaVanishHook(@NotNull final ChatChatPlugin plugin) { 26 | super(plugin); 27 | this.plugin = plugin; 28 | } 29 | 30 | @Override 31 | public boolean register() { 32 | return VersionHelper.CURRENT_VERSION >= VersionHelper.V1_19_0; 33 | } 34 | 35 | @Override 36 | public @NotNull String name() { 37 | return "VanillaVanishHook"; 38 | } 39 | 40 | @Override 41 | public void enable() { 42 | plugin.getServer().getPluginManager().registerEvents(new VanillaVanishListener(plugin), plugin); 43 | } 44 | 45 | @Override 46 | public boolean canSee(@NotNull final ChatUser user, @NotNull final ChatUser target) { 47 | return user.player() 48 | .map(player -> target.player().map(player::canSee).orElse(true)) 49 | .orElse(true); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/listener/EssentialsVanishListener.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.listener; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import net.ess3.api.events.VanishStatusChangeEvent; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.EventPriority; 8 | import org.bukkit.event.Listener; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class EssentialsVanishListener implements Listener { 12 | 13 | private final ChatChatPlugin plugin; 14 | 15 | public EssentialsVanishListener(@NotNull final ChatChatPlugin plugin) { 16 | this.plugin = plugin; 17 | } 18 | 19 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) 20 | private void onVanish(@NotNull final VanishStatusChangeEvent event) { 21 | final var chatUser = (ChatUser) plugin.usersHolder().getUser(event.getAffected().getBase()); 22 | 23 | final var lastMessaged = chatUser.lastMessagedUser(); 24 | if (lastMessaged.isEmpty()) { 25 | return; 26 | } 27 | 28 | if (!lastMessaged.get().uuid().equals(event.getAffected().getUUID())) { 29 | return; 30 | } 31 | 32 | if (chatUser.canSee(lastMessaged.get())) { 33 | return; 34 | } 35 | 36 | chatUser.lastMessagedUser(null); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/listener/GriefPreventionSoftMuteListener.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.listener; 2 | 3 | import at.helpch.chatchat.api.event.ChatChatEvent; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import me.ryanhamshire.GriefPrevention.GriefPrevention; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.EventPriority; 8 | import org.bukkit.event.Listener; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class GriefPreventionSoftMuteListener implements Listener { 12 | 13 | public GriefPreventionSoftMuteListener() { 14 | } 15 | 16 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) 17 | private void onChat(@NotNull final ChatChatEvent event) { 18 | if (!GriefPrevention.instance.dataStore.isSoftMuted(event.user().uuid())) { 19 | return; 20 | } 21 | 22 | event.recipients().removeIf(recipient -> recipient instanceof ChatUser && !GriefPrevention.instance.dataStore.isSoftMuted(recipient.uuid())); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/listener/PlayerListener.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.listener; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import org.bukkit.Bukkit; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.Listener; 8 | import org.bukkit.event.player.PlayerJoinEvent; 9 | import org.bukkit.event.player.PlayerQuitEvent; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | public final class PlayerListener implements Listener { 13 | 14 | private final ChatChatPlugin plugin; 15 | 16 | public PlayerListener(@NotNull final ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @EventHandler 21 | private void onJoin(final PlayerJoinEvent event) { 22 | Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> plugin.usersHolder().getUser(event.getPlayer())); 23 | } 24 | 25 | @EventHandler 26 | private void onLeave(final PlayerQuitEvent event) { 27 | 28 | // find everyone who last messaged the person leaving, and remove their reference 29 | plugin.usersHolder().users().stream() 30 | .filter(user -> user instanceof ChatUser) 31 | .map(user -> (ChatUser) user) 32 | .filter(user -> user.lastMessagedUser().isPresent()) 33 | .filter(user -> user.lastMessagedUser().get().player().equals(event.getPlayer())) 34 | .forEach(user -> user.lastMessagedUser(null)); 35 | 36 | Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> plugin.usersHolder().removeUser(event.getPlayer().getUniqueId())); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/listener/SuperVanishListener.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.listener; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import de.myzelyam.api.vanish.PlayerHideEvent; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.EventPriority; 8 | import org.bukkit.event.Listener; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | public class SuperVanishListener implements Listener { 12 | private final ChatChatPlugin plugin; 13 | 14 | public SuperVanishListener(@NotNull final ChatChatPlugin plugin) { 15 | this.plugin = plugin; 16 | } 17 | 18 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) 19 | public void onVanish(@NotNull final PlayerHideEvent event) { 20 | // find everyone who last messaged the person being vanished, and remove their reference 21 | plugin.usersHolder().users().stream() 22 | .filter(user -> user instanceof ChatUser) 23 | .map(user -> (ChatUser) user) 24 | .filter(user -> user.lastMessagedUser().isPresent()) 25 | .filter(user -> user.lastMessagedUser().get().player().equals(event.getPlayer())) 26 | .filter(user -> !user.canSee(user.lastMessagedUser().get())) 27 | .forEach(user -> user.lastMessagedUser(null)); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/listener/VanillaVanishListener.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.listener; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import org.bukkit.entity.Player; 6 | import org.bukkit.event.EventHandler; 7 | import org.bukkit.event.EventPriority; 8 | import org.bukkit.event.Listener; 9 | import org.bukkit.event.player.PlayerHideEntityEvent; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | public class VanillaVanishListener implements Listener { 13 | 14 | private final ChatChatPlugin plugin; 15 | 16 | public VanillaVanishListener(@NotNull final ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) 21 | private void onVanish(final PlayerHideEntityEvent event) { 22 | if (!(event.getEntity() instanceof Player)) { 23 | return; 24 | } 25 | 26 | final var chatUser = (ChatUser) plugin.usersHolder().getUser(event.getPlayer()); 27 | 28 | final var lastMessaged = chatUser.lastMessagedUser(); 29 | if (lastMessaged.isEmpty()) { 30 | return; 31 | } 32 | 33 | if (!lastMessaged.get().uuid().equals(event.getEntity().getUniqueId())) { 34 | return; 35 | } 36 | 37 | if (chatUser.canSee(lastMessaged.get())) { 38 | return; 39 | } 40 | 41 | chatUser.lastMessagedUser(null); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/mention/ChannelMention.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.mention; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.channel.Channel; 5 | import at.helpch.chatchat.api.event.ChannelMentionEvent; 6 | import at.helpch.chatchat.api.mention.Mention; 7 | import at.helpch.chatchat.api.mention.MentionResult; 8 | import at.helpch.chatchat.api.user.ChatUser; 9 | import at.helpch.chatchat.api.user.User; 10 | import at.helpch.chatchat.util.MentionUtils; 11 | import net.kyori.adventure.text.Component; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | public class ChannelMention implements Mention { 16 | 17 | private final ChatChatPlugin plugin; 18 | 19 | public ChannelMention(@NotNull final ChatChatPlugin plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | @Override 24 | public @NotNull MentionResult processMention( 25 | final boolean async, 26 | @NotNull final User sender, 27 | @NotNull final User target, 28 | @NotNull final Channel channel, 29 | @NotNull final Component message, 30 | @Nullable final Object data 31 | ) { 32 | final var unprocessedResult = new MentionResultImpl(message, false, false); 33 | 34 | if (plugin.configManager().settings().mentions().prefix().isBlank()) { 35 | return unprocessedResult; 36 | } 37 | 38 | if (!(sender instanceof ChatUser)) { 39 | return unprocessedResult; 40 | } 41 | 42 | // In this case the data tells us that we don't want this mention to be parsed at all. We want this when the 43 | // sender's message is updated to include the target's mentions. We don't want to include channel mentions there 44 | // as those will be parsed on their own. 45 | if (data instanceof Boolean && !((boolean) data)) { 46 | return unprocessedResult; 47 | } 48 | 49 | final var chatSender = (ChatUser) sender; 50 | 51 | final var result = MentionUtils.processChannelMentions( 52 | plugin.configManager().settings().mentions().prefix(), 53 | plugin.configManager().settings().mentions().personalFormat(), 54 | chatSender, 55 | target, 56 | message 57 | ); 58 | 59 | if (!result.getKey()) { 60 | return unprocessedResult; 61 | } 62 | 63 | final var event = new ChannelMentionEvent(async, chatSender, target, channel, chatSender.canSee(target)); 64 | plugin.getServer().getPluginManager().callEvent(event); 65 | if (event.isCancelled()) { 66 | return unprocessedResult; 67 | } 68 | 69 | return new MentionResultImpl(result.getValue(), true, event.playSound()); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/mention/MentionManagerImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.mention; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.channel.Channel; 5 | import at.helpch.chatchat.api.mention.Mention; 6 | import at.helpch.chatchat.api.mention.MentionManager; 7 | import at.helpch.chatchat.api.user.User; 8 | import com.google.common.collect.Sets; 9 | 10 | import java.util.Collections; 11 | 12 | import net.kyori.adventure.text.Component; 13 | import org.jetbrains.annotations.NotNull; 14 | 15 | import java.util.Set; 16 | 17 | import org.jetbrains.annotations.Nullable; 18 | 19 | public class MentionManagerImpl implements MentionManager { 20 | 21 | private final Set mentions = Sets.newHashSet(); 22 | 23 | public MentionManagerImpl(@NotNull final ChatChatPlugin plugin) { 24 | mentions.add(new PersonalMention(plugin)); 25 | mentions.add(new ChannelMention(plugin)); 26 | } 27 | 28 | @Override 29 | public void addMention(@NotNull Mention mention) { 30 | mentions.add(mention); 31 | } 32 | 33 | @Override 34 | public @NotNull Set mentions() { 35 | return Collections.unmodifiableSet(mentions); 36 | } 37 | 38 | public @NotNull MentionResultImpl processMentions( 39 | final boolean async, 40 | @NotNull final User sender, 41 | @NotNull final User target, 42 | @NotNull final Channel channel, 43 | @NotNull final Component message, 44 | @Nullable final Object data 45 | ) { 46 | var processedMessage = message; 47 | var mentioned = false; 48 | var playSound = false; 49 | 50 | for (final Mention mention : mentions) { 51 | final var result = mention.processMention(async, sender, target, channel, processedMessage, data); 52 | if (result.mentioned() && result.playSound()) { 53 | mentioned = true; 54 | playSound = true; 55 | } else if (result.mentioned()) { 56 | mentioned = true; 57 | } 58 | 59 | processedMessage = result.message(); 60 | } 61 | 62 | return new MentionResultImpl(processedMessage, mentioned, playSound); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/mention/MentionResultImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.mention; 2 | 3 | import at.helpch.chatchat.api.mention.MentionResult; 4 | import net.kyori.adventure.text.Component; 5 | import org.jetbrains.annotations.NotNull; 6 | 7 | public class MentionResultImpl implements MentionResult { 8 | 9 | private final Component message; 10 | private final boolean mentioned; 11 | private final boolean playSound; 12 | 13 | public MentionResultImpl(@NotNull final Component message, final boolean mentioned, final boolean playSound) { 14 | this.message = message; 15 | this.mentioned = mentioned; 16 | this.playSound = playSound; 17 | } 18 | 19 | @Override 20 | public @NotNull Component message() { 21 | return message; 22 | } 23 | 24 | @Override 25 | public boolean mentioned() { 26 | return mentioned; 27 | } 28 | 29 | @Override 30 | public boolean playSound() { 31 | return playSound; 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/mention/PersonalMention.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.mention; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.channel.Channel; 5 | import at.helpch.chatchat.api.event.PersonalMentionEvent; 6 | import at.helpch.chatchat.api.mention.Mention; 7 | import at.helpch.chatchat.api.mention.MentionResult; 8 | import at.helpch.chatchat.api.user.ChatUser; 9 | import at.helpch.chatchat.api.user.User; 10 | import at.helpch.chatchat.util.MentionUtils; 11 | import net.kyori.adventure.text.Component; 12 | import org.jetbrains.annotations.NotNull; 13 | import org.jetbrains.annotations.Nullable; 14 | 15 | public class PersonalMention implements Mention { 16 | 17 | private final ChatChatPlugin plugin; 18 | 19 | public PersonalMention(@NotNull final ChatChatPlugin plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | @Override 24 | public @NotNull MentionResult processMention( 25 | final boolean async, 26 | @NotNull final User sender, 27 | @NotNull final User target, 28 | @NotNull final Channel channel, 29 | @NotNull final Component message, 30 | @Nullable final Object data 31 | ) { 32 | final var unprocessedResult = new MentionResultImpl(message, false, false); 33 | 34 | if (plugin.configManager().settings().mentions().prefix().isBlank()) { 35 | return unprocessedResult; 36 | } 37 | 38 | if (!(sender instanceof ChatUser)) { 39 | return unprocessedResult; 40 | } 41 | 42 | final var chatSender = (ChatUser) sender; 43 | 44 | if (!(target instanceof ChatUser)) { 45 | return unprocessedResult; 46 | } 47 | 48 | final var chatTarget = (ChatUser) target; 49 | 50 | final var result = MentionUtils.processPersonalMentions( 51 | plugin.configManager().settings().mentions().prefix(), 52 | plugin.configManager().settings().mentions().personalFormat(), 53 | chatSender, 54 | chatTarget, 55 | message 56 | ); 57 | 58 | if (!result.getKey()) { 59 | return unprocessedResult; 60 | } 61 | 62 | // In this case the data tells us if the event should be fired or not. 63 | if (data instanceof Boolean && !((boolean) data)) { 64 | return new MentionResultImpl(result.getValue(), true, chatSender.canSee(chatTarget)); 65 | } 66 | 67 | final var event = new PersonalMentionEvent(async, chatSender, chatTarget, channel, chatSender.canSee(chatTarget)); 68 | plugin.getServer().getPluginManager().callEvent(event); 69 | if (event.isCancelled()) { 70 | return unprocessedResult; 71 | } 72 | 73 | return new MentionResultImpl(result.getValue(), true, event.playSound()); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/placeholder/MiniPlaceholderContext.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.placeholder; 2 | 3 | import at.helpch.chatchat.api.placeholder.MiniPlaceholder; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.api.user.User; 6 | import org.jetbrains.annotations.NotNull; 7 | import org.jetbrains.annotations.Nullable; 8 | 9 | import java.util.Optional; 10 | 11 | public class MiniPlaceholderContext implements MiniPlaceholder.Context { 12 | 13 | private final boolean inMessage; 14 | private final @Nullable ChatUser sender; 15 | private final @Nullable User recipient; 16 | 17 | private MiniPlaceholderContext(final @NotNull Builder builder) { 18 | this.inMessage = builder.inMessage; 19 | this.sender = builder.sender; 20 | this.recipient = builder.recipient; 21 | } 22 | 23 | @Override 24 | public boolean inMessage() { 25 | return inMessage; 26 | } 27 | 28 | @Override 29 | public @NotNull Optional sender() { 30 | return Optional.ofNullable(sender); 31 | } 32 | 33 | @Override 34 | public @NotNull Optional recipient() { 35 | return Optional.ofNullable(recipient); 36 | } 37 | 38 | public @NotNull Builder toBuilder() { 39 | return new Builder(this); 40 | } 41 | 42 | public static @NotNull Builder builder() { 43 | return new Builder(); 44 | } 45 | 46 | public static final class Builder { 47 | 48 | private boolean inMessage = false; 49 | private ChatUser sender = null; 50 | private User recipient = null; 51 | 52 | private Builder() { 53 | } 54 | 55 | private Builder(final @NotNull MiniPlaceholderContext context) { 56 | this.inMessage = context.inMessage; 57 | this.sender = context.sender; 58 | this.recipient = context.recipient; 59 | } 60 | 61 | public @NotNull Builder inMessage(final boolean inMessage) { 62 | this.inMessage = inMessage; 63 | return this; 64 | } 65 | 66 | public @NotNull Builder sender(final @Nullable ChatUser sender) { 67 | this.sender = sender; 68 | return this; 69 | } 70 | 71 | public @NotNull Builder recipient(final @Nullable User recipient) { 72 | this.recipient = recipient; 73 | return this; 74 | } 75 | 76 | public @NotNull MiniPlaceholderContext build() { 77 | return new MiniPlaceholderContext(this); 78 | } 79 | 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/placeholder/MiniPlaceholderManagerImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.placeholder; 2 | 3 | import at.helpch.chatchat.api.placeholder.MiniPlaceholder; 4 | import at.helpch.chatchat.api.placeholder.MiniPlaceholderManager; 5 | import com.google.common.collect.Sets; 6 | import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 7 | import org.jetbrains.annotations.NotNull; 8 | 9 | import java.util.Collections; 10 | import java.util.Set; 11 | 12 | public class MiniPlaceholderManagerImpl implements MiniPlaceholderManager { 13 | 14 | final Set miniPlaceholders = Sets.newHashSet(); 15 | 16 | @Override 17 | public void addPlaceholder(@NotNull final MiniPlaceholder placeholder) { 18 | miniPlaceholders.add(placeholder); 19 | } 20 | 21 | public @NotNull TagResolver compileTags(final @NotNull MiniPlaceholder.Context context) { 22 | return placeholders().stream() 23 | .map(placeholder -> placeholder.toTagResolver(context)) 24 | .filter(tag -> !tag.equals(TagResolver.empty())) 25 | .collect(TagResolver.toTagResolver()); 26 | } 27 | 28 | @Override 29 | public @NotNull Set<@NotNull MiniPlaceholder> placeholders() { 30 | return Collections.unmodifiableSet(miniPlaceholders); 31 | } 32 | 33 | public void clear() { 34 | miniPlaceholders.clear(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/placeholder/PlaceholderAPIPlaceholders.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.placeholder; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import me.clip.placeholderapi.PlaceholderAPI; 6 | import me.clip.placeholderapi.PlaceholderAPIPlugin; 7 | import me.clip.placeholderapi.expansion.PlaceholderExpansion; 8 | import net.kyori.adventure.identity.Identity; 9 | import org.bukkit.OfflinePlayer; 10 | import org.bukkit.entity.Player; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.List; 14 | import java.util.Optional; 15 | 16 | public final class PlaceholderAPIPlaceholders extends PlaceholderExpansion { 17 | private final ChatChatPlugin plugin; 18 | 19 | public PlaceholderAPIPlaceholders(@NotNull final ChatChatPlugin plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | @Override 24 | public @NotNull String getIdentifier() { 25 | return "chatchat"; 26 | } 27 | 28 | @Override 29 | public @NotNull String getAuthor() { 30 | return plugin.getDescription().getAuthors().get(0); 31 | } 32 | 33 | @Override 34 | public @NotNull String getVersion() { 35 | return plugin.getDescription().getVersion(); 36 | } 37 | 38 | @Override 39 | public @NotNull List getPlaceholders() { 40 | return List.of( 41 | "%chatchat_channel_name%", 42 | "%chatchat_channel_prefix%", 43 | "%chatchat_channel_message_prefix%", 44 | "%chatchat_social_spy_enabled%", 45 | "%chatchat_private_messages_enabled%", 46 | "%chatchat_private_messages_recipient%", 47 | "%chatchat_ranged_chat_enabled%" 48 | ); 49 | } 50 | 51 | @Override 52 | public boolean persist() { 53 | return true; 54 | } 55 | 56 | @Override 57 | public String onRequest(final OfflinePlayer offlinePlayer, @NotNull final String input) { 58 | final var parsedInput = PlaceholderAPI.setBracketPlaceholders(offlinePlayer, input); 59 | 60 | if (offlinePlayer != null && !offlinePlayer.isOnline()) { 61 | return null; 62 | } 63 | 64 | final var user = plugin.usersHolder().getUser( 65 | offlinePlayer == null 66 | ? Identity.nil().uuid() 67 | : offlinePlayer.getUniqueId() 68 | ); 69 | 70 | switch(parsedInput) { 71 | case "channel_name": 72 | return user.channel().name(); 73 | case "channel_prefix": 74 | return user.channel().channelPrefix(); 75 | case "channel_message_prefix": 76 | return user.channel().messagePrefix(); 77 | } 78 | 79 | if (!(user instanceof ChatUser)) { 80 | return null; 81 | } 82 | 83 | final var chatUser = (ChatUser) user; 84 | 85 | switch(parsedInput) { 86 | case "social_spy_enabled": 87 | return formatBoolean(chatUser.socialSpy()); 88 | case "private_messages_enabled": 89 | return formatBoolean(chatUser.privateMessages()); 90 | case "ranged_chat_enabled": 91 | return formatBoolean(chatUser.rangedChat()); 92 | case "private_messages_recipient": 93 | return chatUser.lastMessagedUser().map(value -> value.player().map(Player::getName).orElse("")).orElse(""); 94 | } 95 | 96 | return null; 97 | } 98 | 99 | 100 | private @NotNull String formatBoolean(boolean bool) { 101 | return bool ? PlaceholderAPIPlugin.booleanTrue() : PlaceholderAPIPlugin.booleanFalse(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/rule/InvalidCharsRule.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.rule; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.rule.Rule; 5 | import at.helpch.chatchat.api.user.ChatUser; 6 | import at.helpch.chatchat.api.user.User; 7 | 8 | import java.util.Optional; 9 | 10 | import net.kyori.adventure.text.Component; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | public class InvalidCharsRule implements Rule { 14 | 15 | private static final String UTF_PERMISSION = "chatchat.utf"; 16 | 17 | private final ChatChatPlugin plugin; 18 | 19 | public InvalidCharsRule(@NotNull final ChatChatPlugin plugin) { 20 | this.plugin = plugin; 21 | } 22 | 23 | public boolean isAllowedPublic(@NotNull final ChatUser sender, @NotNull final String message) { 24 | return message.chars().noneMatch(it -> it > 127 && it != 248) || sender.hasPermission(UTF_PERMISSION); 25 | } 26 | 27 | public boolean isAllowedPrivate(@NotNull ChatUser sender, @NotNull User recipient, @NotNull String message) { 28 | return message.chars().noneMatch(it -> it > 127 && it != 248) || sender.hasPermission(UTF_PERMISSION); 29 | } 30 | 31 | public @NotNull Optional<@NotNull Component> publicDeniedMessage() { 32 | return Optional.of(plugin.configManager().messages().specialCharactersNoPermission()); 33 | } 34 | 35 | public @NotNull Optional<@NotNull Component> privateDeniedMessage() { 36 | return Optional.of(plugin.configManager().messages().specialCharactersNoPermission()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/rule/RuleManagerImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.rule; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.rule.Rule; 5 | import at.helpch.chatchat.api.rule.RuleManager; 6 | import at.helpch.chatchat.api.user.ChatUser; 7 | import com.google.common.collect.Sets; 8 | import net.kyori.adventure.text.Component; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Collections; 12 | import java.util.Optional; 13 | import java.util.Set; 14 | import java.util.stream.Collectors; 15 | 16 | public class RuleManagerImpl implements RuleManager { 17 | 18 | private final ChatChatPlugin plugin; 19 | 20 | private final Set publicChatRules = Sets.newHashSet(); 21 | private final Set privateChatRules = Sets.newHashSet(); 22 | 23 | public RuleManagerImpl(@NotNull final ChatChatPlugin plugin) { 24 | this.plugin = plugin; 25 | if (plugin.configManager().extensions().addons().deluxeChatUnicodePermissionPublicChat()) { 26 | addPublicChatRule(new InvalidCharsRule(plugin)); 27 | } 28 | if (plugin.configManager().extensions().addons().deluxeChatUnicodePermissionPrivateChat()) { 29 | addPrivateChatRule(new InvalidCharsRule(plugin)); 30 | } 31 | } 32 | 33 | @Override 34 | public void addPublicChatRule(@NotNull final Rule rule) { 35 | this.publicChatRules.add(rule); 36 | } 37 | 38 | @Override 39 | public void addPrivateChatRule(@NotNull final Rule rule) { 40 | this.privateChatRules.add(rule); 41 | } 42 | 43 | @Override 44 | public @NotNull Set publicChatRules() { 45 | return Collections.unmodifiableSet(publicChatRules); 46 | } 47 | 48 | @Override 49 | public @NotNull Set privateChatRules() { 50 | return Collections.unmodifiableSet(privateChatRules); 51 | } 52 | 53 | public Optional isAllowedPublicChat(@NotNull final ChatUser sender, @NotNull final String message) { 54 | final var unfulfilledRules = publicChatRules() 55 | .stream() 56 | .filter(rule -> !rule.isAllowedPublic(sender, message)) 57 | .collect(Collectors.toList()); 58 | 59 | if (unfulfilledRules.isEmpty()) { 60 | return Optional.empty(); 61 | } 62 | 63 | return unfulfilledRules.stream() 64 | .map(Rule::publicDeniedMessage) 65 | .filter(Optional::isPresent) 66 | .findFirst() 67 | .orElse(Optional.of(plugin.configManager().messages().invalidMessage())); 68 | } 69 | 70 | public Optional isAllowedPrivateChat( 71 | @NotNull final ChatUser sender, 72 | @NotNull final ChatUser recipient, 73 | @NotNull final String message 74 | ) { 75 | final var unfulfilledRules = privateChatRules() 76 | .stream() 77 | .filter(rule -> !rule.isAllowedPrivate(sender, recipient, message)) 78 | .collect(Collectors.toList()); 79 | 80 | if (unfulfilledRules.isEmpty()) { 81 | return Optional.empty(); 82 | } 83 | 84 | return unfulfilledRules.stream() 85 | .map(Rule::privateDeniedMessage) 86 | .filter(Optional::isPresent) 87 | .findFirst() 88 | .orElse(Optional.of(plugin.configManager().messages().invalidMessage())); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/user/ConsoleUser.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.user; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.channel.Channel; 5 | import at.helpch.chatchat.api.format.Format; 6 | import at.helpch.chatchat.api.user.User; 7 | import at.helpch.chatchat.channel.ChatChannel; 8 | import at.helpch.chatchat.format.ChatFormat; 9 | import net.kyori.adventure.audience.Audience; 10 | import net.kyori.adventure.identity.Identity; 11 | import org.jetbrains.annotations.NotNull; 12 | 13 | import java.util.Set; 14 | import java.util.UUID; 15 | 16 | public final class ConsoleUser implements User { 17 | 18 | public static final ConsoleUser INSTANCE = new ConsoleUser(); 19 | 20 | private ConsoleUser() { 21 | } 22 | 23 | @Override 24 | public @NotNull Channel channel() { 25 | return ChatChannel.defaultChannel(); 26 | } 27 | 28 | @Override 29 | public void channel(@NotNull final Channel channel) { 30 | } 31 | 32 | @Override 33 | public @NotNull Format format() { 34 | return ChatFormat.defaultFormat(); 35 | } 36 | 37 | @Override 38 | public void format(@NotNull final Format format) { 39 | } 40 | 41 | @Override 42 | public @NotNull UUID uuid() { 43 | return Identity.nil().uuid(); 44 | } 45 | 46 | @Override 47 | public boolean hasPermission(@NotNull final String node) { 48 | return true; 49 | } 50 | 51 | @Override 52 | public boolean canSee(@NotNull final User target) { 53 | return true; 54 | } 55 | 56 | @Override 57 | public @NotNull Set ignoredUsers() { 58 | return Set.of(); 59 | } 60 | 61 | @Override 62 | public void ignoredUsers(@NotNull final Set users) { 63 | } 64 | 65 | @Override 66 | public void ignoreUser(@NotNull final User user) { 67 | } 68 | 69 | @Override 70 | public void unignoreUser(@NotNull final User user) { 71 | } 72 | 73 | @Override 74 | public boolean chatEnabled() { 75 | return true; 76 | } 77 | 78 | @Override 79 | public void chatState(final boolean enabled) { 80 | } 81 | 82 | @Override 83 | public @NotNull Audience audience() { 84 | return ChatChatPlugin.audiences().console(); 85 | } 86 | 87 | @Override 88 | public @NotNull Identity identity() { 89 | return Identity.nil(); 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/user/UserSenderValidator.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.user; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.api.user.User; 6 | import dev.triumphteam.cmd.core.SubCommand; 7 | import dev.triumphteam.cmd.core.message.MessageRegistry; 8 | import dev.triumphteam.cmd.core.sender.SenderValidator; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.Set; 12 | 13 | public final class UserSenderValidator implements SenderValidator { 14 | private final ChatChatPlugin plugin; 15 | 16 | public UserSenderValidator(@NotNull final ChatChatPlugin plugin) { 17 | this.plugin = plugin; 18 | } 19 | 20 | @Override 21 | public @NotNull Set> getAllowedSenders() { 22 | return Set.of(User.class, ChatUser.class, ConsoleUser.class); 23 | } 24 | 25 | @Override 26 | public boolean validate( 27 | @NotNull final MessageRegistry messageRegistry, 28 | @NotNull final SubCommand subCommand, 29 | @NotNull final User sender 30 | ) { 31 | final var senderClass = subCommand.getSenderType(); 32 | 33 | if (senderClass == ChatUser.class && !(sender instanceof ChatUser)) { 34 | sender.sendMessage(plugin.configManager().messages().playersOnly()); 35 | return false; 36 | } 37 | 38 | if (senderClass == ConsoleUser.class && !(sender instanceof ConsoleUser)) { 39 | sender.sendMessage(plugin.configManager().messages().consoleOnly()); 40 | return false; 41 | } 42 | 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/user/UsersHolderImpl.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.user; 2 | 3 | import at.helpch.chatchat.ChatChatPlugin; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.api.user.User; 6 | import at.helpch.chatchat.api.user.UsersHolder; 7 | import org.bukkit.command.CommandSender; 8 | import org.bukkit.command.ConsoleCommandSender; 9 | import org.bukkit.entity.Player; 10 | import org.jetbrains.annotations.NotNull; 11 | 12 | import java.util.Collection; 13 | import java.util.HashMap; 14 | import java.util.Map; 15 | import java.util.UUID; 16 | 17 | public final class UsersHolderImpl implements UsersHolder { 18 | 19 | public static final User CONSOLE = ConsoleUser.INSTANCE; 20 | 21 | private final ChatChatPlugin plugin; 22 | 23 | private @NotNull final Map users = new HashMap<>(); 24 | 25 | public UsersHolderImpl(@NotNull final ChatChatPlugin plugin) { 26 | this.plugin = plugin; 27 | users.put(CONSOLE.uuid(), CONSOLE); 28 | } 29 | 30 | public @NotNull User getUser(@NotNull final UUID uuid) { 31 | return users.computeIfAbsent(uuid, ignored -> plugin.database().loadChatUser(uuid)); 32 | } 33 | 34 | public @NotNull User getUser(@NotNull final CommandSender user) { 35 | if (user instanceof ConsoleCommandSender) { 36 | return CONSOLE; 37 | } 38 | 39 | return getUser(((Player) user).getUniqueId()); 40 | } 41 | 42 | public void removeUser(@NotNull final UUID uuid) { 43 | final var user = users.remove(uuid); 44 | 45 | if (!(user instanceof ChatUser)) { 46 | return; 47 | } 48 | 49 | plugin.database().saveChatUser((ChatUser) user); 50 | } 51 | 52 | public void removeUser(@NotNull final Player player) { 53 | removeUser(player.getUniqueId()); 54 | } 55 | 56 | public @NotNull Collection users() { 57 | return users.values(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/util/ChannelUtils.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.util; 2 | 3 | import at.helpch.chatchat.api.channel.Channel; 4 | import at.helpch.chatchat.api.user.ChatUser; 5 | import at.helpch.chatchat.api.user.User; 6 | import at.helpch.chatchat.channel.ChatChannel; 7 | import org.bukkit.Location; 8 | import org.bukkit.World; 9 | import org.jetbrains.annotations.NotNull; 10 | 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Objects; 14 | import java.util.Optional; 15 | 16 | public final class ChannelUtils { 17 | public static final String BASE_CHANNEL_PERMISSION = "chatchat.channel."; 18 | public static final String SEE_CHANNEL_PERMISSION = BASE_CHANNEL_PERMISSION + "see."; 19 | public static final String USE_CHANNEL_PERMISSION = BASE_CHANNEL_PERMISSION + "use."; 20 | public static final String BYPASS_RADIUS_CHANNEL_PERMISSION = BASE_CHANNEL_PERMISSION + "bypass-radius"; 21 | 22 | private ChannelUtils() { 23 | throw new AssertionError("Util classes are not to be instantiated!"); 24 | } 25 | 26 | public static @NotNull Channel findDefaultChannel( 27 | @NotNull final Map channels, 28 | @NotNull final String defaultChannel) { 29 | final var channel = channels.get(defaultChannel); 30 | return Objects.requireNonNullElseGet(channel, ChatChannel::defaultChannel); 31 | } 32 | 33 | public static @NotNull Optional findChannelByPrefix( 34 | @NotNull final List channels, 35 | @NotNull final String input) { 36 | return channels.stream() 37 | .filter(channel -> !channel.messagePrefix().isEmpty()) // ignore empty prefixes 38 | .filter(channel -> input.startsWith(channel.messagePrefix())) 39 | .findFirst(); 40 | } 41 | 42 | public static boolean isTargetWithinRadius( 43 | @NotNull final User source, 44 | @NotNull final User target, 45 | final int radius) { 46 | if (!(target instanceof ChatUser)) { 47 | return true; 48 | } 49 | 50 | final ChatUser targetChatUser = (ChatUser) target; 51 | 52 | if (target.hasPermission(BYPASS_RADIUS_CHANNEL_PERMISSION) && !targetChatUser.rangedChat()) { 53 | return true; 54 | } 55 | 56 | if (radius != -1 && source instanceof ChatUser) { 57 | var sourcePlayer = ((ChatUser) source).player(); 58 | var targetPlayer = targetChatUser.player(); 59 | 60 | if (sourcePlayer.isEmpty() || targetPlayer.isEmpty()) { 61 | return false; 62 | } 63 | 64 | final Location sourceLocation = sourcePlayer.get().getLocation(); 65 | final Location targetLocation = targetPlayer.get().getLocation(); 66 | 67 | final World sourceWorld = sourceLocation.getWorld(); 68 | final World targetWorld = targetLocation.getWorld(); 69 | 70 | if(sourceWorld != null && targetWorld != null && !sourceWorld.getUID().equals(targetWorld.getUID())) { 71 | return false; 72 | } 73 | 74 | final int relativeX = targetLocation.getBlockX() - sourceLocation.getBlockX(); 75 | final int relativeZ = targetLocation.getBlockZ() - sourceLocation.getBlockZ(); 76 | 77 | return relativeX*relativeX + relativeZ*relativeZ <= radius*radius; 78 | } 79 | 80 | return true; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/util/Kyorifier.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.util; 2 | 3 | import com.google.common.collect.ImmutableMap; 4 | import net.kyori.adventure.text.format.NamedTextColor; 5 | import net.kyori.adventure.text.format.TextDecoration; 6 | 7 | import java.util.Stack; 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | public final class Kyorifier { 12 | private static final ImmutableMap COLOURS = new ImmutableMap.Builder() 13 | .put('0', NamedTextColor.BLACK.toString()) 14 | .put('1', NamedTextColor.DARK_BLUE.toString()) 15 | .put('2', NamedTextColor.DARK_GREEN.toString()) 16 | .put('3', NamedTextColor.DARK_AQUA.toString()) 17 | .put('4', NamedTextColor.DARK_RED.toString()) 18 | .put('5', NamedTextColor.DARK_PURPLE.toString()) 19 | .put('6', NamedTextColor.GOLD.toString()) 20 | .put('7', NamedTextColor.GRAY.toString()) 21 | .put('8', NamedTextColor.DARK_GRAY.toString()) 22 | .put('9', NamedTextColor.BLUE.toString()) 23 | .put('a', NamedTextColor.GREEN.toString()) 24 | .put('b', NamedTextColor.AQUA.toString()) 25 | .put('c', NamedTextColor.RED.toString()) 26 | .put('d', NamedTextColor.LIGHT_PURPLE.toString()) 27 | .put('e', NamedTextColor.YELLOW.toString()) 28 | .put('f', NamedTextColor.WHITE.toString()) 29 | .build(); 30 | 31 | private static final ImmutableMap FORMATTERS = new ImmutableMap.Builder() 32 | .put('k', TextDecoration.OBFUSCATED.toString()) 33 | .put('l', TextDecoration.BOLD.toString()) 34 | .put('m', TextDecoration.STRIKETHROUGH.toString()) 35 | .put('n', TextDecoration.UNDERLINED.toString()) 36 | .put('o', TextDecoration.ITALIC.toString()) 37 | // There is no way to get the reset tag name from Adventure. Also doesn't really matter as we never actually 38 | // use it. Instead, we close all the opened tags. 39 | .put('r', "reset") 40 | .build(); 41 | 42 | private static final Pattern LEGACY_HEX_COLORS_PATTERN = Pattern.compile( 43 | "&(?[\\da-fk-or])|[&{\\[<]?[#x](?(&?[a-f\\d]){6})[}\\]>]?", 44 | Pattern.CASE_INSENSITIVE // Turns out colors are not case-sensitive. 45 | ); 46 | 47 | private static StringBuilder closeAll(Stack activeFormatters) { 48 | final var out = new StringBuilder(); 49 | while (!activeFormatters.isEmpty()) { 50 | out.append(""); 51 | } 52 | return out; 53 | } 54 | 55 | public static String kyorify(String input) { 56 | final Stack activeFormatters = new Stack<>(); 57 | return LEGACY_HEX_COLORS_PATTERN.matcher(input.replace("§", "&")).replaceAll(result -> { 58 | final Matcher matcher = (Matcher) result; 59 | final var hex = matcher.group("hex"); 60 | final var code = matcher.group("code"); 61 | final var colour = hex == null 62 | ? COLOURS.get(Character.toLowerCase(code.charAt(0))) 63 | : "#" + hex.replace("&", ""); 64 | 65 | if (colour == null) { 66 | final var formatter = FORMATTERS.get(Character.toLowerCase(code.charAt(0))); 67 | if (formatter.equals("reset")) { 68 | return closeAll(activeFormatters).toString(); 69 | } 70 | activeFormatters.push(formatter); 71 | return "<" + formatter + ">"; 72 | } 73 | 74 | final var out = closeAll(activeFormatters); 75 | out.append("<").append(colour).append(">"); 76 | return out.toString(); 77 | }); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/util/MessageUtils.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.util; 2 | 3 | import net.kyori.adventure.text.Component; 4 | import net.kyori.adventure.text.minimessage.MiniMessage; 5 | import net.kyori.adventure.text.minimessage.tag.resolver.TagResolver; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.List; 9 | 10 | public final class MessageUtils { 11 | private static final MiniMessage miniMessage = MiniMessage.miniMessage(); 12 | 13 | private MessageUtils() { 14 | throw new AssertionError("Util classes are not to be instantiated!"); 15 | } 16 | 17 | public static @NotNull Component parseToMiniMessage(@NotNull final String formatPart) { 18 | return miniMessage.deserialize(formatPart); 19 | } 20 | 21 | public static @NotNull Component parseToMiniMessage(@NotNull final String formatPart, @NotNull final TagResolver tag) { 22 | return miniMessage.deserialize(formatPart, tag); 23 | } 24 | 25 | public static @NotNull Component parseToMiniMessage(@NotNull final String formatPart, @NotNull final TagResolver... tags) { 26 | return miniMessage.deserialize(formatPart, tags); 27 | } 28 | 29 | public static @NotNull Component parseToMiniMessage(@NotNull final String formatPart, @NotNull final List tags) { 30 | return miniMessage.deserialize(formatPart, TagResolver.resolver(tags)); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /plugin/src/main/java/at/helpch/chatchat/util/VersionHelper.java: -------------------------------------------------------------------------------- 1 | package at.helpch.chatchat.util; 2 | 3 | import at.helpch.chatchat.api.exception.ChatChatException; 4 | import com.google.common.primitives.Ints; 5 | import org.bukkit.Bukkit; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.regex.Matcher; 9 | import java.util.regex.Pattern; 10 | 11 | /** 12 | * Class for detecting server version for legacy support :( 13 | * @author Matt 14 | */ 15 | public final class VersionHelper { 16 | 17 | public static final String NMS_VERSION = getNmsVersion(); 18 | 19 | public static final int CURRENT_VERSION = getCurrentVersion(); 20 | 21 | public static final boolean IS_PAPER = checkPaper(); 22 | 23 | public static final int V1_13_2 = 1132; 24 | public static final int V1_14_4 = 1144; 25 | public static final int V1_15_2 = 1152; 26 | public static final int V1_16_5 = 1165; 27 | public static final int V1_17_1 = 1171; 28 | public static final int V1_18_2 = 1182; 29 | public static final int V1_19_0 = 1190; 30 | 31 | public static final int V1_20_0 = 1200; 32 | 33 | public static boolean HAS_SMITHING_TEMPLATE = CURRENT_VERSION >= V1_20_0; 34 | 35 | /** 36 | * Check if the server has access to the Paper API 37 | * Taken from PaperLib 38 | * 39 | * @return True if on Paper server (or forks), false anything else 40 | */ 41 | private static boolean checkPaper() { 42 | try { 43 | Class.forName("com.destroystokyo.paper.PaperConfig"); 44 | return true; 45 | } catch (ClassNotFoundException ignored) { 46 | return false; 47 | } 48 | } 49 | 50 | /** 51 | * Gets the current server version 52 | * 53 | * @return A protocol like number representing the version, for example 1.16.5 - 1165 54 | */ 55 | private static int getCurrentVersion() { 56 | // No need to cache since will only run once 57 | final Matcher matcher = Pattern.compile("(?\\d+\\.\\d+)(?\\.\\d+)?").matcher(Bukkit.getBukkitVersion()); 58 | 59 | final StringBuilder stringBuilder = new StringBuilder(); 60 | if (matcher.find()) { 61 | stringBuilder.append(matcher.group("version").replace(".", "")); 62 | final String patch = matcher.group("patch"); 63 | if (patch == null) stringBuilder.append("0"); 64 | else stringBuilder.append(patch.replace(".", "")); 65 | } 66 | 67 | //noinspection UnstableApiUsage 68 | final Integer version = Ints.tryParse(stringBuilder.toString()); 69 | 70 | // Should never fail 71 | if (version == null) throw new ChatChatException("Could not retrieve server version!"); 72 | 73 | return version; 74 | } 75 | 76 | private static String getNmsVersion() { 77 | final String version = Bukkit.getServer().getClass().getPackage().getName(); 78 | return version.substring(version.lastIndexOf('.') + 1); 79 | } 80 | 81 | public static Class craftClass(@NotNull final String name) throws ClassNotFoundException { 82 | return Class.forName("org.bukkit.craftbukkit." + NMS_VERSION + "." + name); 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /plugin/src/main/resources/channels.yml: -------------------------------------------------------------------------------- 1 | # Set the default channel to talk in. 2 | default-channel: 'global' 3 | 4 | # Channels configuration 5 | channels: 6 | global: # default channel as set in default-channel, no permission required. 7 | # command to switch channel 8 | # Changes to this setting REQUIRES a server restart 9 | toggle-command: 10 | - 'global' 11 | # prefix the message with this to automatically type the message in channel 12 | message-prefix: '' 13 | # pretty much a variable for the channel prefix, which can be accessed using the PAPI placeholder: %chatchat_channel_prefix% 14 | # Channel prefixes can be formatted using MiniMessage: https://docs.adventure.kyori.net/minimessage/index.html 15 | channel-prefix: '[global]' 16 | formats: # Channel formats have priority over global formats declared in formats.yml 17 | default-channel: # user needs 'chatchat.channel.format.global.default-channel' permission 18 | priority: 1 # lower number = higher priority 19 | parts: 20 | channel: 21 | - "This is a default channel format!'>" 22 | - "%chatchat_channel_prefix%", 23 | - "" 24 | prefix: 25 | - " [ChatChat] " 26 | name: 27 | - "%player_name%" 28 | message: 29 | - " » " 30 | 31 | # radius from sender other players need to be in to see sender's message. -1 for no radius 32 | radius: -1 33 | staff: # permission node: chatchat.channel.see.staff to access this channel (or chatchat.channel.use.staff to talk) 34 | toggle-command: 35 | - 'staffchat' 36 | message-prefix: '#' 37 | channel-prefix: '[STAFF]' 38 | default-channel: # user needs 'chatchat.channel.format.staff.default-channel' permission 39 | priority: 1 # lower number = higher priority 40 | parts: 41 | channel: 42 | - "This is a default channel format!'>" 43 | - "%chatchat_channel_prefix%", 44 | - "" 45 | prefix: 46 | - " [ChatChat] " 47 | name: 48 | - "%player_name%" 49 | message: 50 | - " » " 51 | radius: -1 52 | 53 | # # this one's for towny, uncomment this section if you have towny installed 54 | # town: 55 | # # a special, optional value, indicating that this is a towny town chat 56 | # # valid options are 'TOWNY_TOWN', 'TOWNY_NATION' 57 | # # if the type is not valid, it falls back to a standard chat channel 58 | # type: 'TOWNY_TOWN' 59 | # toggle-command: 'townchat' 60 | # message-prefix: 't:' 61 | # channel-prefix: '[Town]' 62 | # # as above, but for nations instead of towns 63 | # nation: 64 | # type: 'TOWNY_NATION' 65 | # toggle-command: 'nationchat' 66 | # message-prefix: 'n:' 67 | # channel-prefix: '[Nation]' 68 | -------------------------------------------------------------------------------- /plugin/src/main/resources/extensions.yml: -------------------------------------------------------------------------------- 1 | # Any changes made to the addons require a server restart to take effect. 2 | addons: 3 | deluxechat: 4 | # If enabled, lower numbers mean higher priority just like in DeluxeChat. 5 | inverse_priorities: false 6 | # Enable or disable the Unicode Characters rule. This rule only allows people to use non ascii characters if they 7 | # have the permission "chatchat.utf" just like in DeluxeChat. 8 | unicode_permission: 9 | # Enable the rule for public messages. 10 | public_chat: true 11 | # Enable the rule for private messages. 12 | private_chat: true 13 | towny: 14 | # Enable or disable the towny town and nation channel types. If enabled, TOWNY_TOWN and TOWNY_NATION can be used as channel type. 15 | channels: false 16 | discordsrv: 17 | # Enable or disable DiscordSRV support. If enabled, ChatChat channels and DiscordSRV channels that have the same 18 | # name will be bridged. 19 | # NOTE: DiscordSRV channel names are not the same as Discord channel names! They are the names set in the DiscordSRV 20 | # config. 21 | channels_bridging: false 22 | essentials: 23 | # Enable or disable support for Essentials' vanish system. 24 | vanish: true 25 | supervanish: 26 | # Enable or disable support for SuperVanish's vanish system. 27 | vanish: false 28 | griefprevention: 29 | # Enable or disable support for GriefPrevention's soft mute system. 30 | soft_mute: false 31 | -------------------------------------------------------------------------------- /plugin/src/main/resources/formats.yml: -------------------------------------------------------------------------------- 1 | # Set the default format. This will be used when players do not have any other format permissions 2 | default-format: 'default' 3 | # Set the console format. This is the format is very limited on SpigotMC and will not support some tags like: keybind, 4 | # translation, fonts, selector, etc. This format can also break if it contains any extra percent signs (`%`). This is 5 | # not going to be a problem on PaperMC servers. 6 | console-format: 7 | parts: 8 | channel: 9 | - '%chatchat_channel_prefix% ' 10 | prefix: 11 | - '[ChatChat] ' 12 | name: 13 | - %player_name% 14 | message: 15 | - ' » ' 16 | 17 | formats: 18 | default: # this is the default format as set by default-format. No permission is needed. 19 | priority: 2 # lower number = higher priority 20 | # list of all the parts of the format, supports unlimited amount of parts. 21 | # Technically only 1 part is needed and every part only needs one line but to clean up the config, multiple parts 22 | # can be used and each part can have multiple lines. 23 | # These parts can be formatted using MiniMessage, which can be found here: 24 | # https://docs.adventure.kyori.net/minimessage/index.html 25 | parts: 26 | channel: 27 | - '' 28 | - 'Some new line">' 29 | - '%chatchat_channel_prefix%' 30 | - '' 31 | - '' 32 | group: 33 | - 'Some new line">' 34 | - ' [%vault_group%]' 35 | - '' 36 | name: 37 | - 'Some new line">' 38 | - ' %player_displayname%' 39 | - '' 40 | divider: 41 | - '' 42 | - ' > ' 43 | - '' 44 | message: 45 | - '' 46 | - '' 47 | - '!' 48 | - '' 49 | 50 | staff: # user needs 'chatchat.format.staff' permission 51 | priority: 1 52 | parts: 53 | channel: 54 | - '' 55 | - 'Some new line">' 56 | - '%chatchat_channel_prefix%' 57 | - '' 58 | - '' 59 | prefix: 60 | - 'Some new line">' 61 | - ' [STAFF]' 62 | - '' 63 | name: 64 | - 'Some new line">' 65 | - ' %player_displayname%' 66 | - '' 67 | message-and-divider: 68 | - ' >' 69 | - '' 70 | -------------------------------------------------------------------------------- /plugin/src/main/resources/messages.yml: -------------------------------------------------------------------------------- 1 | # https://wiki.helpch.at 2 | 3 | console-only: Only the console can do this! 4 | players-only: Only players can do this! 5 | user-offline: The user is not online! 6 | user-not-in-town: You are not in a town! 7 | 8 | no-replies: You have no one to reply to! 9 | replies-disabled: You can't send private messages while they're disabled! 10 | target-replies-disabled: This user has their private messages disabled! 11 | private-messages-enabled: Your private messages have been enabled! 12 | private-messages-disabled: Your private messages have been disabled! 13 | cant-message-yourself: You can't message yourself! 14 | empty-message: You can't send an empty message! 15 | special-characters-no-permission: You do not have permission to use special characters! 16 | social-spy-enabled: Social spy enabled 17 | social-spy-disabled: Social spy disabled 18 | ignored-player: Successfully ignored . 19 | unignored-player: Successfully un-ignored . 20 | already-ignored: You are already ignoring . 21 | not-ignored: You are not ignoring . 22 | cant-message-ignored-player: You cannot message a player who you ignore. 23 | cant-message-general: You cannot message this player. 24 | 25 | channel-no-permission: You do not have permission to use this channel! 26 | channel-switched: You have switched to the channel! 27 | 28 | command-unknown-command: Unknown Command. 29 | command-invalid-usage: Invalid usage. 30 | command-invalid-argument: Invalid argument. 31 | command-no-permission: No Permission. 32 | 33 | dump-failed: Failed to create dump! 34 | dump-success: 'Dump created successfully! You can find it at: ' 35 | 36 | personal-mentions-enabled: "Successfully enabled personal mentions!" 37 | personal-mentions-disabled: "Successfully disabled personal mentions!" 38 | channel-mentions-enabled: "Successfully enabled channel mentions!" 39 | channel-mentions-disabled: "Successfully disabled channel mentions!" 40 | 41 | invalid-format: "Invalid format!" 42 | 43 | generic-error: "An unexpected error occurred!" 44 | -------------------------------------------------------------------------------- /plugin/src/main/resources/placeholders.yml: -------------------------------------------------------------------------------- 1 | # Represents a list of Mini placeholders. 2 | placeholders: 3 | # The name of the placeholder. The placeholder can be used by putting inside the format. 4 | # Tags will also work in the actual message sent by a user as long as they have the correct permission. 5 | # Permission for tag will be chatchat.tag.placeholder. 6 | # The name must match this pattern: [!?#]?[a-z0-9_-]* 7 | - name: "name" 8 | # If this is set to true, the placeholder message will support recipient and relational tags as well. 9 | requires-recipient: false 10 | # If this is set to true, MiniMessage tags will be parsed within the placeholder message. 11 | parse-mini: false 12 | # This determines if PlaceholderAPI placeholders should be parsed within the placeholder message. To note is that 13 | # %placeholder% placeholders won't work. Instead, you will have to use the , and tags. 14 | parse-papi: true 15 | # This determines if the formatting of the placeholder message will bleed out in the containing message. Set to 16 | # false for bleeding effect, true for no bleeding effect. This will be considered true if parse-mini is set to false. 17 | closing: true 18 | # The message that the placeholder will be replaced with. 19 | message: 'Hello World!' 20 | 21 | - name: "parsing" 22 | requires-recipient: false 23 | parse-mini: true 24 | parse-papi: true 25 | closing: true 26 | message: 'Hello World!' 27 | -------------------------------------------------------------------------------- /plugin/src/main/resources/settings.yml: -------------------------------------------------------------------------------- 1 | # The format to send to the sender of a private message 2 | # All formats can be formatted using MiniMessage: https://docs.adventure.kyori.net/minimessage/index.html 3 | 4 | private-messages: 5 | enabled: true 6 | formats: 7 | sender-format: 8 | parts: 9 | sender: 10 | - 'you' 11 | separator: 12 | - ' -> ' 13 | recipient: 14 | - '' 15 | message: 16 | - ' <#e81cff>» ' 17 | # The format to send to the recipient of a private message 18 | recipient-format: 19 | parts: 20 | sender: 21 | - '%player_name%' 22 | separator: 23 | - ' <#40c9ff>-> ' 24 | recipient: 25 | - 'you' 26 | message: 27 | - ' <#e81cff>» ' 28 | 29 | # The format to send to any players with socialspy enabled 30 | social-spy-format: 31 | parts: 32 | prefix: 33 | - '(spy) ' 34 | sender: 35 | - '%player_name%' 36 | separator: 37 | - ' <#40c9ff>-> ' 38 | recipient: 39 | - '' 40 | message: 41 | - ' <#e81cff>» ' 42 | 43 | # The format that the placeholder will use in chat. Needs to contain . 44 | # Another available internal placeholder is . 45 | item-format: '[ x ]' 46 | 47 | # Custom line that can show in the hover of the placeholder displaying stuff like item's exact name and amount 48 | # Set to empty string '' if you want to disable it from ever showing. 49 | item-format-info: ' x ' 50 | 51 | mentions: 52 | # The prefix to use for mentioning players in chat. Set to empty string '' if you want to disable mentions. 53 | prefix: '@' 54 | # Whether to play the mention sound when a user receives a private message 55 | private-message: true 56 | # The sound to play when a player is mentioned 57 | # The sounds use the format of adventure sounds, which in turn use the original minecraft names, NOT spigot's. 58 | # Name - Set the sound to play: names of all sounds can be found here: https://www.digminecraft.com/lists/sound_list_pc.php 59 | # Source - set where the source can be played through, the list of all sources can also be found on the above website. 60 | sound: 61 | name: entity.experience_orb.pickup 62 | source: master 63 | pitch: 1 64 | volume: 1 65 | # The format to use for individual player mentions. 66 | personal-format: 67 | parts: 68 | name: 69 | - 'This is a mention!">' 70 | - '@%player_name%' 71 | - '' 72 | # The format to use for @channel/@here/@everyone mentions. 73 | channel-format: 74 | parts: 75 | name: 76 | - 'This is a channel mention!">' 77 | - '@everyone' 78 | - '' 79 | 80 | # After how many seconds should the last messaged user be cleared. Set to below 0 to disable expiration. 81 | last-messaged-cache-duration: 300 82 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencyResolutionManagement { 2 | includeBuild("build-logic") 3 | repositories.gradlePluginPortal() 4 | } 5 | 6 | rootProject.name = "chat-chat" 7 | 8 | enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS") 9 | 10 | listOf( 11 | "api", 12 | "plugin", 13 | "test-module", 14 | ).forEach(::includeProject) 15 | 16 | fun includeProject(name: String) { 17 | include(name) { 18 | this.name = "${rootProject.name}-$name" 19 | } 20 | } 21 | 22 | fun include(name: String, block: ProjectDescriptor.() -> Unit) { 23 | include(name) 24 | project(":$name").apply(block) 25 | } 26 | --------------------------------------------------------------------------------