├── .github
└── workflows
│ └── codeql.yml
├── .gitignore
├── .scripts
└── ensure-java-17
├── LICENSE
├── README.md
├── build.gradle
├── docs
├── allclasses-index.html
├── allpackages-index.html
├── constant-values.html
├── copy.svg
├── dev
│ └── unnm3d
│ │ └── redischat
│ │ ├── Permissions.html
│ │ ├── RedisChat.html
│ │ ├── UpdateCheck.html
│ │ ├── api
│ │ ├── DataManager.html
│ │ ├── RedisChatAPI.html
│ │ ├── TagResolverIntegration.html
│ │ ├── VanishIntegration.html
│ │ ├── events
│ │ │ ├── AsyncRedisChatMessageEvent.html
│ │ │ ├── ChannelGuiPopulateEvent.html
│ │ │ ├── FilterEvent.html
│ │ │ ├── MailDeleteEvent.html
│ │ │ ├── MailEditorEvent.MailEditorState.html
│ │ │ ├── MailEditorEvent.html
│ │ │ ├── MailEvent.html
│ │ │ ├── MailReadStatusChangeEvent.html
│ │ │ ├── MailReceivedEvent.html
│ │ │ ├── MailSendEvent.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── channels
│ │ ├── ChannelCommand.html
│ │ ├── ChannelManager.html
│ │ ├── gui
│ │ │ ├── ChannelGUI.html
│ │ │ ├── GlobalChannel.html
│ │ │ ├── PlayerChannel.Status.html
│ │ │ ├── PlayerChannel.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── chat
│ │ ├── ChatColorGUI.html
│ │ ├── ChatFormat.html
│ │ ├── ChatListener.html
│ │ ├── ChatListenerWithPriority.html
│ │ ├── ComponentProvider.html
│ │ ├── JoinQuitManager.html
│ │ ├── KnownChatEntities.html
│ │ ├── PlaceholderManager.html
│ │ ├── RedisChatPAPI.html
│ │ ├── filters
│ │ │ ├── AbstractFilter.Direction.html
│ │ │ ├── AbstractFilter.html
│ │ │ ├── DefaultSettings.html
│ │ │ ├── FilterManager.html
│ │ │ ├── FilterResult.html
│ │ │ ├── incoming
│ │ │ │ ├── IgnorePlayerFilter.IgnorePlayerFilterProperties.html
│ │ │ │ ├── IgnorePlayerFilter.html
│ │ │ │ ├── PermissionFilter.html
│ │ │ │ ├── package-summary.html
│ │ │ │ └── package-tree.html
│ │ │ ├── outgoing
│ │ │ │ ├── CapsFilter.CapsFilterProperties.html
│ │ │ │ ├── CapsFilter.html
│ │ │ │ ├── DuplicateFilter.DuplicateFilterProperties.html
│ │ │ │ ├── DuplicateFilter.html
│ │ │ │ ├── IgnoreFilter.html
│ │ │ │ ├── MutedChannelFilter.html
│ │ │ │ ├── SpamFilter.html
│ │ │ │ ├── TagFilter.html
│ │ │ │ ├── WordBlacklistFilter.WordBlacklistFilterProperties.html
│ │ │ │ ├── WordBlacklistFilter.html
│ │ │ │ ├── package-summary.html
│ │ │ │ └── package-tree.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ ├── objects
│ │ │ ├── AudienceType.html
│ │ │ ├── Channel.ChannelBuilder.html
│ │ │ ├── Channel.html
│ │ │ ├── ChannelAudience.ChannelAudienceBuilder.html
│ │ │ ├── ChannelAudience.html
│ │ │ ├── ChatMessage.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── commands
│ │ ├── AnnounceCommand.html
│ │ ├── BroadcastCommand.html
│ │ ├── ChatAsCommand.html
│ │ ├── ChatColorCommand.html
│ │ ├── ClearChatCommand.html
│ │ ├── IgnoreCommand.html
│ │ ├── IgnoreWhitelistCommand.html
│ │ ├── InvShareCommand.InventoryType.html
│ │ ├── InvShareCommand.html
│ │ ├── MainCommand.html
│ │ ├── MsgCommand.html
│ │ ├── PlayerListManager.html
│ │ ├── ReplyCommand.html
│ │ ├── SetItemCommand.html
│ │ ├── SetPlaceholderCommand.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── datamanagers
│ │ ├── DataKey.html
│ │ ├── RedisDataManager.html
│ │ ├── package-summary.html
│ │ ├── package-tree.html
│ │ ├── redistools
│ │ │ ├── RedisAbstract.html
│ │ │ ├── RoundRobinConnectionPool.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ └── sqlmanagers
│ │ │ ├── MySQLDataManager.html
│ │ │ ├── PluginMessageManager.html
│ │ │ ├── SQLDataManager.html
│ │ │ ├── SQLiteDataManager.html
│ │ │ ├── package-summary.html
│ │ │ └── package-tree.html
│ │ ├── discord
│ │ ├── DiscordWebhook.html
│ │ ├── IDiscordHook.html
│ │ ├── SpicordHook.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── integrations
│ │ ├── OraxenTagResolver.html
│ │ ├── PremiumVanishIntegration.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── mail
│ │ ├── Mail.MailCategory.html
│ │ ├── Mail.html
│ │ ├── MailCommand.html
│ │ ├── MailGUIManager.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── moderation
│ │ ├── MuteCommand.html
│ │ ├── MuteManager.html
│ │ ├── SpyChatCommand.html
│ │ ├── SpyManager.html
│ │ ├── StaffChatCommand.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── package-summary.html
│ │ ├── package-tree.html
│ │ ├── permission
│ │ ├── LuckPermsProvider.html
│ │ ├── PermissionProvider.html
│ │ ├── VaultPermissionProvider.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── settings
│ │ ├── Config.Announcement.html
│ │ ├── Config.DataType.html
│ │ ├── Config.Mysql.html
│ │ ├── Config.RedisSettings.html
│ │ ├── Config.SpicordSettings.html
│ │ ├── Config.html
│ │ ├── ConfigValidator.html
│ │ ├── FiltersConfig.FilterSettings.html
│ │ ├── FiltersConfig.html
│ │ ├── GuiSettings.html
│ │ ├── Messages.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ ├── task
│ │ ├── AnnouncerManager.html
│ │ ├── AnnouncerTask.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
│ │ └── utils
│ │ ├── AdventureWebuiEditorAPI.html
│ │ ├── ItemNameProvider.html
│ │ ├── Metrics.AdvancedBarChart.html
│ │ ├── Metrics.AdvancedPie.html
│ │ ├── Metrics.CustomChart.html
│ │ ├── Metrics.DrilldownPie.html
│ │ ├── Metrics.JsonObjectBuilder.JsonObject.html
│ │ ├── Metrics.JsonObjectBuilder.html
│ │ ├── Metrics.MetricsBase.html
│ │ ├── Metrics.MultiLineChart.html
│ │ ├── Metrics.SimpleBarChart.html
│ │ ├── Metrics.SimplePie.html
│ │ ├── Metrics.SingleLineChart.html
│ │ ├── Metrics.html
│ │ ├── package-summary.html
│ │ └── package-tree.html
├── element-list
├── help-doc.html
├── index-files
│ ├── index-1.html
│ ├── index-10.html
│ ├── index-11.html
│ ├── index-12.html
│ ├── index-13.html
│ ├── index-14.html
│ ├── index-15.html
│ ├── index-16.html
│ ├── index-17.html
│ ├── index-18.html
│ ├── index-19.html
│ ├── index-2.html
│ ├── index-20.html
│ ├── index-21.html
│ ├── index-22.html
│ ├── index-23.html
│ ├── index-3.html
│ ├── index-4.html
│ ├── index-5.html
│ ├── index-6.html
│ ├── index-7.html
│ ├── index-8.html
│ └── index-9.html
├── index.html
├── legal
│ ├── COPYRIGHT
│ ├── LICENSE
│ ├── jquery.md
│ └── jqueryUI.md
├── link.svg
├── member-search-index.js
├── module-search-index.js
├── overview-summary.html
├── overview-tree.html
├── package-search-index.js
├── resources
│ ├── glass.png
│ └── x.png
├── script-dir
│ ├── jquery-3.6.1.min.js
│ ├── jquery-ui.min.css
│ └── jquery-ui.min.js
├── script.js
├── search-page.js
├── search.html
├── search.js
├── stylesheet.css
├── tag-search-index.js
└── type-search-index.js
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── jitpack.yml
├── settings.gradle
└── src
├── main
├── java
│ └── dev
│ │ └── unnm3d
│ │ └── redischat
│ │ ├── Permissions.java
│ │ ├── RedisChat.java
│ │ ├── UpdateCheck.java
│ │ ├── api
│ │ ├── DataManager.java
│ │ ├── RedisChatAPI.java
│ │ ├── TagResolverIntegration.java
│ │ ├── VanishIntegration.java
│ │ ├── events
│ │ │ ├── AsyncRedisChatMessageEvent.java
│ │ │ ├── ChannelGuiPopulateEvent.java
│ │ │ ├── FilterEvent.java
│ │ │ ├── MailDeleteEvent.java
│ │ │ ├── MailEditorEvent.java
│ │ │ ├── MailEvent.java
│ │ │ ├── MailReadStatusChangeEvent.java
│ │ │ ├── MailReceivedEvent.java
│ │ │ └── MailSendEvent.java
│ │ └── objects
│ │ │ ├── AudienceType.java
│ │ │ ├── Channel.java
│ │ │ ├── ChannelAudience.java
│ │ │ ├── ChatMessage.java
│ │ │ └── KnownChatEntities.java
│ │ ├── channels
│ │ ├── ChannelCommand.java
│ │ ├── ChannelManager.java
│ │ └── gui
│ │ │ ├── ChannelGUI.java
│ │ │ ├── GlobalChannel.java
│ │ │ └── PlayerChannel.java
│ │ ├── chat
│ │ ├── ChatColorGUI.java
│ │ ├── ChatFormat.java
│ │ ├── ComponentProvider.java
│ │ ├── PlaceholderManager.java
│ │ ├── RedisChatPAPI.java
│ │ ├── filters
│ │ │ ├── AbstractFilter.java
│ │ │ ├── DefaultSettings.java
│ │ │ ├── FilterManager.java
│ │ │ ├── FilterResult.java
│ │ │ ├── incoming
│ │ │ │ ├── IgnorePlayerFilter.java
│ │ │ │ └── PermissionFilter.java
│ │ │ └── outgoing
│ │ │ │ ├── CapsFilter.java
│ │ │ │ ├── DuplicateFilter.java
│ │ │ │ ├── IgnoreFilter.java
│ │ │ │ ├── MutedChannelFilter.java
│ │ │ │ ├── SpamFilter.java
│ │ │ │ ├── TagFilter.java
│ │ │ │ └── WordBlacklistFilter.java
│ │ └── listeners
│ │ │ ├── ChatListenerWithPriority.java
│ │ │ ├── JoinQuitManager.java
│ │ │ └── UtilsListener.java
│ │ ├── commands
│ │ ├── AnnounceCommand.java
│ │ ├── BroadcastCommand.java
│ │ ├── ChatAsCommand.java
│ │ ├── ChatColorCommand.java
│ │ ├── ClearChatCommand.java
│ │ ├── IgnoreCommand.java
│ │ ├── IgnoreWhitelistCommand.java
│ │ ├── InvShareCommand.java
│ │ ├── MainCommand.java
│ │ ├── PlayerListManager.java
│ │ ├── RedisChatCommand.java
│ │ ├── SetItemCommand.java
│ │ ├── SetPlaceholderCommand.java
│ │ ├── TalkOnCommand.java
│ │ ├── UniformMsgCommand.java
│ │ └── UniformReplyCommand.java
│ │ ├── datamanagers
│ │ ├── DataKey.java
│ │ ├── RedisDataManager.java
│ │ ├── redistools
│ │ │ ├── RedisAbstract.java
│ │ │ └── RoundRobinConnectionPool.java
│ │ └── sqlmanagers
│ │ │ ├── MySQLDataManager.java
│ │ │ ├── PluginMessageManager.java
│ │ │ ├── SQLDataManager.java
│ │ │ └── SQLiteDataManager.java
│ │ ├── discord
│ │ ├── DiscordWebhook.java
│ │ ├── IDiscordHook.java
│ │ └── SpicordHook.java
│ │ ├── integrations
│ │ ├── OraxenTagResolver.java
│ │ ├── PremiumVanishIntegration.java
│ │ └── SuperVanishIntegration.java
│ │ ├── mail
│ │ ├── Mail.java
│ │ ├── MailCommand.java
│ │ └── MailGUIManager.java
│ │ ├── moderation
│ │ ├── MuteCommand.java
│ │ ├── MuteManager.java
│ │ ├── SpyChatCommand.java
│ │ ├── SpyManager.java
│ │ └── StaffChatCommand.java
│ │ ├── permission
│ │ ├── LuckPermsProvider.java
│ │ ├── PermissionProvider.java
│ │ └── VaultPermissionProvider.java
│ │ ├── settings
│ │ ├── Config.java
│ │ ├── ConfigValidator.java
│ │ ├── FiltersConfig.java
│ │ ├── GuiSettings.java
│ │ └── Messages.java
│ │ ├── task
│ │ ├── AnnouncerManager.java
│ │ └── AnnouncerTask.java
│ │ └── utils
│ │ ├── AdventureWebuiEditorAPI.java
│ │ ├── ItemNameProvider.java
│ │ └── Metrics.java
└── resources
│ ├── plugin.yml
│ └── webhook_embed.json
└── test
└── java
└── dev
└── unnm3d
└── redischat
└── JsonTests.java
/.github/workflows/codeql.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ "main" ]
17 | pull_request:
18 | branches: [ "main" ]
19 | schedule:
20 | - cron: '30 2 * * 5'
21 |
22 | jobs:
23 | analyze:
24 | name: Analyze (${{ matrix.language }})
25 | # Runner size impacts CodeQL analysis time. To learn more, please see:
26 | # - https://gh.io/recommended-hardware-resources-for-running-codeql
27 | # - https://gh.io/supported-runners-and-hardware-resources
28 | # - https://gh.io/using-larger-runners (GitHub.com only)
29 | # Consider using larger runners or machines with greater resources for possible analysis time improvements.
30 | runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
31 | timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}
32 | permissions:
33 | # required for all workflows
34 | security-events: write
35 |
36 | # required to fetch internal or private CodeQL packs
37 | packages: read
38 |
39 | # only required for workflows in private repositories
40 | actions: read
41 | contents: read
42 |
43 | strategy:
44 | fail-fast: false
45 | matrix:
46 | include:
47 | - language: java-kotlin
48 | build-mode: none # This mode only analyzes Java. Set this to 'autobuild' or 'manual' to analyze Kotlin too.
49 | # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
50 | # Use `c-cpp` to analyze code written in C, C++ or both
51 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both
52 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
53 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
54 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
55 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
56 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
57 | steps:
58 | - name: Checkout repository
59 | uses: actions/checkout@v4
60 |
61 | # Initializes the CodeQL tools for scanning.
62 | - name: Initialize CodeQL
63 | uses: github/codeql-action/init@v3
64 | with:
65 | languages: ${{ matrix.language }}
66 | build-mode: ${{ matrix.build-mode }}
67 | # If you wish to specify custom queries, you can do so here or in a config file.
68 | # By default, queries listed here will override any specified in a config file.
69 | # Prefix the list here with "+" to use these queries and those in the config file.
70 |
71 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
72 | # queries: security-extended,security-and-quality
73 |
74 | # If the analyze step fails for one of the languages you are analyzing with
75 | # "We were unable to automatically build your code", modify the matrix above
76 | # to set the build mode to "manual" for that language. Then modify this step
77 | # to build your code.
78 | # ℹ️ Command-line programs to run using the OS shell.
79 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
80 | - if: matrix.build-mode == 'manual'
81 | shell: bash
82 | run: |
83 | echo 'If you are using a "manual" build mode for one or more of the' \
84 | 'languages you are analyzing, replace this with the commands to build' \
85 | 'your code, for example:'
86 | echo ' make bootstrap'
87 | echo ' make release'
88 | exit 1
89 |
90 | - name: Perform CodeQL Analysis
91 | uses: github/codeql-action/analyze@v3
92 | with:
93 | category: "/language:${{matrix.language}}"
94 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific stuff
2 | .idea/
3 |
4 | *.iml
5 | *.ipr
6 | *.iws
7 |
8 | # IntelliJ
9 | out/
10 |
11 | # Compiled class file
12 | *.class
13 |
14 | # Log file
15 | *.log
16 |
17 | # BlueJ files
18 | *.ctxt
19 |
20 | # Package Files #
21 | *.jar
22 | *.war
23 | *.nar
24 | *.ear
25 | *.zip
26 | *.tar.gz
27 | *.rar
28 |
29 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
30 | hs_err_pid*
31 |
32 | *~
33 |
34 | # temporary files which can be created if a process still has a handle open of a deleted file
35 | .fuse_hidden*
36 |
37 | # KDE directory preferences
38 | .directory
39 |
40 | # Linux trash folder which might appear on any partition or disk
41 | .Trash-*
42 |
43 | # .nfs files are created when an open file is removed but is still being accessed
44 | .nfs*
45 |
46 | # General
47 | .DS_Store
48 | .AppleDouble
49 | .LSOverride
50 |
51 | # Icon must end with two \r
52 | Icon
53 |
54 | # Thumbnails
55 | ._*
56 |
57 | # Files that might appear in the root of a volume
58 | .DocumentRevisions-V100
59 | .fseventsd
60 | .Spotlight-V100
61 | .TemporaryItems
62 | .Trashes
63 | .VolumeIcon.icns
64 | .com.apple.timemachine.donotpresent
65 |
66 | # Directories potentially created on remote AFP share
67 | .AppleDB
68 | .AppleDesktop
69 | Network Trash Folder
70 | Temporary Items
71 | .apdisk
72 |
73 | # Windows thumbnail cache files
74 | Thumbs.db
75 | Thumbs.db:encryptable
76 | ehthumbs.db
77 | ehthumbs_vista.db
78 |
79 | # Dump file
80 | *.stackdump
81 |
82 | # Folder config file
83 | [Dd]esktop.ini
84 |
85 | # Recycle Bin used on file shares
86 | $RECYCLE.BIN/
87 |
88 | # Windows Installer files
89 | *.cab
90 | *.msi
91 | *.msix
92 | *.msm
93 | *.msp
94 |
95 | # Windows shortcuts
96 | *.lnk
97 |
98 | target/
99 |
100 | pom.xml.tag
101 | pom.xml.releaseBackup
102 | pom.xml.versionsBackup
103 | pom.xml.next
104 |
105 | release.properties
106 | dependency-reduced-pom.xml
107 | buildNumber.properties
108 | .mvn/timing.properties
109 | .mvn/wrapper/maven-wrapper.jar
110 | .flattened-pom.xml
111 |
112 | # Common working directory
113 | run/
114 | src/main/java/dev/unnm3d/redischat/utils/Metrics.java
--------------------------------------------------------------------------------
/.scripts/ensure-java-17:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | JV=$(java -version 2>&1 >/dev/null | head -1)
4 | echo "$JV" | sed -E 's/^.*version "([^".]*)\.[^"]*".*$/\1/'
5 |
6 | if [ "$JV" != 17 ]; then
7 | case "$1" in
8 | install)
9 | echo "installing sdkman..."
10 | curl -s "https://get.sdkman.io" | bash
11 | source ~/.sdkman/bin/sdkman-init.sh
12 | sdk install java 17.0.3-open
13 | ;;
14 | use)
15 | echo "must source ~/.sdkman/bin/sdkman-init.sh"
16 | exit 1
17 | ;;
18 | esac
19 | fi
20 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | This project is owned and maintained by "Emibergo02" and is distributed with "All Rights Reserved".
2 | Emiliano Bergonzani reserves the right to change these terms at any time, you have to comply with the most recent version.
3 | I do NOT provide support to servers involved with piracy in any form, or owners who have downloaded ANY of our plugins from an unofficial/illegal source.
4 |
5 | Things can you CANNOT do:
6 | - Issue a refund on PayPal without our explicit permission, as this is a digital good.
7 | - Redistribute, sell or give an official/modified version of the plugin (with or without any type of counterpart) to anyone else.
8 | - Modify and compile the project source code to bypass an anti-piracy protection.
9 | - Download, compile, decompile or use the plugin on any server without purchasing a license.
10 |
11 | Things can you CAN do when purchasing the plugin:
12 | - Download and decompile the plugin file.
13 | - Fork and modify the project source code to meet your production server's needs.
14 | - Use it on ONE production server or network (= proxy-connected servers) and one private test server at a time.
15 |
16 | You may propose a merge request, under the terms that you grant full rights to us using any pushed code.
17 |
18 | If you are a developer and have not purchased a license, you have the permission to download, fork, edit and compile the project source code, and sell code modifications to your client ONLY IF they have already purchased a license. This only applies to one-time comission works and does NOT apply to public sales.
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # RedisChat
2 | [](https://www.codefactor.io/repository/github/emibergo02/redischat)
3 |
4 | multi-server chat made for large scalable networks
5 |
6 | README coming soon
7 | More info on [the Gitbook page](https://emibergo.gitbook.io/redischat/)
8 |
9 | [Javadoc here](https://emibergo02.github.io/RedisChat/)
10 |
--------------------------------------------------------------------------------
/docs/constant-values.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Constant Field Values
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 |
59 |
60 | dev.unnm3d.*
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
"3.0.0"
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/docs/copy.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
27 |
28 |
29 |
31 |
33 |
34 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/api/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.api Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
64 |
65 |
66 |
67 |
68 | Interface Hierarchy
69 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/channels/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.channels Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/chat/filters/incoming/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.chat.filters.incoming Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/datamanagers/redistools/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.datamanagers.redistools Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/datamanagers/sqlmanagers/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.datamanagers.sqlmanagers Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/discord/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.discord Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
62 | dev.unnm3d.redischat.discord.DiscordWebhook (implements dev.unnm3d.redischat.discord.IDiscordHook )
63 | org.spicord.api.addon.SimpleAddon
64 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | Interface Hierarchy
74 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/integrations/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.integrations Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/moderation/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.moderation Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/permission/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.permission Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
65 |
66 |
67 |
68 |
69 | Interface Hierarchy
70 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/docs/dev/unnm3d/redischat/task/package-tree.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | dev.unnm3d.redischat.task Class Hierarchy
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
48 |
49 |
50 |
53 | Package Hierarchies:
54 |
57 |
58 | Class Hierarchy
59 |
60 | java.lang.Object
61 |
62 | dev.unnm3d.redischat.task.AnnouncerManager
63 | com.github.Anon8281.universalScheduler.UniversalRunnable (implements java.lang.Runnable )
64 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/docs/element-list:
--------------------------------------------------------------------------------
1 | dev.unnm3d.redischat
2 | dev.unnm3d.redischat.api
3 | dev.unnm3d.redischat.api.events
4 | dev.unnm3d.redischat.channels
5 | dev.unnm3d.redischat.channels.gui
6 | dev.unnm3d.redischat.chat
7 | dev.unnm3d.redischat.chat.filters
8 | dev.unnm3d.redischat.chat.filters.incoming
9 | dev.unnm3d.redischat.chat.filters.outgoing
10 | dev.unnm3d.redischat.chat.objects
11 | dev.unnm3d.redischat.commands
12 | dev.unnm3d.redischat.datamanagers
13 | dev.unnm3d.redischat.datamanagers.redistools
14 | dev.unnm3d.redischat.datamanagers.sqlmanagers
15 | dev.unnm3d.redischat.discord
16 | dev.unnm3d.redischat.integrations
17 | dev.unnm3d.redischat.mail
18 | dev.unnm3d.redischat.moderation
19 | dev.unnm3d.redischat.permission
20 | dev.unnm3d.redischat.settings
21 | dev.unnm3d.redischat.task
22 | dev.unnm3d.redischat.utils
23 |
--------------------------------------------------------------------------------
/docs/legal/COPYRIGHT:
--------------------------------------------------------------------------------
1 | Please see ..\java.base\COPYRIGHT
2 |
--------------------------------------------------------------------------------
/docs/legal/LICENSE:
--------------------------------------------------------------------------------
1 | Please see ..\java.base\LICENSE
2 |
--------------------------------------------------------------------------------
/docs/legal/jquery.md:
--------------------------------------------------------------------------------
1 | ## jQuery v3.6.1
2 |
3 | ### jQuery License
4 | ```
5 | jQuery v 3.6.1
6 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining
9 | a copy of this software and associated documentation files (the
10 | "Software"), to deal in the Software without restriction, including
11 | without limitation the rights to use, copy, modify, merge, publish,
12 | distribute, sublicense, and/or sell copies of the Software, and to
13 | permit persons to whom the Software is furnished to do so, subject to
14 | the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be
17 | included in all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | ******************************************
28 |
29 | The jQuery JavaScript Library v3.6.1 also includes Sizzle.js
30 |
31 | Sizzle.js includes the following license:
32 |
33 | Copyright JS Foundation and other contributors, https://js.foundation/
34 |
35 | This software consists of voluntary contributions made by many
36 | individuals. For exact contribution history, see the revision history
37 | available at https://github.com/jquery/sizzle
38 |
39 | The following license applies to all parts of this software except as
40 | documented below:
41 |
42 | ====
43 |
44 | Permission is hereby granted, free of charge, to any person obtaining
45 | a copy of this software and associated documentation files (the
46 | "Software"), to deal in the Software without restriction, including
47 | without limitation the rights to use, copy, modify, merge, publish,
48 | distribute, sublicense, and/or sell copies of the Software, and to
49 | permit persons to whom the Software is furnished to do so, subject to
50 | the following conditions:
51 |
52 | The above copyright notice and this permission notice shall be
53 | included in all copies or substantial portions of the Software.
54 |
55 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
56 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
57 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
58 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
59 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
60 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
61 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
62 |
63 | ====
64 |
65 | All files located in the node_modules and external directories are
66 | externally maintained libraries used by this software which have their
67 | own licenses; we recommend you read them, as their terms may differ from
68 | the terms above.
69 |
70 | *********************
71 |
72 | ```
73 |
--------------------------------------------------------------------------------
/docs/legal/jqueryUI.md:
--------------------------------------------------------------------------------
1 | ## jQuery UI v1.13.2
2 |
3 | ### jQuery UI License
4 | ```
5 | Copyright jQuery Foundation and other contributors, https://jquery.org/
6 |
7 | This software consists of voluntary contributions made by many
8 | individuals. For exact contribution history, see the revision history
9 | available at https://github.com/jquery/jquery-ui
10 |
11 | The following license applies to all parts of this software except as
12 | documented below:
13 |
14 | ====
15 |
16 | Permission is hereby granted, free of charge, to any person obtaining
17 | a copy of this software and associated documentation files (the
18 | "Software"), to deal in the Software without restriction, including
19 | without limitation the rights to use, copy, modify, merge, publish,
20 | distribute, sublicense, and/or sell copies of the Software, and to
21 | permit persons to whom the Software is furnished to do so, subject to
22 | the following conditions:
23 |
24 | The above copyright notice and this permission notice shall be
25 | included in all copies or substantial portions of the Software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
35 | ====
36 |
37 | Copyright and related rights for sample code are waived via CC0. Sample
38 | code is defined as all source code contained within the demos directory.
39 |
40 | CC0: http://creativecommons.org/publicdomain/zero/1.0/
41 |
42 | ====
43 |
44 | All files located in the node_modules and external directories are
45 | externally maintained libraries used by this software which have their
46 | own licenses; we recommend you read them, as their terms may differ from
47 | the terms above.
48 |
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/link.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/docs/module-search-index.js:
--------------------------------------------------------------------------------
1 | moduleSearchIndex = [];updateSearchResults();
--------------------------------------------------------------------------------
/docs/overview-summary.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Generated Documentation (Untitled)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 | index.html
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/docs/package-search-index.js:
--------------------------------------------------------------------------------
1 | packageSearchIndex = [{"l":"All Packages","u":"allpackages-index.html"},{"l":"dev.unnm3d.redischat"},{"l":"dev.unnm3d.redischat.api"},{"l":"dev.unnm3d.redischat.api.events"},{"l":"dev.unnm3d.redischat.channels"},{"l":"dev.unnm3d.redischat.channels.gui"},{"l":"dev.unnm3d.redischat.chat"},{"l":"dev.unnm3d.redischat.chat.filters"},{"l":"dev.unnm3d.redischat.chat.filters.incoming"},{"l":"dev.unnm3d.redischat.chat.filters.outgoing"},{"l":"dev.unnm3d.redischat.chat.objects"},{"l":"dev.unnm3d.redischat.commands"},{"l":"dev.unnm3d.redischat.datamanagers"},{"l":"dev.unnm3d.redischat.datamanagers.redistools"},{"l":"dev.unnm3d.redischat.datamanagers.sqlmanagers"},{"l":"dev.unnm3d.redischat.discord"},{"l":"dev.unnm3d.redischat.integrations"},{"l":"dev.unnm3d.redischat.mail"},{"l":"dev.unnm3d.redischat.moderation"},{"l":"dev.unnm3d.redischat.permission"},{"l":"dev.unnm3d.redischat.settings"},{"l":"dev.unnm3d.redischat.task"},{"l":"dev.unnm3d.redischat.utils"}];updateSearchResults();
--------------------------------------------------------------------------------
/docs/resources/glass.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Emibergo02/RedisChat/3d3a32af6fd827a085ae903228300ef9c9df28f4/docs/resources/glass.png
--------------------------------------------------------------------------------
/docs/resources/x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Emibergo02/RedisChat/3d3a32af6fd827a085ae903228300ef9c9df28f4/docs/resources/x.png
--------------------------------------------------------------------------------
/docs/script-dir/jquery-ui.min.css:
--------------------------------------------------------------------------------
1 | /*! jQuery UI - v1.13.2 - 2023-02-27
2 | * http://jqueryui.com
3 | * Includes: core.css, autocomplete.css, menu.css
4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */
5 |
6 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;-ms-filter:"alpha(opacity=0)"}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}
--------------------------------------------------------------------------------
/docs/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Search
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
20 |
21 | JavaScript is disabled on your browser.
22 |
23 |
24 |
44 |
45 |
46 | Search
47 |
48 |
49 |
50 |
51 | Additional resources
52 |
53 |
54 |
55 |
The help page provides an introduction to the scope and syntax of JavaDoc search.
56 |
You can use the <ctrl> or <cmd> keys in combination with the left and right arrow keys to switch between result tabs in this page.
57 |
The URL template below may be used to configure this page as a search engine in browsers that support this feature. It has been tested to work in Google Chrome and Mozilla Firefox. Note that other browsers may not support this feature or require a different URL format.
58 |
link Copy
59 |
60 |
61 | Redirect to first result
62 |
63 | Loading search index...
64 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/docs/tag-search-index.js:
--------------------------------------------------------------------------------
1 | tagSearchIndex = [{"l":"Constant Field Values","h":"","u":"constant-values.html"}];updateSearchResults();
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Emibergo02/RedisChat/3d3a32af6fd827a085ae903228300ef9c9df28f4/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.7-bin.zip
4 | networkTimeout=10000
5 | validateDistributionUrl=true
6 | zipStoreBase=GRADLE_USER_HOME
7 | zipStorePath=wrapper/dists
8 |
--------------------------------------------------------------------------------
/jitpack.yml:
--------------------------------------------------------------------------------
1 | # JitPack configuration, ensuring the JDK is set to v17
2 | jdk:
3 | - 'openjdk17'
4 | before_install:
5 | - 'git clone https://github.com/Emibergo02/RedisChat.git'
6 | - 'chmod +x gradlew'
7 | - 'chmod +x ./.scripts/ensure-java-17'
8 | - 'bash ./.scripts/ensure-java-17 install'
9 | install:
10 | - 'if ! ./.scripts/ensure-java-17 use; then source ~/.sdkman/bin/sdkman-init.sh; fi'
11 | - 'java -version'
12 | - './gradlew publishToMavenLocal'
13 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'RedisChat'
2 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/Permissions.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat;
2 |
3 | import lombok.Getter;
4 |
5 | @Getter
6 | public enum Permissions {
7 | MESSAGE("redischat.message"),
8 | MAIL_WRITE("redischat.mail.write"),
9 | MAIL_WRITE_PUBLIC("redischat.mail.writepublic"),
10 | MAIL_READ("redischat.mail"),
11 | MAIL_DELETE("redischat.mail.delete"),
12 | MAIL_PUBLIC_DELETE("redischat.mail.deletepublic"),
13 | MAIL_UNREAD("redischat.mail.unread"),
14 | IGNORE("redischat.ignore"),
15 | IGNORE_WHITELIST("redischat.ignore_whitelist"),
16 | BYPASS_FILTER_PREFIX("redischat.bypassfilter."),
17 | USE_FORMATTING("redischat.useformatting"),
18 | USE_DANGEROUS("redischat.usedangeroustags"),
19 | USE_ITEM("redischat.showitem"),
20 | USE_INVENTORY("redischat.showinv"),
21 | USE_ENDERCHEST("redischat.showenderchest"),
22 | USE_EMOJI_PLACEHOLDERS("redischat.use_emoji"),
23 | BROADCAST("redischat.broadcast"),
24 | ANNOUNCER("redischat.announcer"),
25 | CLEARCHAT("redischat.clearchat"),
26 | ADMIN("redischat.admin"),
27 | ADMIN_STAFF_CHAT("redischat.staffchat"),
28 | BYPASS_RATE_LIMIT("redischat.bypass_rate_limit"),
29 | CHANNEL_PREFIX("redischat.channel."),
30 | CHANNEL_PUBLIC("redischat.channel.public"),
31 | CHANNEL_CREATE("redischat.createchannel"),
32 | CHANNEL_INFO("redischat.infochannel"),
33 | CHANNEL_GUI("redischat.channelgui"),
34 | CHANNEL_CHANGE_DISPLAYNAME("redischat.changedisplayname"),
35 | CHANNEL_DELETE("redischat.deletechannel"),
36 | CHANNEL_TOGGLE_PLAYER("redischat.playerchannel"),
37 | CHANNEL_LIST("redischat.listchannel"),
38 | CHANNEL_MUTE("redischat.mutechannel"),
39 | CHANNEL_HIDE_PREFIX("redischat.hidechannel."),
40 | CHANNEL_SHOW_PREFIX("redischat.showchannel."),
41 | JOIN_QUIT("redischat.joinquit"),
42 | CHAT_COLOR("redischat.chatcolor"),
43 | SET_PLACEHOLDER("redischat.setchatplaceholder"),
44 | SPY_OTHERS("redischat.spycommand.other"),
45 | ;
46 |
47 | private final String permission;
48 |
49 | Permissions(String permission) {
50 | this.permission = permission;
51 | }
52 |
53 | }
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/UpdateCheck.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat;
2 |
3 | import com.google.gson.JsonElement;
4 | import com.google.gson.JsonParser;
5 |
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.net.URL;
9 | import java.util.Scanner;
10 | import java.util.concurrent.CompletableFuture;
11 | import java.util.function.Consumer;
12 | import java.util.logging.Logger;
13 |
14 | public class UpdateCheck {
15 |
16 | public final Logger logger;
17 |
18 | public UpdateCheck(RedisChat plugin) {
19 | this.logger = plugin.getLogger();
20 | }
21 |
22 | public void getVersion(final Consumer consumer) {
23 | CompletableFuture.runAsync(() -> {
24 | try (InputStream inputStream = new URL("https://api.spiget.org/v2/resources/111015/versions/latest")
25 | .openStream(); Scanner scanner = new Scanner(inputStream)) {
26 | if (scanner.hasNext()) {
27 | JsonElement element = JsonParser.parseString(scanner.next()).getAsJsonObject().get("name");
28 | if (element != null)
29 | consumer.accept(element.getAsString());
30 | }
31 | } catch (IOException exception) {
32 | logger.severe("Unable to check for updates: " + exception.getMessage());
33 | }
34 | }, RedisChat.getInstance().getExecutorService());
35 | }
36 | }
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/TagResolverIntegration.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public interface TagResolverIntegration {
6 |
7 | /**
8 | * Parse tags/placeholders of a message
9 | * To be used for MiniMessage or other tag/placeholders systems
10 | *
11 | * @param message The message to resolve
12 | * @return The resolved message
13 | */
14 | default @NotNull String parseTags(String message) {
15 | return message;
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/VanishIntegration.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api;
2 |
3 | import org.bukkit.command.CommandSender;
4 | import org.bukkit.entity.Player;
5 |
6 | public interface VanishIntegration {
7 |
8 | /**
9 | * Check if a player can see another player
10 | *
11 | * @param playerName The playerName
12 | * @param viewer The player who is viewing the possible vanished player
13 | * @return true if the viewer can see the player
14 | */
15 | boolean canSee(CommandSender viewer, String playerName);
16 |
17 | /**
18 | * Check if a player is vanished
19 | * Default implementation checks for the PremiumVanish metadata
20 | *
21 | * @param player The player
22 | * @return true if the player is vanished
23 | */
24 | boolean isVanished(Player player);
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/AsyncRedisChatMessageEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.api.objects.ChannelAudience;
4 | import lombok.Getter;
5 | import lombok.Setter;
6 | import net.kyori.adventure.text.Component;
7 | import org.bukkit.command.CommandSender;
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 | public class AsyncRedisChatMessageEvent extends Event implements Cancellable {
14 |
15 | private static final HandlerList HANDLERS = new HandlerList();
16 | @Getter
17 | private final CommandSender sender;
18 | @Setter
19 | @Getter
20 | private ChannelAudience audience;
21 | @Getter
22 | private final Component format;
23 | @Getter
24 | private final Component content;
25 | private boolean cancelled;
26 |
27 | /**
28 | * Creates a RedisChatMessageEvent
29 | *
30 | * @param sender The sender of the message
31 | * @param audience The channel of the message
32 | * @param format The format of the message
33 | * @param content The message content
34 | */
35 | public AsyncRedisChatMessageEvent(CommandSender sender, ChannelAudience audience, Component format, Component content) {
36 | super(true);
37 | this.sender = sender;
38 | this.audience = audience;
39 | this.format = format;
40 | this.content = content;
41 | this.cancelled = false;
42 | }
43 |
44 | @Override
45 | public boolean isCancelled() {
46 | return cancelled;
47 | }
48 |
49 | @Override
50 | public void setCancelled(boolean cancel) {
51 | this.cancelled = cancel;
52 | }
53 |
54 | @Override
55 | public @NotNull HandlerList getHandlers() {
56 | return HANDLERS;
57 | }
58 |
59 | public static HandlerList getHandlerList() {
60 | return HANDLERS;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/ChannelGuiPopulateEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.channels.gui.PlayerChannel;
4 | import lombok.Getter;
5 | import lombok.Setter;
6 | import org.bukkit.entity.Player;
7 | import org.bukkit.event.Event;
8 | import org.bukkit.event.HandlerList;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | import java.util.List;
12 |
13 | @Getter
14 | public class ChannelGuiPopulateEvent extends Event {
15 | private static final HandlerList HANDLERS = new HandlerList();
16 | private final Player player;
17 | @Setter
18 | private List channelItems;
19 |
20 | /**
21 | * Event that is called before the channel GUI is populated
22 | * @param player The player that is opening the GUI
23 | * @param channelItems The list of channels that will be displayed in the GUI
24 | */
25 | public ChannelGuiPopulateEvent(Player player, List channelItems) {
26 | super(true);
27 | this.player = player;
28 | this.channelItems = channelItems;
29 | }
30 |
31 | @Override
32 | public @NotNull HandlerList getHandlers() {
33 | return HANDLERS;
34 | }
35 |
36 | public static HandlerList getHandlerList() {
37 | return HANDLERS;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/FilterEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
4 | import dev.unnm3d.redischat.chat.filters.FilterResult;
5 | import dev.unnm3d.redischat.settings.FiltersConfig;
6 | import lombok.Getter;
7 | import lombok.Setter;
8 | import org.bukkit.Bukkit;
9 | import org.bukkit.event.Event;
10 | import org.bukkit.event.HandlerList;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | @Getter
14 | public class FilterEvent extends Event {
15 | private static final HandlerList HANDLERS = new HandlerList();
16 | private final AbstractFilter extends FiltersConfig.FilterSettings> filter;
17 | @Setter
18 | private FilterResult result;
19 |
20 | /**
21 | * Event that is called when a filter is applied to a message
22 | * @param filter The filter that is being applied
23 | * @param result The result of the filter
24 | */
25 | public FilterEvent(AbstractFilter extends FiltersConfig.FilterSettings> filter, FilterResult result) {
26 | super(!Bukkit.isPrimaryThread());
27 | this.filter = filter;
28 | this.result = result;
29 | }
30 |
31 | @Override
32 | public @NotNull HandlerList getHandlers() {
33 | return HANDLERS;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/MailDeleteEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.mail.Mail;
4 | import lombok.Getter;
5 | import org.bukkit.entity.Player;
6 | import org.bukkit.event.Cancellable;
7 |
8 |
9 | public class MailDeleteEvent extends MailEvent implements Cancellable {
10 | @Getter
11 | private final Player deleter;
12 | private boolean cancelled = false;
13 |
14 | /**
15 | * Event that is called when a mail is deleted
16 | * @param mail The mail that is being deleted
17 | * @param deleter The player that is deleting the mail
18 | */
19 | public MailDeleteEvent(Mail mail, Player deleter) {
20 | super(mail);
21 | this.deleter = deleter;
22 | }
23 |
24 | @Override
25 | public boolean isCancelled() {
26 | return cancelled;
27 | }
28 |
29 | @Override
30 | public void setCancelled(boolean cancelled) {
31 | this.cancelled = cancelled;
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/MailEditorEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.mail.Mail;
4 | import lombok.Getter;
5 |
6 | @Getter
7 | public class MailEditorEvent extends MailEvent {
8 | private final MailEditorState state;
9 |
10 | /**
11 | * Event that is called when a mail is being created via the web editor
12 | * The event is called when the editor is opened and closed
13 | *
14 | * @param mail The mail that is being created
15 | * @param state The state of the editor
16 | */
17 | public MailEditorEvent(Mail mail, MailEditorState state) {
18 | super(mail);
19 | this.state = state;
20 | }
21 |
22 | public enum MailEditorState {
23 | STARTED,
24 | COMPLETED
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/MailEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.mail.Mail;
4 | import lombok.Getter;
5 | import lombok.Setter;
6 | import org.bukkit.Bukkit;
7 | import org.bukkit.event.Event;
8 | import org.bukkit.event.HandlerList;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | @Setter
12 | @Getter
13 | public abstract class MailEvent extends Event {
14 | private static final HandlerList HANDLERS = new HandlerList();
15 |
16 | private Mail mail;
17 |
18 | public MailEvent(Mail mail) {
19 | super(!Bukkit.isPrimaryThread());
20 | this.mail = mail;
21 | }
22 |
23 | public static HandlerList getHandlerList() {
24 | return HANDLERS;
25 | }
26 |
27 | @Override
28 | public @NotNull HandlerList getHandlers() {
29 | return HANDLERS;
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/MailReadStatusChangeEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.mail.Mail;
4 | import lombok.Getter;
5 | import org.bukkit.entity.Player;
6 |
7 | @Getter
8 | public class MailReadStatusChangeEvent extends MailEvent {
9 | private final Player player;
10 |
11 | /**
12 | * Event that is called when a mail is read by a player
13 | * @param mail The mail that is being read
14 | * @param player The player that is reading the mail
15 | */
16 | public MailReadStatusChangeEvent(Mail mail, Player player) {
17 | super(mail);
18 | this.player = player;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/MailReceivedEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.mail.Mail;
4 |
5 | public class MailReceivedEvent extends MailEvent {
6 |
7 | /**
8 | * Event that is called when a mail is received by the server
9 | * @param mail The mail that is being received
10 | */
11 | public MailReceivedEvent(Mail mail) {
12 | super(mail);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/events/MailSendEvent.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.events;
2 |
3 | import dev.unnm3d.redischat.mail.Mail;
4 | import org.bukkit.event.Cancellable;
5 |
6 | public class MailSendEvent extends MailEvent implements Cancellable {
7 | private boolean cancelled = false;
8 |
9 | /**
10 | * Event that is called when a mail is sent
11 | * @param mail The mail that is being sent
12 | */
13 | public MailSendEvent(Mail mail) {
14 | super(mail);
15 | }
16 |
17 | @Override
18 | public boolean isCancelled() {
19 | return cancelled;
20 | }
21 |
22 | @Override
23 | public void setCancelled(boolean cancelled) {
24 | this.cancelled = cancelled;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/objects/AudienceType.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.objects;
2 |
3 | public enum AudienceType {
4 | /**
5 | * Represents a player in the game.
6 | */
7 | PLAYER,
8 |
9 | /**
10 | * Represents a chat channel.
11 | */
12 | CHANNEL,
13 |
14 | /**
15 | * Represents a user/channel on Discord.
16 | */
17 | DISCORD
18 | }
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/objects/ChatMessage.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.objects;
2 |
3 |
4 | import com.google.common.base.Strings;
5 | import lombok.EqualsAndHashCode;
6 | import lombok.Getter;
7 | import lombok.Setter;
8 | import lombok.ToString;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | @Getter
13 | @EqualsAndHashCode
14 | @ToString
15 | public class ChatMessage {
16 | private final ChannelAudience sender;
17 | private final long timestamp;
18 | @Setter
19 | private String format;
20 | @Setter
21 | private String content;
22 | private final ChannelAudience receiver;
23 |
24 |
25 | /**
26 | * Creates a ChatMessageInfo as "Server"
27 | *
28 | * @param content The message content
29 | */
30 | public ChatMessage(String content) {
31 | this(new ChannelAudience(), System.currentTimeMillis(), "{message}", content, ChannelAudience.publicChannelAudience());
32 | }
33 |
34 | /**
35 | * Creates a ChatMessageInfo as "Server"
36 | *
37 | * @param content The message content
38 | */
39 | public ChatMessage(String content, String permissionToSee) {
40 | this(new ChannelAudience(), System.currentTimeMillis(), "{message}", content, ChannelAudience.publicChannelAudience(permissionToSee));
41 | }
42 |
43 | /**
44 | * Used for deserialization
45 | *
46 | * @param sender The sender of the message
47 | * @param format The formatting of the message
48 | * @param content The message content
49 | * @param receiver The receiver of the message
50 | */
51 | public ChatMessage(@NotNull ChannelAudience sender, long timestamp, @Nullable String format, @Nullable String content, @NotNull ChannelAudience receiver) {
52 | this.sender = sender;
53 | this.timestamp = timestamp;
54 | this.format = Strings.nullToEmpty(format);
55 | this.content = Strings.nullToEmpty(content);
56 | this.receiver = receiver;
57 | }
58 |
59 |
60 | /**
61 | * Creates a ChatMessageInfo from a sender, formatting, message and receiver
62 | *
63 | * @param sender The sender of the message
64 | * @param format The formatting of the message
65 | * @param content The message content
66 | * @param receiver The receiver of the message
67 | */
68 | public ChatMessage(@NotNull ChannelAudience sender, @Nullable String format, @Nullable String content, @NotNull ChannelAudience receiver) {
69 | this(sender, System.currentTimeMillis(), format, content, receiver);
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/api/objects/KnownChatEntities.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.api.objects;
2 |
3 | public enum KnownChatEntities {
4 | GENERAL_CHANNEL("public"),
5 | VOID_CHAT("void"),
6 | SERVER_SENDER("*Server*"),
7 | CHANNEL_PREFIX("#"),
8 | DISCORD_PREFIX("@"),
9 | PERMISSION_PREFIX("~"),
10 | STAFFCHAT_CHANNEL_NAME("staffchat"),
11 | ALL_PLAYERS("-ALL-"),
12 | ;
13 |
14 | private final String keyName;
15 |
16 | /**
17 | * @param keyName the name of the key
18 | */
19 | KnownChatEntities(final String keyName) {
20 | this.keyName = keyName;
21 | }
22 |
23 | @Override
24 | public String toString() {
25 | return keyName;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/channels/gui/ChannelGUI.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.channels.gui;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.api.events.ChannelGuiPopulateEvent;
6 | import dev.unnm3d.redischat.api.objects.KnownChatEntities;
7 | import lombok.AllArgsConstructor;
8 | import org.bukkit.entity.Player;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 | import xyz.xenondevs.invui.gui.Gui;
12 | import xyz.xenondevs.invui.gui.PagedGui;
13 | import xyz.xenondevs.invui.gui.structure.Markers;
14 | import xyz.xenondevs.invui.item.Item;
15 | import xyz.xenondevs.invui.item.ItemProvider;
16 | import xyz.xenondevs.invui.item.builder.ItemBuilder;
17 | import xyz.xenondevs.invui.item.impl.controlitem.PageItem;
18 |
19 | import java.util.List;
20 | import java.util.stream.Collectors;
21 |
22 | @AllArgsConstructor
23 | public class ChannelGUI {
24 | private final RedisChat plugin;
25 |
26 |
27 | public Gui getChannelsGUI(@NotNull Player player, @Nullable String activeChannelName) {
28 |
29 | final List items = plugin.getChannelManager().getAllChannels().stream()
30 | .filter(channel -> channel.isShownByDefault() || player.hasPermission(Permissions.CHANNEL_SHOW_PREFIX.getPermission() + channel.getName()))
31 | .map(channel -> new PlayerChannel(channel, player, channel.getName().equals(activeChannelName)))
32 | .filter(playerChannel -> !playerChannel.isHidden())
33 | .collect(Collectors.toList());
34 |
35 | final ChannelGuiPopulateEvent populateEvent = new ChannelGuiPopulateEvent(player, items);
36 | plugin.getServer().getPluginManager().callEvent(populateEvent);
37 |
38 | return PagedGui.items()
39 | .setStructure(
40 | plugin.guiSettings.channelGUIStructure.toArray(new String[0]))
41 | .addIngredient('x', Markers.CONTENT_LIST_SLOT_HORIZONTAL) // where paged items should be put
42 | .addIngredient('<', new PageItem(false) {
43 | @Override
44 | public ItemProvider getItemProvider(PagedGui> gui) {
45 | return new ItemBuilder(plugin.guiSettings.backButton);
46 | }
47 | })
48 | .addIngredient('>', new PageItem(true) {
49 | @Override
50 | public ItemProvider getItemProvider(PagedGui> gui) {
51 | return new ItemBuilder(plugin.guiSettings.forwardButton);
52 | }
53 | })
54 | .addIngredient('G', new GlobalChannel(
55 | plugin.getChannelManager().getPublicChannel(null),
56 | player,
57 | KnownChatEntities.GENERAL_CHANNEL.toString().equals(activeChannelName)))
58 | .setContent(populateEvent.getChannelItems().stream().map(Item.class::cast).toList())
59 | .build();
60 | }
61 |
62 |
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/channels/gui/GlobalChannel.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.channels.gui;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import dev.unnm3d.redischat.api.objects.Channel;
5 | import org.bukkit.entity.Player;
6 | import org.bukkit.inventory.ItemStack;
7 | import org.bukkit.inventory.meta.ItemMeta;
8 | import xyz.xenondevs.invui.item.ItemProvider;
9 | import xyz.xenondevs.invui.item.builder.ItemBuilder;
10 |
11 | public class GlobalChannel extends PlayerChannel {
12 | public GlobalChannel(Channel channel, Player player, boolean isActive) {
13 | super(channel, player, isActive);
14 | }
15 |
16 | @Override
17 | public ItemProvider getItemProvider() {
18 | ItemStack item;
19 | if (status == Status.MUTED) {
20 | item = RedisChat.getInstance().guiSettings.mutedGlobal;
21 | } else if (status == Status.LISTENING) {
22 | item = RedisChat.getInstance().guiSettings.activeGlobal;
23 | } else {
24 | item = RedisChat.getInstance().guiSettings.idleGlobal;
25 | }
26 |
27 | final ItemMeta im = item.getItemMeta();
28 | if (im != null)
29 | im.setDisplayName("§r" + RedisChat.getInstance().getComponentProvider()
30 | .replaceAmpersandCodesWithSection(channel.getDisplayName()));
31 | item.setItemMeta(im);
32 | return new ItemBuilder(item);
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/ChatColorGUI.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import org.bukkit.ChatColor;
5 | import org.bukkit.entity.Player;
6 | import org.bukkit.event.inventory.ClickType;
7 | import org.bukkit.event.inventory.InventoryClickEvent;
8 | import xyz.xenondevs.invui.gui.AbstractGui;
9 |
10 | public class ChatColorGUI extends AbstractGui {
11 | private final RedisChat plugin;
12 |
13 | public ChatColorGUI(RedisChat plugin) {
14 | super(9, plugin.guiSettings.chatColorGUIStructure.size());
15 | this.plugin = plugin;
16 | this.applyStructure(plugin.guiSettings.getChatColorGUIStructure());
17 | }
18 |
19 | @Override
20 | public void handleClick(int slotNumber, Player player, ClickType clickType, InventoryClickEvent event) {
21 | super.handleClick(slotNumber, player, clickType, event);
22 | player.closeInventory();
23 |
24 | StringBuilder sb = new StringBuilder();
25 | plugin.guiSettings.chatColorGUIStructure.forEach(row -> sb.append(row.replace(" ", "")));
26 |
27 | char slotChar = sb.toString().charAt(slotNumber);
28 | final ChatColor color = ChatColor.getByChar(slotChar);
29 | if (color == null) {
30 | plugin.messages.sendMessage(player, plugin.messages.invalid_color);
31 | return;
32 | }
33 | if (color == ChatColor.RESET) {
34 | plugin.getPlaceholderManager().removePlayerPlaceholder(player.getName(), "chat_color");
35 | } else {
36 | plugin.getPlaceholderManager().addPlayerPlaceholder(player.getName(), "chat_color", "<" + color.name().toLowerCase() + ">");
37 | }
38 |
39 | plugin.messages.sendMessage(player, plugin.messages.color_set);
40 |
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/ChatFormat.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat;
2 |
3 | import org.jetbrains.annotations.NotNull;
4 |
5 | public record ChatFormat(
6 | @NotNull String permission,
7 | @NotNull String format,
8 | @NotNull String private_format,
9 | @NotNull String receive_private_format,
10 | @NotNull String mention_format,
11 | @NotNull String link_format,
12 | @NotNull String join_format,
13 | @NotNull String quit_format) {
14 | }
15 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/PlaceholderManager.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import org.bukkit.event.EventHandler;
5 | import org.bukkit.event.Listener;
6 | import org.bukkit.event.player.PlayerLoginEvent;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | import java.util.concurrent.ConcurrentHashMap;
10 |
11 | public class PlaceholderManager implements Listener {
12 |
13 | private final RedisChat plugin;
14 | private final ConcurrentHashMap> playerPlaceholders;
15 |
16 | public PlaceholderManager(RedisChat plugin) {
17 | this.plugin = plugin;
18 | this.playerPlaceholders = new ConcurrentHashMap<>();
19 | plugin.getServer().getPluginManager().registerEvents(this, plugin);
20 | }
21 |
22 | @EventHandler
23 | public void onPlayerJoin(PlayerLoginEvent event) {
24 | updatePlayerPlaceholderCache(event.getPlayer().getName());
25 | }
26 |
27 | public void updatePlayerPlaceholderCache(String playerName) {
28 | this.plugin.getDataManager().getPlayerPlaceholders(playerName)
29 | .thenAccept(redisPlaceholders -> {
30 | if (redisPlaceholders == null) return;
31 | playerPlaceholders.put(playerName, new ConcurrentHashMap<>(redisPlaceholders));
32 | });
33 | }
34 |
35 | public void updatePlayerPlaceholders(String serializedPlaceholders) {
36 | final String playerName = serializedPlaceholders.substring(0,serializedPlaceholders.indexOf("§;"));
37 | final String placeholders = serializedPlaceholders.substring(serializedPlaceholders.indexOf("§;") + 2);
38 | playerPlaceholders.put(playerName, new ConcurrentHashMap<>(plugin.getDataManager().deserializePlayerPlaceholders(placeholders)));
39 | }
40 |
41 | public void addPlayerPlaceholder(String playerName, String placeholder, String value) {
42 | playerPlaceholders.computeIfAbsent(playerName, k -> new ConcurrentHashMap<>()).put(placeholder, value);
43 | this.plugin.getDataManager().setPlayerPlaceholders(playerName, playerPlaceholders.get(playerName));
44 | }
45 |
46 | public void removePlayerPlaceholder(String playerName, String placeholder) {
47 | if (!playerPlaceholders.containsKey(playerName)) return;
48 | if (playerPlaceholders.get(playerName).remove(placeholder) == null) return;
49 | this.plugin.getDataManager().setPlayerPlaceholders(playerName, playerPlaceholders.get(playerName));
50 | }
51 |
52 | public String getPlaceholder(@NotNull String playerName, @NotNull String placeholder) {
53 | return playerPlaceholders.getOrDefault(playerName, new ConcurrentHashMap<>()).getOrDefault(placeholder, "");
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/RedisChatPAPI.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import lombok.AllArgsConstructor;
5 | import me.clip.placeholderapi.expansion.PlaceholderExpansion;
6 | import org.bukkit.OfflinePlayer;
7 | import org.jetbrains.annotations.NotNull;
8 |
9 | @AllArgsConstructor
10 | public class RedisChatPAPI extends PlaceholderExpansion {
11 | private final RedisChat plugin;
12 |
13 | @Override
14 | public @NotNull String getIdentifier() {
15 | return "redischat";
16 | }
17 |
18 | @Override
19 | public @NotNull String getAuthor() {
20 | return "Unnm3d";
21 | }
22 |
23 | @Override
24 | public @NotNull String getVersion() {
25 | return "1.1.0";
26 | }
27 |
28 | @Override
29 | public boolean persist() {
30 | return true;
31 | }
32 |
33 |
34 | @Override
35 | public String onRequest(OfflinePlayer player, @NotNull String params) {
36 | if (params.equalsIgnoreCase("active_channel")) {
37 | if (player.getName() == null) return plugin.getChannelManager().getPublicChannel(null).getName();
38 | return plugin.getChannelManager().getActiveChannel(player.getName());
39 | }
40 |
41 | if (params.equalsIgnoreCase("notify_status")) {
42 | try {
43 | if (plugin.getMailGUIManager().getPublicMails(player.getName()).get()
44 | .stream().anyMatch(mail -> !mail.isRead())) {
45 | return "2";
46 | }
47 | if (plugin.getMailGUIManager().getPrivateMails(player.getName()).get()
48 | .stream().anyMatch(mail -> !mail.isRead())) {
49 | return "1";
50 | }
51 | } catch (Exception e) {
52 | plugin.getLogger().severe("Error getting mail status: " + e);
53 | }
54 | return "0";
55 | }
56 |
57 | if (params.equalsIgnoreCase("ignoring_all")) {
58 | if (player.getName() == null) return "false";
59 | return plugin.getChannelManager().getMuteManager().getIgnoreList(player.getName()).contains("all") ? "true" : "false";
60 | }
61 | if (player != null && player.getName() != null) {
62 | return plugin.getPlaceholderManager().getPlaceholder(player.getName(), params);
63 | }
64 | return null; // Placeholder is unknown by the Expansion
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/AbstractFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters;
2 |
3 | import dev.unnm3d.redischat.api.objects.ChatMessage;
4 | import dev.unnm3d.redischat.settings.FiltersConfig;
5 | import lombok.AllArgsConstructor;
6 | import lombok.Getter;
7 | import lombok.Setter;
8 | import org.bukkit.command.CommandSender;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 | import java.util.function.BiFunction;
12 |
13 | @Getter
14 | @AllArgsConstructor
15 | public abstract class AbstractFilter implements BiFunction {
16 |
17 | protected final String name;
18 | protected final Direction direction;
19 | @Setter
20 | protected T filterSettings;
21 |
22 | @Override
23 | public FilterResult apply(CommandSender player, ChatMessage chatMessage) {
24 | return applyWithPrevious(player, chatMessage);
25 | }
26 |
27 | public abstract FilterResult applyWithPrevious(CommandSender receiver, @NotNull ChatMessage message, ChatMessage... previousMessages);
28 |
29 |
30 | public enum Direction {
31 | INCOMING,
32 | OUTGOING,
33 | BOTH
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/DefaultSettings.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters;
2 |
3 | import dev.unnm3d.redischat.chat.filters.incoming.IgnorePlayerFilter;
4 | import dev.unnm3d.redischat.chat.filters.outgoing.CapsFilter;
5 | import dev.unnm3d.redischat.chat.filters.outgoing.DuplicateFilter;
6 | import dev.unnm3d.redischat.chat.filters.outgoing.IgnoreFilter;
7 | import dev.unnm3d.redischat.chat.filters.outgoing.WordBlacklistFilter;
8 | import dev.unnm3d.redischat.api.objects.AudienceType;
9 | import dev.unnm3d.redischat.settings.FiltersConfig;
10 | import lombok.Getter;
11 |
12 | import java.util.Set;
13 |
14 | @Getter
15 | public enum DefaultSettings {
16 |
17 | IGNORE_PLAYER(new IgnorePlayerFilter.IgnorePlayerFilterProperties()),
18 | PERMISSION(new FiltersConfig.FilterSettings(true, 2, Set.of(AudienceType.CHANNEL), Set.of())),
19 | DISCORD(new FiltersConfig.FilterSettings(true, 1, Set.of(AudienceType.DISCORD), Set.of())),
20 | PRIVATE_OUT(new FiltersConfig.FilterSettings(true, 3, Set.of(AudienceType.PLAYER), Set.of())),
21 | CAPS(new CapsFilter.CapsFilterProperties()),
22 | DUPLICATE(new DuplicateFilter.DuplicateFilterProperties()),
23 | IGNORE(new IgnoreFilter.IgnoreFilterProperties()),
24 | MUTED_CHANNEL(new FiltersConfig.FilterSettings(true, 5, Set.of(AudienceType.CHANNEL), Set.of())),
25 | TAGS(new FiltersConfig.FilterSettings(true, 9, Set.of(), Set.of())),
26 | WORDS(new WordBlacklistFilter.WordBlacklistFilterProperties()),
27 | SPAM(new FiltersConfig.FilterSettings(true, 1, Set.of(), Set.of()));
28 |
29 | private final FiltersConfig.FilterSettings filterSettings;
30 |
31 | DefaultSettings(FiltersConfig.FilterSettings filterSettings) {
32 | this.filterSettings = filterSettings;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/FilterResult.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters;
2 |
3 | import dev.unnm3d.redischat.api.objects.ChatMessage;
4 | import net.kyori.adventure.text.Component;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | import java.util.Optional;
8 |
9 | /**
10 | * The result of a filter
11 | *
12 | * @param message The resulting message (it can be the same as the filter input message or a modified version)
13 | * @param filtered Whether the message was filtered (if true, the message will not be sent)
14 | */
15 | public record FilterResult(@NotNull ChatMessage message, boolean filtered, @NotNull Optional filteredReason) {
16 |
17 | public FilterResult(ChatMessage message, boolean filtered) {
18 | this(message, filtered, Optional.empty());
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/incoming/IgnorePlayerFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.incoming;
2 |
3 | import de.exlll.configlib.Comment;
4 | import de.exlll.configlib.Configuration;
5 | import dev.unnm3d.redischat.RedisChat;
6 | import dev.unnm3d.redischat.api.objects.AudienceType;
7 | import dev.unnm3d.redischat.api.objects.ChatMessage;
8 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
9 | import dev.unnm3d.redischat.chat.filters.FilterResult;
10 | import dev.unnm3d.redischat.settings.FiltersConfig;
11 | import lombok.Getter;
12 | import net.kyori.adventure.text.minimessage.MiniMessage;
13 | import org.bukkit.command.CommandSender;
14 | import org.jetbrains.annotations.NotNull;
15 |
16 | import java.util.Arrays;
17 | import java.util.Optional;
18 | import java.util.Set;
19 |
20 | public class IgnorePlayerFilter extends AbstractFilter {
21 |
22 | public IgnorePlayerFilter(IgnorePlayerFilterProperties filterSettings) {
23 | super("ignore_player", Direction.INCOMING, filterSettings);
24 | }
25 |
26 | @Override
27 | public FilterResult applyWithPrevious(CommandSender receiver, @NotNull ChatMessage chatMessage, ChatMessage... previousMessages) {
28 | boolean isIgnored = RedisChat.getInstance().getChannelManager().getMuteManager()
29 | .isPlayerIgnored(receiver.getName(), chatMessage.getSender().getName());
30 |
31 |
32 | if (isIgnored && (chatMessage.getReceiver().isPlayer() || filterSettings.ignoreChannelMessages)) {
33 |
34 | if (filterSettings.sendWarnWhenIgnoring &&
35 | Arrays.stream(previousMessages)
36 | .filter(message -> message.getSender().getName().equals(chatMessage.getSender().getName()))
37 | .filter(message -> message.getReceiver().getName().equals(chatMessage.getReceiver().getName()))
38 | .findAny()
39 | .isEmpty()) {
40 |
41 | return new FilterResult(chatMessage, true,
42 | Optional.of(MiniMessage.miniMessage().deserialize(RedisChat.getInstance().messages.ignoredMessageReceiver
43 | .replace("%player%", chatMessage.getSender().getName()))));
44 | }
45 |
46 | return new FilterResult(chatMessage, true);
47 | }
48 |
49 | return new FilterResult(chatMessage, false);
50 | }
51 |
52 | @Configuration
53 | @Getter
54 | public static class IgnorePlayerFilterProperties extends FiltersConfig.FilterSettings {
55 | @Comment("If true, send a ignored_player_receiver message when ignoring a player")
56 | private boolean sendWarnWhenIgnoring;
57 | @Comment("If true, sendWarnWhenIgnoring will work on channel messages too")
58 | private boolean ignoreChannelMessages;
59 |
60 | public IgnorePlayerFilterProperties() {
61 | super(true, 4, Set.of(AudienceType.PLAYER, AudienceType.CHANNEL), Set.of());
62 | this.ignoreChannelMessages = true;
63 | this.sendWarnWhenIgnoring = true;
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/incoming/PermissionFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.incoming;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
6 | import dev.unnm3d.redischat.chat.filters.FilterResult;
7 | import dev.unnm3d.redischat.api.objects.Channel;
8 | import dev.unnm3d.redischat.api.objects.ChatMessage;
9 | import dev.unnm3d.redischat.settings.FiltersConfig;
10 | import org.bukkit.command.CommandSender;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | public class PermissionFilter extends AbstractFilter {
14 | private final RedisChat plugin;
15 |
16 | public PermissionFilter(RedisChat plugin, FiltersConfig.FilterSettings filterSettings) {
17 | super("permission", Direction.INCOMING, filterSettings);
18 | this.plugin = plugin;
19 | }
20 |
21 | @Override
22 | public FilterResult applyWithPrevious(CommandSender receiver, @NotNull ChatMessage chatMessage, ChatMessage... previousMessages) {
23 | if (!plugin.getChannelManager().getRegisteredChannel(chatMessage.getReceiver().getName())
24 | .map(Channel::isPermissionEnabled).orElse(true)) {
25 | return new FilterResult(chatMessage, false);
26 | }
27 |
28 | for (String permission : chatMessage.getReceiver().getPermissions()) {
29 | if (!receiver.hasPermission(permission)) {
30 | return new FilterResult(chatMessage, true);
31 | }
32 | }
33 |
34 | //Default read permission check
35 | final String permission = Permissions.CHANNEL_PREFIX.getPermission() + chatMessage.getReceiver().getName();
36 | if (!(receiver.hasPermission(permission) || receiver.hasPermission(permission + ".read"))) {
37 | return new FilterResult(chatMessage, true);
38 | }
39 |
40 | return new FilterResult(chatMessage, false);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/outgoing/CapsFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.outgoing;
2 |
3 | import de.exlll.configlib.Comment;
4 | import de.exlll.configlib.Configuration;
5 | import dev.unnm3d.redischat.RedisChat;
6 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
7 | import dev.unnm3d.redischat.chat.filters.FilterResult;
8 | import dev.unnm3d.redischat.api.objects.ChatMessage;
9 | import dev.unnm3d.redischat.settings.FiltersConfig;
10 | import lombok.Getter;
11 | import org.bukkit.command.CommandSender;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.Optional;
15 | import java.util.Set;
16 |
17 |
18 | public class CapsFilter extends AbstractFilter {
19 | private final RedisChat plugin;
20 |
21 | public CapsFilter(RedisChat plugin) {
22 | super("caps", Direction.OUTGOING, plugin.filterSettings.caps);
23 | this.plugin = plugin;
24 | }
25 |
26 |
27 | /**
28 | * Transform uppercase messages into lowercase
29 | *
30 | * @param message The message to transform
31 | * @return The transformed message
32 | */
33 | public boolean antiCaps(@NotNull String message) {
34 | int capsCount = 0;
35 | for (char c : message.toCharArray())
36 | if (Character.isUpperCase(c))
37 | capsCount++;
38 | return capsCount > message.length() * (filterSettings.percentageCaps / 100.0);
39 | }
40 |
41 | @Override
42 | public FilterResult applyWithPrevious(CommandSender sender, @NotNull ChatMessage message, ChatMessage... previousMessages) {
43 |
44 | //Remove usernames from the message so players can send UPPERCASE USERNAMES
45 | String mentionRemoved = message.getContent();
46 | for (String playerName : plugin.getPlayerListManager().getPlayerList(sender)) {
47 | mentionRemoved = mentionRemoved.replace(playerName, "");
48 | }
49 |
50 | //Then check for the presence of caps
51 | if (antiCaps(mentionRemoved)) {
52 | message.setContent(message.getContent().toLowerCase());
53 | return new FilterResult(message, filterSettings.shouldBlock, Optional.of(
54 | RedisChat.getInstance().getComponentProvider().parse(sender,
55 | RedisChat.getInstance().messages.caps,
56 | true,
57 | false,
58 | false)
59 | ));
60 | }
61 |
62 | return new FilterResult(message, false, Optional.empty());
63 | }
64 |
65 |
66 | @Configuration
67 | @Getter
68 | public static class CapsFilterProperties extends FiltersConfig.FilterSettings {
69 | private int percentageCaps;
70 | @Comment("Should the message be blocked")
71 | private boolean shouldBlock;
72 |
73 | public CapsFilterProperties() {
74 | super(true, 8, Set.of(), Set.of());
75 | this.percentageCaps = 50;
76 | this.shouldBlock = false;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/outgoing/DuplicateFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.outgoing;
2 |
3 | import de.exlll.configlib.Comment;
4 | import de.exlll.configlib.Configuration;
5 | import dev.unnm3d.redischat.RedisChat;
6 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
7 | import dev.unnm3d.redischat.chat.filters.FilterResult;
8 | import dev.unnm3d.redischat.api.objects.ChatMessage;
9 | import dev.unnm3d.redischat.settings.FiltersConfig;
10 | import lombok.Getter;
11 | import org.bukkit.command.CommandSender;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.Arrays;
15 | import java.util.Comparator;
16 | import java.util.Optional;
17 | import java.util.Set;
18 |
19 |
20 | public class DuplicateFilter extends AbstractFilter {
21 |
22 | public DuplicateFilter(DuplicateFilterProperties filterSettings) {
23 | super("duplicate", Direction.OUTGOING, filterSettings);
24 | }
25 |
26 | @Override
27 | public FilterResult applyWithPrevious(CommandSender sender, @NotNull ChatMessage message, ChatMessage... previousMessages) {
28 | //Skip filter if no previous messages
29 | if(previousMessages.length == 0) return new FilterResult(message, false, Optional.empty());
30 |
31 | //Reverse the array to check the last messages first
32 | int checkedMessages = 0;
33 | for (ChatMessage chatMessage :
34 | Arrays.stream(previousMessages)
35 | .sorted(Comparator.comparingLong(ChatMessage::getTimestamp).reversed())
36 | .toList()) {
37 | float similarityPercentage = levenshteinScore(message.getContent(), chatMessage.getContent()) * 100;
38 |
39 | //If the similarity is lower than the percentage, skip filter
40 | if (similarityPercentage < filterSettings.similarityPercentage) {
41 | return new FilterResult(message, false, Optional.empty());
42 | }
43 | if (++checkedMessages == filterSettings.messagesToCheck) break;
44 | }
45 |
46 | return new FilterResult(message, true,
47 | Optional.of(RedisChat.getInstance().getComponentProvider()
48 | .parse(sender, RedisChat.getInstance().messages.duplicate_message, true,
49 | false, false)));
50 | }
51 |
52 | private float levenshteinScore(String first, String second) {
53 | int maxLength = Math.max(first.length(), second.length());
54 | //Can't divide by 0
55 | if (maxLength == 0) return 1.0f;
56 | return ((float) (maxLength - computeEditDistance(first, second))) / (float) maxLength;
57 | }
58 |
59 | private int computeEditDistance(String first, String second) {
60 | first = first.toLowerCase();
61 | second = second.toLowerCase();
62 |
63 | int[] costs = new int[second.length() + 1];
64 | for (int i = 0; i <= first.length(); i++) {
65 | int previousValue = i;
66 | for (int j = 0; j <= second.length(); j++) {
67 | if (i == 0) {
68 | costs[j] = j;
69 | } else if (j > 0) {
70 | int useValue = costs[j - 1];
71 | if (first.charAt(i - 1) != second.charAt(j - 1)) {
72 | useValue = Math.min(Math.min(useValue, previousValue), costs[j]) + 1;
73 | }
74 | costs[j - 1] = previousValue;
75 | previousValue = useValue;
76 |
77 | }
78 | }
79 | if (i > 0) {
80 | costs[second.length()] = previousValue;
81 | }
82 | }
83 | return costs[second.length()];
84 | }
85 |
86 |
87 | @Configuration
88 | @Getter
89 | public static class DuplicateFilterProperties extends FiltersConfig.FilterSettings {
90 | private int similarityPercentage;
91 | @Comment("How many messages to check for duplicates (from the last one)")
92 | private int messagesToCheck;
93 |
94 | public DuplicateFilterProperties() {
95 | super(true, 8, Set.of(), Set.of());
96 | this.similarityPercentage = 60;
97 | this.messagesToCheck = 2;
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/outgoing/IgnoreFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.outgoing;
2 |
3 | import de.exlll.configlib.Configuration;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.api.objects.AudienceType;
6 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
7 | import dev.unnm3d.redischat.chat.filters.FilterResult;
8 | import dev.unnm3d.redischat.api.objects.ChatMessage;
9 | import dev.unnm3d.redischat.settings.FiltersConfig;
10 | import lombok.Getter;
11 | import org.bukkit.command.CommandSender;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.Optional;
15 | import java.util.Set;
16 |
17 | public class IgnoreFilter extends AbstractFilter {
18 |
19 | private final RedisChat plugin;
20 |
21 | public IgnoreFilter(RedisChat plugin, IgnoreFilter.IgnoreFilterProperties filterSettings) {
22 | super("ignore", Direction.OUTGOING, filterSettings);
23 | this.plugin = plugin;
24 | }
25 |
26 |
27 | @Override
28 | public FilterResult applyWithPrevious(CommandSender sender, @NotNull ChatMessage message, ChatMessage... previousMessages) {
29 | if (plugin.getChannelManager().getMuteManager().isPlayerIgnored(sender.getName(), message.getReceiver().getName())) {
30 | return new FilterResult(message, true, Optional.of(
31 | plugin.getComponentProvider().parse(sender, plugin.messages.ignoredMessageSender,
32 | true, false, false)));
33 | }
34 | if (plugin.getChannelManager().getMuteManager().isPlayerIgnored(message.getReceiver().getName(), sender.getName())) {
35 | return new FilterResult(message, true, Optional.of(
36 | plugin.getComponentProvider().parse(sender, plugin.messages.receiverIgnoringSender,
37 | true, false, false)));
38 | }
39 |
40 | return new FilterResult(message, false, Optional.empty());
41 | }
42 |
43 | @Configuration
44 | @Getter
45 | public static class IgnoreFilterProperties extends FiltersConfig.FilterSettings {
46 | private boolean sendWarnWhenIgnored;
47 | private boolean sendWarnWhenIgnoring;
48 |
49 | public IgnoreFilterProperties() {
50 | super(true, 4, Set.of(AudienceType.PLAYER), Set.of());
51 | this.sendWarnWhenIgnored = false;
52 | this.sendWarnWhenIgnoring = true;
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/outgoing/MutedChannelFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.outgoing;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
6 | import dev.unnm3d.redischat.chat.filters.FilterResult;
7 | import dev.unnm3d.redischat.api.objects.Channel;
8 | import dev.unnm3d.redischat.api.objects.ChatMessage;
9 | import dev.unnm3d.redischat.settings.FiltersConfig;
10 | import org.bukkit.command.CommandSender;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.util.Optional;
14 |
15 |
16 | public class MutedChannelFilter extends AbstractFilter {
17 |
18 | private final RedisChat plugin;
19 |
20 | public MutedChannelFilter(RedisChat plugin, FiltersConfig.FilterSettings filterSettings) {
21 | super("muted_channel", Direction.OUTGOING, filterSettings);
22 | this.plugin = plugin;
23 | }
24 |
25 | @Override
26 | public FilterResult applyWithPrevious(CommandSender sender, @NotNull ChatMessage message, ChatMessage... previousMessages) {
27 |
28 | if (plugin.getChannelManager().getMuteManager().isMutedOnChannel(sender.getName(), message.getReceiver().getName())) {
29 | return new FilterResult(message, true, Optional.of(
30 | plugin.getComponentProvider().parse(sender,
31 | plugin.messages.muted_on_channel.replace("%channel%", message.getReceiver().getName()),
32 | true,
33 | false,
34 | false)
35 | ));
36 | }
37 |
38 | if (!plugin.getChannelManager().getRegisteredChannel(message.getReceiver().getName())
39 | .map(Channel::isPermissionEnabled).orElse(true)) {
40 | return new FilterResult(message, false);
41 | }
42 |
43 | final String permission = Permissions.CHANNEL_PREFIX.getPermission() + message.getReceiver().getName();
44 | if (!(sender.hasPermission(permission) || sender.hasPermission(permission + ".write"))) {
45 | return new FilterResult(message, true, Optional.of(
46 | plugin.getComponentProvider().parse(sender,
47 | plugin.messages.channelNoPermission.replace("%channel%", message.getReceiver().getName()),
48 | true,
49 | false,
50 | false)
51 | ));
52 | }
53 |
54 | return new FilterResult(message, false, Optional.empty());
55 |
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/outgoing/SpamFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.outgoing;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.api.objects.Channel;
6 | import dev.unnm3d.redischat.api.objects.ChatMessage;
7 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
8 | import dev.unnm3d.redischat.chat.filters.FilterResult;
9 | import dev.unnm3d.redischat.settings.FiltersConfig;
10 | import org.bukkit.command.CommandSender;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.util.Optional;
14 |
15 |
16 | public class SpamFilter extends AbstractFilter {
17 | private final RedisChat plugin;
18 |
19 | public SpamFilter(RedisChat plugin, FiltersConfig.FilterSettings filterSettings) {
20 | super("spam", Direction.OUTGOING, filterSettings);
21 | this.plugin = plugin;
22 | }
23 |
24 | @Override
25 | public FilterResult applyWithPrevious(CommandSender sender, @NotNull ChatMessage message, ChatMessage... previousMessages) {
26 | if (!message.getReceiver().isChannel()) return new FilterResult(message, false, Optional.empty());
27 |
28 | if (!sender.hasPermission(Permissions.BYPASS_RATE_LIMIT.getPermission())) {
29 | final Channel channel = plugin.getChannelManager().getChannel(message.getReceiver().getName(), null)
30 | .orElse(plugin.getChannelManager().getPublicChannel(null));
31 | if (channel != null && plugin.getDataManager().isRateLimited(sender.getName(), channel)) {
32 | return new FilterResult(message, true, Optional.of(
33 | plugin.getComponentProvider().parse(sender,
34 | plugin.messages.rate_limited,
35 | true,
36 | false,
37 | false)
38 | ));
39 | }
40 | }
41 |
42 | return new FilterResult(message, false, Optional.empty());
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/outgoing/TagFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.outgoing;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.api.objects.ChatMessage;
6 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
7 | import dev.unnm3d.redischat.chat.filters.FilterResult;
8 | import dev.unnm3d.redischat.settings.FiltersConfig;
9 | import me.clip.placeholderapi.PlaceholderAPI;
10 | import net.kyori.adventure.text.minimessage.MiniMessage;
11 | import org.bukkit.command.CommandSender;
12 | import org.jetbrains.annotations.NotNull;
13 |
14 | import java.util.Optional;
15 | import java.util.regex.Matcher;
16 |
17 |
18 | public class TagFilter extends AbstractFilter {
19 |
20 | private final RedisChat plugin;
21 |
22 | public TagFilter(RedisChat plugin, FiltersConfig.FilterSettings filterSettings) {
23 | super("tag", Direction.OUTGOING, filterSettings);
24 | this.plugin = plugin;
25 | }
26 |
27 | @Override
28 | public FilterResult applyWithPrevious(CommandSender sender, @NotNull ChatMessage chatMessage, ChatMessage... previousMessages) {
29 | if (!sender.hasPermission(Permissions.USE_DANGEROUS.getPermission())) {
30 | chatMessage.setContent(chatMessage.getContent()
31 | .replace("run_command", "copy_to_clipboard")
32 | .replace("suggest_command", "copy_to_clipboard"));
33 | }
34 |
35 | if (sender.hasPermission(Permissions.USE_FORMATTING.getPermission()))
36 | return new FilterResult(chatMessage, false);
37 |
38 | final Matcher m = PlaceholderAPI.getPlaceholderPattern().matcher(chatMessage.getContent());
39 | if (m.find()) {
40 | return new FilterResult(chatMessage, true, Optional.of(
41 | plugin.getComponentProvider().parse(sender,
42 | plugin.messages.messageContainsBadWords
43 | .replace("%words%", m.group()),
44 | true,
45 | false,
46 | false)
47 | ));
48 | }
49 |
50 | chatMessage.setContent(plugin.getComponentProvider().purgeTags(chatMessage.getContent()));
51 |
52 | if (chatMessage.getContent().trim().isEmpty()) {
53 | return new FilterResult(chatMessage, true, Optional.of(
54 | MiniMessage.miniMessage().deserialize(plugin.messages.empty_message)
55 | ));
56 | }
57 | return new FilterResult(chatMessage, false);
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/filters/outgoing/WordBlacklistFilter.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.filters.outgoing;
2 |
3 | import de.exlll.configlib.Configuration;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.api.objects.ChatMessage;
6 | import dev.unnm3d.redischat.chat.filters.AbstractFilter;
7 | import dev.unnm3d.redischat.chat.filters.FilterResult;
8 | import dev.unnm3d.redischat.settings.FiltersConfig;
9 | import lombok.Getter;
10 | import org.bukkit.command.CommandSender;
11 | import org.jetbrains.annotations.NotNull;
12 |
13 | import java.util.HashSet;
14 | import java.util.Optional;
15 | import java.util.Set;
16 | import java.util.regex.Matcher;
17 | import java.util.regex.Pattern;
18 |
19 |
20 | public class WordBlacklistFilter extends AbstractFilter {
21 | private final RedisChat plugin;
22 |
23 | public WordBlacklistFilter(RedisChat plugin, WordBlacklistFilterProperties filterSettings) {
24 | super("word_blacklist", Direction.OUTGOING, filterSettings);
25 | this.plugin = plugin;
26 | }
27 |
28 | @Override
29 | public FilterResult applyWithPrevious(CommandSender sender, @NotNull ChatMessage message, ChatMessage... previousMessages) {
30 | String sanitized = message.getContent();
31 |
32 | Set forbiddenWords = new HashSet<>();
33 | //Check for forbidden words, wrapping every blacklisted word in a regex group
34 | for (Pattern pattern : plugin.config.regex_blacklist.stream()
35 | .map(regex -> Pattern.compile("(" + regex + ")"))
36 | .toList()) {
37 | final StringBuilder sanitizedFinal = new StringBuilder();
38 | final Matcher m = pattern.matcher(sanitized);
39 | while (m.find()) {
40 | forbiddenWords.add(m.group().trim());
41 | m.appendReplacement(sanitizedFinal, filterSettings.replacement);
42 | }
43 | m.appendTail(sanitizedFinal);
44 | sanitized = sanitizedFinal.toString();
45 | }
46 |
47 | if (filterSettings.blockCensoredMessage && !forbiddenWords.isEmpty()) {
48 | return new FilterResult(message, true, Optional.of(
49 | plugin.getComponentProvider().parse(sender,
50 | plugin.messages.messageContainsBadWords
51 | .replace("%words%", String.join(",", forbiddenWords)),
52 | true,
53 | false,
54 | false)
55 | ));
56 | }
57 | //Set the sanitized message
58 | message.setContent(sanitized);
59 | return new FilterResult(message, false, Optional.empty());
60 | }
61 |
62 |
63 | @Configuration
64 | @Getter
65 | public static class WordBlacklistFilterProperties extends FiltersConfig.FilterSettings {
66 | private boolean blockCensoredMessage;
67 | private String replacement;
68 |
69 | public WordBlacklistFilterProperties() {
70 | super(true, 1, Set.of(), Set.of());
71 | this.blockCensoredMessage = true;
72 | this.replacement = "***** ";
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/listeners/ChatListenerWithPriority.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.listeners;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import lombok.Getter;
5 | import org.bukkit.event.EventHandler;
6 | import org.bukkit.event.EventPriority;
7 | import org.bukkit.event.Listener;
8 | import org.bukkit.event.player.AsyncPlayerChatEvent;
9 |
10 | @Getter
11 | public enum ChatListenerWithPriority {
12 | LOWEST(new ChatListener() {
13 | @EventHandler(priority = EventPriority.LOWEST)
14 | public void onChat(AsyncPlayerChatEvent event) {
15 | listenChat(event);
16 | }
17 | }),
18 | LOW(new ChatListener() {
19 | @EventHandler(priority = EventPriority.LOW)
20 | public void onChat(AsyncPlayerChatEvent event) {
21 | listenChat(event);
22 | }
23 | }),
24 | NORMAL(new ChatListener() {
25 | @EventHandler(priority = EventPriority.NORMAL)
26 | public void onChat(AsyncPlayerChatEvent event) {
27 | listenChat(event);
28 | }
29 | }),
30 | HIGH(new ChatListener() {
31 | @EventHandler(priority = EventPriority.HIGH)
32 | public void onChat(AsyncPlayerChatEvent event) {
33 | listenChat(event);
34 | }
35 | }),
36 | HIGHEST(new ChatListener() {
37 | @EventHandler(priority = EventPriority.HIGHEST)
38 | public void onChat(AsyncPlayerChatEvent event) {
39 | listenChat(event);
40 | }
41 | }),
42 | MONITOR(new ChatListener() {
43 | @EventHandler(priority = EventPriority.MONITOR)
44 | public void onChat(AsyncPlayerChatEvent event) {
45 | listenChat(event);
46 | }
47 | });
48 |
49 |
50 | private final Listener listener;
51 |
52 | ChatListenerWithPriority(Listener listener) {
53 | this.listener = listener;
54 | }
55 |
56 |
57 | private abstract static class ChatListener implements Listener {
58 | private final RedisChat plugin = RedisChat.getInstance();
59 |
60 | public void listenChat(AsyncPlayerChatEvent event) {
61 | if (event.isCancelled()) return;
62 | event.setCancelled(true);
63 | plugin.getChannelManager().outgoingMessage(event.getPlayer(), event.getMessage());
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/chat/listeners/UtilsListener.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.chat.listeners;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.mail.Mail;
6 | import lombok.AllArgsConstructor;
7 | import org.bukkit.event.EventHandler;
8 | import org.bukkit.event.EventPriority;
9 | import org.bukkit.event.Listener;
10 | import org.bukkit.event.player.PlayerJoinEvent;
11 |
12 | @AllArgsConstructor
13 | public class UtilsListener implements Listener {
14 | private final RedisChat plugin;
15 |
16 | @EventHandler(priority = EventPriority.HIGHEST)
17 | public void onJoinSpy(PlayerJoinEvent event) {
18 | plugin.getSpyManager().onJoin(event.getPlayer());
19 | }
20 |
21 | @EventHandler(priority = EventPriority.LOWEST)
22 | public void onJoinOthers(PlayerJoinEvent event) {
23 | plugin.getDataManager().getActivePlayerChannel(event.getPlayer().getName())
24 | .thenAccept(channelName ->
25 | plugin.getChannelManager().updateActiveChannel(event.getPlayer().getName(), channelName));
26 | //Remove chat color placeholder if player doesn't have permission to edit it
27 | final String activeChatColor = plugin.getPlaceholderManager().getPlaceholder(event.getPlayer().getName(), "chat_color")
28 | .replace("<", "").replace(">", "");
29 | if (!activeChatColor.isEmpty() &&
30 | !event.getPlayer().hasPermission(Permissions.CHAT_COLOR.getPermission() + "." + activeChatColor)) {
31 | plugin.getPlaceholderManager().removePlayerPlaceholder(event.getPlayer().getName(), "chat_color");
32 | }
33 |
34 | if (!plugin.config.enableMails) return;
35 | if (!plugin.config.remindMailOnJoin) return;
36 | if (plugin.getPlayerListManager().getPlayerList(event.getPlayer()).contains(event.getPlayer().getName()))
37 | return;
38 |
39 | //Send mail reminder
40 | plugin.getMailGUIManager().getPublicMails(event.getPlayer().getName())
41 | .thenAccept(mails -> {
42 | if (mails.isEmpty()) return;
43 | for (Mail mail : mails) {
44 | if (mail.isRead()) continue;
45 | plugin.messages.sendMessage(event.getPlayer(), plugin.messages.mailReceived
46 | .replace("%sender%", mail.getSender())
47 | .replace("%title%", mail.getTitle()));
48 | }
49 | });
50 |
51 | //Send mail reminder
52 | plugin.getMailGUIManager().getPrivateMails(event.getPlayer().getName())
53 | .thenAccept(mails -> {
54 | if (mails.isEmpty()) return;
55 | for (Mail mail : mails) {
56 | if (mail.isRead()) continue;
57 | plugin.messages.sendMessage(event.getPlayer(), plugin.messages.mailReceived
58 | .replace("%sender%", mail.getSender())
59 | .replace("%title%", mail.getTitle()));
60 | }
61 | });
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/AnnounceCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import com.google.common.base.Strings;
4 | import dev.jorel.commandapi.CommandAPICommand;
5 | import dev.jorel.commandapi.arguments.ArgumentSuggestions;
6 | import dev.jorel.commandapi.arguments.MultiLiteralArgument;
7 | import dev.jorel.commandapi.arguments.StringArgument;
8 | import dev.unnm3d.redischat.Permissions;
9 | import dev.unnm3d.redischat.RedisChat;
10 | import dev.unnm3d.redischat.settings.Config;
11 | import dev.unnm3d.redischat.task.AnnouncerManager;
12 | import dev.unnm3d.redischat.task.AnnouncerTask;
13 | import lombok.AllArgsConstructor;
14 |
15 | @AllArgsConstructor
16 | public class AnnounceCommand {
17 | private final RedisChat plugin;
18 | private final AnnouncerManager announcerManager;
19 |
20 | public CommandAPICommand getCommand() {
21 |
22 | return new CommandAPICommand("announcer")
23 | .withAliases(plugin.config.getCommandAliases("announcer"))
24 | .withPermission(Permissions.ANNOUNCER.getPermission())
25 | .withArguments(new MultiLiteralArgument("action", "stop", "start"))
26 | .withArguments(new StringArgument("announcementName")
27 | .replaceSuggestions(ArgumentSuggestions.strings(commandSenderSuggestionInfo ->
28 | plugin.config.announcer.stream()
29 | .map(Config.Announcement::announcementName)
30 | .filter(announceName -> announceName.startsWith(commandSenderSuggestionInfo.currentArg()))
31 | .toArray(String[]::new))
32 | ))
33 | .executes((sender, args) -> {
34 | final String announceName = Strings.nullToEmpty((String) args.get(1));
35 | switch (Strings.nullToEmpty((String) args.get(0))) {
36 | case "stop" -> {
37 | if (announcerManager.cancelAnnounce(announceName) == null) {
38 | plugin.messages.sendMessage(sender, plugin.messages.announce_not_found.replace("%name%", announceName));
39 | return;
40 | }
41 | plugin.messages.sendMessage(sender, plugin.messages.action_completed_successfully);
42 | }
43 | case "start" -> {
44 | final AnnouncerTask at = announcerManager.startAnnounce(announceName);
45 | if (at == null) {
46 | plugin.messages.sendMessage(sender, plugin.messages.announce_not_found.replace("%name%", announceName));
47 | return;
48 | }
49 | plugin.messages.sendMessage(sender, plugin.messages.action_completed_successfully);
50 | at.run();
51 | }
52 | default -> plugin.messages.sendMessage(sender, plugin.messages.missing_arguments);
53 | }
54 | });
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/BroadcastCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import com.github.Anon8281.universalScheduler.UniversalRunnable;
4 | import dev.jorel.commandapi.CommandAPICommand;
5 | import dev.jorel.commandapi.arguments.ArgumentSuggestions;
6 | import dev.jorel.commandapi.arguments.GreedyStringArgument;
7 | import dev.jorel.commandapi.arguments.StringArgument;
8 | import dev.unnm3d.redischat.RedisChat;
9 | import dev.unnm3d.redischat.api.objects.Channel;
10 | import lombok.AllArgsConstructor;
11 | import net.kyori.adventure.text.Component;
12 | import net.kyori.adventure.text.minimessage.MiniMessage;
13 |
14 | import java.util.Optional;
15 |
16 | @AllArgsConstructor
17 | public class BroadcastCommand {
18 | private final RedisChat plugin;
19 |
20 |
21 | public CommandAPICommand getBroadcastCommand() {
22 | return new CommandAPICommand("rbroadcast")
23 | .withAliases(plugin.config.getCommandAliases("rbroadcast"))
24 | .withPermission("redischat.broadcast")
25 | .withArguments(new StringArgument("channel")
26 | .replaceSuggestions(ArgumentSuggestions.strings(getChannelsWithPublic())))
27 | .withArguments(new GreedyStringArgument("message"))
28 | .executes((sender, args) -> {
29 | final Optional channel = plugin.getChannelManager().getChannel((String) args.get(0), sender);
30 | final String message = (String) args.get(1);
31 | if (message == null) return;
32 | if (message.isEmpty()) return;
33 | if (channel.isEmpty()) {
34 | plugin.messages.sendMessage(sender, plugin.messages.channelNotFound);
35 | return;
36 | }
37 | new UniversalRunnable() {
38 | @Override
39 | public void run() {
40 | final Component component = plugin.getComponentProvider().parse(null,
41 | plugin.config.broadcast_format.replace("{message}", message),
42 | true, false, false);
43 | plugin.getChannelManager().broadcastMessage(channel.get(), MiniMessage.miniMessage().serialize(component));
44 | }
45 | }.runTaskAsynchronously(plugin);
46 | });
47 | }
48 |
49 | public CommandAPICommand getBroadcastRawCommand() {
50 | return new CommandAPICommand("rbroadcastraw")
51 | .withAliases(plugin.config.getCommandAliases("rbroadcastraw"))
52 | .withPermission("redischat.broadcastraw")
53 | .withArguments(new StringArgument("channel")
54 | .replaceSuggestions(ArgumentSuggestions.strings(getChannelsWithPublic())))
55 | .withArguments(new GreedyStringArgument("message"))
56 | .executes((sender, args) -> {
57 | final Optional channel = plugin.getChannelManager().getChannel((String) args.get(0), sender);
58 | final String message = (String) args.get(1);
59 | if (message == null) return;
60 | if (message.isEmpty()) return;
61 | if (channel.isEmpty()) {
62 | plugin.messages.sendMessage(sender, plugin.messages.channelNotFound);
63 | return;
64 | }
65 | new UniversalRunnable() {
66 | @Override
67 | public void run() {
68 | final Component component = plugin.getComponentProvider().parse(null,
69 | message,
70 | true, false, false);
71 |
72 | plugin.getChannelManager().broadcastMessage(channel.get(), MiniMessage.miniMessage().serialize(component));
73 | }
74 | }.runTaskAsynchronously(plugin);
75 | });
76 | }
77 |
78 | private String[] getChannelsWithPublic() {
79 | final String[] array = new String[plugin.getChannelManager().getRegisteredChannels().size() + 1];
80 | array[0] = "public";
81 | int index = 1;
82 |
83 | for (String s : plugin.getChannelManager().getRegisteredChannels().keySet()) {
84 | array[index] = s;
85 | index++;
86 | }
87 | return array;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/ChatAsCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import dev.jorel.commandapi.CommandAPICommand;
4 | import dev.jorel.commandapi.arguments.GreedyStringArgument;
5 | import dev.jorel.commandapi.arguments.PlayerArgument;
6 | import dev.jorel.commandapi.arguments.StringArgument;
7 | import dev.unnm3d.redischat.RedisChat;
8 | import lombok.AllArgsConstructor;
9 | import org.bukkit.entity.Player;
10 |
11 | @AllArgsConstructor
12 | public class ChatAsCommand {
13 | private RedisChat plugin;
14 |
15 | public CommandAPICommand getCommand() {
16 | return new CommandAPICommand("chatas")
17 | .withPermission("redischat.chatas")
18 | .withArguments(
19 | new PlayerArgument("player"),
20 | new StringArgument("channel"),
21 | new GreedyStringArgument("message"))
22 | .executes((sender, args) -> {
23 | final Player target = (Player) args.get(0);
24 | if (target == null) return;
25 | final String message = (String) args.get(2);
26 | if (message == null) return;
27 |
28 | RedisChat.getScheduler().runTaskAsynchronously(() ->
29 | plugin.getChannelManager().outgoingMessage(target, message));
30 |
31 | });
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/ChatColorCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.chat.ChatColorGUI;
6 | import lombok.AllArgsConstructor;
7 | import net.kyori.adventure.text.format.NamedTextColor;
8 | import org.bukkit.command.Command;
9 | import org.bukkit.command.CommandExecutor;
10 | import org.bukkit.command.CommandSender;
11 | import org.bukkit.command.TabCompleter;
12 | import org.bukkit.entity.Player;
13 | import org.jetbrains.annotations.NotNull;
14 | import xyz.xenondevs.invui.window.Window;
15 |
16 | import java.util.ArrayList;
17 | import java.util.List;
18 | import java.util.Set;
19 |
20 | @AllArgsConstructor
21 | public class ChatColorCommand implements CommandExecutor, TabCompleter {
22 | private final RedisChat plugin;
23 |
24 | @Override
25 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
26 | if (!(sender instanceof Player player)) return true;
27 | if (plugin.config.enableChatColorGUI) {
28 | Window.single()
29 | .setTitle(plugin.guiSettings.chatColorGUITitle)
30 | .setGui(new ChatColorGUI(plugin))
31 | .open(player);
32 | return true;
33 | }
34 |
35 | if (args.length == 0) {
36 | plugin.messages.sendMessage(player, plugin.messages.missing_arguments);
37 | return true;
38 | }
39 | if(args[0].equalsIgnoreCase("reset")){
40 | plugin.getPlaceholderManager().removePlayerPlaceholder(player.getName(), "chat_color");
41 | plugin.messages.sendMessage(player, plugin.messages.color_set);
42 | return true;
43 | }
44 | if (!args[0].matches("#[0-9A-Fa-f]{6}")) {
45 | if (!getAvailableColors().contains(args[0])) {
46 | plugin.messages.sendMessage(player, plugin.messages.invalid_color);
47 | return true;
48 | } else if (!player.hasPermission(Permissions.CHAT_COLOR.getPermission() + "." + args[0].toLowerCase())) {
49 | plugin.messages.sendMessage(player, plugin.messages.noPermission);
50 | return true;
51 | }
52 | } else if (!player.hasPermission(Permissions.CHAT_COLOR.getPermission() + ".hex")) {
53 | plugin.messages.sendMessage(player, plugin.messages.noPermission);
54 | return true;
55 | }
56 |
57 | plugin.getPlaceholderManager().addPlayerPlaceholder(player.getName(), "chat_color", "<" + args[0] + ">");
58 | plugin.messages.sendMessage(player, plugin.messages.color_set);
59 | return true;
60 | }
61 |
62 | @Override
63 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
64 | if (!sender.hasPermission(Permissions.CHAT_COLOR.getPermission()) || plugin.config.enableChatColorGUI)
65 | return List.of();
66 | final List colors = new ArrayList<>(getAvailableColors());
67 | colors.add("#RRGGBB");
68 | colors.add("reset");
69 | return colors.stream().filter(s -> s.toLowerCase().startsWith(args[args.length - 1].toLowerCase())).toList();
70 | }
71 |
72 | private Set getAvailableColors() {
73 | return NamedTextColor.NAMES.keys();
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/ClearChatCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import com.github.Anon8281.universalScheduler.UniversalRunnable;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.api.objects.ChatMessage;
6 | import lombok.AllArgsConstructor;
7 | import org.bukkit.command.Command;
8 | import org.bukkit.command.CommandExecutor;
9 | import org.bukkit.command.CommandSender;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | @AllArgsConstructor
13 | public class ClearChatCommand implements CommandExecutor {
14 | private final RedisChat plugin;
15 |
16 | @Override
17 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
18 | new UniversalRunnable() {
19 | @Override
20 | public void run() {
21 | plugin.getDataManager().sendChatMessage(
22 | new ChatMessage(RedisChat.getInstance().config.clear_chat_message));
23 | }
24 | }.runTaskAsynchronously(plugin);
25 | return true;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/IgnoreCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import lombok.AllArgsConstructor;
6 | import org.bukkit.command.Command;
7 | import org.bukkit.command.CommandExecutor;
8 | import org.bukkit.command.CommandSender;
9 | import org.bukkit.command.TabCompleter;
10 | import org.bukkit.entity.Player;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import java.util.ArrayList;
15 | import java.util.List;
16 |
17 | @AllArgsConstructor
18 | public class IgnoreCommand implements CommandExecutor, TabCompleter {
19 | private final RedisChat plugin;
20 |
21 | @Override
22 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
23 | if (!(sender instanceof Player)) return true;
24 | if (args.length == 0) {
25 | plugin.messages.sendMessage(sender, plugin.messages.missing_arguments);
26 | return true;
27 | }
28 |
29 | if (label.equalsIgnoreCase("ignore") && plugin.getChannelManager().getMuteManager()
30 | .isWhitelistEnabledPlayer(sender.getName())) {
31 | plugin.messages.sendMessage(sender, plugin.messages.ignore_whitelist_enabled);
32 | return true;
33 | } else if (label.equalsIgnoreCase("allowmsg") && !plugin.getChannelManager().getMuteManager()
34 | .isWhitelistEnabledPlayer(sender.getName())) {
35 | plugin.messages.sendMessage(sender, plugin.messages.ignore_whitelist_disabled);
36 | return true;
37 | }
38 |
39 | if (args[0].equalsIgnoreCase(sender.getName())) {
40 | plugin.getComponentProvider().sendMessage(sender, plugin.getComponentProvider().parse(sender, plugin.messages.cannot_ignore_yourself,
41 | true, false, false));
42 | return true;
43 | }
44 |
45 | if (args[0].equalsIgnoreCase("list")) {
46 | final String stringList = String.join(", ", plugin.getChannelManager().getMuteManager().getIgnoreList(sender.getName()));
47 | plugin.getComponentProvider().sendMessage(sender,
48 | plugin.getComponentProvider().parse(null,
49 | plugin.messages.ignoring_list.replace("%list%", stringList), true, false, false));
50 |
51 | return true;
52 | }
53 |
54 | //Apply ignore
55 | final String message = plugin.getChannelManager().getMuteManager().toggleIgnorePlayer(sender.getName(), args[0]) ?
56 | plugin.messages.ignoring_player.replace("%player%", args[0]) :
57 | plugin.messages.not_ignoring_player.replace("%player%", args[0]);
58 |
59 | plugin.getComponentProvider().sendMessage(sender, plugin.getComponentProvider().parse(null, message, true, false, false));
60 |
61 | return true;
62 | }
63 |
64 | @Nullable
65 | @Override
66 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
67 | if (!sender.hasPermission(Permissions.IGNORE.getPermission()) || args.length > 1) {
68 | return List.of();
69 | }
70 |
71 | List suggestions = new ArrayList<>();
72 | suggestions.add("list");
73 |
74 | if (!plugin.config.allPlayersString.isEmpty()) {
75 | suggestions.add(plugin.config.allPlayersString);
76 | }
77 |
78 | String input = args.length > 0 ? args[0].toLowerCase() : "";
79 | suggestions.addAll(plugin.getPlayerListManager().getPlayerList(sender)
80 | .stream()
81 | .filter(name -> name.toLowerCase().startsWith(input))
82 | .toList());
83 |
84 | return suggestions;
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/IgnoreWhitelistCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import dev.jorel.commandapi.CommandAPICommand;
4 | import dev.jorel.commandapi.arguments.PlayerArgument;
5 | import dev.unnm3d.redischat.Permissions;
6 | import dev.unnm3d.redischat.RedisChat;
7 | import lombok.AllArgsConstructor;
8 | import org.bukkit.entity.Player;
9 |
10 |
11 | @AllArgsConstructor
12 | public class IgnoreWhitelistCommand {
13 | private final RedisChat plugin;
14 |
15 | public CommandAPICommand getCommand() {
16 | return new CommandAPICommand("ignorewhitelist")
17 | .withPermission(Permissions.IGNORE_WHITELIST.getPermission())
18 | .withOptionalArguments(new PlayerArgument("player"))
19 | .executesPlayer((sender, args) -> {
20 | //Get the target player name or sender name
21 | final String targetName = args.getOptional("player")
22 | .map(o -> ((Player) o).getName())
23 | .orElseGet(sender::getName);
24 | if (!sender.hasPermission(Permissions.IGNORE_WHITELIST.getPermission() + ".other") &&
25 | !sender.getName().equals(targetName)) {
26 | plugin.messages.sendMessage(sender, plugin.messages.noPermission);
27 | return;
28 | }
29 | if (plugin.getChannelManager().getMuteManager().isWhitelistEnabledPlayer(targetName)) {
30 | plugin.getChannelManager().getMuteManager().setWhitelistEnabledPlayer(targetName, false);
31 | plugin.messages.sendMessage(sender, plugin.messages.ignore_whitelist_disabled);
32 | } else {
33 | plugin.getChannelManager().getMuteManager().setWhitelistEnabledPlayer(targetName, true);
34 | plugin.messages.sendMessage(sender, plugin.messages.ignore_whitelist_enabled);
35 | }
36 | });
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/RedisChatCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import net.william278.uniform.paper.LegacyPaperCommand;
4 |
5 | public interface RedisChatCommand {
6 | LegacyPaperCommand getCommand();
7 | }
8 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/SetItemCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import lombok.AllArgsConstructor;
5 | import org.bukkit.command.Command;
6 | import org.bukkit.command.CommandExecutor;
7 | import org.bukkit.command.CommandSender;
8 | import org.bukkit.command.TabCompleter;
9 | import org.bukkit.entity.Player;
10 | import org.bukkit.inventory.ItemStack;
11 | import org.jetbrains.annotations.NotNull;
12 | import org.jetbrains.annotations.Nullable;
13 |
14 | import java.lang.reflect.Field;
15 | import java.util.Arrays;
16 | import java.util.List;
17 |
18 | @AllArgsConstructor
19 | public class SetItemCommand implements CommandExecutor, TabCompleter {
20 | private RedisChat plugin;
21 |
22 | @Override
23 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
24 |
25 | if (!(sender instanceof Player player)) {
26 | plugin.getComponentProvider().sendMessage(sender, plugin.messages.noConsole);
27 | return true;
28 | }
29 |
30 | if (args.length == 0) {
31 | plugin.getComponentProvider().sendMessage(sender, plugin.messages.missing_arguments);
32 | return true;
33 | }
34 | plugin.guiSettings.setIngredient(args[0], player.getInventory().getItemInMainHand());
35 | plugin.saveGuiSettings();
36 | plugin.getComponentProvider().sendMessage(sender, plugin.messages.itemSet);
37 |
38 | return true;
39 | }
40 |
41 | @Nullable
42 | @Override
43 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
44 | if (args.length == 1) {
45 | return Arrays.stream(plugin.guiSettings.getClass().getDeclaredFields())
46 | .filter(field -> field.getType().equals(ItemStack.class))
47 | .map(Field::getName)
48 | .filter(name -> name.startsWith(args[0]))
49 | .toList();
50 | }
51 | return List.of();
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/SetPlaceholderCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import lombok.AllArgsConstructor;
5 | import org.bukkit.command.Command;
6 | import org.bukkit.command.CommandExecutor;
7 | import org.bukkit.command.CommandSender;
8 | import org.bukkit.command.TabCompleter;
9 | import org.jetbrains.annotations.NotNull;
10 | import org.jetbrains.annotations.Nullable;
11 |
12 | import java.util.List;
13 |
14 | @AllArgsConstructor
15 | public class SetPlaceholderCommand implements CommandExecutor, TabCompleter {
16 | private final RedisChat plugin;
17 |
18 | @Override
19 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
20 | if (args.length < 3) {
21 | plugin.messages.sendMessage(sender, plugin.messages.missing_arguments);
22 | return true;
23 | }
24 | if (args[2].equals("delete")) {
25 | plugin.getPlaceholderManager().removePlayerPlaceholder(args[0], args[1]);
26 | plugin.messages.sendMessage(sender, plugin.messages.placeholder_deleted
27 | .replace("%placeholder%", args[1])
28 | .replace("%player%", args[0]));
29 | return true;
30 | }
31 |
32 | plugin.getPlaceholderManager().addPlayerPlaceholder(args[0], args[1], args[2]);
33 |
34 | plugin.messages.sendMessage(sender, plugin.messages.placeholder_set
35 | .replace("%player%", args[0])
36 | .replace("%placeholder%", args[1])
37 | .replace("%value%", args[2].replace("<", "\\<"))
38 | );
39 | return true;
40 | }
41 |
42 | @Nullable
43 | @Override
44 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
45 | if (args.length == 1) {
46 | return plugin.getPlayerListManager().getPlayerList(sender)
47 | .stream().filter(s ->
48 | s.toLowerCase().startsWith(args[args.length - 1].toLowerCase())
49 | ).toList();
50 | } else if (args.length == 2 && args[args.length - 1].isEmpty()) {
51 | return List.of("chat_color", "placeholder");
52 | } else if (args.length == 3 && args[args.length - 1].isEmpty()) {
53 | return List.of("value");
54 | }
55 | return List.of();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/TalkOnCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import dev.unnm3d.redischat.api.objects.ChannelAudience;
6 | import lombok.AllArgsConstructor;
7 | import org.bukkit.command.Command;
8 | import org.bukkit.command.CommandExecutor;
9 | import org.bukkit.command.CommandSender;
10 | import org.bukkit.command.TabCompleter;
11 | import org.bukkit.entity.Player;
12 | import org.jetbrains.annotations.NotNull;
13 | import org.jetbrains.annotations.Nullable;
14 |
15 | import java.util.List;
16 | import java.util.stream.Collectors;
17 | import java.util.stream.Stream;
18 |
19 | @AllArgsConstructor
20 | public class TalkOnCommand implements CommandExecutor, TabCompleter {
21 | private RedisChat plugin;
22 |
23 | @Override
24 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
25 |
26 | if (!(sender instanceof Player)) {
27 | plugin.getComponentProvider().sendMessage(sender, plugin.messages.noConsole);
28 | return true;
29 | }
30 |
31 | if (args.length == 0) {
32 | plugin.getComponentProvider().sendMessage(sender, plugin.messages.missing_arguments);
33 | return true;
34 | }
35 |
36 | if (getAvailableChannelNames(sender).noneMatch(name -> name.equalsIgnoreCase(args[0])) && !args[0].equalsIgnoreCase("public")) {
37 | plugin.getComponentProvider().sendMessage(sender, plugin.messages.channelNotFound);
38 | return true;
39 | }
40 |
41 | plugin.getChannelManager().setActiveChannel(sender.getName(), args[0].equalsIgnoreCase("public") ? null : args[0]);
42 | plugin.messages.sendMessage(sender, plugin.messages.channelTalk
43 | .replace("%channel%", args[0])
44 | );
45 |
46 | return true;
47 | }
48 |
49 | @Nullable
50 | @Override
51 | public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) {
52 | if (args.length == 1) {
53 | return getAvailableChannelNames(sender)
54 | .filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase()))
55 | .collect(Collectors.collectingAndThen(Collectors.toList(), list -> {
56 | if ("public".startsWith(args[0].toLowerCase())) list.add("public");
57 | return list;
58 | }));
59 | }
60 | return List.of();
61 | }
62 |
63 | public Stream getAvailableChannelNames(CommandSender sender) {
64 | return plugin.getChannelManager().getAllChannels().stream()
65 | .filter(channel -> {
66 | if (channel.isShownByDefault()) {
67 | return sender.isOp() || !sender.hasPermission(Permissions.CHANNEL_HIDE_PREFIX.getPermission() + channel.getName());
68 | }
69 | return sender.hasPermission(Permissions.CHANNEL_SHOW_PREFIX.getPermission() + channel.getName());
70 |
71 | })
72 | .map(ChannelAudience::getName);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/UniformMsgCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import com.mojang.brigadier.arguments.StringArgumentType;
4 | import dev.unnm3d.redischat.Permissions;
5 | import dev.unnm3d.redischat.RedisChat;
6 | import lombok.AllArgsConstructor;
7 | import net.william278.uniform.Permission;
8 | import net.william278.uniform.paper.LegacyPaperCommand;
9 |
10 | import java.util.List;
11 |
12 | @AllArgsConstructor
13 | public class UniformMsgCommand implements RedisChatCommand {
14 |
15 | @Override
16 | public LegacyPaperCommand getCommand() {
17 | RedisChat plugin = RedisChat.getInstance();
18 | return LegacyPaperCommand.builder("msg")
19 | .setDescription("Send a message to another player")
20 | .setAliases(plugin.config.commandAliases.getOrDefault("msg", List.of()))
21 | .setPermission(new Permission(Permissions.MESSAGE.getPermission(), Permission.Default.TRUE))
22 | .addArgument("target", StringArgumentType.word(), (context, builder) -> {
23 | RedisChat.getInstance().getPlayerListManager().getPlayerList(context.getSource())
24 | .stream().filter(playerName -> playerName.toLowerCase().startsWith(builder.getRemainingLowerCase()))
25 | .forEach(builder::suggest);
26 | return builder.buildFuture();
27 | })
28 | .execute(commandContext -> RedisChat.getScheduler().runTaskAsynchronously(() -> {
29 | String target = commandContext.getArgument("target", String.class);
30 | String content = commandContext.getArgument("content", String.class);
31 | if (content.isEmpty()) {
32 | plugin.messages.sendMessage(commandContext.getSource(), plugin.messages.missing_arguments);
33 | return;
34 | }
35 | if (target.isEmpty()) {
36 | plugin.messages.sendMessage(commandContext.getSource(), plugin.messages.missing_arguments);
37 | return;
38 | }
39 |
40 | if (!plugin.config.debug)
41 | if (target.equalsIgnoreCase(commandContext.getSource().getName())) {
42 | plugin.messages.sendMessage(commandContext.getSource(), plugin.messages.cannot_message_yourself);
43 | return;
44 | }
45 |
46 | if (!plugin.getPlayerListManager().getPlayerList(commandContext.getSource()).contains(target)) {
47 | plugin.messages.sendMessage(commandContext.getSource(),
48 | plugin.messages.player_not_online.replace("%player%", target));
49 | return;
50 | }
51 |
52 | plugin.getChannelManager().outgoingPrivateMessage(commandContext.getSource(), target, content);
53 |
54 | //Set reply name for /reply
55 | plugin.getDataManager().setReplyName(target, commandContext.getSource().getName());
56 |
57 | }), "target")
58 | .build();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/commands/UniformReplyCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.commands;
2 |
3 | import com.mojang.brigadier.arguments.StringArgumentType;
4 | import dev.unnm3d.redischat.Permissions;
5 | import dev.unnm3d.redischat.RedisChat;
6 | import lombok.AllArgsConstructor;
7 | import net.william278.uniform.BaseCommand;
8 | import net.william278.uniform.Permission;
9 | import net.william278.uniform.paper.LegacyPaperCommand;
10 | import org.bukkit.command.CommandSender;
11 |
12 | import java.util.List;
13 |
14 | @AllArgsConstructor
15 | public class UniformReplyCommand implements RedisChatCommand {
16 |
17 | @Override
18 | public LegacyPaperCommand getCommand() {
19 | RedisChat plugin = RedisChat.getInstance();
20 | return LegacyPaperCommand.builder("reply")
21 | .setAliases(plugin.config.commandAliases.getOrDefault("reply", List.of()))
22 | .setPermission(new Permission(Permissions.MESSAGE.getPermission(), Permission.Default.TRUE))
23 | .setDescription("Send a message to another player")
24 | .addArgument("content", StringArgumentType.greedyString(),
25 | (commandContext, builder) -> {
26 | if (builder.getRemaining().isEmpty()) {
27 | builder.suggest(plugin.messages.replySuggestion);
28 | }
29 | return builder.buildFuture();
30 | })
31 | .execute(commandContext -> RedisChat.getScheduler().runTaskAsynchronously(() -> {
32 | CommandSender sender = commandContext.getSource();
33 | plugin.getDataManager().getReplyName(sender.getName())
34 | .thenAcceptAsync(receiverOpt -> {
35 | if (receiverOpt.isEmpty()) {
36 | plugin.getComponentProvider().sendMessage(sender, plugin.messages.no_reply_found);
37 | return;
38 | }
39 |
40 | String receiverName = receiverOpt.get();
41 | if (!plugin.getPlayerListManager().getPlayerList(sender).contains(receiverName)) {
42 | plugin.getComponentProvider().sendMessage(sender,
43 | plugin.messages.reply_not_online.replace("%player%", receiverName));
44 | return;
45 | }
46 |
47 | String content = commandContext.getArgument("content", String.class);
48 | plugin.getChannelManager().outgoingPrivateMessage(sender, receiverName, content);
49 |
50 | plugin.getDataManager().setReplyName(receiverName, sender.getName());
51 |
52 | }, plugin.getExecutorService());
53 | }), "content")
54 | .build();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/datamanagers/DataKey.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.datamanagers;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 |
5 | public enum DataKey {
6 | CHAT_CHANNEL("rchat:chat"),
7 | GLOBAL_CHANNEL("rchat:g_chat"),
8 | CHANNEL_UPDATE("rchat:ch_update"),
9 | REJOIN_CHANNEL("rchat:rejoin"),
10 | PLAYERLIST("rchat:playerlist"),
11 | MAIL_UPDATE_CHANNEL("rchat:mail_update"),
12 | PLAYER_ACTIVE_CHANNEL_PREFIX("rchat:ach_"),
13 | PLAYER_ACTIVE_CHANNEL_UPDATE("rchat:achup"),
14 | CHANNELS("rchat:ch"),
15 | ACTIVE_CHANNEL_ID("!activech"),
16 | IGNORE_PREFIX("rchat:ignore_"),
17 | MUTED_ENTITIES("rchat:muted"),
18 | RATE_LIMIT_PREFIX("rchat:ratelimit_"),
19 | REPLY("rchat:reply"),
20 | PLAYER_PLACEHOLDERS("rchat:p_ph"),
21 | INVSHARE_ITEM("rchat:item"),
22 | INVSHARE_INVENTORY("rchat:inventory"),
23 | INVSHARE_ENDERCHEST("rchat:enderchest"),
24 | SPYING_LIST("rchat:spying"),
25 | PRIVATE_MAIL_PREFIX("rmail:"),
26 | PUBLIC_MAIL("rmail:public"),
27 | MUTED_UPDATE("rchat:m_update"),
28 | WHITELIST_ENABLED_PLAYERS("rchat:wl_enabled"),
29 | WHITELIST_ENABLED_UPDATE("rchat:wl_enabled_update"),
30 | READ_MAIL_MAP("rchat:read_mails:"),
31 | DELETE_TAG("§del§"),
32 | ;
33 |
34 | private final String keyName;
35 |
36 |
37 | /**
38 | * @param keyName the name of the key
39 | */
40 | DataKey(final String keyName) {
41 | this.keyName = keyName;
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | return RedisChat.getInstance().config.clusterId + keyName;
47 | }
48 |
49 | public String withoutCluster() {
50 | return keyName;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/datamanagers/redistools/RedisAbstract.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.datamanagers.redistools;
2 |
3 | import io.lettuce.core.RedisClient;
4 | import io.lettuce.core.TransactionResult;
5 | import io.lettuce.core.api.StatefulRedisConnection;
6 | import io.lettuce.core.api.async.RedisAsyncCommands;
7 | import io.lettuce.core.api.sync.RedisCommands;
8 | import io.lettuce.core.pubsub.RedisPubSubListener;
9 | import io.lettuce.core.pubsub.StatefulRedisPubSubConnection;
10 | import org.bukkit.Bukkit;
11 |
12 | import java.util.List;
13 | import java.util.Optional;
14 | import java.util.concurrent.CompletionStage;
15 | import java.util.concurrent.ConcurrentHashMap;
16 | import java.util.function.Consumer;
17 | import java.util.function.Function;
18 |
19 |
20 | public abstract class RedisAbstract {
21 | private final RoundRobinConnectionPool roundRobinConnectionPool;
22 | private final ConcurrentHashMap> pubSubConnections;
23 | protected RedisClient lettuceRedisClient;
24 |
25 | public RedisAbstract(RedisClient lettuceRedisClient, int poolSize) {
26 | this.lettuceRedisClient = lettuceRedisClient;
27 | this.roundRobinConnectionPool = new RoundRobinConnectionPool<>(lettuceRedisClient::connect, poolSize);
28 | this.pubSubConnections = new ConcurrentHashMap<>();
29 | }
30 |
31 | public abstract void receiveMessage(String channel, String message);
32 |
33 | protected void registerSub(String... listenedChannels) {
34 | if (listenedChannels.length == 0) {
35 | return;
36 | }
37 | final StatefulRedisPubSubConnection pubSubConnection = lettuceRedisClient.connectPubSub();
38 | pubSubConnections.put(listenedChannels, pubSubConnection);
39 | pubSubConnection.addListener(new RedisPubSubListener<>() {
40 | @Override
41 | public void message(String channel, String message) {
42 | receiveMessage(channel, message);
43 | }
44 |
45 | @Override
46 | public void message(String pattern, String channel, String message) {
47 | }
48 |
49 | @Override
50 | public void subscribed(String channel, long count) {
51 | }
52 |
53 | @Override
54 | public void psubscribed(String pattern, long count) {
55 | }
56 |
57 | @Override
58 | public void unsubscribed(String channel, long count) {
59 | }
60 |
61 | @Override
62 | public void punsubscribed(String pattern, long count) {
63 | }
64 | });
65 | pubSubConnection.async().subscribe(listenedChannels)
66 | .exceptionally(throwable -> {
67 | throwable.printStackTrace();
68 | return null;
69 | });
70 | }
71 |
72 | public CompletionStage getConnectionAsync(Function, CompletionStage> redisCallBack) {
73 | return redisCallBack.apply(roundRobinConnectionPool.get().async());
74 | }
75 |
76 | public CompletionStage getConnectionPipeline(Function, CompletionStage> redisCallBack) {
77 | StatefulRedisConnection connection = roundRobinConnectionPool.get();
78 | connection.setAutoFlushCommands(false);
79 | CompletionStage completionStage = redisCallBack.apply(connection.async());
80 | connection.flushCommands();
81 | connection.setAutoFlushCommands(true);
82 | return completionStage;
83 | }
84 |
85 | public Optional> executeTransaction(Consumer> redisCommandsConsumer) {
86 | final RedisCommands syncCommands = roundRobinConnectionPool.get().sync();
87 | syncCommands.multi();
88 | redisCommandsConsumer.accept(syncCommands);
89 | final TransactionResult transactionResult = syncCommands.exec();
90 | return Optional.ofNullable(transactionResult.wasDiscarded() ? null : transactionResult.stream().toList());
91 | }
92 |
93 | public void close() {
94 | pubSubConnections.values().forEach(StatefulRedisPubSubConnection::close);
95 | Bukkit.getLogger().info("Closing pubsub connection");
96 | lettuceRedisClient.shutdown();
97 | Bukkit.getLogger().info("Lettuce shutdown connection");
98 | }
99 |
100 |
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/datamanagers/redistools/RoundRobinConnectionPool.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.datamanagers.redistools;
2 |
3 |
4 | import io.lettuce.core.api.StatefulRedisConnection;
5 |
6 | import java.util.concurrent.atomic.AtomicInteger;
7 | import java.util.function.Supplier;
8 |
9 | public class RoundRobinConnectionPool {
10 | private final AtomicInteger next = new AtomicInteger(0);
11 | private final StatefulRedisConnection[] elements;
12 | private final Supplier> statefulRedisConnectionSupplier;
13 |
14 | @SuppressWarnings("unchecked")
15 | public RoundRobinConnectionPool(Supplier> statefulRedisConnectionSupplier, int poolSize) {
16 | this.statefulRedisConnectionSupplier = statefulRedisConnectionSupplier;
17 | this.elements = new StatefulRedisConnection[poolSize];
18 | for (int i = 0; i < poolSize; i++) {
19 | elements[i] = statefulRedisConnectionSupplier.get();
20 | }
21 | }
22 |
23 | public StatefulRedisConnection get() {
24 | int index = next.getAndIncrement() % elements.length;
25 | StatefulRedisConnection connection = elements[index];
26 | if (connection != null)
27 | if (connection.isOpen())
28 | if (connection.isMulti()) {
29 | return get();
30 | } else
31 | return connection;
32 |
33 | connection = statefulRedisConnectionSupplier.get();
34 | elements[index] = connection;
35 | return connection;
36 | }
37 |
38 | }
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/datamanagers/sqlmanagers/MySQLDataManager.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.datamanagers.sqlmanagers;
2 |
3 | import com.zaxxer.hikari.HikariDataSource;
4 | import dev.unnm3d.redischat.RedisChat;
5 |
6 | import java.sql.Connection;
7 | import java.sql.SQLException;
8 | import java.sql.Statement;
9 | import java.util.Map;
10 | import java.util.Properties;
11 |
12 | public class MySQLDataManager extends SQLDataManager {
13 | private HikariDataSource dataSource;
14 |
15 | public MySQLDataManager(RedisChat plugin) {
16 | super(plugin);
17 | initialize();
18 | }
19 |
20 | @Override
21 | protected void initialize() throws IllegalStateException {
22 | // Initialize the Hikari pooled connection
23 | dataSource = new HikariDataSource();
24 |
25 | dataSource.setDriverClassName(plugin.config.mysql.driverClass());
26 | dataSource.setJdbcUrl("jdbc:" + (plugin.config.mysql.driverClass().contains("mariadb") ? "mariadb" : "mysql")
27 | + "://"
28 | + plugin.config.mysql.host()
29 | + ":"
30 | + plugin.config.mysql.port()
31 | + "/"
32 | + plugin.config.mysql.database()
33 | + plugin.config.mysql.connectionParameters()
34 | );
35 |
36 |
37 | // Authenticate with the database
38 | dataSource.setUsername(plugin.config.mysql.username());
39 | dataSource.setPassword(plugin.config.mysql.password());
40 |
41 | // Set connection pool options
42 | dataSource.setMaximumPoolSize(plugin.config.mysql.poolSize());
43 | dataSource.setMinimumIdle(plugin.config.mysql.poolIdle());
44 | dataSource.setConnectionTimeout(plugin.config.mysql.poolTimeout());
45 | dataSource.setMaxLifetime(plugin.config.mysql.poolLifetime());
46 | dataSource.setKeepaliveTime(plugin.config.mysql.poolKeepAlive());
47 |
48 | // Set additional connection pool properties
49 | final Properties properties = new Properties();
50 | properties.putAll(
51 | Map.of("cachePrepStmts", "true",
52 | "prepStmtCacheSize", "250",
53 | "prepStmtCacheSqlLimit", "2048",
54 | "useServerPrepStmts", "true",
55 | "useLocalSessionState", "true",
56 | "useLocalTransactionState", "true"
57 | ));
58 | properties.putAll(
59 | Map.of(
60 | "rewriteBatchedStatements", "true",
61 | "cacheResultSetMetadata", "true",
62 | "cacheServerConfiguration", "true",
63 | "elideSetAutoCommits", "true",
64 | "maintainTimeStats", "false")
65 | );
66 | dataSource.setDataSourceProperties(properties);
67 |
68 | // Prepare database schema; make tables if they don't exist
69 | try (Connection connection = dataSource.getConnection()) {
70 | try (Statement statement = connection.createStatement()) {
71 | for (String tableCreationStatement : getSQLSchema()) {
72 | statement.execute(tableCreationStatement);
73 | }
74 | } catch (SQLException e) {
75 | throw new IllegalStateException("Failed to create database tables. Make sure you're running MySQL v8.0+"
76 | + "and that your connecting user account has privileges to create tables.", e);
77 | }
78 | } catch (SQLException e) {
79 | throw new IllegalStateException("Failed to establish a connection to the MySQL database. "
80 | + "Please check the supplied database credentials in the config file", e);
81 | }
82 | }
83 |
84 | @Override
85 | protected Connection getConnection() throws SQLException {
86 | return dataSource.getConnection();
87 | }
88 |
89 | @Override
90 | public void close() {
91 | dataSource.close();
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/discord/DiscordWebhook.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.discord;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import dev.unnm3d.redischat.api.objects.Channel;
5 | import dev.unnm3d.redischat.api.objects.ChatMessage;
6 | import net.kyori.adventure.text.minimessage.MiniMessage;
7 |
8 | import javax.net.ssl.HttpsURLConnection;
9 | import java.io.IOException;
10 | import java.io.OutputStream;
11 | import java.net.URL;
12 | import java.nio.charset.StandardCharsets;
13 | import java.util.Optional;
14 | import java.util.concurrent.CompletableFuture;
15 |
16 | public class DiscordWebhook implements IDiscordHook {
17 | private final RedisChat plugin;
18 |
19 |
20 | public DiscordWebhook(RedisChat plugin) {
21 | this.plugin = plugin;
22 | }
23 |
24 | @Override
25 | public void sendDiscordMessage(ChatMessage message) {
26 | if (message.getReceiver().isChannel()) {
27 | final Optional channel = plugin.getChannelManager().getChannel(message.getReceiver().getName(), null);
28 | if(channel.isEmpty()) {
29 | plugin.getLogger().warning("Channel not found: " + message.getReceiver().getName());
30 | return;
31 | }
32 |
33 | if (channel.get().getDiscordWebhook() == null || channel.get().getDiscordWebhook().isEmpty() || message.getSender().isDiscord())
34 | return;
35 |
36 | CompletableFuture.runAsync(() -> {
37 | try {
38 | final HttpsURLConnection connection = (HttpsURLConnection) new URL(channel.get().getDiscordWebhook()).openConnection();
39 | connection.setRequestMethod("POST");
40 | connection.setRequestProperty("Content-Type", "application/json");
41 | connection.setRequestProperty("User-Agent", "Mozilla/5.0 (X11; U; Linux i686) Gecko/20071127 Firefox/2.0.0.11");
42 | connection.setDoOutput(true);
43 | try (final OutputStream outputStream = connection.getOutputStream()) {
44 | final String avatarUrl = !message.getSender().isServer() ?
45 | plugin.getServer().getOnlinePlayers().stream()
46 | .filter(p -> p.getName().equals(message.getSender().getName()))
47 | .findFirst()
48 | .map(p -> "https://minotar.net/helm/" + p.getUniqueId().toString().replace("-", "") + ".png")
49 | .orElse("") :
50 | "";
51 |
52 | outputStream.write((String.format("""
53 | {"username": "%s",
54 | "avatar_url": "%s",
55 | "content": "%s",
56 | "embeds": []
57 | }
58 | """,
59 | message.getSender().isServer() ? "Server" : message.getSender().getName(),
60 | avatarUrl,
61 | MiniMessage.miniMessage().stripTags(message.getContent())
62 | ).getBytes(StandardCharsets.UTF_8)));
63 | }
64 | connection.getInputStream();
65 | } catch (final IOException e) {
66 | throw new RuntimeException(e);
67 | }
68 | }, plugin.getExecutorService()).exceptionally((e) -> {
69 | plugin.getLogger().warning("Unable to send message to Discord channel " + channel.get().getName() + ": " + e.getMessage());
70 | return null;
71 | });
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/discord/IDiscordHook.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.discord;
2 |
3 | import dev.unnm3d.redischat.api.objects.ChatMessage;
4 |
5 | public interface IDiscordHook {
6 |
7 | default void sendDiscordMessage(ChatMessage message) {
8 |
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/integrations/OraxenTagResolver.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.integrations;
2 |
3 | import dev.unnm3d.redischat.api.TagResolverIntegration;
4 | import io.th0rgal.oraxen.utils.AdventureUtils;
5 | import org.jetbrains.annotations.NotNull;
6 |
7 | public class OraxenTagResolver implements TagResolverIntegration {
8 | @Override
9 | public @NotNull String parseTags(String message) {
10 | return AdventureUtils.parseMiniMessage(message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/integrations/PremiumVanishIntegration.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.integrations;
2 |
3 | import de.myzelyam.api.vanish.PlayerVanishStateChangeEvent;
4 | import de.myzelyam.api.vanish.VanishAPI;
5 | import dev.unnm3d.redischat.RedisChat;
6 | import dev.unnm3d.redischat.api.VanishIntegration;
7 | import org.bukkit.command.CommandSender;
8 | import org.bukkit.entity.Player;
9 | import org.bukkit.event.EventHandler;
10 | import org.bukkit.event.Listener;
11 |
12 | import java.util.HashSet;
13 | import java.util.Set;
14 |
15 | public class PremiumVanishIntegration implements VanishIntegration {
16 | protected final Set vanishedPlayers = new HashSet<>();
17 |
18 | public PremiumVanishIntegration(RedisChat plugin) {
19 | plugin.getServer().getPluginManager().registerEvents(new VanishListener(), plugin);
20 | }
21 |
22 | @Override
23 | public boolean canSee(CommandSender viewer, String playerName) {
24 | if (viewer.hasPermission("pv.see")) return true;
25 | return !vanishedPlayers.contains(playerName);
26 | }
27 |
28 | @Override
29 | public boolean isVanished(Player player) {
30 | return VanishAPI.isInvisible(player);
31 | }
32 |
33 | private class VanishListener implements Listener {
34 | @EventHandler
35 | public void onVanish(PlayerVanishStateChangeEvent event) {
36 | if (event.isVanishing()) {
37 | vanishedPlayers.add(event.getName());
38 | } else {
39 | vanishedPlayers.remove(event.getName());
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/integrations/SuperVanishIntegration.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.integrations;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import org.bukkit.command.CommandSender;
5 |
6 | public class SuperVanishIntegration extends PremiumVanishIntegration {
7 |
8 | public SuperVanishIntegration(RedisChat plugin) {
9 | super(plugin);
10 | }
11 |
12 | @Override
13 | public boolean canSee(CommandSender viewer, String playerName) {
14 | if (viewer.hasPermission("sv.see")) return true;
15 | return !vanishedPlayers.contains(playerName);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/moderation/MuteCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.moderation;
2 |
3 | import dev.jorel.commandapi.CommandAPICommand;
4 | import dev.jorel.commandapi.arguments.Argument;
5 | import dev.jorel.commandapi.arguments.ArgumentSuggestions;
6 | import dev.jorel.commandapi.arguments.StringArgument;
7 | import dev.unnm3d.redischat.Permissions;
8 | import dev.unnm3d.redischat.RedisChat;
9 | import dev.unnm3d.redischat.api.objects.KnownChatEntities;
10 | import lombok.AllArgsConstructor;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 | import java.util.stream.Collectors;
15 |
16 | @AllArgsConstructor
17 | public class MuteCommand {
18 |
19 | private RedisChat plugin;
20 |
21 |
22 | public CommandAPICommand getMuteCommand() {
23 | return new CommandAPICommand("rmutechat")
24 | .withPermission(Permissions.CHANNEL_MUTE.getPermission())
25 | .withAliases(plugin.config.getCommandAliases("rmutechat"))
26 | .withArguments(getPlayerArgument())
27 | .withOptionalArguments(getChannelArgument())
28 | .executes((sender, args) -> {
29 | final String playerName = (String) args.get("player");
30 | if (playerName == null) {
31 | plugin.messages.sendMessage(sender, plugin.messages.missing_arguments);
32 | return;
33 | }
34 | final String channelName = (String) args.getOptional("channel").orElse(KnownChatEntities.GENERAL_CHANNEL.toString());
35 |
36 | plugin.getChannelManager().getMuteManager().toggleMuteOnChannel(playerName, channelName, true);
37 | plugin.messages.sendMessage(sender, plugin.messages.muted_player
38 | .replace("%player%", playerName)
39 | .replace("%channel%", channelName)
40 | );
41 | });
42 | }
43 |
44 | public CommandAPICommand getUnMuteCommand() {
45 | return new CommandAPICommand("runmutechat")
46 | .withPermission(Permissions.CHANNEL_MUTE.getPermission())
47 | .withAliases(plugin.config.getCommandAliases("runmutechat"))
48 | .withArguments(getPlayerArgument())
49 | .withOptionalArguments(getChannelArgument())
50 | .executes((sender, args) -> {
51 | final String playerName = (String) args.get(0);
52 | if (playerName == null) {
53 | plugin.messages.sendMessage(sender, plugin.messages.missing_arguments);
54 | return;
55 | }
56 | String channelName = (String) args.getOptional("channel").orElse(KnownChatEntities.GENERAL_CHANNEL.toString());
57 |
58 | plugin.getChannelManager().getMuteManager().toggleMuteOnChannel(playerName, channelName, false);
59 | plugin.messages.sendMessage(sender, plugin.messages.unmuted_player
60 | .replace("%player%", playerName)
61 | .replace("%channel%", channelName)
62 | );
63 | });
64 | }
65 |
66 | private Argument getPlayerArgument() {
67 | return new StringArgument("player")
68 | .replaceSuggestions(ArgumentSuggestions.stringCollection(functi1 -> {
69 | final List suggestions = plugin.getPlayerListManager().getPlayerList(functi1.sender())
70 | .stream().filter(s -> s.toLowerCase().startsWith(functi1.currentArg().toLowerCase()))
71 | .collect(Collectors.toCollection(ArrayList::new));
72 | if (!plugin.config.allPlayersString.isEmpty()) suggestions.add(plugin.config.allPlayersString);
73 | return suggestions;
74 | }));
75 | }
76 |
77 | private Argument getChannelArgument() {
78 | return new StringArgument("channel")
79 | .replaceSuggestions(ArgumentSuggestions.stringCollection(functi1 -> {
80 | final List suggestions = plugin.getChannelManager().getRegisteredChannels().keySet()
81 | .stream().filter(s -> s.toLowerCase().startsWith(functi1.currentArg().toLowerCase()))
82 | .collect(Collectors.toCollection(ArrayList::new));
83 | suggestions.add(KnownChatEntities.GENERAL_CHANNEL.toString());
84 | return suggestions;
85 | }));
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/moderation/SpyChatCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.moderation;
2 |
3 | import dev.unnm3d.redischat.Permissions;
4 | import dev.unnm3d.redischat.RedisChat;
5 | import lombok.AllArgsConstructor;
6 | import org.bukkit.command.Command;
7 | import org.bukkit.command.CommandExecutor;
8 | import org.bukkit.command.CommandSender;
9 | import org.bukkit.entity.Player;
10 | import org.jetbrains.annotations.NotNull;
11 |
12 | @AllArgsConstructor
13 | public class SpyChatCommand implements CommandExecutor {
14 | private final RedisChat plugin;
15 |
16 | @Override
17 | public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
18 |
19 | if (args.length == 0 && !(sender instanceof Player)) {
20 | plugin.messages.sendMessage(sender, plugin.messages.player_not_online.replace("%player%", "CONSOLE"));
21 | return true;
22 | }
23 |
24 | String playerName = args.length == 0 ? sender.getName() : args[0];
25 | if (args.length > 0 && !sender.hasPermission(Permissions.SPY_OTHERS.getPermission())) {
26 | plugin.messages.sendMessage(sender, plugin.messages.noPermission);
27 | return true;
28 | }
29 |
30 | if (plugin.getSpyManager().toggleSpying(playerName)) {
31 | plugin.getComponentProvider().sendMessage(sender, plugin.getComponentProvider().parse(null, plugin.messages.spychat_enabled.replace("%player%", playerName), true, false, false));
32 | } else {
33 | plugin.getComponentProvider().sendMessage(sender, plugin.getComponentProvider().parse(null, plugin.messages.spychat_disabled.replace("%player%", playerName), true, false, false));
34 | }
35 |
36 | return true;
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/moderation/SpyManager.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.moderation;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import org.bukkit.entity.Player;
5 |
6 | import java.util.HashSet;
7 | import java.util.Optional;
8 | import java.util.Set;
9 | import java.util.concurrent.ConcurrentHashMap;
10 | import java.util.concurrent.ConcurrentMap;
11 |
12 | public class SpyManager {
13 | private final RedisChat plugin;
14 | private final Set isSpyingNames;
15 |
16 | public SpyManager(RedisChat plugin) {
17 | this.plugin = plugin;
18 | this.isSpyingNames = ConcurrentHashMap.newKeySet();
19 | }
20 |
21 | public void onJoin(Player player) {
22 | plugin.getDataManager().isSpying(player.getName()).thenAccept(isSpying -> {
23 | if (isSpying) {
24 | this.isSpyingNames.add(player.getName());
25 | } else {
26 | this.isSpyingNames.remove(player.getName());
27 | }
28 | });
29 | }
30 |
31 | public boolean toggleSpying(String playerName) {
32 | if (isSpyingNames.contains(playerName)) {
33 | isSpyingNames.remove(playerName);
34 | plugin.getDataManager().setSpying(playerName, false);
35 | return false;
36 | } else {
37 | isSpyingNames.add(playerName);
38 | plugin.getDataManager().setSpying(playerName, true);
39 | return true;
40 | }
41 | }
42 |
43 | public boolean isSpying(String playerName) {
44 | return isSpyingNames.contains(playerName);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/moderation/StaffChatCommand.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.moderation;
2 |
3 | import com.mojang.brigadier.arguments.StringArgumentType;
4 | import dev.jorel.commandapi.CommandAPICommand;
5 | import dev.jorel.commandapi.arguments.GreedyStringArgument;
6 | import dev.unnm3d.redischat.Permissions;
7 | import dev.unnm3d.redischat.RedisChat;
8 | import dev.unnm3d.redischat.commands.RedisChatCommand;
9 | import lombok.AllArgsConstructor;
10 | import net.william278.uniform.BaseCommand;
11 | import net.william278.uniform.Permission;
12 | import net.william278.uniform.paper.LegacyPaperCommand;
13 | import org.bukkit.command.CommandSender;
14 |
15 | import java.util.List;
16 |
17 | @AllArgsConstructor
18 | public class StaffChatCommand implements RedisChatCommand {
19 |
20 | @Override
21 | public LegacyPaperCommand getCommand() {
22 | return LegacyPaperCommand.builder("staffchat")
23 | .addPermissions(new Permission(Permissions.ADMIN_STAFF_CHAT.getPermission(), Permission.Default.IF_OP))
24 | .setAliases(RedisChat.getInstance().config.commandAliases.getOrDefault("staffchat", List.of()))
25 | .addArgument("content", StringArgumentType.greedyString(),
26 | (commandContext, builder) -> {
27 | if (builder.getRemaining().isEmpty()) {
28 | builder.suggest(RedisChat.getInstance().messages.replySuggestion);
29 | }
30 | return builder.buildFuture();
31 | })
32 | .execute(commandContext -> {
33 | String message = commandContext.getArgument("content", String.class);
34 | if (message == null) return;
35 | if (message.isEmpty()) {
36 | RedisChat.getInstance().messages.sendMessage(commandContext.getSource(), RedisChat.getInstance().messages.missing_arguments);
37 | return;
38 | }
39 | RedisChat.getScheduler().runTaskAsynchronously(() ->
40 | RedisChat.getInstance().getChannelManager().outgoingMessage(commandContext.getSource(), RedisChat.getInstance().getChannelManager().getStaffChatChannel(), message));
41 | }, "content").build();
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/permission/LuckPermsProvider.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.permission;
2 |
3 | import net.luckperms.api.LuckPerms;
4 | import net.luckperms.api.node.Node;
5 | import org.bukkit.Bukkit;
6 | import org.bukkit.OfflinePlayer;
7 | import org.bukkit.plugin.RegisteredServiceProvider;
8 |
9 | public class LuckPermsProvider implements PermissionProvider {
10 | private LuckPerms perms;
11 |
12 | public LuckPermsProvider() {
13 | RegisteredServiceProvider rsp = Bukkit.getServicesManager().getRegistration(LuckPerms.class);
14 | if (rsp != null)
15 | perms = rsp.getProvider();
16 | }
17 |
18 | @Override
19 | public void setPermission(OfflinePlayer player, String permission) {
20 | if (perms == null) return;
21 | perms.getUserManager().modifyUser(player.getUniqueId(), user ->
22 | user.data().add(
23 | Node.builder(permission)
24 | .context(perms.getContextManager().getStaticContext())
25 | .value(true)
26 | .build()));
27 | }
28 |
29 | @Override
30 | public void unsetPermission(OfflinePlayer player, String permission) {
31 | if (perms == null) return;
32 | perms.getUserManager().modifyUser(player.getUniqueId(), user ->
33 | user.data().add(
34 | Node.builder(permission)
35 | .context(perms.getContextManager().getStaticContext())
36 | .value(false)
37 | .build()));
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/permission/PermissionProvider.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.permission;
2 |
3 | import org.bukkit.OfflinePlayer;
4 |
5 | public interface PermissionProvider {
6 |
7 | default void setPermission(OfflinePlayer player, String permission) {
8 | }
9 |
10 | default void unsetPermission(OfflinePlayer player, String permission) {
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/permission/VaultPermissionProvider.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.permission;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import net.milkbowl.vault.permission.Permission;
5 | import org.bukkit.Bukkit;
6 | import org.bukkit.OfflinePlayer;
7 | import org.bukkit.entity.Player;
8 | import org.bukkit.plugin.RegisteredServiceProvider;
9 |
10 | public class VaultPermissionProvider implements PermissionProvider {
11 | private Permission perms;
12 |
13 | public VaultPermissionProvider() {
14 | RegisteredServiceProvider rsp = Bukkit.getServicesManager().getRegistration(Permission.class);
15 | if (rsp != null)
16 | perms = rsp.getProvider();
17 | }
18 |
19 | @Override
20 | public void setPermission(OfflinePlayer player, String permission) {
21 | if (!(player instanceof Player onlinePlayer)) {
22 | RedisChat.getInstance().getLogger().warning("Player " + player.getName() + " is not online, can't set permission " + permission);
23 | return;
24 | }
25 |
26 | if (perms != null)
27 | perms.playerAdd(onlinePlayer, permission);
28 | }
29 |
30 | @Override
31 | public void unsetPermission(OfflinePlayer player, String permission) {
32 | if (!(player instanceof Player onlinePlayer)) {
33 | RedisChat.getInstance().getLogger().warning("Player " + player.getName() + " is not online, can't unset permission " + permission);
34 | return;
35 | }
36 |
37 | if (perms != null)
38 | perms.playerRemove(onlinePlayer, permission);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/settings/ConfigValidator.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.settings;
2 |
3 | public interface ConfigValidator {
4 | boolean validateConfig();
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/settings/FiltersConfig.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.settings;
2 |
3 | import de.exlll.configlib.*;
4 | import dev.unnm3d.redischat.chat.filters.DefaultSettings;
5 | import dev.unnm3d.redischat.chat.filters.incoming.IgnorePlayerFilter;
6 | import dev.unnm3d.redischat.chat.filters.outgoing.*;
7 | import dev.unnm3d.redischat.api.objects.AudienceType;
8 | import lombok.AllArgsConstructor;
9 | import lombok.Getter;
10 |
11 | import java.util.*;
12 |
13 |
14 | @Configuration
15 | public final class FiltersConfig {
16 |
17 | //INCOMING
18 | @Comment({"Filters incoming private messages: Checks if the player is ignoring the sender",
19 | "If the player is ignoring the sender, it may send a warning message"})
20 | public IgnorePlayerFilter.IgnorePlayerFilterProperties ignorePlayer = (IgnorePlayerFilter.IgnorePlayerFilterProperties) DefaultSettings.IGNORE_PLAYER.getFilterSettings();
21 | @Comment({"Filters incoming channel messages: Checks if the player has all the permissions",
22 | "to see the message (if the channel is permission-enabled)"})
23 | public FilterSettings permission = DefaultSettings.PERMISSION.getFilterSettings();
24 |
25 | //OUTGOING
26 | public CapsFilter.CapsFilterProperties caps = (CapsFilter.CapsFilterProperties) DefaultSettings.CAPS.getFilterSettings();
27 | public FilterSettings spam = DefaultSettings.SPAM.getFilterSettings();
28 | public DuplicateFilter.DuplicateFilterProperties duplicate = (DuplicateFilter.DuplicateFilterProperties) DefaultSettings.DUPLICATE.getFilterSettings();
29 | @Comment({"Filters outgoing private messages: If a player is ignoring the receiver",
30 | "or the receiver is ignoring the sender, the message will not be sent"})
31 | public IgnoreFilter.IgnoreFilterProperties ignore = (IgnoreFilter.IgnoreFilterProperties) DefaultSettings.IGNORE.getFilterSettings();
32 | @Comment({"Filters outgoing channel messages: If a player is muted on that channel",
33 | "or does not have permission to write, the message will not be sent"})
34 | public FilterSettings mutedChannel = DefaultSettings.MUTED_CHANNEL.getFilterSettings();
35 | @Comment({"Filters outgoing channel messages: Replace dangerous tags with safer ones",
36 | "and checks if the player has permission to use them"})
37 | public FilterSettings tags = DefaultSettings.TAGS.getFilterSettings();
38 | public WordBlacklistFilter.WordBlacklistFilterProperties words = (WordBlacklistFilter.WordBlacklistFilterProperties) DefaultSettings.WORDS.getFilterSettings();
39 |
40 |
41 | @Configuration
42 | @AllArgsConstructor
43 | @Getter
44 | public static class FilterSettings {
45 | protected boolean enabled;
46 | protected int priority;
47 | protected Set audienceWhitelist;
48 | protected Set channelWhitelist;
49 |
50 | public FilterSettings() {
51 | this(false, 1, Set.of(), Set.of());
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/task/AnnouncerManager.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.task;
2 |
3 | import dev.unnm3d.redischat.RedisChat;
4 | import dev.unnm3d.redischat.settings.Config;
5 |
6 | import java.util.HashMap;
7 |
8 |
9 | public class AnnouncerManager {
10 | private final HashMap announcerTasks;
11 | private final RedisChat plugin;
12 |
13 | public AnnouncerManager(RedisChat plugin) {
14 | this.announcerTasks = new HashMap<>();
15 | this.plugin = plugin;
16 | reload();
17 | }
18 |
19 | public void reload() {
20 | cancelAll();
21 | announcerTasks.clear();
22 | int fullInterval = plugin.config.announcer.stream().mapToInt(Config.Announcement::delay).sum();
23 | int previousDelay = 0;
24 | for (Config.Announcement announce : plugin.config.announcer) {
25 | final AnnouncerTask at = new AnnouncerTask(plugin,
26 | announce.message(),
27 | announce.channelName() == null || announce.channelName().isEmpty() ? "public" : announce.channelName(),
28 | previousDelay + announce.delay(),
29 | fullInterval);
30 | previousDelay += announce.delay();
31 | announcerTasks.put(announce.announcementName(), at);
32 | at.start();
33 | }
34 | }
35 |
36 | public void cancelAll() {
37 | announcerTasks.values().forEach(at->{
38 | try {
39 | at.cancel();
40 | } catch (IllegalStateException ignored) {
41 | }
42 | });
43 | }
44 |
45 | public AnnouncerTask cancelAnnounce(String name) {
46 | AnnouncerTask at = announcerTasks.remove(name);
47 | if (at == null) return null;
48 |
49 | try {
50 | at.cancel();
51 | } catch (IllegalStateException ignored) {
52 | }
53 |
54 | at = new AnnouncerTask(plugin, at.getMessage(), at.getChannelName(), at.getDelay(), at.getInterval());
55 | announcerTasks.put(name, at);
56 | return at;
57 | }
58 |
59 | public AnnouncerTask startAnnounce(String name) {
60 | AnnouncerTask at = announcerTasks.get(name);
61 | if (at != null) {
62 | at.start();
63 | }
64 |
65 | return at;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/task/AnnouncerTask.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.task;
2 |
3 | import com.github.Anon8281.universalScheduler.UniversalRunnable;
4 | import com.google.common.base.Strings;
5 | import dev.unnm3d.redischat.RedisChat;
6 | import dev.unnm3d.redischat.api.objects.ChannelAudience;
7 | import dev.unnm3d.redischat.api.objects.ChatMessage;
8 | import lombok.Getter;
9 | import org.jetbrains.annotations.NotNull;
10 |
11 |
12 | public class AnnouncerTask extends UniversalRunnable {
13 |
14 | @Getter
15 | private final RedisChat plugin;
16 | private final String message;
17 | @Getter
18 | private final String channelName;
19 | @Getter
20 | private final int delay;
21 | @Getter
22 | private final int interval;
23 |
24 | public AnnouncerTask(RedisChat plugin, String message, String channelName, int delay, int interval) {
25 | this.plugin = plugin;
26 | this.message = message;
27 | this.channelName = channelName;
28 | this.delay = delay;
29 | this.interval = interval;
30 | }
31 |
32 | public void start() {
33 | try {
34 | runTaskTimerAsynchronously(plugin, delay * 20L, interval * 20L);
35 | } catch (IllegalStateException alreadyStarted) {
36 | getPlugin().getLogger().warning("AnnounceTask already started");
37 | }
38 | }
39 |
40 | @Override
41 | public void run() {
42 | plugin.getDataManager().sendChatMessage(
43 | new ChatMessage(
44 | new ChannelAudience(),
45 | "{message}",
46 | getMessage(),
47 | new ChannelAudience(channelName)
48 | ));
49 | }
50 |
51 | public @NotNull String getMessage() {
52 | return Strings.nullToEmpty(message);
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/dev/unnm3d/redischat/utils/ItemNameProvider.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat.utils;
2 |
3 | import org.bukkit.Bukkit;
4 | import org.bukkit.inventory.meta.ItemMeta;
5 |
6 | import java.lang.reflect.InvocationTargetException;
7 | import java.lang.reflect.Method;
8 |
9 |
10 | public class ItemNameProvider {
11 | private Method getItemNameMethod;
12 | private Method hasItemNameMethod;
13 | private final boolean useItemName;
14 |
15 | public ItemNameProvider(boolean useItemName) {
16 | try {
17 | this.getItemNameMethod = ItemMeta.class.getDeclaredMethod("getItemName");
18 | this.hasItemNameMethod = ItemMeta.class.getDeclaredMethod("hasItemName");
19 | } catch (NoSuchMethodException ignored) {
20 | this.useItemName = false;
21 | Bukkit.getLogger().warning("Failed to find ItemMeta#getItemName() method. Falling back to display name.");
22 | return;
23 | }
24 | this.useItemName = useItemName;
25 | }
26 |
27 | public String getItemName(ItemMeta itemMeta) {
28 | if (getItemNameMethod == null || !useItemName)
29 | return itemMeta.getDisplayName();
30 | try {
31 | return (String) getItemNameMethod.invoke(itemMeta);
32 | } catch (IllegalAccessException | InvocationTargetException e) {
33 | throw new RuntimeException(e);
34 | }
35 | }
36 |
37 | public boolean hasItemName(ItemMeta itemMeta) {
38 | if (hasItemNameMethod == null || !useItemName)
39 | return itemMeta.hasDisplayName();
40 | try {
41 | return (boolean) hasItemNameMethod.invoke(itemMeta);
42 | } catch (IllegalAccessException | InvocationTargetException e) {
43 | throw new RuntimeException(e);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/resources/webhook_embed.json:
--------------------------------------------------------------------------------
1 | {
2 | "title": "{SENDER_USERNAME} • {SENDER_CHANNEL}",
3 | "description": "{CHAT_MESSAGE}",
4 | "color": 64410,
5 | "footer": {
6 | "text": "{SENDER_USERNAME} • {SENDER_CHANNEL}",
7 | "icon_url": "https://crafatar.com/avatars/{SENDER_UUID}?size=64"
8 | },
9 | "timestamp": "{CURRENT_TIMESTAMP}"
10 | }
--------------------------------------------------------------------------------
/src/test/java/dev/unnm3d/redischat/JsonTests.java:
--------------------------------------------------------------------------------
1 | package dev.unnm3d.redischat;
2 |
3 |
4 | import com.google.gson.Gson;
5 | import dev.unnm3d.redischat.api.objects.KnownChatEntities;
6 | import dev.unnm3d.redischat.api.objects.AudienceType;
7 | import dev.unnm3d.redischat.api.objects.ChannelAudience;
8 | import dev.unnm3d.redischat.api.objects.Channel;
9 | import dev.unnm3d.redischat.api.objects.ChatMessage;
10 | import org.junit.jupiter.api.DisplayName;
11 | import org.junit.jupiter.api.Test;
12 |
13 | import static org.junit.jupiter.api.Assertions.assertEquals;
14 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
15 |
16 | public class JsonTests {
17 | private static final Gson gson = new Gson();
18 |
19 | @Test
20 | @DisplayName("Channel serialization")
21 | public void testChannelSerialization() {
22 | Channel nc = Channel.builder("name")
23 | .format("fabrizio {message}")
24 | .rateLimit(10)
25 | .rateLimitPeriod(1000)
26 | .discordWebhook("webhook")
27 | .proximityDistance(50)
28 | .filtered(false)
29 | .permission("perm1")
30 | .notificationSound("sound")
31 | .build();
32 | Channel nc2 = gson.fromJson(gson.toJson(nc), Channel.class);
33 | assertEquals(nc, nc2);
34 | System.out.println(nc.getProximityDistance());
35 | System.out.println(nc2.getProximityDistance());
36 | }
37 |
38 | @Test
39 | @DisplayName("Channel serialization")
40 | public void testChannelAudienceSerialization() {
41 | ChannelAudience nc = ChannelAudience.builder("name")
42 | .proximityDistance(-1)
43 | .permission("perm1")
44 | .type(AudienceType.PLAYER)
45 | .permission("perm2")
46 | .build();
47 | ChannelAudience nc2 = gson.fromJson(gson.toJson(nc), ChannelAudience.class);
48 | assertEquals(nc, nc2);
49 | System.out.println(nc);
50 | System.out.println(nc2);
51 | }
52 |
53 | @Test
54 | @DisplayName("ChatMessage serialization")
55 | public void testChatMessageSerialization() {
56 | ChannelAudience receiver = ChannelAudience.builder("name")
57 | .proximityDistance(-1)
58 | .permission("perm1")
59 | .type(AudienceType.PLAYER)
60 | .permission("perm2")
61 | .build();
62 | ChatMessage ncm = new ChatMessage(
63 | new ChannelAudience(AudienceType.PLAYER, KnownChatEntities.SERVER_SENDER.toString()),
64 | "{message}",
65 | "Hello World",
66 | receiver
67 | );
68 | ChatMessage ncm2 = gson.fromJson(gson.toJson(ncm), ChatMessage.class);
69 | assertEquals(ncm, ncm2);
70 |
71 | //Change a superclass field
72 | ncm2.getReceiver().setProximityDistance(10);
73 | assertNotEquals(ncm, ncm2);
74 | }
75 |
76 |
77 | }
78 |
--------------------------------------------------------------------------------