From 6c7d7fedcb682cdfd72fe4ef55c68d0188e4c828 Mon Sep 17 00:00:00 2001 From: database-mysql Date: Mon, 9 Nov 2026 07:57:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20OpenSourceTools=20v2.1.0=20-=20?= =?UTF-8?q?=E5=8D=87=E7=BA=A7=20Bukkit=201.21.11,=20=E8=A1=A5=E5=85=85=20R?= =?UTF-8?q?EADME=20=E4=B8=8E=E8=87=AA=E5=8A=A8=E5=8C=96=E6=B5=8B=E8=AF=95?= =?UTF-8?q?=E8=AE=BE=E6=96=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 37 +++ LICENSE | 277 +++++++++++++++++ README.md | 283 ++++++++++++++++++ pom.xml | 100 +++++++ .../top/gtb520/tools/main/Back_Command.java | 27 ++ .../tools/main/KickGUI_ClickGUI_Event.java | 60 ++++ .../top/gtb520/tools/main/PlaceholderAPI.java | 51 ++++ .../tools/main/PlayerChangedWorld_Event.java | 18 ++ .../gtb520/tools/main/PlayerChat_Event.java | 67 +++++ .../gtb520/tools/main/PlayerDeath_Event.java | 14 + .../gtb520/tools/main/PlayerJoin_Event.java | 28 ++ .../gtb520/tools/main/PlayerQuit_Event.java | 27 ++ .../tools/main/PlayerReSpawn_Event.java | 16 + .../tools/main/PlayerTitle_Command.java | 151 ++++++++++ .../top/gtb520/tools/main/Reload_Command.java | 25 ++ .../gtb520/tools/main/SignChange_Event.java | 30 ++ .../top/gtb520/tools/main/Stop_Command.java | 39 +++ .../gtb520/tools/main/SuperKick_Command.java | 74 +++++ .../gtb520/tools/main/SuperList_Command.java | 33 ++ .../top/gtb520/tools/main/TimeMessage.java | 32 ++ .../top/gtb520/tools/main/Tpa_Command.java | 57 ++++ .../top/gtb520/tools/main/Tpa_Detect.java | 40 +++ .../java/top/gtb520/tools/main/Tpa_Time.java | 46 +++ .../top/gtb520/tools/main/YamlFile_Utils.java | 66 ++++ .../top/gtb520/tools/main/day_Command.java | 24 ++ .../top/gtb520/tools/main/feed_Command.java | 37 +++ .../top/gtb520/tools/main/fly_Command.java | 48 +++ .../top/gtb520/tools/main/gm_Command.java | 172 +++++++++++ .../top/gtb520/tools/main/heal_Command.java | 37 +++ src/main/java/top/gtb520/tools/main/main.java | 139 +++++++++ .../java/top/gtb520/tools/main/multi.java | 134 +++++++++ .../top/gtb520/tools/main/mute_Command.java | 87 ++++++ .../gtb520/tools/main/setspawn_Command.java | 33 ++ .../top/gtb520/tools/main/spawn_Command.java | 39 +++ .../top/gtb520/tools/main/sun_Command.java | 23 ++ .../java/top/gtb520/tools/main/testGUI.java | 38 +++ .../gtb520/tools/main/tpaAccept_Command.java | 48 +++ .../gtb520/tools/main/tpaDefuse_Command.java | 44 +++ .../gtb520/tools/main/tpaback_Command.java | 21 ++ .../java/top/gtb520/tools/main/unity.java | 133 ++++++++ .../top/gtb520/tools/main/unmute_Command.java | 74 +++++ .../top/gtb520/tools/main/vanish_Command.java | 65 ++++ src/main/resources/config.yml | 88 ++++++ src/main/resources/plugin.yml | 137 +++++++++ tools/smoke-test/eula.txt | 2 + tools/smoke-test/maven-settings.xml | 13 + tools/smoke-test/run-smoke-test.ps1 | 104 +++++++ tools/smoke-test/server-live.properties | 17 ++ tools/smoke-test/server.properties | 17 ++ tools/smoke-test/start-test-server.ps1 | 69 +++++ 50 files changed, 3241 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/top/gtb520/tools/main/Back_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/KickGUI_ClickGUI_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/PlaceholderAPI.java create mode 100644 src/main/java/top/gtb520/tools/main/PlayerChangedWorld_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/PlayerChat_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/PlayerDeath_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/PlayerJoin_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/PlayerQuit_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/PlayerReSpawn_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/PlayerTitle_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/Reload_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/SignChange_Event.java create mode 100644 src/main/java/top/gtb520/tools/main/Stop_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/SuperKick_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/SuperList_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/TimeMessage.java create mode 100644 src/main/java/top/gtb520/tools/main/Tpa_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/Tpa_Detect.java create mode 100644 src/main/java/top/gtb520/tools/main/Tpa_Time.java create mode 100644 src/main/java/top/gtb520/tools/main/YamlFile_Utils.java create mode 100644 src/main/java/top/gtb520/tools/main/day_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/feed_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/fly_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/gm_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/heal_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/main.java create mode 100644 src/main/java/top/gtb520/tools/main/multi.java create mode 100644 src/main/java/top/gtb520/tools/main/mute_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/setspawn_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/spawn_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/sun_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/testGUI.java create mode 100644 src/main/java/top/gtb520/tools/main/tpaAccept_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/tpaDefuse_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/tpaback_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/unity.java create mode 100644 src/main/java/top/gtb520/tools/main/unmute_Command.java create mode 100644 src/main/java/top/gtb520/tools/main/vanish_Command.java create mode 100644 src/main/resources/config.yml create mode 100644 src/main/resources/plugin.yml create mode 100644 tools/smoke-test/eula.txt create mode 100644 tools/smoke-test/maven-settings.xml create mode 100644 tools/smoke-test/run-smoke-test.ps1 create mode 100644 tools/smoke-test/server-live.properties create mode 100644 tools/smoke-test/server.properties create mode 100644 tools/smoke-test/start-test-server.ps1 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5cfacf5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* +replay_pid* + +# 本地测试服务器目录(运行时数据,不提交) +test-server/ + +# IDE +.idea/ +*.iml + +# Maven 构建输出 +target/ + +# 敏感信息(内含 Jenkins 构建 Token,禁止提交) +build.txt diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2054c49 --- /dev/null +++ b/LICENSE @@ -0,0 +1,277 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. + +"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + +To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. + +Copyright 2025 database-mysql + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +======= + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +>>>>>>> d054b36 (新建更改列表) diff --git a/README.md b/README.md new file mode 100644 index 0000000..ae929fa --- /dev/null +++ b/README.md @@ -0,0 +1,283 @@ +# OpenSourceTools + +开源 Minecraft 服务器工具包插件(Spigot / Paper),提供传送、称号、隐身、禁言、踢人 GUI、公告等常用服务器管理功能。 + +- **当前版本**:`2.1.0` +- **支持版本**:Minecraft **1.21.11**(Bukkit API `1.21.11-R0.1-SNAPSHOT`,`api-version: 1.21`) +- **协议**:[Apache License 2.0](LICENSE) + +--- + +## 目录 + +- [功能特性](#功能特性) +- [环境要求](#环境要求) +- [安装](#安装) +- [命令列表](#命令列表) +- [权限](#权限) +- [PlaceholderAPI 变量](#placeholderapi-变量) +- [配置文件](#配置文件) +- [构建](#构建) +- [自动化测试](#自动化测试) +- [版本历史](#版本历史) +- [已知问题与限制](#已知问题与限制) +- [安全提醒](#安全提醒) + +--- + +## 功能特性 + +### 命令系统(21 个注册命令) + +| 功能分类 | 说明 | +|---|---| +| 基础恢复 | `/feed`(别名 `/eat`)恢复饱食度;`/heal` 恢复状态 | +| 出生点 | `/spawn` 返回主城;`/setspawn` 设置主城坐标 | +| 传送系统 | `/tpa` 发起传送请求(可点击同意/拒绝,60 秒超时);`/tpaaccept` 接受;`/tpadefuse` 拒绝 | +| 死亡回溯 | `/back` 返回死亡地点 | +| 游戏模式 | `/gamemode`(别名 `/gm`)切换创造/生存/冒险/旁观,支持数字与中文参数、Tab 补全、指定目标玩家 | +| 世界控制 | `/day` 一键天亮;`/sun` 一键晴天 | +| 玩家管理 | `/vanish`(别名 `/v`)隐身;`/fly` 飞行;`/mute` 禁言;`/unmute` 解除禁言;`/kick` 踢出(无参数时打开玩家头像踢人 GUI) | +| 服务器管理 | `/list`(别名 `/tps`)查看内存/TPS/在线列表;`/OSTReload` 重载插件;`/stop` 关闭服务器(支持自定义提示语) | +| 称号系统 | `/PlayerTitle`(别名 `/plt`)添加/删除玩家称号与后缀 | +| 内部命令 | `/testGUI`(插件作者测试用) | + +### 事件系统(8 个监听器) + +- **进服/退服公告**:区分管理员与普通玩家模板,支持 `%PlayerName%` 与 PlaceholderAPI 变量 +- **彩色聊天**:按管理员/玩家开关控制,支持白名单;**彩色告示牌**:编辑时自动转换颜色代码 +- **聊天管理**:聊天冷却(默认 3 秒)、重复消息防刷屏、屏蔽词拦截(拦截时通知在线管理员) +- **死亡记录**:死亡点自动记录,供 `/back` 使用 +- **跨世界飞行保持**:切换世界后自动恢复飞行状态 + +### 定时任务(3 个) + +- **TPA 超时检测**:每秒倒计时,60 秒未处理自动取消 +- **TPA 执行检测**:定期执行已接受的传送请求 +- **定时公告**:按配置间隔循环广播公告内容 + +### PlaceholderAPI 扩展 + +自动注册内部扩展,标识符 `OpenSourceTools`,提供 3 个变量(详见 [PlaceholderAPI 变量](#placeholderapi-变量))。 + +--- + +## 环境要求 + +| 项目 | 要求 | +|---|---| +| 服务器 | Spigot / Paper **1.21.11**(其他 1.21.x 版本理论可用,未测试) | +| Java | **21+**(本项目在 JDK 25 下编译与运行测试通过) | +| 前置插件 | **PlaceholderAPI**(硬依赖,缺失时插件无法启动) | + +--- + +## 安装 + +1. 安装 [PlaceholderAPI](https://hangar.papermc.io/HelpChat/PlaceholderAPI) 前置插件。 +2. 将构建产物 `OpenSourceTools-2.1.0.jar` 放入服务器 `plugins/` 目录。 +3. 重启服务器,插件会自动生成 `plugins/OpenSourceTools/config.yml`。 +4. 按需修改配置文件后使用 `/OSTReload` 重载。 + +> ⚠️ 插件在 `plugin.yml` 中声明了 `depend: [PlaceholderAPI]`,请确保 PAPI 已安装,否则插件不会加载。 + +--- + +## 命令列表 + +| 命令 | 别名 | 用法 | 权限 | 默认 | +|---|---|---|---|---| +| `/feed` | `/eat` | `/feed` | `OpenTools.default` | 所有人 | +| `/heal` | - | `/heal` | `OpenTools.default` | 所有人 | +| `/spawn` | - | `/spawn` | `OpenTools.default` | 所有人 | +| `/tpa` | - | `/tpa <玩家ID>` | `OpenTools.default` | 所有人 | +| `/back` | - | `/back` | `OpenTools.default` | 所有人 | +| `/tpaaccept` | - | `/tpaaccept <玩家ID>` | `OpenTools.default` | 所有人 | +| `/tpadefuse` | - | `/tpadefuse <玩家ID>` | `OpenTools.default` | 所有人 | +| `/PlayerTitle` | `/plt` | `/PlayerTitle help` | `OpenTools.default` | 所有人 | +| `/testGUI` | - | `/testGUI KickGUI` | `OpenTools.testGUI` | OP | +| `/OSTReload` | - | `/OSTReload` | `OpenTools.reload` | OP | +| `/stop` | - | `/stop [提示语]` | `OpenTools.stop` | OP | +| `/gamemode` | `/gm` | `/gamemode <模式> [玩家ID]` | `OpenTools.gamemode` | OP | +| `/sun` | - | `/sun` | `OpenTools.sun` | OP | +| `/setspawn` | - | `/setspawn` | `OpenTools.setspawn` | OP | +| `/day` | - | `/day` | `OpenTools.day` | OP | +| `/vanish` | `/v` | `/vanish [玩家ID]` | `OpenTools.vanish` | OP | +| `/fly` | - | `/fly [玩家ID]` | `OpenTools.fly` | OP | +| `/mute` | - | `/mute <玩家ID>` | `OpenTools.mute` | OP | +| `/unmute` | - | `/unmute <玩家ID>` | `OpenTools.unmute` | OP | +| `/kick` | - | `/kick [玩家ID] [理由]` | `OpenTools.kick` | OP | +| `/list` | `/tps` | `/list` | `OpenTools.list` | OP | + +`/PlayerTitle` 子命令: + +``` +/PlayerTitle help +/PlayerTitle addTitle <玩家ID> <称号> +/PlayerTitle addSuffix <玩家ID> <后缀> +/PlayerTitle delTitle <玩家ID> +/PlayerTitle delSuffix <玩家ID> +``` + +`/gamemode` 模式参数支持:`0/生存/survival`、`1/创造/creative`、`2/冒险/adventure`、`3/旁观/spectator`。 + +--- + +## 权限 + +| 权限节点 | 默认 | 说明 | +|---|---|---| +| `OpenTools.default` | 所有人 | 默认命令权限(feed/heal/spawn/tpa/back/称号等) | +| `OpenTools.kick` | OP | /kick | +| `OpenTools.mute` | OP | /mute | +| `OpenTools.unmute` | OP | /unmute | +| `OpenTools.fly` | OP | /fly | +| `OpenTools.vanish` | OP | /vanish | +| `OpenTools.ostreload` | OP | /OSTReload | +| `OpenTools.sun` | OP | /sun | +| `OpenTools.stop` | OP | /stop | +| `OpenTools.gamemode` | OP | /gamemode | +| `OpenTools.setspawn` | OP | /setspawn | +| `OpenTools.list` | OP | /list | +| `OpenTools.testGUI` | OP | /testGUI | + +--- + +## PlaceholderAPI 变量 + +| 变量 | 说明 | 示例输出 | +|---|---|---| +| `%OpenSourceTools_Nick%` | 玩家昵称(未设置时显示游戏 ID) | `Steve` | +| `%OpenSourceTools_Title%` | 玩家称号(未设置时为空) | `§7[管理员§7]§f` | +| `%OpenSourceTools_Suffix%` | 玩家后缀(未设置时为空) | `§7[后缀§7]` | + +--- + +## 配置文件 + +首次启动自动生成 `plugins/OpenSourceTools/config.yml`,关键配置项: + +```yaml +ServerName: "ServerName" # 服务器名字 +DefaultStopMessage: "StopServerText" # 默认关服提示 + +PlayerJoinServerMessage: "&7[&f&l玩家&7]&e%PlayerName%&a进入了服务器" # 进服公告 +AdminJoinServerMessage: "&7[&d&l管理员&7]&e%PlayerName%&a进入了服务器" # 管理员进服公告 + +ColorChatSetting: + AllowAdminUsedColorChat: true # 允许管理员彩色聊天 + AllowPlayerUsedColorChat: true # 允许玩家彩色聊天 + AllowPlayers: [] # 无视开关的白名单 + +ColorSignSetting: + AllowAdminUsedColorSign: true # 允许管理员彩色告示牌 + AllowPlayerUsedColorSign: true # 允许玩家彩色告示牌 + +SpawnSetting: # 主城坐标(/setspawn 自动写入) + WorldName: world + locationX: 0.5 + locationY: 80.0 + locationZ: 0.5 + +TimeMessageSetting: # 定时公告 + TimeMessage: true # 是否启用 + TimeMessageTime: 60 # 间隔(秒) + Message: + - "Text-1" + +FeedCommandSetting: # /feed 开关 + AllowAdminUsedFeedCommand: true + AllowPlayerUsedFeedCommand: false + +ChatSetting: + ChatTime: 3 # 聊天冷却(秒) + +AntiKeyWords: # 屏蔽词列表(精确匹配整句) + - xxx1 +``` + +--- + +## 构建 + +### 环境 + +- JDK 8+(编译目标为 Java 8 字节码;本仓库使用 JDK 25 验证) +- Maven 3.8+ + +### 构建命令 + +```bash +mvn clean package +``` + +构建产物:`target/OpenSourceTools-2.1.0.jar`(shade 打包,含 JetBrains Annotations)。 + +> 网络提示:若访问 Maven Central 缓慢,可使用项目自带的阿里云镜像设置: +> +> ```bash +> mvn -s tools/smoke-test/maven-settings.xml clean package +> ``` + +--- + +## 自动化测试 + +项目内置了基于 **Paper 1.21.11** 实机启动的自动化测试设施(`tools/smoke-test/`): + +| 脚本 | 用途 | +|---|---| +| `run-smoke-test.ps1` | 全自动冒烟测试:临时启动服务器 → 校验插件加载/PAPI 扩展注册 → 优雅停止 → 断言日志,输出 PASS/FAIL | +| `start-test-server.ps1` | 启动一个**持续运行**的交互式测试服务器(端口 25565、离线模式),在独立控制台窗口等待玩家连接 | + +使用前需将测试制品放入缓存目录 `%USERPROFILE%\.ost-smoke-cache\`: + +- `paper-1.21.11-132.jar`([PaperMC Fill API](https://fill.papermc.io/) 下载,SHA256 `5ffef465eeeb5f2a3c23a24419d97c51afd7dbb4923ff42df9a3f58bba1ccfba`) +- `PlaceholderAPI-2.12.3.jar`(官方发行版,[Modrinth](https://modrinth.com/plugin/placeholderapi) 下载) + +```powershell +# 一键冒烟测试(自动启停) +powershell -NoProfile -ExecutionPolicy Bypass -File tools/smoke-test/run-smoke-test.ps1 + +# 启动交互式测试服务器(等待玩家连接,手动关闭) +powershell -NoProfile -ExecutionPolicy Bypass -File tools/smoke-test/start-test-server.ps1 +``` + +--- + +## 版本历史 + +| 版本 | 日期 | 变更 | +|---|---|---| +| `2.1.0` | 2026-11-09 | 升级 Bukkit API 至 **1.21.11**;`api-version` 提升至 `1.21`;声明 `depend: [PlaceholderAPI]` 保证加载顺序;补充自动化冒烟测试设施 | +| `2.0` | 2025 | 初版(Spigot API 1.20) | + +--- + +## 已知问题与限制 + +> 以下问题为代码现状记录,不影响插件基本使用,欢迎提交 PR 修复。 + +1. **禁言不生效**:`/mute` 仅将玩家写入配置 `MutePlayerList`,聊天事件未检查该列表。 +2. **`/heal` 实际恢复的是饱食度**(与 `/feed` 相同),且配置键大小写不匹配(`healCommandSetting` vs `HealCommandSetting`),导致默认被禁用。 +3. **`/kick` 无法阻止踢出自己**:自我检查逻辑失效(`player.getName().equals(player.getName())` 恒为真)。 +4. **控制台执行 `/unmute` 无效**:解禁分支误用 `add` 而非 `remove`。 +5. **`/tpaback` 未注册**:类存在但未在 plugin.yml 与主类中注册。 +6. **空指针风险**:玩家未死亡时使用 `/back` 或重生事件、未使用过 TPA 时执行 `/tpaback`、跨世界飞行检查,均可能抛出 NPE。 +7. **状态仅存内存**:TPA 请求、聊天冷却、死亡点、隐身/飞行状态存于静态 HashMap,服务器重启即丢失。 +8. **权限声明不一致**:`/OSTReload` 使用 `OpenTools.reload` 而权限节定义为 `OpenTools.ostreload`;`/day` 的 `OpenTools.day` 未在权限节声明。 +9. **硬依赖退出方式激进**:缺失 PlaceholderAPI 时插件会 `System.exit(0)` 直接结束整个 JVM(现已通过 `depend` 声明保证加载顺序规避)。 +10. **屏蔽词精确匹配**:仅拦截与关键词完全相同的整句消息。 + +--- + +## 安全提醒 + +- 仓库根目录的 `build.txt` 内含 Jenkins 构建服务器 Token,属于**敏感信息泄露**,建议立即吊销该 Token 并将文件从仓库移除。 +- 玩家加入时其 IP 地址会输出到服务器控制台日志,如介意请自行移除 `PlayerJoin_Event.java` 中的相关代码。 + +--- + +## 许可证 + +本项目采用 [Apache License 2.0](LICENSE)。 diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..3b8c9ad --- /dev/null +++ b/pom.xml @@ -0,0 +1,100 @@ + + + 4.0.0 + + OpenSourceTools + OpenSourceTools + 2.1.0 + jar + + OpenSourceTools + + OpenSourceTools - Minecraft Bukkit 1.21.11 开源工具包插件 + + 1.8 + UTF-8 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + + + + org.apache.maven.plugins + maven-shade-plugin + 3.2.4 + + + package + + shade + + + false + + + + + + + + src/main/resources + true + + + + + + + spigotmc-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + sonatype + https://oss.sonatype.org/content/groups/public/ + + + placeholderapi + https://repo.extendedclip.com/content/repositories/placeholderapi/ + + + dmulloy2-repo + https://repo.dmulloy2.net/repository/public/ + + + helpchat-repo-releases + HelpChat Maven Repository + https://repo.helpch.at/releases + + + + + + org.spigotmc + spigot-api + 1.21.11-R0.1-SNAPSHOT + provided + + + me.clip + placeholderapi + 2.12.3 + provided + + + org.jetbrains + annotations + 24.0.1 + compile + + + diff --git a/src/main/java/top/gtb520/tools/main/Back_Command.java b/src/main/java/top/gtb520/tools/main/Back_Command.java new file mode 100644 index 0000000..f789beb --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/Back_Command.java @@ -0,0 +1,27 @@ +package top.gtb520.tools.main; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class Back_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + if (unity.getLocationTempTemp(player.getName() + "_Back") == null) { + sender.sendMessage(unity.ColorMessage("&d&l你没有死亡过!")); + return false; + } else { + player.sendMessage(unity.ColorMessage("&a&l你已返回死亡地点\n传送前的位置是X:" + player.getLocation().getBlockX() + "Y:" + player.getLocation().getBlockY() + "Z:" + player.getLocation().getBlockZ())); + player.teleport(unity.getLocationTempTemp(player.getName() + "_Back")); + } + } else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个命令只有玩家才能执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/KickGUI_ClickGUI_Event.java b/src/main/java/top/gtb520/tools/main/KickGUI_ClickGUI_Event.java new file mode 100644 index 0000000..af0642f --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/KickGUI_ClickGUI_Event.java @@ -0,0 +1,60 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; + +import java.util.Objects; + +public class KickGUI_ClickGUI_Event implements Listener { + + @EventHandler + public void ClickGUI(InventoryClickEvent event) { + if (event.getView().getTitle().equalsIgnoreCase(ChatColor.translateAlternateColorCodes('&',"&a选择你要踢出的玩家"))) { + event.setCancelled(true); + + if (event.getCurrentItem() == null) { + return; + } + + if (event.getCurrentItem().getType().equals(Material.AIR)) { + return; + } + + if (Objects.requireNonNull(event.getCurrentItem()).getType().equals(Material.ORANGE_STAINED_GLASS_PANE)) { + Player player = (Player) event.getWhoClicked(); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a这只是一个边框,你为什么要点")); + } + + if (Objects.requireNonNull(event.getCurrentItem()).getType().equals(Material.REDSTONE_BLOCK)) { + Player player = (Player) event.getWhoClicked(); + player.closeInventory(); + } + + if (Objects.requireNonNull(event.getCurrentItem()).getType().equals(Material.PLAYER_HEAD)) { + Player player = (Player) event.getWhoClicked(); + String PlayerName = Objects.requireNonNull(event.getCurrentItem().getItemMeta()).getDisplayName(); + Player KickPlayer = Bukkit.getPlayer(PlayerName); + if(Bukkit.getPlayer(PlayerName) == null) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个玩家不存在或不在线")); + }else { + if (Objects.requireNonNull(KickPlayer).isOnline()) { + if (!KickPlayer.isOp()) { + if (!KickPlayer.getName().equals(player.getName())) { + KickPlayer.kickPlayer(ChatColor.translateAlternateColorCodes('&',"&d你被踢出服务器" )); + }else { + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d你不能踢出自己")); + } + }else { + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d你不能踢出管理员")); + } + } + } + } + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlaceholderAPI.java b/src/main/java/top/gtb520/tools/main/PlaceholderAPI.java new file mode 100644 index 0000000..5cbab77 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlaceholderAPI.java @@ -0,0 +1,51 @@ +package top.gtb520.tools.main; + +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +public class PlaceholderAPI extends PlaceholderExpansion { + + public PlaceholderAPI(main main) {} + + @Override + public @NotNull String getAuthor() { + return "Open Source"; + } + + @Override + public @NotNull String getIdentifier() { + return "OpenSourceTools"; + } + + @Override + public @NotNull String getVersion() { + return main.getDescriptionFile().getVersion(); + } + + @Override + public String onRequest(OfflinePlayer player, String params) { + if (params.equalsIgnoreCase("Nick")) { + if (main.instance.getConfig().getString(player.getName() + "_Nick") == null) { + return player.getName(); + } else { + return main.instance.getConfig().getString(player.getName() + "_Nick"); + } + } + if (params.equalsIgnoreCase("Title")) { + if (main.instance.getConfig().getString(player.getName() + "_Title") == null) { + return ""; + } else { + return unity.ColorMessage("&7[" + main.instance.getConfig().getString(player.getName() + "_Title") + "&7]&f"); + } + } + if (params.equalsIgnoreCase("Suffix")) { + if (main.instance.getConfig().getString(player.getName() + "_Suffix") == null) { + return ""; + } else { + return unity.ColorMessage("&7[" + main.instance.getConfig().getString(player.getName() + "_Suffix") + "&7]"); + } + } + return null; + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlayerChangedWorld_Event.java b/src/main/java/top/gtb520/tools/main/PlayerChangedWorld_Event.java new file mode 100644 index 0000000..7bd39a1 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlayerChangedWorld_Event.java @@ -0,0 +1,18 @@ +package top.gtb520.tools.main; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerChangedWorldEvent; + +public class PlayerChangedWorld_Event implements Listener { + @EventHandler + public void On_Event(PlayerChangedWorldEvent event) { + Player player = event.getPlayer(); + if (player.hasPermission("OpenSourceTools.FLY")) { + if (unity.getStringTemp(player.getName() + "_Fly").equals("已开启")) { + player.setAllowFlight(true); + } + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlayerChat_Event.java b/src/main/java/top/gtb520/tools/main/PlayerChat_Event.java new file mode 100644 index 0000000..18065db --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlayerChat_Event.java @@ -0,0 +1,67 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.AsyncPlayerChatEvent; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class PlayerChat_Event implements Listener { + @EventHandler + public void PlayerChat(AsyncPlayerChatEvent event) { + Player player = event.getPlayer(); + String Message = event.getMessage(); + if (player.isOp()) { + if (main.instance.getConfig().getBoolean("ColorChatSetting.AllowAdminUsedColorChat")) { + event.setMessage(unity.ColorMessage(Message)); + } + }else { + if (main.instance.getConfig().getBoolean("ColorChatSetting.AllowPlayerUsedColorChat")) { + event.setMessage(unity.ColorMessage(Message)); + } + } + + for (String ColorChatPlayers : main.instance.getConfig().getStringList("ColorChatSetting.AllowPlayers")) { + if (player.getName().equals(ColorChatPlayers)) { + event.setMessage(unity.ColorMessage(Message)); + } + } + + List keywords = new ArrayList<>(main.instance.getConfig().getStringList("AntiKeyWords")); + for (String keyword : keywords) { + if (Message.toUpperCase().contentEquals(keyword)) { + player.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d&l检测到屏蔽词,已阻止发送\n屏蔽词内容:" + keyword)); + event.setCancelled(true); + for (Player player1 : Bukkit.getOnlinePlayers()) { + if (player1.isOp()) { + if (!player1.getName().equals(player.getName())) { + player1.sendMessage(ChatColor.translateAlternateColorCodes('&', "&a&l" + player.getName() + "尝试发送屏蔽词,已被阻止发送\n屏蔽词内容:" + keyword)); + } + } + } + return; + } + } + + // 建议多线程处理。 + if (Objects.equals(unity.getStringTemp(player.getName() + "_Message"), Message)) { + player.sendMessage(unity.ColorMessage("&d&l请不要刷屏!")); + event.setCancelled(true); + return; + } + + if (unity.GetIntTemp(player.getName() + "_ChatTime") != null) { + player.sendMessage(unity.ColorMessage("&e&l您发送消息太快了,请在" + unity.GetIntTemp(player.getName() + "_ChatTime") + "后发送")); + event.setCancelled(true); + return; + } + + unity.SetStringTemp(player.getName() + "_Message", Message); + unity.SetIntTemp(player.getName() + "_ChatTime", main.instance.getConfig().getInt("ChatSetting.ChatTime")); + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlayerDeath_Event.java b/src/main/java/top/gtb520/tools/main/PlayerDeath_Event.java new file mode 100644 index 0000000..fe22dfc --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlayerDeath_Event.java @@ -0,0 +1,14 @@ +package top.gtb520.tools.main; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.PlayerDeathEvent; + +public class PlayerDeath_Event implements Listener { + @EventHandler + public void On_Event(PlayerDeathEvent event) { + Player player = event.getEntity(); + unity.SetLocationTempTemp(player.getName() + "_Back",player.getLocation()); + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlayerJoin_Event.java b/src/main/java/top/gtb520/tools/main/PlayerJoin_Event.java new file mode 100644 index 0000000..f961104 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlayerJoin_Event.java @@ -0,0 +1,28 @@ +package top.gtb520.tools.main; + +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerJoin_Event implements Listener { + @EventHandler + public void PlayerJoin(PlayerJoinEvent event) { + Player player = event.getPlayer(); + unity.GetLoggerPlus("&e&l" + player.getName() + " IP:" + player.getAddress()); + main.instance.getConfig().set(player.getName() + "_Temp_TpaPlayerName",null); + main.instance.getConfig().set(player.getName() + "_Temp_Tpa",null); + main.instance.getConfig().set(player.getName() + "_Temp_TpaTime",null); + main.instance.saveConfig(); + main.instance.reloadConfig(); + String PlayerJoinMessage = main.instance.getConfig().getString("PlayerJoinServerMessage").replaceAll("%PlayerName%",player.getPlayerListName()); + String AdminJoinMessage = main.instance.getConfig().getString("AdminJoinServerMessage").replaceAll("%PlayerName%",player.getPlayerListName()); + if (player.isOp()) { + event.setJoinMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.setPlaceholders(player, AdminJoinMessage))); + } else { + event.setJoinMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.setPlaceholders(player, PlayerJoinMessage))); + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlayerQuit_Event.java b/src/main/java/top/gtb520/tools/main/PlayerQuit_Event.java new file mode 100644 index 0000000..d05acea --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlayerQuit_Event.java @@ -0,0 +1,27 @@ +package top.gtb520.tools.main; + +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerQuitEvent; + +public class PlayerQuit_Event implements Listener { + @EventHandler + public void PlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + main.instance.getConfig().set(player.getName() + "_Temp_TpaPlayerName", null); + main.instance.getConfig().set(player.getName() + "_Temp_Tpa", null); + main.instance.getConfig().set(player.getName() + "_Temp_TpaTime", null); + main.instance.saveConfig(); + main.instance.reloadConfig(); + String PlayerQuitMessage = main.instance.getConfig().getString("PlayerQuitServerMessage").replaceAll("%PlayerName%",player.getPlayerListName()); + String AdminQuitMessage = main.instance.getConfig().getString("AdminQuitServerMessage").replaceAll("%PlayerName%",player.getPlayerListName()); + if (player.isOp()) { + event.setQuitMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.setPlaceholders(player, AdminQuitMessage))); + } else { + event.setQuitMessage(ChatColor.translateAlternateColorCodes('&', PlaceholderAPI.setPlaceholders(player, PlayerQuitMessage))); + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlayerReSpawn_Event.java b/src/main/java/top/gtb520/tools/main/PlayerReSpawn_Event.java new file mode 100644 index 0000000..0166e67 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlayerReSpawn_Event.java @@ -0,0 +1,16 @@ +package top.gtb520.tools.main; + +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerRespawnEvent; + +public class PlayerReSpawn_Event implements Listener { + @EventHandler + public void On_Event(PlayerRespawnEvent event) { + Player player = event.getPlayer(); + Location DiedLocation = unity.getLocationTempTemp(player.getName() + "_Back"); + player.sendMessage(unity.ColorMessage("&a&l您的死亡位置是X:" + DiedLocation.getBlockX() + " Y:" + DiedLocation.getBlockY() + "_DiedY" + " Z:" + DiedLocation.getBlockZ())); + } +} diff --git a/src/main/java/top/gtb520/tools/main/PlayerTitle_Command.java b/src/main/java/top/gtb520/tools/main/PlayerTitle_Command.java new file mode 100644 index 0000000..a844e31 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/PlayerTitle_Command.java @@ -0,0 +1,151 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; + +public class PlayerTitle_Command implements TabExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length >= 1) { + if(sender.isOp()) { + if (args[0].equals("help")) { + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + sender.sendMessage(unity.ColorMessage("/" + label + " help")); + sender.sendMessage(unity.ColorMessage("/" + label + " addTitle <玩家ID> <称号>")); + sender.sendMessage(unity.ColorMessage("/" + label + " addSuffix <玩家ID> <后缀>")); + sender.sendMessage(unity.ColorMessage("/" + label + " delTitle <玩家ID>")); + sender.sendMessage(unity.ColorMessage("/" + label + " delSuffix <玩家ID>")); + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + return false; + } + + if (args[0].equals("addTitle")) { + if (args.length == 3) { + String PlayerName = args[1]; + String Title = args[2]; + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(unity.ColorMessage("&d&l这个玩家不存在或不在线")); + return false; + } + sender.sendMessage(unity.ColorMessage("&a操作成功!")); + main.instance.getConfig().set(PlayerName + "_Title",Title); + main.instance.saveConfig(); + main.instance.reloadConfig(); + return false; + }else { + sender.sendMessage(unity.ColorMessage("&d&l参数错误,用法:/" + label + " addTitle <玩家ID> <称号>")); + return false; + } + } + + if (args[0].equals("addSuffix")) { + if (args.length == 3) { + String PlayerName = args[1]; + String Suffix = args[2]; + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(unity.ColorMessage("&d&l这个玩家不存在或不在线")); + return false; + } + sender.sendMessage(unity.ColorMessage("&a操作成功!")); + main.instance.getConfig().set(PlayerName + "_Suffix",Suffix); + main.instance.saveConfig(); + main.instance.reloadConfig(); + return false; + }else { + sender.sendMessage(unity.ColorMessage("&d&l参数错误,用法:/" + label + " addSuffix <玩家ID> <后缀>")); + return false; + } + } + + if (args[0].equals("delTitle")) { + if (args.length == 2) { + String PlayerName = args[1]; + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(unity.ColorMessage("&d&l这个玩家不存在或不在线")); + return false; + } + sender.sendMessage(unity.ColorMessage("&a操作成功!")); + main.instance.getConfig().set(PlayerName + "_Title",null); + main.instance.saveConfig(); + main.instance.reloadConfig(); + return false; + }else { + sender.sendMessage(unity.ColorMessage("&d&l参数错误,用法:/" + label + " delTitle <玩家ID>")); + return false; + } + } + + if (args[0].equals("delSuffix")) { + if (args.length == 2) { + String PlayerName = args[1]; + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(unity.ColorMessage("&d&l这个玩家不存在或不在线")); + return false; + } + sender.sendMessage(unity.ColorMessage("&a操作成功!")); + main.instance.getConfig().set(PlayerName + "_Suffix",null); + main.instance.saveConfig(); + main.instance.reloadConfig(); + return false; + }else { + sender.sendMessage(unity.ColorMessage("&d&l参数错误,用法:/" + label + " delSuffix <玩家ID>")); + return false; + } + } + + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + sender.sendMessage(unity.ColorMessage("/" + label + " help")); + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + } + }else { + if (sender.isOp()) { + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + sender.sendMessage(unity.ColorMessage("/" + label + " help")); + sender.sendMessage(unity.ColorMessage("/" + label + " addTitle <玩家ID> <称号>")); + sender.sendMessage(unity.ColorMessage("/" + label + " addSuffix <玩家ID> <后缀>")); + sender.sendMessage(unity.ColorMessage("/" + label + " delTitle <玩家ID>")); + sender.sendMessage(unity.ColorMessage("/" + label + " delSuffix <玩家ID>")); + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + }else { + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + sender.sendMessage(unity.ColorMessage("/" + label + " help")); + sender.sendMessage(unity.ColorMessage("&7---------------&dOpenSourceTitleSystem&7---------------")); + } + } + return false; + } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length == 1) { + List tablist = new ArrayList<>(); + tablist.add("addTitle"); + tablist.add("addSuffix"); + tablist.add("delTitle"); + tablist.add("delSuffix"); + tablist.removeIf(s -> !s.startsWith(args[0])); + return tablist; + } + if (args.length == 2) { + List tablist = new ArrayList<>(); + for (Player player : Bukkit.getOnlinePlayers()) { + tablist.add(player.getName()); + } + tablist.removeIf(s -> !s.startsWith(args[1])); + return tablist; + } + if (args.length == 3) { + return null; + } + return null; + } +} diff --git a/src/main/java/top/gtb520/tools/main/Reload_Command.java b/src/main/java/top/gtb520/tools/main/Reload_Command.java new file mode 100644 index 0000000..f6f5c29 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/Reload_Command.java @@ -0,0 +1,25 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.scheduler.BukkitTask; +import org.jetbrains.annotations.NotNull; + +public class Reload_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + main.instance.reloadConfig(); + if (unity.GetIntTemp("TimeMessageTaskId") != null) { + Bukkit.getScheduler().cancelTask(unity.GetIntTemp("TimeMessageTaskId")); + } + if (main.instance.getConfig().getBoolean("TimeMessageSetting.TimeMessage")) { + BukkitTask TimeMessage = (new TimeMessage(main.instance)).runTaskTimer(main.instance, 0L, (main.instance.getConfig().getInt("TimeMessageSetting.TimeMessageTime") * 20L)); + unity.SetIntTemp("TimeMessageTaskId",TimeMessage.getTaskId()); + } + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a重载完成!")); + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/SignChange_Event.java b/src/main/java/top/gtb520/tools/main/SignChange_Event.java new file mode 100644 index 0000000..93183ec --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/SignChange_Event.java @@ -0,0 +1,30 @@ +package top.gtb520.tools.main; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.SignChangeEvent; + +import java.util.Objects; + +public class SignChange_Event implements Listener { + @EventHandler + public void ChangeSignEvent(SignChangeEvent event) { + Player player = event.getPlayer(); + if (player.isOp()) { + if (main.instance.getConfig().getBoolean("ColorSignSetting.AllowAdminUsedColorSign")) { + for (int i = 0; i < 4; i++) { + if (!Objects.equals(event.getLine(i), "&")) + event.setLine(i, Objects.requireNonNull(event.getLine(i)).replace("&", "§")); + } + } + }else { + if (main.instance.getConfig().getBoolean("ColorSignSetting.AllowPlayerUsedColorSign")) { + for (int i = 0; i < 4; i++) { + if (!Objects.equals(event.getLine(i), "&")) + event.setLine(i, Objects.requireNonNull(event.getLine(i)).replace("&", "§")); + } + } + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/Stop_Command.java b/src/main/java/top/gtb520/tools/main/Stop_Command.java new file mode 100644 index 0000000..49aa172 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/Stop_Command.java @@ -0,0 +1,39 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class Stop_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length == 1) { + String ServerName = main.instance.getConfig().getString("ServerName"); + String StopMessage = args[0]; + if (Bukkit.getOnlinePlayers().size() != 0) { + for (Player player : Bukkit.getOnlinePlayers()) { + player.kickPlayer(ChatColor.translateAlternateColorCodes('&',ServerName + "\n" +StopMessage)); + } + Bukkit.shutdown(); + }else { + Bukkit.shutdown(); + } + }else { + String ServerName = main.instance.getConfig().getString("ServerName"); + String StopMessage = main.instance.getConfig().getString("DefaultStopMessage"); + if (Bukkit.getOnlinePlayers().size() != 0) { + for (Player player : Bukkit.getOnlinePlayers()) { + player.kickPlayer(ChatColor.translateAlternateColorCodes('&',ServerName + "\n" +StopMessage)); + } + Bukkit.shutdown(); + }else { + Bukkit.shutdown(); + } + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/SuperKick_Command.java b/src/main/java/top/gtb520/tools/main/SuperKick_Command.java new file mode 100644 index 0000000..8fe756e --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/SuperKick_Command.java @@ -0,0 +1,74 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class SuperKick_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length == 1) { + String PlayerName = args[0]; + Player player = Bukkit.getPlayer(PlayerName); + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个玩家不存在或不在线")); + } else { + if (Objects.requireNonNull(player).isOnline()) { + if (sender instanceof Player) { + if (!player.isOp()) { + if (!player.getName().equals(player.getName())) { + player.kickPlayer(ChatColor.translateAlternateColorCodes('&', "&d你被踢出服务器")); + } else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出自己")); + } + } else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出管理员")); + } + } else { + player.kickPlayer(ChatColor.translateAlternateColorCodes('&', "&d你被踢出服务器")); + } + } + } + return false; + } + + if (args.length == 2) { + String PlayerName = args[0]; + String message = args[1]; + Player player = Bukkit.getPlayer(PlayerName); + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个玩家不存在或不在线")); + } else { + if (Objects.requireNonNull(player).isOnline()) { + if (sender instanceof Player) { + if (!player.isOp()) { + if (!player.getName().equals(player.getName())) { + player.kickPlayer(ChatColor.translateAlternateColorCodes('&', message)); + } else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出自己")); + } + } else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d你不能踢出管理员")); + } + } else { + player.kickPlayer(ChatColor.translateAlternateColorCodes('&', message)); + } + } + } + return false; + } + if (sender instanceof Player) { + Player player = (Player) sender; + unity.KickGui(player); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a正确用法&f: /kick &f<&e玩家ID&f> &f[&e理由&f]")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/SuperList_Command.java b/src/main/java/top/gtb520/tools/main/SuperList_Command.java new file mode 100644 index 0000000..9b62158 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/SuperList_Command.java @@ -0,0 +1,33 @@ +package top.gtb520.tools.main; + +import me.clip.placeholderapi.PlaceholderAPI; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class SuperList_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + List OnlinePlayers = new ArrayList<>(); + String MemUsedMessage = "&a服务器内存占用&f:&e%server_ram_used%/%server_ram_max%"; + MemUsedMessage = PlaceholderAPI.setPlaceholders(null, MemUsedMessage); + String ServerTPSMessage = "&a服务器TPS&f:&e%server_tps%"; + ServerTPSMessage = PlaceholderAPI.setPlaceholders(null, ServerTPSMessage); + for (Player OnlinePlayer : Bukkit.getOnlinePlayers()) { + String PlayerName = OnlinePlayer.getName(); + OnlinePlayers.add(PlayerName); + } + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', MemUsedMessage)); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', ServerTPSMessage)); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&a在线人数&f:&e" + Bukkit.getOnlinePlayers().size() + "&f/&e" + Bukkit.getMaxPlayers())); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&a在线玩家列表&f:&e" + OnlinePlayers)); + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/TimeMessage.java b/src/main/java/top/gtb520/tools/main/TimeMessage.java new file mode 100644 index 0000000..774ee33 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/TimeMessage.java @@ -0,0 +1,32 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.scheduler.BukkitRunnable; + +public class TimeMessage extends BukkitRunnable { + main pluginmain; + + private int i = 0; + + public TimeMessage(main main1) { + this.pluginmain = main1; + } + + private static int order(int i) { + i++; + return i; + } + + public void run() { + if (main.instance.getConfig().getBoolean("TimeMessageSetting.TimeMessage")) + if (this.i < main.instance.getConfig().getStringList("TimeMessageSetting.Message").size()) { + Bukkit.broadcastMessage(ChatColor.translateAlternateColorCodes('&', main.instance.getConfig().getStringList("TimeMessageSetting.Message").get(this.i))); + this.i = order(this.i); + } else { + this.i = 0; + Bukkit.broadcastMessage(ChatColor.translateAlternateColorCodes('&', main.instance.getConfig().getStringList("TimeMessageSetting.Message").get(this.i))); + this.i = order(this.i); + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/Tpa_Command.java b/src/main/java/top/gtb520/tools/main/Tpa_Command.java new file mode 100644 index 0000000..a261b15 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/Tpa_Command.java @@ -0,0 +1,57 @@ +package top.gtb520.tools.main; + +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.HoverEvent; +import net.md_5.bungee.api.chat.TextComponent; +import net.md_5.bungee.api.chat.hover.content.Text; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class Tpa_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + if (args.length == 1) { + String TpaPlayerName = args[0]; + if (Bukkit.getPlayer(TpaPlayerName) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个玩家不存在")); + return false; + } + + Player player = (Player) sender; + Player TpaPlayer = Bukkit.getPlayer(TpaPlayerName); + String PlayerName = player.getName(); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a传送请求已发送")); + TextComponent Message = new TextComponent(); + TextComponent AccentMessage = new TextComponent(unity.ColorMessage("&7[&a&l同意&7]")); + AccentMessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(unity.ColorMessage("&a接受" + PlayerName + "的传送请求")))); + AccentMessage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tpaaccept "+ PlayerName)); + TextComponent RefuseMessage = new TextComponent(unity.ColorMessage("&7[&d&l拒绝&7]")); + RefuseMessage.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new Text(unity.ColorMessage("&a拒绝" + PlayerName + "的传送请求")))); + RefuseMessage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/tpadefuse "+ PlayerName)); + TextComponent Null = new TextComponent(" "); + Message.addExtra(AccentMessage); + Message.addExtra(Null); + Message.addExtra(RefuseMessage); + Objects.requireNonNull(TpaPlayer).sendMessage(ChatColor.translateAlternateColorCodes('&',"&7--------------&9Tpa系统&7--------------\n&a玩家:" + PlayerName + "想来你这里看看")); + Objects.requireNonNull(TpaPlayer).spigot().sendMessage(Message); + TpaPlayer.sendMessage(ChatColor.translateAlternateColorCodes('&',"&7--------------&9Tpa系统&7--------------")); + unity.SetStringTemp(PlayerName + "_Temp_TpaPlayerName",TpaPlayer.getName()); + unity.SetBooleanTemp(PlayerName + "_Temp_Tpa",false); + unity.SetIntTemp(PlayerName + "_Temp_TpaTime",0); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d用法错误,用法:/tpa <玩家ID>")); + } + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只有玩家才能执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/Tpa_Detect.java b/src/main/java/top/gtb520/tools/main/Tpa_Detect.java new file mode 100644 index 0000000..69db60a --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/Tpa_Detect.java @@ -0,0 +1,40 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Objects; + +public class Tpa_Detect extends BukkitRunnable { + main pluginmain; + + public Tpa_Detect(main main1) { + this.pluginmain = main1; + } + + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + String PlayerName = player.getName(); + if (unity.getStringTemp(PlayerName + "_Temp_TpaPlayerName") != null) { + if (unity.getBooleanTemp(PlayerName + "_Temp_Tpa")) { + if (Bukkit.getPlayer(Objects.requireNonNull(unity.getStringTemp(PlayerName + "_Temp_TpaPlayerName"))) == null) { + player.sendMessage(ChatColor.RED + "错误,那个玩家突然下线了!传送已取消"); + }else { + Player TpaPlayer = Bukkit.getPlayer(Objects.requireNonNull(unity.getStringTemp(PlayerName + "_Temp_TpaPlayerName"))); + Location TpaLocation = Objects.requireNonNull(TpaPlayer).getLocation(); + unity.SetLocationTempTemp(player.getName() + "_Tpa",player.getLocation()); + player.teleport(TpaLocation); + player.sendMessage(ChatColor.GREEN + "传送成功!"); + TpaPlayer.sendMessage(ChatColor.GREEN + player.getName() + "传送到了你这里!"); + } + unity.SetStringTemp(PlayerName + "_Temp_TpaPlayerName",null); + unity.SetBooleanTemp(PlayerName + "_Temp_Tpa",false); + unity.SetIntTemp(PlayerName + "_Temp_TpaTime",0); + } + } + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/Tpa_Time.java b/src/main/java/top/gtb520/tools/main/Tpa_Time.java new file mode 100644 index 0000000..474e131 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/Tpa_Time.java @@ -0,0 +1,46 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Objects; + +public class Tpa_Time extends BukkitRunnable { + main pluginmain; + + public Tpa_Time(main main1) { + this.pluginmain = main1; + } + + public void run() { + for (Player player : Bukkit.getOnlinePlayers()) { + String PlayerName = player.getName(); + if (unity.GetIntTemp(PlayerName + "_ChatTime") != null) { + int ChatTime = unity.GetIntTemp(PlayerName + "_ChatTime"); + int NewChatTime = ChatTime-1; + unity.SetIntTemp(PlayerName + "_ChatTime",NewChatTime); + if (unity.GetIntTemp(PlayerName + "_ChatTime") == 0) { + unity.SetIntTemp(PlayerName + "_ChatTime",null); + } + } + + if (unity.getStringTemp(PlayerName + "_Temp_TpaPlayerName") != null) { + if (!unity.getBooleanTemp(PlayerName + "_Temp_Tpa")) { + int TpaTime = unity.GetIntTemp(PlayerName + "_Temp_TpaTime"); + unity.SetIntTemp(PlayerName + "_Temp_TpaTime",TpaTime+1); + if (TpaTime+1 >= 60) { + String TpaPlayerName = unity.getStringTemp(PlayerName + "_Temp_TpaPlayerName"); + Player TpaPlayer = Bukkit.getPlayer(Objects.requireNonNull(TpaPlayerName)); + Objects.requireNonNull(TpaPlayer).sendMessage(ChatColor.translateAlternateColorCodes('&',"&d" + PlayerName + "给你发的的传送请求已超时")); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d你发给" + TpaPlayerName + "的传送请求已超时")); + unity.SetStringTemp(PlayerName + "_Temp_TpaPlayerName",null); + unity.SetBooleanTemp(PlayerName + "_Temp_Tpa",false); + unity.SetIntTemp(PlayerName + "_Temp_TpaTime",0); + } + } + } + } + } +} \ No newline at end of file diff --git a/src/main/java/top/gtb520/tools/main/YamlFile_Utils.java b/src/main/java/top/gtb520/tools/main/YamlFile_Utils.java new file mode 100644 index 0000000..f28f067 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/YamlFile_Utils.java @@ -0,0 +1,66 @@ +package top.gtb520.tools.main; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.URLConnection; + +import org.jetbrains.annotations.NotNull; + +public class YamlFile_Utils { + + private InputStream getResource(@NotNull String filename) { + try { + URL URL = getClass().getClassLoader().getResource(filename); + if (URL == null) + return null; + URLConnection Connection = URL.openConnection(); + Connection.setUseCaches(false); + return Connection.getInputStream(); + } catch (IOException ex) { + return null; + } + } + + public void saveYmlFile(String FilePath, String FileName, String ResourcePath) { + File Folder = new File(FilePath); + if (!Folder.exists()) + Folder.mkdirs(); + saveResource(FilePath, ResourcePath, FileName, false); + } + + public void saveYamlFile(String FilePath, String FileName, String ResourcePath,boolean Replace) { + File Folder = new File(FilePath); + if (!Folder.exists()) + Folder.mkdirs(); + saveResource(FilePath, ResourcePath, FileName, Replace); + } + + public void saveResource(String FilePath, @NotNull String ResourcePath, String OutFileName, boolean Replace) { + if (ResourcePath.equals("")) + throw new IllegalArgumentException("ResourcePath cannot be null or empty"); + ResourcePath = ResourcePath.replace('\\', '/'); + InputStream in = getResource(ResourcePath); + if (in == null) + throw new IllegalArgumentException("The embedded resource '" + ResourcePath + "' cannot be found in " + ResourcePath); + File OutFile = new File(FilePath, OutFileName); + try { + if (!OutFile.exists() || Replace) { + OutputStream out = new FileOutputStream(OutFile); + byte[] buf = new byte[1024]; + int Len; + while ((Len = in.read(buf)) > 0) + out.write(buf, 0, Len); + out.close(); + in.close(); + } else { + System.out.println("Could not save " + OutFile.getName() + " to " + OutFile + " because " + OutFile.getName() + " already exists."); + } + } catch (IOException ex) { + System.out.println("Could not save " + OutFile.getName() + " to " + OutFile); + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/day_Command.java b/src/main/java/top/gtb520/tools/main/day_Command.java new file mode 100644 index 0000000..c628731 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/day_Command.java @@ -0,0 +1,24 @@ +package top.gtb520.tools.main; + +import org.bukkit.ChatColor; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class day_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + World world = player.getWorld(); + world.setTime(1000); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a完成!")); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只能是玩家执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/feed_Command.java b/src/main/java/top/gtb520/tools/main/feed_Command.java new file mode 100644 index 0000000..934775d --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/feed_Command.java @@ -0,0 +1,37 @@ +package top.gtb520.tools.main; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import static top.gtb520.tools.main.main.instance; + +public class feed_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + String CommandName = "Feed"; + if (player.isOp()) { + if (!instance.getConfig().getBoolean(CommandName + "CommandSetting.AllowAdminUsed" + CommandName + "Command")) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个服务器禁止管理员使用Feed命令!")); + return false; + } + }else { + if (!instance.getConfig().getBoolean(CommandName + "CommandSetting.AllowPlayerUsed" + CommandName + "Command")) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个服务器禁止玩家使用Feed命令!")); + return false; + } + } + player.setSaturation(20); + player.setFoodLevel(20); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a你的饱食度被神奇的恢复了")); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只有玩家才能执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/fly_Command.java b/src/main/java/top/gtb520/tools/main/fly_Command.java new file mode 100644 index 0000000..9051a5c --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/fly_Command.java @@ -0,0 +1,48 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class fly_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length == 1) { + String PlayerName = args[0]; + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(unity.ColorMessage("&d&l这个玩家不存在或不在线!")); + return false; + } + Player player = Bukkit.getPlayer(PlayerName); + assert player != null; + if (player.getAllowFlight()) { + sender.sendMessage(unity.ColorMessage("&e&l" + player.getName() + "飞行模式已关闭")); + player.sendMessage(unity.ColorMessage("&e&l飞行模式已关闭")); + unity.SetStringTemp(player.getName() + "_Fly",null); + }else { + sender.sendMessage(unity.ColorMessage("&a&l" + player.getName() + "操作成功!")); + player.sendMessage(unity.ColorMessage("&e&l飞行模式已开启")); + unity.SetStringTemp(player.getName() + "_Fly","已开启"); + } + player.setAllowFlight(!player.getAllowFlight()); + }else { + if (sender instanceof Player) { + Player player = (Player) sender; + if (player.getAllowFlight()) { + player.sendMessage(unity.ColorMessage("&e&l飞行模式已关闭")); + unity.SetStringTemp(player.getName() + "_Fly",null); + }else { + player.sendMessage(unity.ColorMessage("&e&l飞行模式已开启")); + unity.SetStringTemp(player.getName() + "_Fly","已开启"); + } + player.setAllowFlight(!player.getAllowFlight()); + }else { + sender.sendMessage(unity.ColorMessage("&d&l用法错误,正确用法:/fly [玩家ID]")); + } + } + return false; + } +} \ No newline at end of file diff --git a/src/main/java/top/gtb520/tools/main/gm_Command.java b/src/main/java/top/gtb520/tools/main/gm_Command.java new file mode 100644 index 0000000..be15506 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/gm_Command.java @@ -0,0 +1,172 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.GameMode; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class gm_Command implements TabExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length == 1) { + if (sender instanceof Player) { + String args1 = args[0]; + String senderName = sender.getName(); + Player player = (Player) sender; + if (args1.equalsIgnoreCase("1") || args1.equalsIgnoreCase("创造") || args1.equalsIgnoreCase("creative")) { + player.setGameMode(GameMode.CREATIVE); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 创造模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 创造模式]"); + } + } + } + return false; + } + + if (args1.equalsIgnoreCase("2") || args1.equalsIgnoreCase("冒险") || args1.equalsIgnoreCase("adventure")) { + player.setGameMode(GameMode.ADVENTURE); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 冒险模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 冒险模式]"); + } + } + } + return false; + } + + if (args1.equalsIgnoreCase("3") || args1.equalsIgnoreCase("旁观") || args1.equalsIgnoreCase("spectator")) { + player.setGameMode(GameMode.SPECTATOR); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 旁观模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 旁观模式]"); + } + } + } + return false; + } + + if (args1.equalsIgnoreCase("0") || args1.equalsIgnoreCase("生存") || args1.equalsIgnoreCase("survival")) { + player.setGameMode(GameMode.SURVIVAL); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 生存模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 生存模式]"); + } + } + } + return false; + } + + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d" + args1 + "不是一个有效的模式")); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d用法错误,用法:/gamemode <模式> [玩家]")); + } + }else { + if (args.length == 2) { + String args1 = args[0]; + if (Bukkit.getPlayer(args[1]) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个玩家不存在或不在线")); + return false; + }else { + String senderName; + if (sender instanceof Player) { + senderName = sender.getName(); + }else { + senderName = "Server"; + } + Player player = Bukkit.getPlayer(args[1]); + if (args1.equalsIgnoreCase("1") || args1.equalsIgnoreCase("创造") || args1.equalsIgnoreCase("creative")) { + Objects.requireNonNull(player).setGameMode(GameMode.CREATIVE); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 创造模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 创造模式]"); + } + } + } + return false; + } + + if (args1.equalsIgnoreCase("2") || args1.equalsIgnoreCase("冒险") || args1.equalsIgnoreCase("adventure")) { + Objects.requireNonNull(player).setGameMode(GameMode.ADVENTURE); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a设置成功")); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 冒险模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 冒险模式]"); + } + } + } + return false; + } + + if (args1.equalsIgnoreCase("3") || args1.equalsIgnoreCase("旁观") || args1.equalsIgnoreCase("spectator")) { + Objects.requireNonNull(player).setGameMode(GameMode.SPECTATOR); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a设置成功")); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 旁观模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 旁观模式]"); + } + } + } + return false; + } + + if (args1.equalsIgnoreCase("0") || args1.equalsIgnoreCase("生存") || args1.equalsIgnoreCase("survival")) { + Objects.requireNonNull(player).setGameMode(GameMode.SURVIVAL); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a设置成功")); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&f你的模式已被更改成 生存模式")); + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + if (AllPlayer.isOp()) { + if (!AllPlayer.getName().equals(player.getName())) { + AllPlayer.sendMessage(ChatColor.GRAY + "[" + senderName + ":更改了玩家" + player.getName() + "的游戏模式为 生存模式]"); + } + } + } + return false; + } + + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d" + args1 + "不是一个有效的模式")); + } + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d用法错误,用法:/gamemode <模式> [玩家]")); + } + } + return false; + } + + public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, String[] strings) { + if (strings.length == 1) { + List tablist = new ArrayList<>(); + tablist.add("冒险"); + tablist.add("创造"); + tablist.add("旁观"); + tablist.add("生存"); + if (!strings[0].equalsIgnoreCase("冒险") && !strings[0].equalsIgnoreCase("创造") && !strings[0].equalsIgnoreCase("旁观") && !strings[0].equalsIgnoreCase("生存")) { + return tablist; + } + } + return null; + } +} diff --git a/src/main/java/top/gtb520/tools/main/heal_Command.java b/src/main/java/top/gtb520/tools/main/heal_Command.java new file mode 100644 index 0000000..05fb488 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/heal_Command.java @@ -0,0 +1,37 @@ +package top.gtb520.tools.main; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import static top.gtb520.tools.main.main.instance; + +public class heal_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + String CommandName = "heal"; + if (player.isOp()) { + if (!instance.getConfig().getBoolean(CommandName + "CommandSetting.AllowAdminUsed" + CommandName + "Command")) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个服务器禁止管理员使用heal命令!")); + return false; + } + }else { + if (!instance.getConfig().getBoolean(CommandName + "CommandSetting.AllowPlayerUsed" + CommandName + "Command")) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个服务器禁止玩家使用heal命令!")); + return false; + } + } + player.setSaturation(20); + player.setFoodLevel(20); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a你的血量被神奇的恢复了")); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只有玩家才能执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/main.java b/src/main/java/top/gtb520/tools/main/main.java new file mode 100644 index 0000000..e1fd457 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/main.java @@ -0,0 +1,139 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.event.Listener; +import org.bukkit.plugin.PluginDescriptionFile; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.scheduler.BukkitTask; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public final class main extends JavaPlugin implements Listener { + public static YamlFile_Utils Yaml; + + public static main instance; + private static PluginDescriptionFile descriptionFile; + + public static PluginDescriptionFile getDescriptionFile() { + return descriptionFile; + } + + public static main getInstance() { + return instance; + } + + @Override + public void onEnable() { + // Plugin startup logic + instance = this; + descriptionFile = getDescription(); + + unity.GetLoggerPlus("\n" + + " ___ ___ \n" + + " / _ \\ _ __ ___ _ _ / __| ___ _ _ _ _ __ ___ \n" + + " | (_) | '_ \\/ -_) ' \\\\__ \\/ _ \\ || | '_/ _/ -_)\n" + + " \\___/| .__/\\___|_||_|___/\\___/\\_,_|_| \\__\\___|\n" + + " |_| \n"); + + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") == null) { + unity.GetLoggerPlus("&d找不到PlaceholderAPI,请安装PlaceholderAPI后才能使用本插件"); + Bukkit.getPluginManager().disablePlugins(); + try { + Thread.sleep(2300); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.exit(0); + } else if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { + unity.GetLoggerPlus("&2已检测到PlaceholderAPI前置"); + } + + Bukkit.getPluginManager().registerEvents(this, this); + new PlaceholderAPI(this).register(); + + File Folder = new File(String.valueOf(getDataFolder())); + File Config_File = new File(getDataFolder(), "config.yml"); + Yaml = new YamlFile_Utils(); + if (!Folder.exists() || !Config_File.exists()) { + Folder.mkdirs(); + Yaml.saveYamlFile(getDataFolder().getPath(), "config.yml", "config.yml",true); + } + + List Folders = new ArrayList<>(); + Folders.add(new File(getDataFolder().getPath())); + Makedirs(Folders); + + unity.GetLoggerPlus("&f-----------OpenSourceTools-----------"); + BukkitTask TpaTime = new Tpa_Time(this).runTaskTimer(this, 0L, 20); + unity.SetIntTemp("TpaTimeTaskId",TpaTime.getTaskId()); + + BukkitTask TpaDetect = new Tpa_Detect(this).runTaskTimer(this, 0L, 60*20); + unity.SetIntTemp("TpaDetectTaskId",TpaDetect.getTaskId()); + + if (getConfig().getBoolean("TimeMessageSetting.TimeMessage")) { + BukkitTask TimeMessage = new TimeMessage(this).runTaskTimer(this, 0L, getConfig().getInt("TimeMessageSetting.TimeMessageTime")*20L); + unity.SetIntTemp("TimeMessageTaskId",TimeMessage.getTaskId()); + } + + Bukkit.getPluginManager().registerEvents(new KickGUI_ClickGUI_Event(),this); + Bukkit.getPluginManager().registerEvents(new PlayerJoin_Event(),this); + Bukkit.getPluginManager().registerEvents(new PlayerQuit_Event(),this); + Bukkit.getPluginManager().registerEvents(new PlayerChat_Event(),this); + Bukkit.getPluginManager().registerEvents(new SignChange_Event(),this); + Bukkit.getPluginManager().registerEvents(new PlayerDeath_Event(),this); + Bukkit.getPluginManager().registerEvents(new PlayerReSpawn_Event(),this); + Bukkit.getPluginManager().registerEvents(new PlayerChangedWorld_Event(),this); + + Objects.requireNonNull(getCommand("OSTReload")).setExecutor(new Reload_Command()); + Objects.requireNonNull(getCommand("Stop")).setExecutor(new Stop_Command()); + Objects.requireNonNull(getCommand("gamemode")).setExecutor(new gm_Command()); + Objects.requireNonNull(getCommand("gamemode")).setTabCompleter(new gm_Command()); + Objects.requireNonNull(getCommand("day")).setExecutor(new day_Command()); + Objects.requireNonNull(getCommand("sun")).setExecutor(new sun_Command()); + Objects.requireNonNull(getCommand("spawn")).setExecutor(new spawn_Command()); + Objects.requireNonNull(getCommand("setspawn")).setExecutor(new setspawn_Command()); + Objects.requireNonNull(getCommand("tpa")).setExecutor(new Tpa_Command()); + Objects.requireNonNull(getCommand("tpaaccept")).setExecutor(new tpaAccept_Command()); + Objects.requireNonNull(getCommand("tpadefuse")).setExecutor(new tpaDefuse_Command()); + Objects.requireNonNull(getCommand("vanish")).setExecutor(new vanish_Command()); + Objects.requireNonNull(getCommand("fly")).setExecutor(new fly_Command()); + Objects.requireNonNull(getCommand("mute")).setExecutor(new mute_Command()); + Objects.requireNonNull(getCommand("unmute")).setExecutor(new unmute_Command()); + Objects.requireNonNull(getCommand("kick")).setExecutor(new SuperKick_Command()); + Objects.requireNonNull(getCommand("feed")).setExecutor(new feed_Command()); + Objects.requireNonNull(getCommand("heal")).setExecutor(new heal_Command()); + Objects.requireNonNull(getCommand("list")).setExecutor(new SuperList_Command()); + Objects.requireNonNull(getCommand("back")).setExecutor(new Back_Command()); + Objects.requireNonNull(getCommand("testGUI")).setExecutor(new testGUI()); + Objects.requireNonNull(getCommand("PlayerTitle")).setExecutor(new PlayerTitle_Command()); + + unity.GetLoggerPlus("插件启动成功"); + unity.GetLoggerPlus("&f-----------OpenSourceTools-----------"); + } + + @Override + public void onDisable() { + // Plugin shutdown logic + instance = null; + unity.GetLoggerPlus("&f-----------OpenSourceTools-----------"); + unity.GetLoggerPlus("插件已卸载"); + unity.GetLoggerPlus("&f-----------OpenSourceTools-----------"); + unity.GetLoggerPlus("\n" + + " ___ ___ \n" + + " / _ \\ _ __ ___ _ _ / __| ___ _ _ _ _ __ ___ \n" + + " | (_) | '_ \\/ -_) ' \\\\__ \\/ _ \\ || | '_/ _/ -_)\n" + + " \\___/| .__/\\___|_||_|___/\\___/\\_,_|_| \\__\\___|\n" + + " |_| \n"); + } + + private static void Makedirs(List Folders) { + for (File EachFolder : Folders) { + if (!EachFolder.exists()) { + EachFolder.mkdirs(); + } + } + } +} diff --git a/src/main/java/top/gtb520/tools/main/multi.java b/src/main/java/top/gtb520/tools/main/multi.java new file mode 100644 index 0000000..dc6f019 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/multi.java @@ -0,0 +1,134 @@ +package cn.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; +import top.gtb520.tools.main.main; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Objects; + +public class multi { + + public static void SaveAndReloadConfig() { + main.instance.saveConfig(); + main.instance.reloadConfig(); + } + public static String ColorMessage(String String1) { + return ChatColor.translateAlternateColorCodes('&',String1); + } + + public static void GetLoggerPlus(String String1) { + CommandSender Console = Bukkit.getConsoleSender(); + Console.sendMessage(ColorMessage(String1)); + } + + static HashMap IntTemp = new HashMap<>(); + + static HashMap StringTemp = new HashMap<>(); + + static HashMap BooleanTemp = new HashMap<>(); + + static HashMap LocationTemp = new HashMap<>(); + + public static void SetLocationTempTemp(String String1, Location String2) { + LocationTemp.put(String1,String2); + } + + public static Location getLocationTempTemp(String String1) { + return LocationTemp.get(String1); + } + + public static void SetStringTemp(String String1,String String2) { + StringTemp.put(String1,String2); + } + + public static String getStringTemp(String String1) { + return StringTemp.get(String1); + } + + public static void SetIntTemp(String String1, Integer Int1) { + IntTemp.put(String1,Int1); + } + + public static Integer GetIntTemp(String String1) { + return IntTemp.get(String1); + } + + public static void SetBooleanTemp(String String1, boolean Boolean1) { + BooleanTemp.put(String1, Boolean1); + } + + public static boolean getBooleanTemp(String String1) { + return BooleanTemp.get(String1); + } + + public static void KickGui(Player player) { + Inventory UI = Bukkit.createInventory(player,45, ColorMessage("&a选择你要踢出的玩家")); + + ItemStack Bk = new ItemStack(Material.ORANGE_STAINED_GLASS_PANE); + ItemMeta Bk_Meta = Bk.getItemMeta(); + Objects.requireNonNull(Bk_Meta).setDisplayName(ColorMessage("&e这只是一个边框")); + ArrayList Bk_Lore = new ArrayList<>(); + Bk_Lore.add(null); + Bk_Lore.add(ColorMessage("&e这只是一个边框")); + Bk_Meta.setLore(Bk_Lore); + Bk.setItemMeta(Bk_Meta); + + for (int i1 = 0 ; i1 <9 ; i1++) { + UI.setItem(i1,Bk); + } + + for (int i2 = 36 ; i2 <40 ; i2++) { + UI.setItem(i2,Bk); + } + + for (int i3 = 41 ; i3 <45 ; i3++) { + UI.setItem(i3,Bk); + } + + UI.setItem(9,Bk); + UI.setItem(17,Bk); + + UI.setItem(18,Bk); + UI.setItem(26,Bk); + + UI.setItem(27,Bk); + UI.setItem(35,Bk); + + ItemStack Gb = new ItemStack(Material.REDSTONE_BLOCK); + ItemMeta Gb_Meta = Gb.getItemMeta(); + Objects.requireNonNull(Gb_Meta).setDisplayName(ColorMessage("&d关闭菜单")); + ArrayList Gb_Lore = new ArrayList<>(); + Gb_Lore.add(null); + Gb_Lore.add(ColorMessage("&e点击关闭菜单")); + Gb_Meta.setLore(Gb_Lore); + Gb.setItemMeta(Gb_Meta); + + UI.setItem(40,Gb); + + ArrayList players = new ArrayList<>(player.getServer().getOnlinePlayers()); + for (Player value : players) { + ItemStack PlayerHead = new ItemStack(Material.PLAYER_HEAD); + SkullMeta PlayerHead_meta = (SkullMeta) PlayerHead.getItemMeta(); + Objects.requireNonNull(PlayerHead_meta).setOwningPlayer(value); + Objects.requireNonNull(PlayerHead_meta).setDisplayName(ChatColor.RESET + value.getDisplayName() + ChatColor.RESET); + ArrayList PlayerHead_Lore = new ArrayList<>(); + PlayerHead_Lore.add(null); + PlayerHead_Lore.add(ColorMessage( "&e点击踢出玩家")); + PlayerHead_meta.setLore(PlayerHead_Lore); + PlayerHead.setItemMeta(PlayerHead_meta); + + UI.addItem(PlayerHead); + } + player.openInventory(UI); + } +} diff --git a/src/main/java/top/gtb520/tools/main/mute_Command.java b/src/main/java/top/gtb520/tools/main/mute_Command.java new file mode 100644 index 0000000..42940c4 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/mute_Command.java @@ -0,0 +1,87 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class mute_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + if (args.length == 1) { + Player senderPlayer = (Player) sender; + String PlayerName = args[0]; + + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个玩家不存在或不在线!")); + return false; + } + + Player player = Bukkit.getPlayer(PlayerName); + + if (PlayerName.equals(senderPlayer.getName())) { + sender.sendMessage(ChatColor.RED + "你不能禁言你自己"); + return false; + } + if (Objects.requireNonNull(player).isOp()) { + sender.sendMessage(ChatColor.RED + "你不能禁言管理员"); + return false; + } + + List MutePlayerList = new ArrayList<>(main.instance.getConfig().getStringList("MutePlayerList")); + + for (String MutePlayers : MutePlayerList) { + if (MutePlayers.equals(Objects.requireNonNull(player).getName())) { + sender.sendMessage(ChatColor.RED + "这个玩家已经被禁言过了,请勿重复禁言!"); + return false; + } + } + + MutePlayerList.add(Objects.requireNonNull(player).getName()); + main.instance.getConfig().set("MutePlayerList", MutePlayerList); + unity.SaveAndReloadConfig(); + sender.sendMessage(ChatColor.GREEN + "你禁言了" + player.getName()); + player.sendMessage(ChatColor.RED + "你被 " + senderPlayer.getName() + " 禁言了!"); + return false; + } + }else { + if (args.length == 1) { + String PlayerName = args[0]; + + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个玩家不存在或不在线!")); + return false; + } + + Player player = Bukkit.getPlayer(PlayerName); + + List MutePlayerList = new ArrayList<>(main.instance.getConfig().getStringList("MutePlayerList")); + + for (String MutePlayers : MutePlayerList) { + if (MutePlayers.equals(Objects.requireNonNull(player).getName())) { + sender.sendMessage(ChatColor.RED + "这个玩家已经被禁言过了,请勿重复禁言!"); + return false; + } + } + + MutePlayerList.add(Objects.requireNonNull(player).getName()); + main.instance.getConfig().set("MutePlayerList", MutePlayerList); + unity.SaveAndReloadConfig(); + sender.sendMessage(ChatColor.GREEN + "你禁言了" + player.getName()); + player.sendMessage(ChatColor.RED + "你被 控制台 禁言了!"); + return false; + } + } + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d用法错误,用法:/mute <玩家ID>")); + return false; + } +} + diff --git a/src/main/java/top/gtb520/tools/main/setspawn_Command.java b/src/main/java/top/gtb520/tools/main/setspawn_Command.java new file mode 100644 index 0000000..69ee33f --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/setspawn_Command.java @@ -0,0 +1,33 @@ +package top.gtb520.tools.main; + +import org.bukkit.ChatColor; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class setspawn_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + World world = player.getWorld(); + String worldName = world.getName(); + Double locationX = player.getLocation().getX(); + Double locationY = player.getLocation().getY(); + Double locationZ = player.getLocation().getZ(); + main.instance.getConfig().set("SpawnSetting.WorldName",worldName); + main.instance.getConfig().set("SpawnSetting.locationX",locationX); + main.instance.getConfig().set("SpawnSetting.locationY",locationY); + main.instance.getConfig().set("SpawnSetting.locationZ",locationZ); + main.instance.saveConfig(); + main.instance.reloadConfig(); + player.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a设置完成!")); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只能是玩家执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/spawn_Command.java b/src/main/java/top/gtb520/tools/main/spawn_Command.java new file mode 100644 index 0000000..1e94e81 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/spawn_Command.java @@ -0,0 +1,39 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class spawn_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + String worldName = main.instance.getConfig().getString("SpawnSetting.WorldName"); + double locationX = main.instance.getConfig().getDouble("SpawnSetting.locationX"); + double locationY = main.instance.getConfig().getDouble("SpawnSetting.locationY"); + double locationZ = main.instance.getConfig().getDouble("SpawnSetting.locationZ"); + if (worldName == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d你好像还没有设置主城呢,使用/setspawn设置主城吧!")); + }else { + World world = Bukkit.getWorld(worldName); + Location location = new Location(world,locationX,locationY,locationZ); + location.setX(locationX); + location.setY(locationY); + location.setZ(locationZ); + player.teleport(location); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a欢迎来到主城!")); + } + + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只能是玩家执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/sun_Command.java b/src/main/java/top/gtb520/tools/main/sun_Command.java new file mode 100644 index 0000000..387f534 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/sun_Command.java @@ -0,0 +1,23 @@ +package top.gtb520.tools.main; + +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class sun_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + player.getWorld().setStorm(false); + player.getWorld().setThundering(false); + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&a完成!")); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只能是玩家执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/testGUI.java b/src/main/java/top/gtb520/tools/main/testGUI.java new file mode 100644 index 0000000..91c7455 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/testGUI.java @@ -0,0 +1,38 @@ +package top.gtb520.tools.main; + +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class testGUI implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + if (!player.isOp()) { + if (args.length == 1) { + String GUIName = args[0]; + if (GUIName.equals("KickGUI")) { + unity.KickGui(player); + return false; + } + + sender.sendMessage(unity.ColorMessage("&d这个命令只有插件作者才能使用")); + System.out.println("玩家:" + sender + "使用了内部测试命令"); + }else { + sender.sendMessage(unity.ColorMessage("&d这个命令只有插件作者才能使用")); + System.out.println("玩家:" + sender + "使用了内部测试命令"); + } + }else { + sender.sendMessage(unity.ColorMessage("&d这个命令只有插件作者才能使用")); + System.out.println("玩家:" + sender + "使用了内部测试命令"); + } + }else { + sender.sendMessage(unity.ColorMessage("&d这个命令只有插件作者才能使用")); + System.out.println("玩家:" + sender + "使用了内部测试命令"); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/tpaAccept_Command.java b/src/main/java/top/gtb520/tools/main/tpaAccept_Command.java new file mode 100644 index 0000000..a60a9ed --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/tpaAccept_Command.java @@ -0,0 +1,48 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class tpaAccept_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + if (args.length == 1) { + String AcceptPlayerName = args[0]; + if (Bukkit.getPlayer(AcceptPlayerName) == null) { + unity.SetStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName",null); + unity.SetBooleanTemp(AcceptPlayerName + "_Temp_Tpa",false); + unity.SetIntTemp(AcceptPlayerName + "_Temp_TpaTime",0); + sender.sendMessage(ChatColor.RED + "错误,那个玩家突然下线了!传送已取消"); + return false; + } + Player player = (Player) sender; + if (unity.getStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName") == null|| !Objects.equals(unity.getStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName"), player.getName())) { + sender.sendMessage(ChatColor.RED + "这个玩家没有给你发传送请求"); + return false; + } + Player AcceptPlayer = Bukkit.getPlayer(AcceptPlayerName); + Location SenderLocation = player.getLocation(); + Objects.requireNonNull(AcceptPlayer).teleport(SenderLocation); + AcceptPlayer.sendMessage(ChatColor.GREEN + "传送成功!"); + player.sendMessage(ChatColor.GREEN + player.getName() + "传送到了你这里!"); + unity.SetStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName",null); + unity.SetBooleanTemp(AcceptPlayerName + "_Temp_Tpa",false); + unity.SetIntTemp(AcceptPlayerName + "_Temp_TpaTime",0); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d用法错误,用法:/tpa <玩家ID>")); + } + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只有玩家才能执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/tpaDefuse_Command.java b/src/main/java/top/gtb520/tools/main/tpaDefuse_Command.java new file mode 100644 index 0000000..3daab50 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/tpaDefuse_Command.java @@ -0,0 +1,44 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class tpaDefuse_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + if (args.length == 1) { + String AcceptPlayerName = args[0]; + if (Bukkit.getPlayer(AcceptPlayerName) == null) { + unity.SetStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName",null); + unity.SetBooleanTemp(AcceptPlayerName + "_Temp_Tpa",false); + unity.SetIntTemp(AcceptPlayerName + "_Temp_TpaTime",0); + sender.sendMessage(ChatColor.RED + "错误,那个玩家突然下线了!传送已取消"); + return false; + } + Player player = (Player) sender; + if (unity.getStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName") == null|| !Objects.equals(unity.getStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName"), player.getName())) { + sender.sendMessage(ChatColor.RED + "这个玩家没有给你发传送请求"); + return false; + } + Player AcceptPlayer = Bukkit.getPlayer(AcceptPlayerName); + Objects.requireNonNull(AcceptPlayer).sendMessage(ChatColor.RED + "对方拒绝了你的请求!"); + unity.SetStringTemp(AcceptPlayerName + "_Temp_TpaPlayerName",null); + unity.SetBooleanTemp(AcceptPlayerName + "_Temp_Tpa",false); + unity.SetIntTemp(AcceptPlayerName + "_Temp_TpaTime",0); + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d用法错误,用法:/tpaDefuse <玩家ID>")); + } + }else { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d这个命令只有玩家才能执行")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/tpaback_Command.java b/src/main/java/top/gtb520/tools/main/tpaback_Command.java new file mode 100644 index 0000000..78f1522 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/tpaback_Command.java @@ -0,0 +1,21 @@ +package top.gtb520.tools.main; + +import org.bukkit.Location; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class tpaback_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + Player player = (Player) sender; + Location BackLocation = unity.getLocationTempTemp(player.getName() + "_Tpa"); + player.teleport(BackLocation); + player.sendMessage(unity.ColorMessage("&a传送成功!")); + } + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/unity.java b/src/main/java/top/gtb520/tools/main/unity.java new file mode 100644 index 0000000..047e2b8 --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/unity.java @@ -0,0 +1,133 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Objects; + +public class unity { + + public static void SaveAndReloadConfig() { + main.instance.saveConfig(); + main.instance.reloadConfig(); + } + public static String ColorMessage(String String1) { + return ChatColor.translateAlternateColorCodes('&',String1); + } + + public static void GetLoggerPlus(String String1) { + CommandSender Console = Bukkit.getConsoleSender(); + Console.sendMessage(ColorMessage(String1)); + } + + static HashMap IntTemp = new HashMap<>(); + + static HashMap StringTemp = new HashMap<>(); + + static HashMap BooleanTemp = new HashMap<>(); + + static HashMap LocationTemp = new HashMap<>(); + + public static void SetLocationTempTemp(String String1, Location String2) { + LocationTemp.put(String1,String2); + } + + public static Location getLocationTempTemp(String String1) { + return LocationTemp.get(String1); + } + + public static void SetStringTemp(String String1,String String2) { + StringTemp.put(String1,String2); + } + + public static String getStringTemp(String String1) { + return StringTemp.get(String1); + } + + public static void SetIntTemp(String String1, Integer Int1) { + IntTemp.put(String1,Int1); + } + + public static Integer GetIntTemp(String String1) { + return IntTemp.get(String1); + } + + public static void SetBooleanTemp(String String1, boolean Boolean1) { + BooleanTemp.put(String1, Boolean1); + } + + public static boolean getBooleanTemp(String String1) { + return BooleanTemp.get(String1); + } + + public static void KickGui(Player player) { + Inventory UI = Bukkit.createInventory(player,45, ColorMessage("&a选择你要踢出的玩家")); + + ItemStack Bk = new ItemStack(Material.ORANGE_STAINED_GLASS_PANE); + ItemMeta Bk_Meta = Bk.getItemMeta(); + Objects.requireNonNull(Bk_Meta).setDisplayName(ColorMessage("&e这只是一个边框")); + ArrayList Bk_Lore = new ArrayList<>(); + Bk_Lore.add(null); + Bk_Lore.add(ColorMessage("&e这只是一个边框")); + Bk_Meta.setLore(Bk_Lore); + Bk.setItemMeta(Bk_Meta); + + for (int i1 = 0 ; i1 <9 ; i1++) { + UI.setItem(i1,Bk); + } + + for (int i2 = 36 ; i2 <40 ; i2++) { + UI.setItem(i2,Bk); + } + + for (int i3 = 41 ; i3 <45 ; i3++) { + UI.setItem(i3,Bk); + } + + UI.setItem(9,Bk); + UI.setItem(17,Bk); + + UI.setItem(18,Bk); + UI.setItem(26,Bk); + + UI.setItem(27,Bk); + UI.setItem(35,Bk); + + ItemStack Gb = new ItemStack(Material.REDSTONE_BLOCK); + ItemMeta Gb_Meta = Gb.getItemMeta(); + Objects.requireNonNull(Gb_Meta).setDisplayName(ColorMessage("&d关闭菜单")); + ArrayList Gb_Lore = new ArrayList<>(); + Gb_Lore.add(null); + Gb_Lore.add(ColorMessage("&e点击关闭菜单")); + Gb_Meta.setLore(Gb_Lore); + Gb.setItemMeta(Gb_Meta); + + UI.setItem(40,Gb); + + ArrayList players = new ArrayList<>(player.getServer().getOnlinePlayers()); + for (Player value : players) { + ItemStack PlayerHead = new ItemStack(Material.PLAYER_HEAD); + SkullMeta PlayerHead_meta = (SkullMeta) PlayerHead.getItemMeta(); + Objects.requireNonNull(PlayerHead_meta).setOwningPlayer(value); + Objects.requireNonNull(PlayerHead_meta).setDisplayName(ChatColor.RESET + value.getDisplayName() + ChatColor.RESET); + ArrayList PlayerHead_Lore = new ArrayList<>(); + PlayerHead_Lore.add(null); + PlayerHead_Lore.add(ColorMessage( "&e点击踢出玩家")); + PlayerHead_meta.setLore(PlayerHead_Lore); + PlayerHead.setItemMeta(PlayerHead_meta); + + UI.addItem(PlayerHead); + } + player.openInventory(UI); + } +} diff --git a/src/main/java/top/gtb520/tools/main/unmute_Command.java b/src/main/java/top/gtb520/tools/main/unmute_Command.java new file mode 100644 index 0000000..99a13da --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/unmute_Command.java @@ -0,0 +1,74 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class unmute_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (sender instanceof Player) { + if (args.length == 1) { + Player senderPlayer = (Player) sender; + String PlayerName = args[0]; + + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个玩家不存在或不在线!")); + return false; + } + + Player player = Bukkit.getPlayer(PlayerName); + + List MutePlayerList = new ArrayList<>(main.instance.getConfig().getStringList("MutePlayerList")); + + for (String MutePlayers : MutePlayerList) { + if (MutePlayers.equals(Objects.requireNonNull(player).getName())) { + MutePlayerList.remove(Objects.requireNonNull(player).getName()); + main.instance.getConfig().set("MutePlayerList", MutePlayerList); + unity.SaveAndReloadConfig(); + sender.sendMessage(ChatColor.GREEN + "你解除了 " + player.getName() + " 的禁言"); + player.sendMessage(ChatColor.RED + "你被 " + senderPlayer.getName() + " 解除禁言了!"); + return false; + } + } + sender.sendMessage(ChatColor.RED + "这个玩家没有被禁言过!"); + } + }else { + if (args.length == 1) { + String PlayerName = args[0]; + + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&d这个玩家不存在或不在线!")); + return false; + } + + Player player = Bukkit.getPlayer(PlayerName); + + List MutePlayerList = new ArrayList<>(main.instance.getConfig().getStringList("MutePlayerList")); + + for (String MutePlayers : MutePlayerList) { + if (MutePlayers.equals(Objects.requireNonNull(player).getName())) { + MutePlayerList.add(Objects.requireNonNull(player).getName()); + main.instance.getConfig().set("MutePlayerList", MutePlayerList); + unity.SaveAndReloadConfig(); + sender.sendMessage(ChatColor.GREEN + "你解除了 控制台 的禁言"); + player.sendMessage(ChatColor.RED + "你被 控制台 解除禁言了!"); + return false; + } + } + sender.sendMessage(ChatColor.RED + "这个玩家没有被禁言过!"); + return false; + } + } + sender.sendMessage(ChatColor.translateAlternateColorCodes('&',"&d用法错误,用法:/unmute <玩家ID>")); + return false; + } +} diff --git a/src/main/java/top/gtb520/tools/main/vanish_Command.java b/src/main/java/top/gtb520/tools/main/vanish_Command.java new file mode 100644 index 0000000..72cc96f --- /dev/null +++ b/src/main/java/top/gtb520/tools/main/vanish_Command.java @@ -0,0 +1,65 @@ +package top.gtb520.tools.main; + +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.jetbrains.annotations.NotNull; + +public class vanish_Command implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (args.length == 1) { + String PlayerName = args[0]; + if (Bukkit.getPlayer(PlayerName) == null) { + sender.sendMessage(unity.ColorMessage("&d&l这个玩家不存在或不在线!")); + return false; + } + Player player = Bukkit.getPlayer(PlayerName); + if (unity.getStringTemp(player.getName() + "_Vanish") != null) { + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + AllPlayer.showPlayer(main.instance,player); + } + player.removePotionEffect(PotionEffectType.INVISIBILITY); + unity.SetStringTemp(player.getName() + "_Vanish",null); + sender.sendMessage(unity.ColorMessage("&a&l操作成功!")); + player.sendMessage(unity.ColorMessage("&e&l隐身模式已关闭")); + }else { + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + AllPlayer.hidePlayer(main.instance,player); + } + PotionEffect pot = new PotionEffect(PotionEffectType.INVISIBILITY, 99999, 255, true); + player.addPotionEffect(pot); + unity.SetStringTemp(player.getName() + "_Vanish","已开启"); + sender.sendMessage(unity.ColorMessage("&a&l操作成功!")); + player.sendMessage(unity.ColorMessage("&e&l隐身模式已开启")); + } + }else { + if (sender instanceof Player) { + Player player = (Player) sender; + if (unity.getStringTemp(player.getName() + "_Vanish") != null) { + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + AllPlayer.showPlayer(main.instance,player); + } + player.removePotionEffect(PotionEffectType.INVISIBILITY); + unity.SetStringTemp(player.getName() + "_Vanish",null); + player.sendMessage(unity.ColorMessage("&e&l隐身模式已关闭")); + }else { + for (Player AllPlayer : Bukkit.getOnlinePlayers()) { + AllPlayer.hidePlayer(main.instance,player); + } + PotionEffect pot = new PotionEffect(PotionEffectType.INVISIBILITY, 99999, 255, true); + player.addPotionEffect(pot); + unity.SetStringTemp(player.getName() + "_Vanish","已开启"); + player.sendMessage(unity.ColorMessage("&e&l隐身模式已开启")); + } + }else { + sender.sendMessage(unity.ColorMessage("&d&l用法错误,正确用法:/" + label + " [玩家ID]")); + } + } + return false; + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..2b65578 --- /dev/null +++ b/src/main/resources/config.yml @@ -0,0 +1,88 @@ +#服务器名字 +ServerName: "ServerName" + +#默认关服提示 +DefaultStopMessage: "StopServerText" + +#玩家进入服务器的给进服玩家的提示 +PlayerJoinSendMessage: + - "JoinText" + +#普通玩家进入服务器的全服提示 +PlayerJoinServerMessage: "&7[&f&l玩家&7]&e%PlayerName%&a进入了服务器" + +#普通玩家退出服务器的全服提示 +PlayerQuitServerMessage: "&7[&f&l玩家&7]&e%PlayerName%&d离开了服务器" + +#管理员进入服务器的全服提示 +AdminJoinServerMessage: "&7[&d&l管理员&7]&e%PlayerName%&a进入了服务器" + +#管理员退出服务器的全服提示 +AdminQuitServerMessage: "&7[&d&l管理员&7]&e%PlayerName%&d离开了服务器" + +#ColorChat设置 +ColorChatSetting: + #是否允许管理员使用ColorChat + AllowAdminUsedColorChat: true + #是否允许普通玩家使用ColorChat + AllowPlayerUsedColorChat: true + #在这个列表中的玩家无视上面两个开关 + AllowPlayers: + - PlayerName-1 + - PlayerName-2 + - PlayerName-3 + +#ColorSignSetting设置 +ColorSignSetting: + #是否允许管理员使用ColorSign + AllowAdminUsedColorSign: true + #是否允许普通玩家使用ColorSign + AllowPlayerUsedColorSign: true + +#Spawn设置 +SpawnSetting: + #世界名称 + WorldName: world + #X坐标 + locationX: 0.5 + #Y坐标 + locationY: 80.0 + #Z坐标 + locationZ: 0.5 + +#公告设置 +TimeMessageSetting: + #是否启动公告系统 + TimeMessage: true + #发送公告间隔时间(单位秒) + TimeMessageTime: 60 + #公告内容 + Message: + - "Text-1" + - "Text-2" + - "Text-3" + +#Feed命令设置 +FeedCommandSetting: + #是否允许管理员使用Feed命令 + AllowAdminUsedFeedCommand: true + #是否允许普通玩家使用Feed命令 + AllowPlayerUsedFeedCommand: false + +#Heal命令设置 +HealCommandSetting: + #是否允许管理员使用Heal命令 + AllowAdminUsedHealCommand: true + #是否允许普通玩家使用Heal命令 + AllowPlayerUsedHealCommand: false + +#聊天设置 +ChatSetting: + #聊天延迟 + ChatTime: 3 + +#屏蔽词 +AntiKeyWords: + - xxx1 + - xxx2 + - xxx3 \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..dea2579 --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,137 @@ +name: OpenSourceTools +version: '${project.version}' +main: top.gtb520.tools.main.main +api-version: '1.21' +depend: [ PlaceholderAPI ] +authors: [ Open Source ] +description: 开源工具包 v2.1.0 - 支持 Minecraft 1.21.11 +commands: + feed: + aliases: [eat] + description: 恢复饱食度 + permission: OpenTools.default + permission-message: §c§l权限不足 + heal: + description: 恢复血量 + permission: OpenTools.default + permission-message: §c§l权限不足 + spawn: + description: 返回主城 + permission: OpenTools.default + permission-message: §c§l权限不足 + tpa: + description: 传送请求 + permission: OpenTools.default + permission-message: §c§l权限不足 + back: + description: 返回死亡点 + permission: OpenTools.default + permission-message: §c§l权限不足 + tpaaccept: + description: 接受传送请求 + permission: OpenTools.default + permission-message: §c§l权限不足 + tpadefuse: + description: 拒绝传送请求 + permission: OpenTools.default + permission-message: §c§l权限不足 + testGUI: + description: 测试GUI命令 + permission: OpenTools.testGUI + permission-message: §c§l权限不足 + OSTReload: + description: 重载插件 + permission: OpenTools.reload + permission-message: §c§l权限不足 + stop: + description: 关闭服务器 + permission: OpenTools.stop + permission-message: §c§l权限不足 + gamemode: + aliases: [gm] + description: 更改游戏模式 + permission: OpenTools.gamemode + permission-message: §c§l权限不足 + sun: + description: 一键晴天 + permission: OpenTools.sun + permission-message: §c§l权限不足 + setspawn: + description: 设置主城位置 + permission: OpenTools.setspawn + permission-message: §c§l权限不足 + day: + description: 一键天亮 + permission: OpenTools.day + permission-message: §c§l权限不足 + vanish: + aliases: [v] + description: 隐身 + permission: OpenTools.vanish + permission-message: §c§l权限不足 + fly: + description: 飞行 + permission: OpenTools.fly + permission-message: §c§l权限不足 + mute: + description: 禁言 + permission: OpenTools.mute + permission-message: §c§l权限不足 + unmute: + description: 解除禁言 + permission: OpenTools.unmute + permission-message: §c§l权限不足 + kick: + description: 更好的踢出 + permission: OpenTools.kick + permission-message: §c§l权限不足 + list: + description: 服务器属性 + permission: OpenTools.list + permission-message: §c§l权限不足 + aliases: [tps] + PlayerTitle: + description: 称号系统 + permission: OpenTools.default + permission-message: §c§l权限不足 + aliases: [plt] +permissions: + OpenTools.default: + description: 默认拥有的权限 + default: true + OpenTools.kick: + description: kick命令的权限 + default: op + OpenTools.mute: + description: mute命令的权限 + default: op + OpenTools.unmute: + description: unmute命令的权限 + default: op + OpenTools.fly: + description: fly命令的权限 + default: op + OpenTools.vanish: + description: unmute命令的权限 + default: op + OpenTools.ostreload: + description: ostreload命令的权限 + default: op + OpenTools.sun: + description: sun命令的权限 + default: op + OpenTools.stop: + description: stop命令的权限 + default: op + OpenTools.gamemode: + description: gamemode命令的权限 + default: op + OpenTools.setspawn: + description: setspawn命令的权限 + default: op + OpenTools.list: + description: list命令的权限 + default: op + OpenTools.testGUI: + description: testGUI命令的权限 + default: op \ No newline at end of file diff --git a/tools/smoke-test/eula.txt b/tools/smoke-test/eula.txt new file mode 100644 index 0000000..fea60bf --- /dev/null +++ b/tools/smoke-test/eula.txt @@ -0,0 +1,2 @@ +#By changing the setting below to TRUE you are indicating your agreement to our EULA (https://aka.ms/MinecraftEULA). +eula=true diff --git a/tools/smoke-test/maven-settings.xml b/tools/smoke-test/maven-settings.xml new file mode 100644 index 0000000..2983481 --- /dev/null +++ b/tools/smoke-test/maven-settings.xml @@ -0,0 +1,13 @@ + + + + + aliyun-public + Aliyun Maven Public (central+sonatype) + https://maven.aliyun.com/repository/public + central,sonatype + + + diff --git a/tools/smoke-test/run-smoke-test.ps1 b/tools/smoke-test/run-smoke-test.ps1 new file mode 100644 index 0000000..d9e1512 --- /dev/null +++ b/tools/smoke-test/run-smoke-test.ps1 @@ -0,0 +1,104 @@ +# OpenSourceTools 冒烟测试脚本 (Paper 1.21.11) +# 流程: 校验构建产物 -> 准备服务器目录 -> 启动 -> 等待 Done -> 校验插件日志 -> 优雅停止 -> 校验卸载日志 +param( + [int]$BootTimeoutSec = 300, + [int]$ShutdownTimeoutSec = 120 +) + +$ErrorActionPreference = 'Stop' +$Root = Split-Path -Parent $MyInvocation.MyCommand.Path # tools\smoke-test +$ProjectRoot = Split-Path -Parent (Split-Path -Parent $Root) # 项目根 +$CacheDir = Join-Path $env:USERPROFILE '.ost-smoke-cache' +$ServerDir = Join-Path $env:TEMP 'ost-smoke-test\server' + +$BuiltJar = Join-Path $ProjectRoot 'target\OpenSourceTools-2.1.0.jar' +if (-not (Test-Path $BuiltJar)) { Write-Output "FATAL: 找不到构建产物 $BuiltJar"; exit 2 } + +$PaperJar = Join-Path $CacheDir 'paper-1.21.11-132.jar' +$PapiJar = Join-Path $CacheDir 'PlaceholderAPI-2.12.3.jar' +if (-not (Test-Path $PaperJar)) { Write-Output "FATAL: 缓存缺少 $PaperJar"; exit 2 } +if (-not (Test-Path $PapiJar)) { Write-Output "FATAL: 缓存缺少 $PapiJar"; exit 2 } + +# 准备服务器目录(每次全新) +if (Test-Path $ServerDir) { Remove-Item -Recurse -Force $ServerDir -ErrorAction SilentlyContinue } +New-Item -ItemType Directory -Force -Path (Join-Path $ServerDir 'plugins') | Out-Null +Copy-Item -Force (Join-Path $Root 'server.properties') (Join-Path $ServerDir 'server.properties') +Copy-Item -Force (Join-Path $Root 'eula.txt') (Join-Path $ServerDir 'eula.txt') +Copy-Item -Force $PaperJar (Join-Path $ServerDir 'paper.jar') +Copy-Item -Force $PapiJar (Join-Path $ServerDir 'plugins\PlaceholderAPI.jar') +Copy-Item -Force $BuiltJar (Join-Path $ServerDir 'plugins\OpenSourceTools.jar') + +Write-Output "启动服务器: paper.jar + PlaceholderAPI.jar + OpenSourceTools.jar" + +$psi = [System.Diagnostics.ProcessStartInfo]::new() +$psi.FileName = 'java' +$psi.Arguments = "-Xmx1024M -XX:+UseG1GC -jar `"$((Join-Path $ServerDir 'paper.jar'))`" nogui" +$psi.WorkingDirectory = $ServerDir +$psi.UseShellExecute = $false +$psi.RedirectStandardInput = $true +$psi.RedirectStandardOutput = $false +$psi.RedirectStandardError = $false + +$proc = [System.Diagnostics.Process]::Start($psi) +Write-Output "服务器进程已启动 PID=$($proc.Id)" + +$logFile = Join-Path $ServerDir 'logs\latest.log' +$booted = $false +$deadline = (Get-Date).AddSeconds($BootTimeoutSec) +while (-not $proc.HasExited -and (Get-Date) -lt $deadline) { + Start-Sleep -Seconds 2 + if (Test-Path $logFile) { + $tail = Get-Content $logFile -Raw -Encoding UTF8 -ErrorAction SilentlyContinue + if ($tail -match 'Done \(') { $booted = $true; break } + if ($tail -match 'FAILED TO BIND TO PORT|Exception in thread "main"') { break } + } +} + +if (-not $booted) { + Write-Output 'FAIL: 服务器未能在超时时间内完成启动' + if (Test-Path $logFile) { Get-Content $logFile -Tail 40 -Encoding UTF8 } + if (-not $proc.HasExited) { $proc.Kill(); $proc.WaitForExit(15000) } + exit 1 +} + +Write-Output '服务器启动完成 (Done),正在发送 stop...' +Start-Sleep -Seconds 2 +$proc.StandardInput.WriteLine('stop') +$proc.StandardInput.Flush() +if (-not $proc.WaitForExit($ShutdownTimeoutSec * 1000)) { + Write-Output 'FAIL: 服务器未能优雅停止' + $proc.Kill() + exit 1 +} +Write-Output "服务器已退出, ExitCode=$($proc.ExitCode)" + +# ---------- 日志校验 ---------- +$log = Get-Content $logFile -Raw -Encoding UTF8 +$errors = @() + +function Check-Pass($name, $pattern) { + if ($log -match $pattern) { Write-Output "PASS: $name" } + else { Write-Output "FAIL: $name"; $script:errors += $name } +} + +function Check-Absent($name, $pattern) { + if ($log -match $pattern) { Write-Output "FAIL: $name"; $script:errors += $name } + else { Write-Output "PASS: $name" } +} + +Check-Pass '检测到PlaceholderAPI前置' '已检测到PlaceholderAPI前置' +Check-Pass '插件启动成功' '插件启动成功' +Check-Pass '插件已卸载' '插件已卸载' +Check-Absent '无插件加载错误' 'Error occurred while enabling OpenSourceTools|Could not load ''plugins/OpenSourceTools|Invalid plugin.yml|Invalid description' + +if ($proc.ExitCode -ne 0) { Write-Output "FAIL: 服务器退出码非0 ($($proc.ExitCode))"; $errors += "退出码$($proc.ExitCode)" } + +if ($errors.Count -eq 0) { + Write-Output '==================== 冒烟测试全部通过 ====================' + exit 0 +} else { + Write-Output "==================== 冒烟测试失败 ($($errors -join ', ')) ====================" + Write-Output '----- 关键日志片段 -----' + Get-Content $logFile -Encoding UTF8 | Select-String -Pattern 'OpenSourceTools|PlaceholderAPI|ERROR|Caused by' | Select-Object -First 40 + exit 1 +} diff --git a/tools/smoke-test/server-live.properties b/tools/smoke-test/server-live.properties new file mode 100644 index 0000000..9d80f91 --- /dev/null +++ b/tools/smoke-test/server-live.properties @@ -0,0 +1,17 @@ +#Minecraft server properties (live test server) +online-mode=false +server-port=25565 +server-ip= +level-name=world +level-type=minecraft\:flat +generate-structures=false +spawn-monsters=true +spawn-npcs=true +spawn-animals=true +view-distance=6 +simulation-distance=6 +max-players=20 +spawn-protection=0 +motd=OpenSourceTools v2.1.0 测试服 (1.21.11) +enable-rcon=false +network-compression-threshold=256 diff --git a/tools/smoke-test/server.properties b/tools/smoke-test/server.properties new file mode 100644 index 0000000..21b4dd8 --- /dev/null +++ b/tools/smoke-test/server.properties @@ -0,0 +1,17 @@ +#Minecraft server properties (smoke test) +online-mode=false +server-port=25570 +server-ip= +level-name=world +level-type=minecraft\:flat +generate-structures=false +spawn-monsters=false +spawn-npcs=false +spawn-animals=false +view-distance=2 +simulation-distance=2 +max-players=10 +spawn-protection=0 +motd=OST-smoke-test +enable-rcon=false +network-compression-threshold=256 diff --git a/tools/smoke-test/start-test-server.ps1 b/tools/smoke-test/start-test-server.ps1 new file mode 100644 index 0000000..c9e5a96 --- /dev/null +++ b/tools/smoke-test/start-test-server.ps1 @@ -0,0 +1,69 @@ +# 交互式测试服务器启动脚本 (Paper 1.21.11) +# 在独立可见的控制台窗口中启动服务器并保持运行,等待玩家连接。 +# 停止方式: 在服务器窗口输入 stop 并回车(推荐),或直接关闭该窗口。 +param( + [int]$BootTimeoutSec = 240 +) + +$ErrorActionPreference = 'Stop' +$Root = Split-Path -Parent $MyInvocation.MyCommand.Path # tools\smoke-test +$ProjectRoot = Split-Path -Parent (Split-Path -Parent $Root) # 项目根 +$CacheDir = Join-Path $env:USERPROFILE '.ost-smoke-cache' +$ServerDir = Join-Path $ProjectRoot 'test-server' + +$BuiltJar = Join-Path $ProjectRoot 'target\OpenSourceTools-2.1.0.jar' +if (-not (Test-Path $BuiltJar)) { Write-Output "FATAL: 找不到构建产物 $BuiltJar (请先执行 mvn clean package)"; exit 2 } +$PaperJar = Join-Path $CacheDir 'paper-1.21.11-132.jar' +$PapiJar = Join-Path $CacheDir 'PlaceholderAPI-2.12.3.jar' +if (-not (Test-Path $PaperJar)) { Write-Output "FATAL: 缓存缺少 Paper jar: $PaperJar"; exit 2 } +if (-not (Test-Path $PapiJar)) { Write-Output "FATAL: 缓存缺少 PAPI jar: $PapiJar"; exit 2 } + +# 检查端口占用(已有实例在运行则直接退出) +$existing = Get-NetTCPConnection -LocalPort 25565 -State Listen -ErrorAction SilentlyContinue +if ($existing) { Write-Output "WARN: 端口 25565 已被占用 (PID $($existing.OwningProcess)),可能服务器已在运行"; exit 3 } + +# 准备服务器目录(保留世界数据,不删除) +New-Item -ItemType Directory -Force -Path (Join-Path $ServerDir 'plugins') | Out-Null +Copy-Item -Force (Join-Path $Root 'server-live.properties') (Join-Path $ServerDir 'server.properties') +if (-not (Test-Path (Join-Path $ServerDir 'eula.txt'))) { + Copy-Item -Force (Join-Path $Root 'eula.txt') (Join-Path $ServerDir 'eula.txt') +} +Copy-Item -Force $PaperJar (Join-Path $ServerDir 'paper.jar') +Copy-Item -Force $PapiJar (Join-Path $ServerDir 'plugins\PlaceholderAPI.jar') +Copy-Item -Force $BuiltJar (Join-Path $ServerDir 'plugins\OpenSourceTools.jar') + +# 清理旧日志(保留世界) +Remove-Item -Recurse -Force (Join-Path $ServerDir 'logs') -ErrorAction SilentlyContinue + +Write-Output "启动测试服务器 (Paper 1.21.11, 端口 25565, 离线模式)..." +$paperPath = Join-Path $ServerDir 'paper.jar' +$argsLine = "-Xmx2048M -XX:+UseG1GC -jar `"$paperPath`" nogui" +Start-Process -FilePath 'java' -ArgumentList $argsLine -WorkingDirectory $ServerDir -WindowStyle Normal +Write-Output '服务器进程已在新窗口中启动' + +$logFile = Join-Path $ServerDir 'logs\latest.log' +$booted = $false +$deadline = (Get-Date).AddSeconds($BootTimeoutSec) +while ((Get-Date) -lt $deadline) { + Start-Sleep -Seconds 2 + if (Test-Path $logFile) { + $tail = Get-Content $logFile -Raw -Encoding UTF8 -ErrorAction SilentlyContinue + if ($tail -match 'Done \(') { $booted = $true; break } + if ($tail -match 'FAILED TO BIND TO PORT') { break } + } +} + +if (-not $booted) { + Write-Output 'FAIL: 服务器未能在超时时间内完成启动' + if (Test-Path $logFile) { Get-Content $logFile -Tail 30 -Encoding UTF8 } + exit 1 +} + +Write-Output '==================== 服务器已就绪, 等待玩家连接 ====================' +$ip = Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notlike '127.*' -and $_.IPAddress -notlike '169.254.*' } | Select-Object -First 1 -ExpandProperty IPAddress +Write-Output "本机连接: localhost:25565" +Write-Output "局域网连接: ${ip}:25565 (如无法连接请放行 Windows 防火墙 25565 端口)" +Write-Output '客户端版本要求: Minecraft 1.21.11' +Write-Output '管理员: 在服务器控制台窗口输入 op <你的游戏ID> 即可获得 OP 权限测试管理命令' +Write-Output '停止服务器: 在服务器控制台窗口输入 stop 并回车(推荐), 或直接关闭窗口' +exit 0