├── .github ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── en_bug_report.yml │ ├── en_feature_request.yml │ ├── zh_bug_report.yml │ └── zh_feature_request.yml └── workflows │ └── build.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libs └── paper-api-1.19.2-R0.1-20220912.114321-31.jar ├── plugin └── build.gradle.kts ├── project ├── build.gradle.kts ├── common │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── me │ │ │ └── arasple │ │ │ └── mc │ │ │ └── trchat │ │ │ ├── module │ │ │ └── internal │ │ │ │ └── filter │ │ │ │ ├── BCConvert.java │ │ │ │ ├── Filter.java │ │ │ │ ├── FilterSet.java │ │ │ │ ├── FilteredObject.java │ │ │ │ └── WordNode.java │ │ │ └── util │ │ │ ├── ServerUtil.java │ │ │ └── proxy │ │ │ └── common │ │ │ ├── ByteUtils.java │ │ │ ├── Message.java │ │ │ ├── MessageBuilder.java │ │ │ ├── MessagePacket.java │ │ │ └── MessageReader.java │ │ └── kotlin │ │ └── me │ │ └── arasple │ │ └── mc │ │ └── trchat │ │ ├── TrChat.kt │ │ ├── api │ │ ├── ChannelManager.kt │ │ ├── ClientMessageManager.kt │ │ ├── ComponentManager.kt │ │ ├── FilterManager.kt │ │ ├── ProxyMessageManager.kt │ │ ├── ProxyMode.kt │ │ ├── TrChatAPI.kt │ │ └── impl │ │ │ ├── DefaultFilterManager.kt │ │ │ └── DefaultTrChatAPI.kt │ │ ├── module │ │ └── internal │ │ │ └── service │ │ │ ├── Metrics.kt │ │ │ └── Updater.kt │ │ └── util │ │ ├── ArrayConverter.kt │ │ ├── Cooldown.kt │ │ ├── Util.kt │ │ ├── YamlUpdater.kt │ │ └── proxy │ │ └── ProxyUtil.kt ├── module-adventure │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── me │ │ └── arasple │ │ └── mc │ │ └── trchat │ │ └── module │ │ └── adventure │ │ └── Adventure.kt ├── module-compat │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── me │ │ └── arasple │ │ └── mc │ │ └── trchat │ │ └── module │ │ └── internal │ │ └── hook │ │ ├── HookAbstract.kt │ │ ├── HookPlugin.kt │ │ ├── impl │ │ ├── HookDiscordSRV.kt │ │ ├── HookEcoEnchants.kt │ │ ├── HookItemsAdder.kt │ │ └── HookNova.kt │ │ └── type │ │ └── HookDisplayItem.kt ├── module-nms │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── me │ │ └── arasple │ │ └── mc │ │ └── trchat │ │ └── api │ │ └── nms │ │ ├── NMS.kt │ │ ├── NMSImpl.kt │ │ └── NMSImpl12005.kt ├── runtime-bukkit │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── java │ │ └── me │ │ │ └── arasple │ │ │ └── mc │ │ │ └── trchat │ │ │ └── util │ │ │ └── color │ │ │ └── HexUtils.java │ │ ├── kotlin │ │ └── me │ │ │ └── arasple │ │ │ └── mc │ │ │ └── trchat │ │ │ ├── api │ │ │ ├── event │ │ │ │ ├── CustomDatabaseEvent.kt │ │ │ │ ├── TrChatEvent.kt │ │ │ │ ├── TrChatItemShowEvent.kt │ │ │ │ ├── TrChatMentionEvent.kt │ │ │ │ ├── TrChatReceiveEvent.kt │ │ │ │ └── TrChatReloadEvent.kt │ │ │ └── impl │ │ │ │ ├── BukkitChannelManager.kt │ │ │ │ ├── BukkitComponentManager.kt │ │ │ │ └── BukkitProxyManager.kt │ │ │ ├── module │ │ │ ├── conf │ │ │ │ ├── Loader.kt │ │ │ │ ├── Property.kt │ │ │ │ └── file │ │ │ │ │ ├── Filters.kt │ │ │ │ │ ├── Functions.kt │ │ │ │ │ └── Settings.kt │ │ │ ├── display │ │ │ │ ├── ChatSession.kt │ │ │ │ ├── channel │ │ │ │ │ ├── Channel.kt │ │ │ │ │ ├── PrivateChannel.kt │ │ │ │ │ └── obj │ │ │ │ │ │ ├── ChannelBindings.kt │ │ │ │ │ │ ├── ChannelEvents.kt │ │ │ │ │ │ ├── ChannelExecuteResult.kt │ │ │ │ │ │ ├── ChannelRange.kt │ │ │ │ │ │ └── ChannelSettings.kt │ │ │ │ ├── format │ │ │ │ │ ├── Format.kt │ │ │ │ │ ├── Group.kt │ │ │ │ │ ├── JsonComponent.kt │ │ │ │ │ ├── MsgComponent.kt │ │ │ │ │ └── obj │ │ │ │ │ │ ├── Style.kt │ │ │ │ │ │ └── Text.kt │ │ │ │ └── function │ │ │ │ │ ├── CustomFunction.kt │ │ │ │ │ ├── Function.kt │ │ │ │ │ ├── StandardFunction.kt │ │ │ │ │ └── standard │ │ │ │ │ ├── EnderChestShow.kt │ │ │ │ │ ├── InventoryShow.kt │ │ │ │ │ ├── ItemShow.kt │ │ │ │ │ ├── Mention.kt │ │ │ │ │ └── MentionAll.kt │ │ │ └── internal │ │ │ │ ├── TrChatBukkit.kt │ │ │ │ ├── command │ │ │ │ ├── CommandHandler.kt │ │ │ │ ├── main │ │ │ │ │ ├── CommandChannel.kt │ │ │ │ │ ├── CommandIgnore.kt │ │ │ │ │ ├── CommandMute.kt │ │ │ │ │ ├── CommandReply.kt │ │ │ │ │ └── CommandViews.kt │ │ │ │ └── sub │ │ │ │ │ ├── CommandColor.kt │ │ │ │ │ └── CommandRecallMessage.kt │ │ │ │ ├── data │ │ │ │ ├── ChatLogs.kt │ │ │ │ ├── Databases.kt │ │ │ │ └── PlayerData.kt │ │ │ │ ├── hook │ │ │ │ └── ext │ │ │ │ │ └── HookPlaceholderAPI.kt │ │ │ │ ├── listener │ │ │ │ ├── ListenerAnvilChange.kt │ │ │ │ ├── ListenerBookEdit.kt │ │ │ │ ├── ListenerBukkitChat.kt │ │ │ │ ├── ListenerCommand.kt │ │ │ │ ├── ListenerDiscordSRV.kt │ │ │ │ ├── ListenerJoin.kt │ │ │ │ ├── ListenerPackets.kt │ │ │ │ ├── ListenerPaperChat.kt │ │ │ │ ├── ListenerQuit.kt │ │ │ │ ├── ListenerSignChange.kt │ │ │ │ └── ListenerTabComplete.kt │ │ │ │ ├── proxy │ │ │ │ ├── BukkitProxyProcessor.kt │ │ │ │ └── redis │ │ │ │ │ ├── RedisManager.kt │ │ │ │ │ └── TrRedisMessage.kt │ │ │ │ └── script │ │ │ │ ├── Condition.kt │ │ │ │ ├── Reaction.kt │ │ │ │ ├── js │ │ │ │ ├── Assist.kt │ │ │ │ └── JavaScriptAgent.kt │ │ │ │ └── kether │ │ │ │ ├── KetherActions.kt │ │ │ │ └── KetherHandler.kt │ │ │ └── util │ │ │ ├── BukkitUtil.kt │ │ │ ├── ComponentUtil.kt │ │ │ ├── PAPIUtil.kt │ │ │ └── color │ │ │ ├── CustomColor.kt │ │ │ ├── Hex.kt │ │ │ └── MessageColors.kt │ │ └── resources │ │ ├── channels │ │ ├── Global.yml │ │ ├── Normal.yml │ │ ├── Private.yml │ │ └── Staff.yml │ │ ├── filter.yml │ │ ├── function.yml │ │ ├── lang │ │ ├── en_US.yml │ │ ├── es_ES.yml │ │ └── zh_CN.yml │ │ └── settings.yml ├── runtime-bungee │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── me │ │ └── arasple │ │ └── mc │ │ └── trchat │ │ ├── api │ │ └── impl │ │ │ ├── BungeeComponentManager.kt │ │ │ └── BungeeProxyManager.kt │ │ └── module │ │ └── internal │ │ ├── TrChatBungee.kt │ │ └── listener │ │ └── ListenerBungeeTransfer.kt └── runtime-velocity │ ├── build.gradle.kts │ └── src │ └── main │ └── kotlin │ └── me │ └── arasple │ └── mc │ └── trchat │ ├── api │ └── impl │ │ └── VelocityProxyManager.kt │ └── module │ └── internal │ ├── TrChatVelocity.kt │ └── listener │ └── ListenerVelocityTransfer.kt └── settings.gradle.kts /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: TrChat Document 4 | url: https://trchat.trixey.cc/ 5 | about: Official wiki of TrChat (Only Chinese now) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/en_bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Error Report 2 | description: 'Warning: Failure to properly follow the prompts for feedback errors will be closed.' 3 | title: "[issue] " 4 | labels: ['Bug | 漏洞'] 5 | body: 6 | - type: checkboxes 7 | id: latests 8 | attributes: 9 | label: 'Whether the latest version has been tried' 10 | description: 'Your problem may have been found and fixed in the [latest version](https://github.com/TrPlugins/TrChat/actions)' 11 | options: 12 | - label: 'I have updated TrChat to the latest version, and the issue is also reproduced.' 13 | required: true 14 | 15 | - type: checkboxes 16 | id: wikis 17 | attributes: 18 | label: 'Have you checked the Wiki' 19 | description: 'Often many problems are caused by not checking the wiki in detail, or the wiki already has a solution, have you read [Wiki](https://trchat.trixey.cc/guide/known-issues)?' 20 | options: 21 | - label: 'I have checked the Wiki for this problem and determined that the problem exists.' 22 | required: true 23 | 24 | - type: textarea 25 | id: description 26 | attributes: 27 | label: 'Detailed description' 28 | description: 'Actions and prerequisites that can be reproduced' 29 | placeholder: | 30 | 1. ... 31 | 2. ... 32 | 3. ... 33 | validations: 34 | required: true 35 | 36 | - type: textarea 37 | id: configuration 38 | attributes: 39 | label: 'configuration file' 40 | description: 'The channel file or settings.yml where the error occurred' 41 | render: 'YAML' 42 | validations: 43 | required: true 44 | 45 | - type: textarea 46 | id: logs 47 | attributes: 48 | label: 'logs' 49 | description: 'If there is a message/error in the server/client backend when an error occurs, please provide it' 50 | validations: 51 | required: false 52 | 53 | - type: textarea 54 | id: environments 55 | attributes: 56 | label: 'Server environment' 57 | description: 'Paste the results of /version and /plugins here' 58 | value: | 59 | Server version: 60 | ... 61 | Plugin list: 62 | ... 63 | validations: 64 | required: true 65 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/en_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: 'Warning: If you don’t follow the prompts to give feedback, this issue may be ignored or closed.' 3 | title: "[Feature] " 4 | labels: ['Enhancement | 新功能'] 5 | body: 6 | - type: checkboxes 7 | id: wikis 8 | attributes: 9 | label: 'Have you checked the Wiki' 10 | description: 'Often many questions are caused by not checking the Wiki in detail, have you read [Wiki](https://trchat.trixey.cc)?' 11 | options: 12 | - label: 'I have checked the Wiki and determined that this feature does not exist.' 13 | required: true 14 | 15 | - type: checkboxes 16 | id: issues-reviewed 17 | attributes: 18 | label: 'Is there a duplicate issue' 19 | description: 'Some features may have been mentioned by others, have you read it [Issues](https://github.com/TrPlugins/TrChat/issues)?' 20 | options: 21 | - label: 'I have looked through the existing issue and found no duplicate content, or a more detailed description of the existing issue.' 22 | required: true 23 | 24 | - type: textarea 25 | id: description 26 | attributes: 27 | label: 'Detailed description' 28 | description: 'Describe the function clearly.' 29 | value: | 30 | ``` 31 | 1. ... 32 | 2. ... 33 | 3. ... 34 | ``` 35 | validations: 36 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/zh_bug_report.yml: -------------------------------------------------------------------------------- 1 | name: 错误报告 2 | description: '注意: 未正确根据提示进行反馈错误可能会被忽略或关闭.' 3 | title: "[问题] " 4 | labels: ['Bug | 漏洞'] 5 | body: 6 | - type: checkboxes 7 | id: latests 8 | attributes: 9 | label: '是否已尝试最新的版本' 10 | description: '你的问题也许已经被发现并被修复于[最新版](https://github.com/TrPlugins/TrChat/actions)' 11 | options: 12 | - label: '我已更新 TrChat 至最新的版本, 并且同样复现该问题.' 13 | required: true 14 | 15 | - type: checkboxes 16 | id: wikis 17 | attributes: 18 | label: '是否已查阅 Wiki' 19 | description: '往往很多问题都是因为没有详细查阅 Wiki, 或是Wiki已经有解决方案, 你是否已阅读 [Wiki](https://trchat.trixey.cc/guide/known-issues)?' 20 | options: 21 | - label: '我已查阅 Wiki 对于该问题的相关内容, 并确定该问题是存在的.' 22 | required: true 23 | 24 | - type: checkboxes 25 | id: proxy 26 | attributes: 27 | label: '如果使用跨服功能, 是否在代理端上安装了TrChat或使用redis转发?' 28 | description: '如果没有, 你将不能正常使用跨服功能' 29 | options: 30 | - label: '我已在代理端上安装了TrChat或使用redis转发' 31 | required: true 32 | 33 | - type: textarea 34 | id: description 35 | attributes: 36 | label: '详细描述' 37 | description: '能够重现的动作及前提' 38 | placeholder: | 39 | 1. ... 40 | 2. ... 41 | 3. ... 42 | validations: 43 | required: true 44 | 45 | - type: textarea 46 | id: configuration 47 | attributes: 48 | label: '配置文件' 49 | description: '发生错误的频道文件或settings.yml' 50 | render: 'YAML' 51 | validations: 52 | required: true 53 | 54 | - type: textarea 55 | id: logs 56 | attributes: 57 | label: '日志' 58 | description: '若发生错误时服务端/客户端后台出现信息/报错, 请提供' 59 | validations: 60 | required: false 61 | 62 | - type: textarea 63 | id: environments 64 | attributes: 65 | label: '服务器环境' 66 | description: '在此处粘贴 /version 和 /plugins 的返回结果' 67 | value: | 68 | 服务器版本: 69 | ... 70 | 插件列表: 71 | ... 72 | validations: 73 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/zh_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 功能请求 2 | description: '注意: 未正确根据提示发布功能请求可能会被忽略或关闭.' 3 | title: "[功能] " 4 | labels: ['Enhancement | 新功能'] 5 | body: 6 | - type: checkboxes 7 | id: wikis 8 | attributes: 9 | label: '是否已查阅 Wiki' 10 | description: '往往很多需求都是因为没有详细查阅 Wiki, 你是否已阅读 [Wiki](https://trchat.trixey.cc)?' 11 | options: 12 | - label: '我已查阅 Wiki 并确定没有存在该功能.' 13 | required: true 14 | 15 | - type: checkboxes 16 | id: issues-reviewed 17 | attributes: 18 | label: '是否存在重复 issue' 19 | description: '有些功能可能已经被别人提到过,你翻阅过吗 [Issues](https://github.com/TrPlugins/TrChat/issues)?' 20 | options: 21 | - label: '我已翻阅现有的 issue 没有发现内容重复, 亦或是对现有 issue 的更详细的描述.' 22 | required: true 23 | 24 | - type: textarea 25 | id: description 26 | attributes: 27 | label: '详细的描述' 28 | description: '对该功能清晰地描述.' 29 | value: | 30 | ``` 31 | 1. ... 32 | 2. ... 33 | 3. ... 34 | ``` 35 | validations: 36 | required: true -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: TrChat build 2 | on: [ push ] 3 | 4 | jobs: 5 | build: 6 | if: contains(github.event.head_commit.message, '[actions skip]') == false 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: checkout repository 10 | uses: actions/checkout@v2 11 | - name: cache gradle packages 12 | uses: actions/cache@v4 13 | with: 14 | key: ${{ runner.os }}-build-${{ env.cache-name }} 15 | path: | 16 | ~/.gradle/caches 17 | ~/.gradle/wrapper 18 | - name: validate gradle wrapper 19 | uses: gradle/wrapper-validation-action@v1 20 | - name: setup jdk 8.0 21 | uses: actions/setup-java@v2 22 | with: 23 | distribution: adopt 24 | java-version: 8.0 25 | - name: make gradle wrapper executable 26 | run: chmod +x ./gradlew 27 | - name: build 28 | run: ./gradlew build 29 | - name: capture build artifacts 30 | uses: actions/upload-artifact@v4 31 | with: 32 | name: TrChat Artifacts 33 | path: plugin/build/libs/ 34 | # - name: automatic releases 35 | # uses: marvinpinto/action-automatic-releases@v1.2.1 36 | # with: 37 | # repo_token: "${{ secrets.GITHUB_TOKEN }}" 38 | # automatic_release_tag: "latest" 39 | # prerelease: false 40 | # title: "TrChat 自动构建最新版本" 41 | # files: | 42 | # plugin/build/libs/*.* -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 TrPlugins 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![trchat2](https://user-images.githubusercontent.com/34670283/160282372-a048a12c-911a-40da-8dce-a737c9596055.png) 2 | 3 | [![Version](https://img.shields.io/github/v/release/TrPlugins/TrChat?logo=VirusTotal&style=for-the-badge)](https://github.com/FlickerProjects/TrChat/releases) 4 | [![Issues](https://img.shields.io/github/issues/TrPlugins/TrChat?logo=StackOverflow&style=for-the-badge)](https://github.com/FlickerProjects/TrChat/issues) 5 | [![Last Commit](https://img.shields.io/github/last-commit/TrPlugins/TrChat?logo=ApacheRocketMQ&style=for-the-badge&color=1e90ff)](https://github.com/FlickerProjects/TrChat/commits/v2) 6 | [![Downloads](https://img.shields.io/github/downloads/TrPlugins/TrChat/total?style=for-the-badge&logo=docusign)](https://github.com/FlickerProjects/TrChat/releases) 7 | --- 8 | 9 | ### 🔔 What's new in TrChat v2? 10 | - **Optimized performance** 11 | - **New Channel & Format System** 12 | - **Better compatibility with other plugins** 13 | 14 | --- 15 | 16 | ### ⛏ API usage: 17 | ```java 18 | public class Demo implements Listener { 19 | 20 | @EventHandler 21 | private void e(TrChatEvent e) { 22 | e.getChannel(); // 获取聊天频道 23 | e.setCanceled(true); // 取消发送聊天 24 | e.setMessage("..."); // 改变聊天内容 25 | } 26 | } 27 | ``` 28 | -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | import io.izzel.taboolib.gradle.* 2 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 3 | 4 | plugins { 5 | java 6 | id("io.izzel.taboolib") version "2.0.23" 7 | id("org.jetbrains.kotlin.jvm") version "1.8.22" 8 | } 9 | 10 | subprojects { 11 | apply() 12 | apply(plugin = "io.izzel.taboolib") 13 | apply(plugin = "org.jetbrains.kotlin.jvm") 14 | 15 | taboolib { 16 | env { 17 | install("basic-configuration") 18 | install( 19 | BukkitHook, 20 | BukkitNMSUtil, 21 | BukkitNMSItemTag, 22 | BukkitUI 23 | ) 24 | install( 25 | "database", 26 | "database-alkaid-redis", 27 | "database-player" 28 | ) 29 | install( 30 | "minecraft-chat", 31 | "minecraft-command-helper", 32 | "minecraft-i18n", 33 | "minecraft-kether", 34 | "minecraft-metrics" 35 | ) 36 | install(JavaScript) 37 | install(Bukkit, BungeeCord, Velocity) 38 | } 39 | version { 40 | taboolib = "6.2.3-8cc2f66" 41 | coroutines = null 42 | // isSkipKotlin = true 43 | // isSkipKotlinRelocate = true 44 | } 45 | } 46 | 47 | // 全局仓库 48 | repositories { 49 | mavenLocal() 50 | mavenCentral() 51 | maven("https://jitpack.io") 52 | maven("https://oss.sonatype.org/content/repositories/snapshots") 53 | maven("https://repo.papermc.io/repository/maven-public/") 54 | maven("https://repo.xenondevs.xyz/releases") 55 | maven("https://repo.extendedclip.com/content/repositories/placeholderapi/") 56 | maven("https://repo.codemc.io/repository/maven-public/") 57 | } 58 | 59 | // 全局依赖 60 | dependencies { 61 | compileOnly(kotlin("stdlib")) 62 | compileOnly("com.google.code.gson:gson:2.8.5") 63 | compileOnly("com.google.guava:guava:21.0") 64 | compileOnly("net.kyori:adventure-api:4.17.0") 65 | } 66 | 67 | // 编译配置 68 | java { 69 | withSourcesJar() 70 | sourceCompatibility = JavaVersion.VERSION_1_8 71 | targetCompatibility = JavaVersion.VERSION_1_8 72 | } 73 | tasks.withType { 74 | options.encoding = "UTF-8" 75 | } 76 | tasks.withType { 77 | kotlinOptions { 78 | jvmTarget = "1.8" 79 | freeCompilerArgs = listOf("-Xjvm-default=all", "-Xextended-compiler-checks") 80 | } 81 | } 82 | } 83 | 84 | gradle.buildFinished { 85 | buildDir.deleteRecursively() 86 | } 87 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=me.arasple.mc.trchat 2 | version=2.2.3 3 | kotlin.incremental=true 4 | kotlin.incremental.java=true 5 | kotlin.incremental.useClasspathSnapshot=true 6 | kotlin.caching.enabled=true 7 | kotlin.parallel.tasks.in.project=true -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrPlugins/TrChat/e835297ed3f1d30c5ceebf943b1052c91e1a88d9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.9-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /libs/paper-api-1.19.2-R0.1-20220912.114321-31.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrPlugins/TrChat/e835297ed3f1d30c5ceebf943b1052c91e1a88d9/libs/paper-api-1.19.2-R0.1-20220912.114321-31.jar -------------------------------------------------------------------------------- /plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | taboolib { 2 | description { 3 | name(rootProject.name) 4 | desc("Advanced Minecraft Chat Control") 5 | links { 6 | name("homepage").url("https://trchat.trixey.cc/") 7 | } 8 | contributors { 9 | name("Arasple") 10 | name("ItsFlicker") 11 | } 12 | dependencies { 13 | name("PlaceholderAPI").with("bukkit") 14 | name("DiscordSRV").with("bukkit").optional(true) 15 | name("EcoEnchants").with("bukkit").optional(true) 16 | name("ItemsAdder").with("bukkit").optional(true) 17 | name("Nova").with("bukkit").optional(true) 18 | name("Multiverse-Core").with("bukkit").loadafter(true) 19 | name("Geyser-Spigot").with("bukkit").loadafter(true) 20 | } 21 | } 22 | relocate("com.eatthepath.uuid.", "${rootProject.group}.library.uuid.") 23 | // relocate("com.electronwill.nightconfig", "com.electronwill.nightconfig_3_6_7") 24 | } 25 | 26 | dependencies { 27 | taboo("com.eatthepath:fast-uuid:0.2.0") 28 | } 29 | 30 | tasks { 31 | jar { 32 | // 构件名 33 | archiveBaseName.set(rootProject.name) 34 | // 打包子项目源代码 35 | rootProject.subprojects.forEach { from(it.sourceSets["main"].output) } 36 | } 37 | sourcesJar { 38 | // 构件名 39 | archiveBaseName.set(rootProject.name) 40 | // 打包子项目源代码 41 | rootProject.subprojects.forEach { from(it.sourceSets["main"].allSource) } 42 | } 43 | } -------------------------------------------------------------------------------- /project/build.gradle.kts: -------------------------------------------------------------------------------- 1 | gradle.buildFinished { 2 | buildDir.deleteRecursively() 3 | } -------------------------------------------------------------------------------- /project/common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly("com.eatthepath:fast-uuid:0.2.0") 3 | } 4 | 5 | taboolib { subproject = true } -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/module/internal/filter/BCConvert.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.filter; 2 | 3 | public class BCConvert { 4 | 5 | private static final char DBC_CHAR_START = 33; 6 | private static final char DBC_CHAR_END = 126; 7 | private static final char SBC_CHAR_START = 65281; 8 | private static final char SBC_CHAR_END = 65374; 9 | private static final int CONVERT_STEP = 65248; 10 | private static final char SBC_SPACE = 12288; 11 | private static final char DBC_SPACE = ' '; 12 | 13 | public static String bj2qj(String src) { 14 | if (src == null) { 15 | return null; 16 | } 17 | StringBuilder buf = new StringBuilder(src.length()); 18 | char[] ca = src.toCharArray(); 19 | for (char c : ca) { 20 | if (c == DBC_SPACE) { 21 | buf.append(SBC_SPACE); 22 | } else if ((c >= DBC_CHAR_START) && (c <= DBC_CHAR_END)) { 23 | buf.append((char) (c + CONVERT_STEP)); 24 | } else { 25 | buf.append(c); 26 | } 27 | } 28 | return buf.toString(); 29 | } 30 | 31 | public static int bj2qj(char src) { 32 | int r = src; 33 | if ((src >= DBC_CHAR_START) && (src <= DBC_CHAR_END)) { 34 | r = src + CONVERT_STEP; 35 | } 36 | return r; 37 | } 38 | 39 | 40 | public static String qj2bj(String src) { 41 | if (src == null) { 42 | return null; 43 | } 44 | StringBuilder buf = new StringBuilder(src.length()); 45 | char[] ca = src.toCharArray(); 46 | for (int i = 0; i < src.length(); i++) { 47 | if (ca[i] >= SBC_CHAR_START && ca[i] <= SBC_CHAR_END) { 48 | buf.append((char) (ca[i] - CONVERT_STEP)); 49 | } else if (ca[i] == SBC_SPACE) { 50 | buf.append(DBC_SPACE); 51 | } else { 52 | buf.append(ca[i]); 53 | } 54 | } 55 | return buf.toString(); 56 | } 57 | 58 | public static int qj2bj(char src) { 59 | int r = src; 60 | if (src >= SBC_CHAR_START && src <= SBC_CHAR_END) { 61 | r = src - CONVERT_STEP; 62 | } else if (src == SBC_SPACE) { 63 | r = DBC_SPACE; 64 | } 65 | return r; 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/module/internal/filter/FilterSet.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.filter; 2 | 3 | public class FilterSet { 4 | 5 | private final long[] elements; 6 | 7 | public FilterSet() { 8 | elements = new long[1 + (65535 >>> 6)]; 9 | } 10 | 11 | public void add(final int no) { 12 | elements[no >>> 6] |= (1L << (no & 63)); 13 | } 14 | 15 | public void add(final int... no) { 16 | for (int currNo : no) { 17 | elements[currNo >>> 6] |= (1L << (currNo & 63)); 18 | } 19 | } 20 | 21 | public void remove(final int no) { 22 | elements[no >>> 6] &= ~(1L << (no & 63)); 23 | } 24 | 25 | public boolean addAndNotify(final int no) { 26 | int eWordNum = no >>> 6; 27 | long oldElements = elements[eWordNum]; 28 | elements[eWordNum] |= (1L << (no & 63)); 29 | return elements[eWordNum] != oldElements; 30 | } 31 | 32 | public boolean removeAndNotify(final int no) { 33 | int eWordNum = no >>> 6; 34 | long oldElements = elements[eWordNum]; 35 | elements[eWordNum] &= ~(1L << (no & 63)); 36 | return elements[eWordNum] != oldElements; 37 | } 38 | 39 | public boolean contains(final int no) { 40 | return (elements[no >>> 6] & (1L << (no & 63))) == 0; 41 | } 42 | 43 | public boolean containsAll(final int... no) { 44 | if (no.length == 0) { 45 | return true; 46 | } 47 | for (int currNo : no) { 48 | if ((elements[currNo >>> 6] & (1L << (currNo & 63))) == 0) { 49 | return false; 50 | } 51 | } 52 | return true; 53 | } 54 | 55 | public boolean containsAllUselessWay(final int... no) { 56 | long[] elements = new long[this.elements.length]; 57 | for (int currNo : no) { 58 | elements[currNo >>> 6] |= (1L << (currNo & 63)); 59 | } 60 | for (int i = 0; i < elements.length; i++) { 61 | if ((elements[i] & ~this.elements[i]) != 0) { 62 | return false; 63 | } 64 | } 65 | return true; 66 | } 67 | 68 | public int size() { 69 | int size = 0; 70 | for (long element : elements) { 71 | size += Long.bitCount(element); 72 | } 73 | return size; 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/module/internal/filter/FilteredObject.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.filter; 2 | 3 | /** 4 | * @author Arasple 5 | * @since 2019/9/12 17:40 6 | */ 7 | public class FilteredObject { 8 | 9 | private final String filtered; 10 | 11 | private final int sensitiveWords; 12 | 13 | public FilteredObject(String filtered, int sensitiveWords) { 14 | this.filtered = filtered; 15 | this.sensitiveWords = sensitiveWords; 16 | } 17 | 18 | public String getFiltered() { 19 | return filtered; 20 | } 21 | 22 | public int getSensitiveWords() { 23 | return sensitiveWords; 24 | } 25 | } -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/module/internal/filter/WordNode.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.filter; 2 | 3 | import java.util.LinkedList; 4 | import java.util.List; 5 | 6 | public class WordNode { 7 | 8 | private final int value; 9 | private List subNodes; 10 | private boolean isLast; 11 | 12 | public WordNode(int value) { 13 | this.value = value; 14 | } 15 | 16 | public WordNode(int value, boolean isLast) { 17 | this.value = value; 18 | this.isLast = isLast; 19 | } 20 | 21 | private WordNode addSubNode(final WordNode subNode) { 22 | if (subNodes == null) { 23 | subNodes = new LinkedList<>(); 24 | } 25 | subNodes.add(subNode); 26 | return subNode; 27 | } 28 | 29 | public WordNode addIfNoExist(final int value, final boolean isLast) { 30 | if (subNodes == null) { 31 | return addSubNode(new WordNode(value, isLast)); 32 | } 33 | for (WordNode subNode : subNodes) { 34 | if (subNode.value == value) { 35 | if (!subNode.isLast && isLast) 36 | subNode.isLast = true; 37 | return subNode; 38 | } 39 | } 40 | return addSubNode(new WordNode(value, isLast)); 41 | } 42 | 43 | public WordNode querySub(final int value) { 44 | if (subNodes == null) { 45 | return null; 46 | } 47 | for (WordNode subNode : subNodes) { 48 | if (subNode.value == value) { 49 | return subNode; 50 | } 51 | } 52 | return null; 53 | } 54 | 55 | public boolean isLast() { 56 | return isLast; 57 | } 58 | 59 | public void setLast(boolean isLast) { 60 | this.isLast = isLast; 61 | } 62 | 63 | @Override 64 | public int hashCode() { 65 | return value; 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/util/ServerUtil.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util; 2 | 3 | public class ServerUtil { 4 | 5 | public static boolean isModdedServer = false; 6 | 7 | static { 8 | try { 9 | Class.forName("catserver.server.CatServerLaunch"); 10 | isModdedServer = true; 11 | } catch (Throwable ignored) { 12 | } 13 | try { 14 | Class.forName("com.mohistmc.MohistMC"); 15 | isModdedServer = true; 16 | } catch (Throwable ignored) { 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/util/proxy/common/ByteUtils.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util.proxy.common; 2 | 3 | import java.nio.charset.StandardCharsets; 4 | import java.util.Base64; 5 | 6 | /** 7 | * @author 坏黑 8 | * @since 2018-04-16 9 | */ 10 | public class ByteUtils { 11 | 12 | public static String serialize(String var) { 13 | return Base64.getEncoder().encodeToString(var.getBytes(StandardCharsets.UTF_8)); 14 | } 15 | 16 | public static String deSerialize(String var) { 17 | return new String(Base64.getDecoder().decode(var), StandardCharsets.UTF_8); 18 | } 19 | 20 | public static String[] serialize(String... var) { 21 | String[] varEncode = new String[var.length]; 22 | for (int i = 0; i < var.length; i++) { 23 | varEncode[i] = Base64.getEncoder().encodeToString(var[i].getBytes(StandardCharsets.UTF_8)); 24 | } 25 | return varEncode; 26 | } 27 | 28 | public static String[] deSerialize(String... var) { 29 | String[] varEncode = new String[var.length]; 30 | for (int i = 0; i < var.length; i++) { 31 | varEncode[i] = new String(Base64.getDecoder().decode(var[i]), StandardCharsets.UTF_8); 32 | } 33 | return varEncode; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/util/proxy/common/Message.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util.proxy.common; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonParser; 6 | import org.jetbrains.annotations.NotNull; 7 | 8 | import java.util.Comparator; 9 | import java.util.List; 10 | 11 | /** 12 | * 通讯信息容器 13 | * 14 | * @author 坏黑 15 | * @since 2019-02-13 11:07 16 | */ 17 | public class Message { 18 | 19 | private final List messages = Lists.newCopyOnWriteArrayList(); 20 | 21 | /** 22 | * 构建为可读取的通讯内容 23 | */ 24 | @NotNull 25 | public String[] build() { 26 | StringBuilder builder = new StringBuilder(); 27 | messages.sort(Comparator.comparingInt(MessagePacket::getIndex)); 28 | messages.forEach(message -> builder.append(message.getData())); 29 | JsonArray json = new JsonParser().parse(ByteUtils.deSerialize(builder.toString())).getAsJsonArray(); 30 | String[] args = new String[json.size()]; 31 | for (int i = 0; i < json.size(); i++) { 32 | args[i] = json.get(i).getAsString(); 33 | } 34 | return args; 35 | } 36 | 37 | /** 38 | * 所有数据包是否接收完成 39 | */ 40 | public boolean isCompleted() { 41 | return !messages.isEmpty() && messages.size() == messages.get(0).getTotal(); 42 | } 43 | 44 | @NotNull 45 | public List getMessages() { 46 | return messages; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/util/proxy/common/MessageBuilder.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util.proxy.common; 2 | 3 | import com.google.common.collect.Lists; 4 | import com.google.gson.JsonArray; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.JsonPrimitive; 7 | 8 | import java.nio.charset.StandardCharsets; 9 | import java.util.List; 10 | 11 | /** 12 | * 通讯信息数据包创建工具 13 | * 14 | * @author 坏黑 15 | * @since 2020-10-15 16 | */ 17 | public class MessageBuilder { 18 | 19 | /** 20 | * 单个数据包允许的最大字节 21 | */ 22 | public static final int MESSAGE_LENGTH = 30000; 23 | 24 | /** 25 | * 将源数据分割为数个大小合理且协议相同的数据包 26 | * 第一个参数将作为数据包的 UID 识别 27 | * 28 | * @param message 源数据 29 | */ 30 | public static List create(String[] message) { 31 | List messages = Lists.newArrayList(); 32 | JsonArray array = new JsonArray(); 33 | for (int i = 1; i < message.length; i++) { 34 | array.add(new JsonPrimitive(message[i])); 35 | } 36 | String source = ByteUtils.serialize(array.toString()); 37 | int times = (int) Math.ceil(source.length() / (double) MESSAGE_LENGTH); 38 | for (int i = 0; i < times; i++) { 39 | JsonObject json = new JsonObject(); 40 | json.addProperty("uid", message[0]); 41 | json.addProperty("index", i + 1); 42 | json.addProperty("total", times); 43 | if (source.length() < MESSAGE_LENGTH) { 44 | json.addProperty("data", source); 45 | } else { 46 | json.addProperty("data", source.substring(0, source.length() - (source.length() - MESSAGE_LENGTH))); 47 | source = source.substring(MESSAGE_LENGTH); 48 | } 49 | messages.add(json.toString().getBytes(StandardCharsets.UTF_8)); 50 | } 51 | return messages; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/util/proxy/common/MessagePacket.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util.proxy.common; 2 | 3 | import java.util.UUID; 4 | 5 | /** 6 | * 通讯信息数据包 7 | * 因客户端限制每个数据包大小不超过 32767 字节 8 | * 故需要将较大数据包分割为数个小数据包分别发送 9 | *

10 | * 数据包格式如下 11 | * { 12 | * "uid": "0000-0000-0000-0000", 13 | * "data": "abc", 14 | * "index": 1, 15 | * "total": 100 16 | * } 17 | * 18 | * @author 坏黑 19 | * @since 2019-02-13 9:28 20 | */ 21 | public class MessagePacket { 22 | 23 | private final UUID uid; 24 | private final String data; 25 | private final int index; 26 | private final int total; 27 | 28 | MessagePacket(UUID uid, String data, int index, int total) { 29 | this.uid = uid; 30 | this.data = data; 31 | this.index = index; 32 | this.total = total; 33 | } 34 | 35 | public UUID getUID() { 36 | return uid; 37 | } 38 | 39 | public String getData() { 40 | return data; 41 | } 42 | 43 | public int getIndex() { 44 | return index; 45 | } 46 | 47 | public int getTotal() { 48 | return total; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /project/common/src/main/java/me/arasple/mc/trchat/util/proxy/common/MessageReader.java: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util.proxy.common; 2 | 3 | import com.google.common.cache.Cache; 4 | import com.google.common.cache.CacheBuilder; 5 | import com.google.gson.JsonObject; 6 | import com.google.gson.JsonParser; 7 | import me.arasple.mc.trchat.util.UtilKt; 8 | 9 | import java.nio.charset.StandardCharsets; 10 | import java.util.concurrent.TimeUnit; 11 | 12 | /** 13 | * 通讯信息数据包读取工具 14 | * 15 | * @author 坏黑 16 | * @since 2020-10-15 17 | */ 18 | public class MessageReader { 19 | 20 | private static final Cache queueMessages = CacheBuilder.newBuilder() 21 | .expireAfterWrite(10, TimeUnit.SECONDS) 22 | .build(); 23 | 24 | /** 25 | * 将通讯数据读取为数据包 26 | * 27 | * @param packet 通讯数据(未经过处理的原始内容) 28 | */ 29 | public static Message read(byte[] packet) { 30 | return read(new String(packet, StandardCharsets.UTF_8)); 31 | } 32 | 33 | /** 34 | * 通过通讯数据读取为数据包 35 | * 36 | * @param packet 通讯数据(未经过处理的原始内容) 37 | */ 38 | public static Message read(String packet) { 39 | JsonObject json = new JsonParser().parse(packet).getAsJsonObject(); 40 | Message message = queueMessages.getIfPresent(json.get("uid").getAsString()); 41 | if (message == null) { 42 | message = new Message(); 43 | queueMessages.put(json.get("uid").getAsString(), message); 44 | } 45 | message.getMessages().add(new MessagePacket( 46 | UtilKt.toUUID(json.get("uid").getAsString()), 47 | json.get("data").getAsString(), 48 | json.get("index").getAsInt(), 49 | json.get("total").getAsInt() 50 | )); 51 | return message; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/TrChat.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat 2 | 3 | import me.arasple.mc.trchat.api.TrChatAPI 4 | 5 | /** 6 | * @author ItsFlicker 7 | * @since 2022/6/18 14:50 8 | */ 9 | object TrChat { 10 | 11 | private var api: TrChatAPI? = null 12 | 13 | fun api(): TrChatAPI { 14 | return api ?: error("TrChat is loading or failed to load!") 15 | } 16 | 17 | fun register(api: TrChatAPI) { 18 | this.api = api 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/ChannelManager.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api 2 | 3 | import taboolib.common.platform.ProxyCommandSender 4 | 5 | /** 6 | * @author ItsFlicker 7 | * @since 2022/6/19 19:55 8 | */ 9 | interface ChannelManager { 10 | 11 | /** 12 | * 加载所有聊天频道 13 | * 14 | * @param sender lang消息接收者 15 | */ 16 | fun loadChannels(sender: ProxyCommandSender) 17 | 18 | /** 19 | * 获取聊天频道 20 | * 21 | * Bukkit -> Channel 22 | */ 23 | fun getChannel(id: String): Any? 24 | 25 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/ClientMessageManager.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api 2 | 3 | import java.util.concurrent.ExecutorService 4 | import java.util.concurrent.Future 5 | 6 | interface ClientMessageManager { 7 | 8 | var port: Int 9 | 10 | val executor: ExecutorService 11 | 12 | val mode: ProxyMode 13 | 14 | fun close() = Unit 15 | 16 | fun getPlayerNames(): Map 17 | 18 | fun getExactName(name: String): String? 19 | 20 | fun isPlayerOnline(name: String): Boolean 21 | 22 | fun sendMessage(recipient: Any?, data: Array): Future<*> 23 | 24 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/ComponentManager.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api 2 | 3 | import taboolib.module.chat.ComponentText 4 | 5 | /** 6 | * @author ItsFlicker 7 | * @since 2022/6/18 15:16 8 | */ 9 | interface ComponentManager { 10 | 11 | /** 12 | * 发送玩家聊天Component 13 | * 14 | * @param receiver 接收者 (ProxyCommandSender / Platform CommandSender) 15 | * @param component 内容 16 | * @param sender 发送者 (ProxyCommandSender / Platform CommandSender / UUID) 17 | */ 18 | fun sendComponent(receiver: Any, component: ComponentText, sender: Any? = null) 19 | 20 | /** 21 | * 过滤Component 22 | * 23 | * @param component 原内容 24 | * @param maxLength 最大长度 (负数为不验证) 25 | * @return 过滤后内容 26 | */ 27 | fun filterComponent(component: ComponentText, maxLength: Int = -1): ComponentText 28 | 29 | /** 30 | * 合法化Component 31 | * 32 | * @param maxLength 最大长度 (负数为不验证) 33 | */ 34 | fun validateComponent(component: ComponentText, maxLength: Int = -1): ComponentText 35 | 36 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/FilterManager.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api 2 | 3 | import me.arasple.mc.trchat.module.internal.filter.FilteredObject 4 | import taboolib.common.platform.ProxyCommandSender 5 | import taboolib.common.platform.ProxyPlayer 6 | import taboolib.common.platform.function.console 7 | 8 | interface FilterManager { 9 | 10 | /** 11 | * 加载聊天过滤器 12 | * 13 | * @param updateCloud 是否更新云端词库 14 | * @param notify 接受通知反馈 15 | */ 16 | fun loadFilter( 17 | localWords: List, 18 | punctuations: List, 19 | replacement: Char, 20 | isCloudEnabled: Boolean, 21 | cloudUrls: List, 22 | ignoredCloudWords: List, 23 | updateCloud: Boolean = true, 24 | notify: ProxyCommandSender? = console() 25 | ) 26 | 27 | /** 28 | * 加载云端词库 29 | */ 30 | fun loadCloudThesaurus(notify: ProxyCommandSender? = console()) 31 | 32 | /** 33 | * 根据玩家的权限 (trchat.bypass.filter),过滤一个字符串 34 | * 35 | * @param string 待过滤字符串 36 | * @param player 玩家 37 | * @param execute 是否真的过滤 38 | * @return 过滤后的字符串 39 | */ 40 | fun filter(string: String, player: ProxyPlayer? = null, execute: Boolean = true): FilteredObject 41 | 42 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/ProxyMessageManager.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api 2 | 3 | import java.util.concurrent.ExecutorService 4 | import java.util.concurrent.Future 5 | 6 | interface ProxyMessageManager { 7 | 8 | val executor: ExecutorService 9 | 10 | val allNames: MutableMap> 11 | 12 | fun sendMessage(recipient: Any, vararg args: String): Future<*> 13 | 14 | fun updateAllNames() 15 | 16 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/ProxyMode.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api 2 | 3 | enum class ProxyMode { 4 | 5 | NONE, REDIS, BUNGEE, VELOCITY 6 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/TrChatAPI.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api 2 | 3 | /** 4 | * @author ItsFlicker 5 | * @since 2022/6/18 15:13 6 | */ 7 | interface TrChatAPI { 8 | 9 | fun getComponentManager(): ComponentManager 10 | 11 | fun getChannelManager(): ChannelManager 12 | 13 | fun getFilterManager(): FilterManager 14 | 15 | fun getClientMessageManager(): ClientMessageManager 16 | 17 | fun getProxyMessageManager(): ProxyMessageManager 18 | 19 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/api/impl/DefaultTrChatAPI.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.impl 2 | 3 | import me.arasple.mc.trchat.TrChat 4 | import me.arasple.mc.trchat.api.* 5 | import taboolib.common.LifeCycle 6 | import taboolib.common.platform.Awake 7 | import taboolib.common.platform.PlatformFactory 8 | 9 | /** 10 | * @author ItsFlicker 11 | * @since 2022/6/18 15:26 12 | */ 13 | object DefaultTrChatAPI : TrChatAPI { 14 | 15 | @Awake(LifeCycle.CONST) 16 | fun init() { 17 | TrChat.register(this) 18 | } 19 | 20 | override fun getComponentManager() = PlatformFactory.getAPI() 21 | 22 | override fun getChannelManager() = PlatformFactory.getAPI() 23 | 24 | override fun getFilterManager() = PlatformFactory.getAPI() 25 | 26 | override fun getClientMessageManager() = PlatformFactory.getAPI() 27 | 28 | override fun getProxyMessageManager() = PlatformFactory.getAPI() 29 | 30 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/module/internal/service/Metrics.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.service 2 | 3 | import taboolib.common.LifeCycle 4 | import taboolib.common.platform.Awake 5 | import taboolib.common.platform.Platform 6 | import taboolib.common.platform.function.pluginVersion 7 | import taboolib.common.platform.function.runningPlatform 8 | import taboolib.module.metrics.Metrics 9 | import taboolib.module.metrics.charts.SingleLineChart 10 | 11 | /** 12 | * @author Arasple 13 | */ 14 | object Metrics { 15 | 16 | private var metrics: Metrics? = null 17 | 18 | private val counts = intArrayOf(0, 0) 19 | 20 | @Awake(LifeCycle.ACTIVE) 21 | internal fun init() { 22 | metrics = when (runningPlatform) { 23 | Platform.BUKKIT -> Metrics(5802, pluginVersion, runningPlatform).apply { 24 | // 聊天次数统计 25 | addCustomChart(SingleLineChart("chat_counts") { 26 | val i = counts[0] 27 | counts[0] = 0 28 | i 29 | }) 30 | // 敏感词过滤器启用统计 31 | addCustomChart(SingleLineChart("filter_counts") { 32 | val i = counts[1] 33 | counts[1] = 0 34 | i 35 | }) 36 | } 37 | Platform.BUNGEE -> Metrics(5803, pluginVersion, runningPlatform) 38 | Platform.VELOCITY -> Metrics(12541, pluginVersion, runningPlatform) 39 | else -> null 40 | } 41 | } 42 | 43 | fun increase(index: Int, value: Int = 1) { 44 | if (counts[index] < Int.MAX_VALUE) { 45 | counts[index] += value 46 | } 47 | } 48 | 49 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/module/internal/service/Updater.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.service 2 | 3 | import me.arasple.mc.trchat.util.parseJson 4 | import taboolib.common.LifeCycle 5 | import taboolib.common.PrimitiveIO 6 | import taboolib.common.platform.ProxyPlayer 7 | import taboolib.common.platform.SkipTo 8 | import taboolib.common.platform.function.console 9 | import taboolib.common.platform.function.pluginVersion 10 | import taboolib.common.util.Version 11 | import taboolib.module.lang.sendLang 12 | import java.io.BufferedInputStream 13 | import java.net.URL 14 | import java.nio.charset.StandardCharsets 15 | import java.util.* 16 | 17 | @SkipTo(LifeCycle.LOAD) 18 | object Updater { 19 | 20 | private const val api_url = "https://api.github.com/repos/TrPlugins/TrChat/releases/latest" 21 | private var notify = false 22 | val notified = mutableListOf() 23 | val current_version = Version(pluginVersion) 24 | var latest_Version = Version("0.0") 25 | var information = "" 26 | 27 | fun grabInfo() { 28 | if (latest_Version.version[0] > 0) { 29 | return 30 | } 31 | kotlin.runCatching { 32 | URL(api_url).openConnection().also { it.connectTimeout = 30 * 1000; it.readTimeout = 30 * 1000 }.getInputStream().use { inputStream -> 33 | BufferedInputStream(inputStream).use { bufferedInputStream -> 34 | val read = PrimitiveIO.readFully(bufferedInputStream, StandardCharsets.UTF_8) 35 | val json = read.parseJson().asJsonObject 36 | val latestVersion = json["tag_name"].asString.removePrefix("v") 37 | latest_Version = Version(latestVersion) 38 | information = json["body"].asString 39 | notifyConsole() 40 | } 41 | } 42 | } 43 | } 44 | 45 | fun notifyPlayer(player: ProxyPlayer) { 46 | if (player.hasPermission("trchat.admin") && latest_Version > current_version && player.uniqueId !in notified) { 47 | player.sendLang("Plugin-Updater-Header", current_version.source, latest_Version.source) 48 | information.lines().forEach { 49 | player.sendMessage(it) 50 | } 51 | player.sendLang("Plugin-Updater-Footer") 52 | notified.add(player.uniqueId) 53 | } 54 | } 55 | 56 | private fun notifyConsole() { 57 | if (latest_Version > current_version) { 58 | console().sendLang("Plugin-Updater-Header", current_version.source, latest_Version.source) 59 | console().sendMessage(information) 60 | console().sendLang("Plugin-Updater-Footer") 61 | } else { 62 | if (!notify) { 63 | notify = true 64 | if (current_version > latest_Version) { 65 | console().sendLang("Plugin-Updater-Dev") 66 | } else { 67 | console().sendLang("Plugin-Updater-Latest") 68 | } 69 | } 70 | } 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/util/ArrayConverter.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util 2 | 3 | import taboolib.common.util.asList 4 | import taboolib.library.configuration.Converter 5 | 6 | class ArrayConverter : Converter, Any> { 7 | override fun convertToField(value: Any): Array { 8 | return value.asList().toTypedArray() 9 | } 10 | 11 | override fun convertFromField(value: Array): Any { 12 | return if (value.size == 1) value[0] else value.toList() 13 | } 14 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/util/Cooldown.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util 2 | 3 | import java.util.* 4 | import java.util.concurrent.ConcurrentHashMap 5 | 6 | object Cooldowns { 7 | 8 | private val COOLDOWNS = ConcurrentHashMap() 9 | 10 | fun getCooldownLeft(uuid: UUID, type: String): Long { 11 | return COOLDOWNS.computeIfAbsent(uuid) { Cooldown() }.data.getOrDefault(type, 0L) - System.currentTimeMillis() 12 | } 13 | 14 | fun isInCooldown(uuid: UUID, type: String): Boolean { 15 | return getCooldownLeft(uuid, type) > 0 16 | } 17 | 18 | fun updateCooldown(uuid: UUID, type: String, lasts: Long) { 19 | COOLDOWNS.computeIfAbsent(uuid) { Cooldown() }.data[type] = System.currentTimeMillis() + lasts 20 | } 21 | } 22 | 23 | data class Cooldown(val data: ConcurrentHashMap = ConcurrentHashMap()) 24 | 25 | enum class CooldownType(val alias: String) { 26 | 27 | /** 28 | * Chat Cooldown Types 29 | */ 30 | 31 | CHAT("Chat"), 32 | ITEM_SHOW("ItemShow"), 33 | MENTION("Mention"), 34 | MENTION_ALL("MentionAll"), 35 | INVENTORY_SHOW("InventoryShow"), 36 | ENDERCHEST_SHOW("EnderChestShow"), 37 | IMAGE_SHOW("ImageShow") 38 | 39 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/util/Util.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util 2 | 3 | import com.eatthepath.uuid.FastUUID 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonParser 6 | import taboolib.common.platform.function.console 7 | import java.util.* 8 | 9 | private val jsonParser = JsonParser() 10 | private val reportedErrors = mutableListOf() 11 | val nilUUID = UUID(0, 0) 12 | val papiRegex = "(%)(.+?)(%)|(:)(.+?)(:)|(?!\\{\")((\\{)(.+?)(}))".toRegex() 13 | 14 | fun Throwable.print(title: String, printStackTrace: Boolean = true) { 15 | console().sendMessage("§c[TrChat] §7$title") 16 | console().sendMessage("§7${javaClass.name}: $localizedMessage") 17 | if (printStackTrace){ 18 | stackTrace.forEach { console().sendMessage("§8\tat $it") } 19 | printCause() 20 | } 21 | } 22 | 23 | private fun Throwable.printCause() { 24 | val cause = cause 25 | if (cause != null) { 26 | console().sendMessage("§7Caused by: ${javaClass.name}: ${cause.localizedMessage}") 27 | cause.stackTrace.forEach { console().sendMessage("§8\tat $it") } 28 | cause.printCause() 29 | } 30 | } 31 | 32 | fun Throwable.reportOnce(title: String, printStackTrace: Boolean = true) { 33 | if (title !in reportedErrors) { 34 | print(title, printStackTrace) 35 | reportedErrors += title 36 | } 37 | } 38 | 39 | fun String.parseJson(): JsonElement = jsonParser.parse(this)!! 40 | 41 | fun String.toUUID(): UUID = FastUUID.parseUUID(this) 42 | 43 | fun UUID.parseString(): String = FastUUID.toString(this) -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/util/YamlUpdater.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util 2 | 3 | import taboolib.common.PrimitiveIO 4 | import taboolib.common.PrimitiveSettings 5 | import taboolib.common.platform.function.getDataFolder 6 | import taboolib.library.configuration.ConfigurationSection 7 | import taboolib.module.configuration.Configuration 8 | import java.io.File 9 | 10 | /** 11 | * module-starrysky 12 | * com.mcstarrysky.starrysky.config.YamlUpdater 13 | * 14 | * @author 米擦亮 15 | * @since 2023/9/6 20:50 16 | */ 17 | object YamlUpdater { 18 | 19 | fun update(path: String, skipNodes: Array = emptyArray(), updateExists: Boolean = true) { 20 | // 读取 Jar 包内的对应配置文件 21 | val cache = Configuration.loadFromInputStream(javaClass.classLoader.getResourceAsStream(path) ?: error("resource not found: $path")) 22 | val file = File(getDataFolder(), path) 23 | if (!file.exists()) { 24 | return 25 | } 26 | val config = Configuration.loadFromFile(file) 27 | 28 | val updated = mutableListOf() 29 | read(cache, config, skipNodes, updated, updateExists) 30 | if (updated.isNotEmpty()) { 31 | config.saveToFile(config.file) 32 | } 33 | 34 | if (PrimitiveSettings.IS_DEBUG_MODE) { 35 | PrimitiveIO.println("Auto updated configuration: $path, with ${updated.size} elements updated.") 36 | for (node in updated) { 37 | PrimitiveIO.println("|- $node") 38 | } 39 | } 40 | } 41 | 42 | private fun read(cache: ConfigurationSection, to: ConfigurationSection, skipNodes: Array, updated: MutableList, updateExists: Boolean) { 43 | var name = cache.name 44 | var c = cache 45 | while (c.parent != null) { 46 | name = "${c.parent!!.name}.$name" 47 | c = c.parent!! 48 | } 49 | if (name.isNotEmpty()) { 50 | name += '.' 51 | } 52 | // 遍历给定新版配置文件的所有配置项目 53 | for (key in cache.getKeys(false)) { 54 | // 白名单配置项不进行任何检查 55 | if (key in skipNodes) continue 56 | 57 | // 旧版没有, 添加 58 | if (!to.contains(key)) { 59 | updated += "$name$key (+)" 60 | to[key] = cache[key] 61 | continue 62 | } 63 | 64 | // 是否不更新已存在配置, 只补全缺失项 65 | if (!updateExists) continue 66 | 67 | // 好像 switch case 不能判断为空, 我基础没学好 68 | if (cache[key] == null) { 69 | updated += "$name$key (${to[key]} -> null)" 70 | to[key] = null 71 | continue 72 | } 73 | 74 | val read = cache[key] 75 | 76 | if (read is ConfigurationSection) { 77 | val write = to[key] 78 | // 根本不是配置选区, 那肯定要覆盖掉了, 没话说了 79 | if (write == null || write !is ConfigurationSection) { 80 | updated += "$name$key (${to[key]} -> $read)" 81 | to[key] = read 82 | continue 83 | } 84 | read(read, write, skipNodes, updated, true) 85 | } else { 86 | if (read == to[key]) continue 87 | updated += "$name$key (${to[key]} -> $read)" 88 | to[key] = read 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/me/arasple/mc/trchat/util/proxy/ProxyUtil.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.util.proxy 2 | 3 | import me.arasple.mc.trchat.util.parseString 4 | import me.arasple.mc.trchat.util.proxy.common.MessageBuilder 5 | import java.util.* 6 | 7 | fun buildMessage(vararg messages: String): List { 8 | return MessageBuilder.create(arrayOf(UUID.randomUUID().parseString(), *messages)) 9 | } -------------------------------------------------------------------------------- /project/module-adventure/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly(project(":project:common")) 3 | compileOnly(project(":project:module-nms")) 4 | compileOnly("net.kyori:adventure-platform-bukkit:4.3.4") 5 | compileOnly(fileTree(rootDir.resolve("libs"))) 6 | } 7 | 8 | taboolib { subproject = true } -------------------------------------------------------------------------------- /project/module-adventure/src/main/kotlin/me/arasple/mc/trchat/module/adventure/Adventure.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.adventure 2 | 3 | import net.kyori.adventure.text.Component 4 | import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer 5 | import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer 6 | import org.bukkit.inventory.ItemStack 7 | import taboolib.module.chat.ComponentText 8 | import taboolib.module.chat.Components 9 | 10 | private val legacySerializer: Any? = try { 11 | LegacyComponentSerializer.legacySection() 12 | } catch (_: Throwable) { 13 | null 14 | } 15 | 16 | private val gsonSerializer: Any? = try { 17 | GsonComponentSerializer.gson() 18 | } catch (_: Throwable) { 19 | null 20 | } 21 | 22 | fun gson(component: Component) = (gsonSerializer as GsonComponentSerializer).serialize(component) 23 | 24 | fun gson(string: String) = (gsonSerializer as GsonComponentSerializer).deserialize(string) 25 | 26 | fun Component.toNative() = Components.parseRaw(gson(this)) 27 | 28 | fun ComponentText.toAdventure() = gson(toRawMessage()) 29 | 30 | fun ComponentText.hoverItemAdventure(item: ItemStack): ComponentText { 31 | return toAdventure().hoverEvent(item.asHoverEvent()).toNative() 32 | } -------------------------------------------------------------------------------- /project/module-compat/build.gradle.kts: -------------------------------------------------------------------------------- 1 | repositories { 2 | maven("https://nexus.scarsz.me/content/groups/public/") 3 | maven("https://repo.oraxen.com/releases") 4 | // maven("https://repo.nexomc.com/releases") 5 | } 6 | 7 | dependencies { 8 | compileOnly(project(":project:common")) 9 | compileOnly("ink.ptms.core:v12005:12005:universal") 10 | 11 | compileOnly("com.discordsrv:discordsrv:1.26.0") { isTransitive = false } 12 | compileOnly("com.willfp:eco:6.35.1") { isTransitive = false } 13 | 14 | compileOnly("com.github.LoneDev6:api-itemsadder:3.6.3-beta-14") { isTransitive = false } 15 | // compileOnly("com.nexomc:nexo:0.7.0") 16 | 17 | compileOnly("xyz.xenondevs.nova:nova-api:0.12.13") { isTransitive = false } 18 | compileOnly("io.th0rgal:oraxen:1.170.0") { isTransitive = false } 19 | } 20 | 21 | taboolib { subproject = true } -------------------------------------------------------------------------------- /project/module-compat/src/main/kotlin/me/arasple/mc/trchat/module/internal/hook/HookAbstract.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.hook 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.plugin.Plugin 5 | import taboolib.common.util.unsafeLazy 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2021/1/26 22:02 10 | */ 11 | abstract class HookAbstract { 12 | 13 | open val name by unsafeLazy { getPluginName() } 14 | 15 | val plugin: Plugin? by unsafeLazy { 16 | Bukkit.getPluginManager().getPlugin(name) 17 | } 18 | 19 | val isHooked by unsafeLazy { 20 | plugin != null && plugin!!.isEnabled 21 | } 22 | 23 | open fun getPluginName(): String { 24 | return javaClass.simpleName.substring(4) 25 | } 26 | 27 | open fun init() = Unit 28 | 29 | } -------------------------------------------------------------------------------- /project/module-compat/src/main/kotlin/me/arasple/mc/trchat/module/internal/hook/HookPlugin.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.hook 2 | 3 | import me.arasple.mc.trchat.module.internal.hook.impl.HookDiscordSRV 4 | import me.arasple.mc.trchat.module.internal.hook.impl.HookEcoEnchants 5 | import me.arasple.mc.trchat.module.internal.hook.impl.HookItemsAdder 6 | import me.arasple.mc.trchat.module.internal.hook.impl.HookNova 7 | import me.arasple.mc.trchat.module.internal.hook.type.HookDisplayItem 8 | import org.bukkit.entity.Player 9 | import org.bukkit.inventory.ItemStack 10 | import taboolib.common.platform.Platform 11 | import taboolib.common.platform.PlatformSide 12 | import taboolib.common.platform.function.console 13 | import taboolib.module.lang.sendLang 14 | import java.util.function.BiFunction 15 | 16 | /** 17 | * @author Arasple 18 | * @date 2021/1/26 22:04 19 | */ 20 | @PlatformSide(Platform.BUKKIT) 21 | object HookPlugin { 22 | 23 | val registry = arrayListOf( 24 | HookDiscordSRV(), 25 | HookEcoEnchants(), 26 | HookItemsAdder(), 27 | HookNova() 28 | ) 29 | 30 | fun printInfo() { 31 | registry.filter { it.isHooked }.forEach { 32 | it.init() 33 | console().sendLang("Plugin-Dependency-Hooked", it.name) 34 | } 35 | } 36 | 37 | fun addHook(element: HookAbstract) { 38 | registry.add(element) 39 | console().sendLang("Plugin-Dependency-Hooked", element.name) 40 | } 41 | 42 | fun registerDisplayItemHook(name: String, func: BiFunction) { 43 | addHook(object : HookDisplayItem() { 44 | override fun getPluginName(): String { 45 | return name 46 | } 47 | override fun displayItem(item: ItemStack, player: Player): ItemStack { 48 | return func.apply(item, player) 49 | } 50 | }) 51 | } 52 | 53 | fun getDiscordSRV(): HookDiscordSRV { 54 | return registry[0] as HookDiscordSRV 55 | } 56 | 57 | fun getEcoEnchants(): HookEcoEnchants { 58 | return registry[1] as HookEcoEnchants 59 | } 60 | 61 | fun getItemsAdder(): HookItemsAdder { 62 | return registry[2] as HookItemsAdder 63 | } 64 | 65 | fun getNova(): HookNova { 66 | return registry[3] as HookNova 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /project/module-compat/src/main/kotlin/me/arasple/mc/trchat/module/internal/hook/impl/HookDiscordSRV.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.hook.impl 2 | 3 | import github.scarsz.discordsrv.DiscordSRV 4 | import me.arasple.mc.trchat.module.internal.hook.HookAbstract 5 | 6 | class HookDiscordSRV : HookAbstract() { 7 | 8 | fun registerListener(listener: Any) { 9 | if (!isHooked) return 10 | DiscordSRV.api.subscribe(listener) 11 | } 12 | 13 | } -------------------------------------------------------------------------------- /project/module-compat/src/main/kotlin/me/arasple/mc/trchat/module/internal/hook/impl/HookEcoEnchants.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.hook.impl 2 | 3 | import com.willfp.eco.core.display.Display 4 | import me.arasple.mc.trchat.module.internal.hook.type.HookDisplayItem 5 | import org.bukkit.entity.Player 6 | import org.bukkit.inventory.ItemStack 7 | import taboolib.platform.util.isAir 8 | 9 | /** 10 | * @author ItsFlicker 11 | * @since 2022/2/5 22:30 12 | */ 13 | class HookEcoEnchants : HookDisplayItem() { 14 | 15 | override fun displayItem(item: ItemStack, player: Player): ItemStack { 16 | if (!isHooked || item.isAir()) { 17 | return item 18 | } 19 | return try { 20 | Display.displayAndFinalize(item, player) 21 | } catch (_: Throwable){ 22 | Display.displayAndFinalize(item) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /project/module-compat/src/main/kotlin/me/arasple/mc/trchat/module/internal/hook/impl/HookItemsAdder.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.hook.impl 2 | 3 | import dev.lone.itemsadder.api.FontImages.FontImageWrapper 4 | import me.arasple.mc.trchat.module.internal.hook.HookAbstract 5 | import org.bukkit.entity.Player 6 | import taboolib.module.nms.MinecraftVersion.versionId 7 | 8 | /** 9 | * @author ItsFlicker 10 | * @since 2022/2/5 22:30 11 | */ 12 | class HookItemsAdder : HookAbstract() { 13 | 14 | fun replaceFontImages(message: String, player: Player?): String { 15 | if (!isHooked) { 16 | return message 17 | } 18 | return try { 19 | if (player == null || versionId >= 12005) { 20 | FontImageWrapper.replaceFontImages(message) 21 | } else { 22 | FontImageWrapper.replaceFontImages(player, message) 23 | } 24 | } catch (_: Throwable) { 25 | message 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /project/module-compat/src/main/kotlin/me/arasple/mc/trchat/module/internal/hook/impl/HookNova.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.hook.impl 2 | 3 | import me.arasple.mc.trchat.module.internal.hook.type.HookDisplayItem 4 | import org.bukkit.entity.Player 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.common.platform.function.adaptPlayer 7 | import taboolib.library.xseries.XMaterial 8 | import taboolib.module.lang.getLocale 9 | import taboolib.platform.util.buildItem 10 | import taboolib.platform.util.isAir 11 | import xyz.xenondevs.nova.api.Nova 12 | 13 | class HookNova : HookDisplayItem() { 14 | 15 | override fun displayItem(item: ItemStack, player: Player): ItemStack { 16 | if (!isHooked || item.isAir()) { 17 | return item 18 | } 19 | val novaMaterial = Nova.materialRegistry.getOrNull(item) ?: return item 20 | return buildItem(XMaterial.SHULKER_SHELL) { 21 | amount = item.amount 22 | name = "§f" + novaMaterial.getLocalizedName(adaptPlayer(player).getLocale().lowercase()) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /project/module-compat/src/main/kotlin/me/arasple/mc/trchat/module/internal/hook/type/HookDisplayItem.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.internal.hook.type 2 | 3 | import me.arasple.mc.trchat.module.internal.hook.HookAbstract 4 | import org.bukkit.entity.Player 5 | import org.bukkit.inventory.ItemStack 6 | 7 | /** 8 | * TrChat 9 | * me.arasple.mc.trchat.module.internal.hook.type.HookDisplayItem 10 | * 11 | * @author xiaomu 12 | * @since 2022/10/24 8:22 PM 13 | */ 14 | abstract class HookDisplayItem : HookAbstract() { 15 | 16 | abstract fun displayItem(item: ItemStack, player: Player): ItemStack 17 | } -------------------------------------------------------------------------------- /project/module-nms/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | compileOnly(project(":project:common")) 3 | // compileOnly("ink.ptms.core:v12101:12101:mapped") 4 | // compileOnly("ink.ptms.core:v12005:12005:mapped") 5 | compileOnly("ink.ptms.core:v12004:12004:mapped") 6 | compileOnly("ink.ptms.core:v12002:12002:mapped") 7 | compileOnly("ink.ptms.core:v11903:11903:mapped") 8 | compileOnly("ink.ptms.core:v11902:11902:mapped") 9 | compileOnly("ink.ptms.core:v11901:11901:mapped") 10 | compileOnly("ink.ptms.core:v11900:11900:mapped") 11 | compileOnly("ink.ptms:nms-all:1.0.0") 12 | compileOnly("com.velocitypowered:velocity-brigadier:1.0.0-SNAPSHOT") 13 | } 14 | 15 | taboolib { subproject = true } -------------------------------------------------------------------------------- /project/module-nms/src/main/kotlin/me/arasple/mc/trchat/api/nms/NMS.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.nms 2 | 3 | import org.bukkit.entity.Player 4 | import org.bukkit.inventory.ItemStack 5 | import taboolib.common.util.unsafeLazy 6 | import taboolib.module.chat.ComponentText 7 | import taboolib.module.nms.MinecraftLanguage 8 | import taboolib.module.nms.MinecraftVersion 9 | import taboolib.module.nms.nmsProxy 10 | import java.util.* 11 | 12 | abstract class NMS { 13 | 14 | /** 15 | * ComponentText -> IChatBaseComponent 16 | */ 17 | abstract fun craftChatMessageFromComponent(component: ComponentText): Any 18 | 19 | /** 20 | * IChatBaseComponent -> raw string 21 | */ 22 | abstract fun rawMessageFromCraftChatMessage(component: Any): String 23 | 24 | abstract fun sendMessage(receiver: Player, component: ComponentText, sender: UUID?, usePacket: Boolean = true) 25 | 26 | abstract fun hoverItem(component: ComponentText, itemStack: ItemStack): ComponentText 27 | 28 | abstract fun optimizeNBT(itemStack: ItemStack, nbtWhitelist: Array = whitelistTags): ItemStack 29 | 30 | abstract fun getLocaleKey(itemStack: ItemStack): MinecraftLanguage.LanguageKey 31 | 32 | companion object { 33 | 34 | @JvmStatic 35 | val instance by unsafeLazy { 36 | if (MinecraftVersion.versionId < 12005) nmsProxy() 37 | else nmsProxy("me.arasple.mc.trchat.api.nms.NMSImpl12005") 38 | } 39 | 40 | // 1.20.4- 41 | val whitelistTags = arrayOf( 42 | // 附魔 43 | "ench", 44 | // 附魔 1.14 45 | "Enchantments", 46 | // 附魔书 47 | "StoredEnchantments", 48 | // 展示 49 | "display", 50 | // 属性 51 | "AttributeModifiers", 52 | // 药水 53 | "Potion", 54 | // 特殊药水 55 | "CustomPotionEffects", 56 | // 隐藏标签 57 | "HideFlags" 58 | ) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /project/module-nms/src/main/kotlin/me/arasple/mc/trchat/api/nms/NMSImpl12005.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.nms 2 | 3 | import me.arasple.mc.trchat.util.ServerUtil 4 | import net.minecraft.network.chat.IChatBaseComponent 5 | import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer 6 | import org.bukkit.craftbukkit.v1_20_R3.util.CraftChatMessage 7 | import org.bukkit.entity.Player 8 | import org.bukkit.inventory.ItemStack 9 | import taboolib.common.platform.function.adaptPlayer 10 | import taboolib.module.chat.ComponentText 11 | import taboolib.module.nms.MinecraftLanguage 12 | import taboolib.module.nms.getLanguageKey 13 | import taboolib.platform.Folia 14 | import taboolib.platform.util.hoverItem 15 | import java.util.* 16 | 17 | class NMSImpl12005 : NMS() { 18 | 19 | override fun craftChatMessageFromComponent(component: ComponentText): Any { 20 | return CraftChatMessage.fromJSON(component.toRawMessage()) 21 | } 22 | 23 | override fun rawMessageFromCraftChatMessage(component: Any): String { 24 | return CraftChatMessage.toJSON(component as IChatBaseComponent) 25 | } 26 | 27 | override fun sendMessage(receiver: Player, component: ComponentText, sender: UUID?, usePacket: Boolean) { 28 | if (!usePacket || Folia.isFolia || ServerUtil.isModdedServer) { 29 | component.sendTo(adaptPlayer(receiver)) 30 | return 31 | } 32 | val player = (receiver as CraftPlayer).handle 33 | player.sendSystemMessage(craftChatMessageFromComponent(component) as IChatBaseComponent) 34 | } 35 | 36 | override fun hoverItem(component: ComponentText, itemStack: ItemStack): ComponentText { 37 | return component.hoverItem(itemStack) 38 | } 39 | 40 | override fun optimizeNBT(itemStack: ItemStack, nbtWhitelist: Array): ItemStack { 41 | return itemStack 42 | } 43 | 44 | override fun getLocaleKey(itemStack: ItemStack): MinecraftLanguage.LanguageKey { 45 | return itemStack.getLanguageKey() 46 | } 47 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/build.gradle.kts: -------------------------------------------------------------------------------- 1 | repositories { 2 | maven("https://nexus.scarsz.me/content/groups/public/") 3 | } 4 | 5 | dependencies { 6 | compileOnly(project(":project:common")) 7 | compileOnly(project(":project:module-adventure")) 8 | compileOnly(project(":project:module-compat")) 9 | compileOnly(project(":project:module-nms")) 10 | compileOnly("ink.ptms.core:v12005:12005:universal") 11 | compileOnly("net.md-5:bungeecord-api:1.21-R0.2") 12 | compileOnly(fileTree(rootDir.resolve("libs"))) 13 | 14 | compileOnly("me.clip:placeholderapi:2.11.5") { isTransitive = false } 15 | compileOnly("com.discordsrv:discordsrv:1.26.0") { isTransitive = false } 16 | } 17 | 18 | taboolib { subproject = true } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/api/event/CustomDatabaseEvent.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.event 2 | 3 | import taboolib.expansion.Database 4 | import taboolib.platform.type.BukkitProxyEvent 5 | 6 | class CustomDatabaseEvent(val name: String, var database: Database? = null) : BukkitProxyEvent() { 7 | 8 | override val allowCancelled: Boolean 9 | get() = false 10 | 11 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/api/event/TrChatEvent.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.event 2 | 3 | import me.arasple.mc.trchat.module.display.ChatSession 4 | import me.arasple.mc.trchat.module.display.channel.Channel 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | /** 8 | * TrChatEvent 9 | * me.arasple.mc.trchat.api.event 10 | * 11 | * @author ItsFlicker 12 | * @since 2021/8/20 20:53 13 | */ 14 | class TrChatEvent( 15 | val channel: Channel, 16 | val session: ChatSession, 17 | var message: String, 18 | val forward: Boolean = true 19 | ) : BukkitProxyEvent() { 20 | 21 | val player = session.player 22 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/api/event/TrChatItemShowEvent.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.event 2 | 3 | import org.bukkit.entity.Player 4 | import org.bukkit.inventory.ItemStack 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | class TrChatItemShowEvent( 8 | val player: Player, 9 | var item: ItemStack, 10 | val isCompatibleMode: Boolean 11 | ) : BukkitProxyEvent() { 12 | 13 | override val allowCancelled: Boolean 14 | get() = false 15 | 16 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/api/event/TrChatMentionEvent.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.event 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.platform.type.BukkitProxyEvent 5 | 6 | class TrChatMentionEvent( 7 | val sender: Player, 8 | val receiver: String 9 | ) : BukkitProxyEvent() { 10 | 11 | override val allowCancelled: Boolean 12 | get() = true 13 | 14 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/api/event/TrChatReceiveEvent.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.event 2 | 3 | import me.arasple.mc.trchat.module.display.ChatSession 4 | import me.arasple.mc.trchat.util.session 5 | import org.bukkit.command.CommandSender 6 | import org.bukkit.entity.Player 7 | import taboolib.module.chat.ComponentText 8 | import taboolib.platform.type.BukkitProxyEvent 9 | import java.util.* 10 | 11 | class TrChatReceiveEvent( 12 | val receiver: CommandSender, 13 | var sender: UUID?, 14 | var message: ComponentText, 15 | val session: ChatSession? = (receiver as? Player)?.session 16 | ): BukkitProxyEvent() { 17 | 18 | val player = session?.player 19 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/api/event/TrChatReloadEvent.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.event 2 | 3 | import taboolib.platform.type.BukkitProxyEvent 4 | 5 | class TrChatReloadEvent { 6 | 7 | class Function(val functions: MutableList) : BukkitProxyEvent() { 8 | 9 | override val allowCancelled: Boolean 10 | get() = false 11 | 12 | } 13 | 14 | class Channel(val channels: MutableMap) : BukkitProxyEvent() { 15 | 16 | override val allowCancelled: Boolean 17 | get() = false 18 | 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/api/impl/BukkitChannelManager.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.api.impl 2 | 3 | import me.arasple.mc.trchat.api.ChannelManager 4 | import me.arasple.mc.trchat.module.conf.Loader 5 | import me.arasple.mc.trchat.module.display.channel.Channel 6 | import taboolib.common.LifeCycle 7 | import taboolib.common.platform.* 8 | 9 | /** 10 | * @author ItsFlicker 11 | * @since 2022/6/19 19:57 12 | */ 13 | @PlatformSide(Platform.BUKKIT) 14 | object BukkitChannelManager : ChannelManager { 15 | 16 | @Awake(LifeCycle.CONST) 17 | fun init() { 18 | PlatformFactory.registerAPI(this) 19 | } 20 | 21 | override fun loadChannels(sender: ProxyCommandSender) { 22 | Loader.loadChannels(sender) 23 | } 24 | 25 | override fun getChannel(id: String): Channel? { 26 | return Channel.channels[id] 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/conf/Property.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.conf 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/2/11 17:26 6 | */ 7 | enum class Property(val regex: Regex, val group: Int) { 8 | 9 | CONDITION("\\{condition[:=] ?(.+)}"), 10 | 11 | EXACT("\\{exact[:=] ?(.+)}"), 12 | 13 | RELOCATE("\\{relocate[:=] ?(.+)}"), 14 | 15 | COOLDOWN("\\{cooldown[:=] ?(.+)}"); 16 | 17 | constructor(regex: String, group: Int = 1) : this(regex.toRegex(RegexOption.IGNORE_CASE), group) 18 | 19 | companion object { 20 | 21 | fun from(string: String): Pair> { 22 | var content = string 23 | val map = values().mapNotNull { 24 | val value = it.regex.find(content)?.groupValues?.get(it.group) 25 | value?.let { v -> 26 | content = content.replace(it.regex, "") 27 | it to v 28 | } 29 | }.toMap() 30 | 31 | return content to map 32 | } 33 | 34 | fun serialize(contents: Any): List>> { 35 | return when (contents) { 36 | is String -> listOf(from(contents)) 37 | is List<*> -> contents.map { from(it!!.toString()) } 38 | else -> error("Unexpected part: $contents") 39 | } 40 | } 41 | 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/conf/file/Filters.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.conf.file 2 | 3 | import me.arasple.mc.trchat.TrChat 4 | import taboolib.common.LifeCycle 5 | import taboolib.common.platform.Awake 6 | import taboolib.common.platform.Platform 7 | import taboolib.common.platform.PlatformSide 8 | import taboolib.common.platform.ProxyCommandSender 9 | import taboolib.common.platform.function.console 10 | import taboolib.module.configuration.Config 11 | import taboolib.module.configuration.Configuration 12 | 13 | /** 14 | * @author ItsFlicker 15 | * @since 2022/2/4 13:04 16 | */ 17 | @PlatformSide(Platform.BUKKIT) 18 | object Filters { 19 | 20 | @Config("filter.yml") 21 | lateinit var conf: Configuration 22 | private set 23 | 24 | @Awake(LifeCycle.ENABLE) 25 | fun init() { 26 | conf.onReload { reload() } 27 | } 28 | 29 | fun reload(notify: ProxyCommandSender = console()) { 30 | TrChat.api().getFilterManager().loadFilter( 31 | conf.getStringList("Local"), 32 | conf.getStringList("Ignored-Punctuations"), 33 | conf.getString("Replacement", "*")!![0], 34 | conf.getBoolean("Cloud-Thesaurus.Enabled"), 35 | conf.getStringList("Cloud-Thesaurus.Urls"), 36 | conf.getStringList("Cloud-Thesaurus.Ignored"), 37 | updateCloud = true, 38 | notify = notify 39 | ) 40 | } 41 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/conf/file/Functions.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.conf.file 2 | 3 | import me.arasple.mc.trchat.module.conf.Loader 4 | import me.arasple.mc.trchat.module.conf.Property 5 | import org.bukkit.Bukkit 6 | import taboolib.common.LifeCycle 7 | import taboolib.common.platform.Awake 8 | import taboolib.common.platform.Platform 9 | import taboolib.common.platform.PlatformSide 10 | import taboolib.common.platform.function.console 11 | import taboolib.common.util.ResettableLazy 12 | import taboolib.common5.Baffle 13 | import taboolib.module.configuration.Config 14 | import taboolib.module.configuration.ConfigNode 15 | import taboolib.module.configuration.ConfigNodeTransfer 16 | import taboolib.module.configuration.Configuration 17 | import java.util.concurrent.TimeUnit 18 | 19 | /** 20 | * @author ItsFlicker 21 | * @since 2021/12/12 11:40 22 | */ 23 | @PlatformSide(Platform.BUKKIT) 24 | object Functions { 25 | 26 | @Config("function.yml", autoReload = true) 27 | lateinit var conf: Configuration 28 | private set 29 | 30 | @Awake(LifeCycle.LOAD) 31 | fun init() { 32 | conf.onReload { 33 | Loader.loadFunctions(console()) 34 | ResettableLazy.reset("functions") 35 | } 36 | } 37 | 38 | @ConfigNode("General.Command-Controller.List", "function.yml") 39 | val commandController = ConfigNodeTransfer, Map> { 40 | associate { string -> 41 | val (cmd, property) = Property.from(string!!.toString()) 42 | val mCmd = Bukkit.getCommandAliases().entries.firstOrNull { (_, value) -> 43 | value.any { it.equals(cmd.split(" ")[0], ignoreCase = true) } 44 | } 45 | val key = if (mCmd != null) mCmd.key + cmd.substringAfter(' ') else cmd 46 | val exact = property[Property.EXACT].toBoolean() 47 | val condition = property[Property.CONDITION] 48 | val baffle = property[Property.COOLDOWN]?.toFloat()?.let { 49 | Baffle.of((it * 1000).toLong(), TimeUnit.MILLISECONDS) 50 | } 51 | val relocate = property[Property.RELOCATE]?.split(';') 52 | key to Command(exact, condition, baffle, relocate) 53 | } 54 | } 55 | 56 | class Command(val exact: Boolean, val condition: String?, val baffle: Baffle?, val relocate: List?) 57 | 58 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/conf/file/Settings.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.conf.file 2 | 3 | import me.arasple.mc.trchat.module.internal.service.Updater 4 | import taboolib.common.LifeCycle 5 | import taboolib.common.platform.Awake 6 | import taboolib.common.platform.Platform 7 | import taboolib.common.platform.PlatformSide 8 | import taboolib.common.platform.function.submitAsync 9 | import taboolib.common5.util.parseMillis 10 | import taboolib.module.configuration.Config 11 | import taboolib.module.configuration.ConfigNode 12 | import taboolib.module.configuration.ConfigNodeTransfer 13 | import taboolib.module.configuration.Configuration 14 | import taboolib.module.kether.Kether 15 | 16 | /** 17 | * @author ItsFlicker 18 | * @since 2021/12/11 23:59 19 | */ 20 | @PlatformSide(Platform.BUKKIT) 21 | object Settings { 22 | 23 | @Config("settings.yml") 24 | lateinit var conf: Configuration 25 | private set 26 | 27 | @ConfigNode("Options.Use-Packets", "settings.yml") 28 | var usePackets = true 29 | private set 30 | 31 | @ConfigNode("Channel.Default", "settings.yml") 32 | var defaultChannel = "Normal" 33 | private set 34 | 35 | @ConfigNode("Chat.Cooldown", "settings.yml") 36 | val chatCooldown = ConfigNodeTransfer { parseMillis() } 37 | 38 | @ConfigNode("Chat.Anti-Repeat", "settings.yml") 39 | var chatSimilarity = 0.85 40 | private set 41 | 42 | @ConfigNode("Chat.Length-Limit", "settings.yml") 43 | var chatLengthLimit = 100 44 | private set 45 | 46 | @ConfigNode("Options.Component-Max-Length", "settings.yml") 47 | var componentMaxLength = 32700 48 | private set 49 | 50 | @ConfigNode("Simple-Component.Hover", "settings.yml") 51 | var simpleHover = false 52 | private set 53 | 54 | @Awake(LifeCycle.ENABLE) 55 | fun init() { 56 | conf.onReload { 57 | Kether.isAllowToleranceParser = conf.getBoolean("Options.Kether-Allow-Tolerance-Parser", true) 58 | } 59 | if (conf.getBoolean("Options.Check-Update", true)) { 60 | submitAsync(delay = 20, period = 15 * 60 * 20) { 61 | Updater.grabInfo() 62 | } 63 | } 64 | } 65 | 66 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/channel/obj/ChannelBindings.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.channel.obj 2 | 3 | /** 4 | * @author ItsFlicker 5 | * @since 2022/2/7 15:15 6 | */ 7 | class ChannelBindings( 8 | val prefix: List?, 9 | val command: List? 10 | ) -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/channel/obj/ChannelEvents.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.channel.obj 2 | 3 | import me.arasple.mc.trchat.module.internal.script.Reaction 4 | import org.bukkit.entity.Player 5 | 6 | /** 7 | * @author ItsFlicker 8 | * @since 2022/6/15 18:03 9 | */ 10 | class ChannelEvents( 11 | private val process: Reaction?, 12 | private val send: Reaction?, 13 | private val join: Reaction?, 14 | private val quit: Reaction? 15 | ) { 16 | 17 | fun process(sender: Player, message: String): String? { 18 | process ?: return message 19 | return when (val result = process.eval(sender, "message" to message)) { 20 | null -> message 21 | is Boolean -> message.takeIf { result } 22 | is String -> result 23 | else -> message 24 | } 25 | } 26 | 27 | fun send(sender: Player, receiver: String, message: String): Boolean { 28 | send ?: return true 29 | return when (val result = send.eval(sender, "receiver" to receiver, "message" to message)) { 30 | null -> true 31 | is Boolean -> result 32 | else -> true 33 | } 34 | } 35 | 36 | fun join(sender: Player) { 37 | join?.eval(sender) 38 | } 39 | 40 | fun quit(sender: Player) { 41 | quit?.eval(sender) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/channel/obj/ChannelExecuteResult.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.channel.obj 2 | 3 | import taboolib.module.chat.ComponentText 4 | 5 | class ChannelExecuteResult( 6 | val senderComponent: ComponentText? = null, 7 | val receiverComponent: ComponentText? = null, 8 | val failedReason: FailReason? = null 9 | ) { 10 | 11 | enum class FailReason { 12 | 13 | LIMITED, NO_RECEIVER, NO_FORMAT, EVENT, EXCEPTION 14 | } 15 | 16 | companion object { 17 | 18 | fun success(senderComponent: ComponentText, receiverComponent: ComponentText? = null): ChannelExecuteResult { 19 | return ChannelExecuteResult(senderComponent, receiverComponent) 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/channel/obj/ChannelRange.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.channel.obj 2 | 3 | /** 4 | * @author ItsFlicker 5 | * @since 2022/2/6 11:13 6 | */ 7 | class ChannelRange(val type: Type, val distance: Int) { 8 | 9 | enum class Type { ALL, SINGLE_WORLD, DISTANCE, SELF } 10 | } -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/channel/obj/ChannelSettings.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.channel.obj 2 | 3 | import me.arasple.mc.trchat.module.internal.script.Condition 4 | 5 | /** 6 | * @author ItsFlicker 7 | * @since 2022/2/5 13:25 8 | */ 9 | class ChannelSettings( 10 | val joinPermission: String = "", 11 | val listenPermission: String = "", 12 | val speakCondition: Condition = Condition.EMPTY, 13 | val alwaysListen: Boolean = true, 14 | val isPrivate: Boolean = false, 15 | val range: ChannelRange = ChannelRange(ChannelRange.Type.ALL, -1), 16 | val proxy: Boolean = false, 17 | val forceProxy: Boolean = false, 18 | val doubleTransfer: Boolean = true, 19 | val ports: List = emptyList(), 20 | val disabledFunctions: List = emptyList(), 21 | val filterBeforeSending: Boolean = false, 22 | val sendToDiscord: Boolean = true, 23 | val receiveFromDiscord: Boolean = true, 24 | val discordChannel: String = "" 25 | ) -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/format/Format.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.format 2 | 3 | import me.arasple.mc.trchat.module.internal.script.Condition 4 | 5 | /** 6 | * @author ItsFlicker 7 | * @since 2021/12/11 23:27 8 | */ 9 | class Format( 10 | val condition: Condition?, 11 | val priority: Int, 12 | val prefix: Map>, 13 | val msg: List, 14 | val suffix: Map> 15 | ) -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/format/Group.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.format 2 | 3 | import me.arasple.mc.trchat.module.internal.script.Condition 4 | 5 | /** 6 | * @author ItsFlicker 7 | * @since 2022/2/5 11:05 8 | */ 9 | class Group( 10 | val condition: Condition?, 11 | val priority: Int, 12 | val content: JsonComponent 13 | ) -------------------------------------------------------------------------------- /project/runtime-bukkit/src/main/kotlin/me/arasple/mc/trchat/module/display/format/JsonComponent.kt: -------------------------------------------------------------------------------- 1 | package me.arasple.mc.trchat.module.display.format 2 | 3 | import me.arasple.mc.trchat.module.display.format.obj.Style 4 | import me.arasple.mc.trchat.module.display.format.obj.Style.Companion.applyTo 5 | import me.arasple.mc.trchat.module.display.format.obj.Text 6 | import me.arasple.mc.trchat.util.pass 7 | import org.bukkit.command.CommandSender 8 | import taboolib.module.chat.ComponentText 9 | import taboolib.module.chat.Components 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2019/11/30 12:42 14 | */ 15 | open class JsonComponent( 16 | val text: List?, 17 | val style: List