├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── en_bug_request.yml │ ├── en_feature_request.yml │ ├── zh_bug_request.yml │ └── zh_feature_request.yml └── workflows │ └── build.yml ├── .gitignore ├── LICENSE.md ├── README.md ├── api ├── action │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── trplugins │ │ └── menu │ │ └── api │ │ ├── action │ │ ├── ActionHandle.kt │ │ ├── base │ │ │ ├── ActionBase.kt │ │ │ ├── ActionContents.kt │ │ │ └── ActionEntry.kt │ │ └── impl │ │ │ ├── logic │ │ │ ├── Break.kt │ │ │ └── Delay.kt │ │ │ └── send │ │ │ ├── Actionbar.kt │ │ │ ├── Chat.kt │ │ │ ├── Command.kt │ │ │ ├── Console.kt │ │ │ ├── Tell.kt │ │ │ ├── Tellraw.kt │ │ │ └── Title.kt │ │ └── reaction │ │ ├── ConditionalReaction.kt │ │ ├── Reaction.kt │ │ ├── Reactions.kt │ │ └── SingleReaction.kt ├── build.gradle.kts └── receptacle │ ├── build.gradle.kts │ └── src │ └── main │ └── kotlin │ └── trplugins │ └── menu │ └── api │ └── receptacle │ ├── Receptacle.kt │ ├── ReceptacleAPI.kt │ ├── ReceptacleClickType.kt │ ├── ReceptacleCloseEvent.kt │ ├── ReceptacleInteractEvent.kt │ ├── ReceptacleLayout.kt │ ├── hook │ └── HookFloodgate.kt │ ├── provider │ └── PlatformProvider.kt │ └── vanilla │ └── window │ ├── ChestInventory.kt │ ├── NMS.kt │ ├── NMSImpl.kt │ ├── StaticInventory.kt │ ├── WindowLayout.kt │ ├── WindowListener.kt │ └── WindowReceptacle.kt ├── build.gradle.kts ├── common ├── build.gradle.kts └── src │ └── main │ └── kotlin │ └── trplugins │ └── menu │ └── util │ ├── ClassUtils.kt │ ├── Cooldown.kt │ ├── EvalResult.kt │ ├── JsonUtils.kt │ ├── Regexs.kt │ ├── Reloadable.kt │ ├── Time.kt │ ├── collections │ ├── CycleList.kt │ ├── IndivList.kt │ └── Variables.kt │ ├── concurrent │ └── TaskConcurrent.kt │ ├── conf │ └── Property.kt │ ├── file │ └── FileListener.kt │ └── net │ ├── PasteGG.kt │ └── Paster.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin ├── build.gradle.kts ├── libs │ ├── BossShopPro.jar │ ├── DeluxeMenus-1.13.3-Release.jar │ ├── HeadDatabaseAPI.jar │ └── api-itemsadder-3.2.5.jar └── src │ └── main │ ├── kotlin │ └── trplugins │ │ └── menu │ │ ├── TrMenu.kt │ │ ├── api │ │ ├── MenuType.kt │ │ ├── TrMenuAPI.kt │ │ ├── action │ │ │ └── impl │ │ │ │ ├── func │ │ │ │ ├── Catcher.kt │ │ │ │ ├── EditItem.kt │ │ │ │ ├── EnchantItem.kt │ │ │ │ ├── GiveItem.kt │ │ │ │ ├── RepairItem.kt │ │ │ │ └── TakeItem.kt │ │ │ │ ├── hook │ │ │ │ ├── AddMoney.kt │ │ │ │ ├── AddPoint.kt │ │ │ │ ├── SetMoney.kt │ │ │ │ ├── SetPoint.kt │ │ │ │ ├── TakeMoney.kt │ │ │ │ └── TakePoint.kt │ │ │ │ ├── menu │ │ │ │ ├── Close.kt │ │ │ │ ├── DelArguments.kt │ │ │ │ ├── Open.kt │ │ │ │ ├── Page.kt │ │ │ │ ├── Refresh.kt │ │ │ │ ├── ReloadInventory.kt │ │ │ │ ├── Reset.kt │ │ │ │ ├── Retype.kt │ │ │ │ ├── SetAgent.kt │ │ │ │ ├── SetArguments.kt │ │ │ │ ├── SetTitle.kt │ │ │ │ ├── SilenceClose.kt │ │ │ │ ├── SilenceOpen.kt │ │ │ │ └── Update.kt │ │ │ │ ├── metadaa │ │ │ │ ├── DelData.kt │ │ │ │ ├── DelGlobalData.kt │ │ │ │ ├── DelMeta.kt │ │ │ │ ├── SetData.kt │ │ │ │ ├── SetGlobalData.kt │ │ │ │ └── SetMeta.kt │ │ │ │ ├── script │ │ │ │ ├── JavaScript.kt │ │ │ │ └── Kether.kt │ │ │ │ └── send │ │ │ │ ├── Bossbar.kt │ │ │ │ ├── CommandOp.kt │ │ │ │ ├── Connect.kt │ │ │ │ └── Sound.kt │ │ ├── event │ │ │ ├── CustomDatabaseEvent.kt │ │ │ ├── CustomItemSourceEvent.kt │ │ │ ├── MenuCloseEvent.kt │ │ │ ├── MenuOpenEvent.kt │ │ │ └── MenuPageChangeEvent.kt │ │ └── menu │ │ │ ├── IIcon.kt │ │ │ ├── IItem.kt │ │ │ ├── IManager.kt │ │ │ ├── IPosition.kt │ │ │ ├── ISerializer.kt │ │ │ └── ITexture.kt │ │ ├── module │ │ ├── conf │ │ │ ├── Loader.kt │ │ │ ├── MenuSerializer.kt │ │ │ └── prop │ │ │ │ ├── RunningPerformance.kt │ │ │ │ ├── SerializeError.kt │ │ │ │ └── SerialzeResult.kt │ │ ├── display │ │ │ ├── Menu.kt │ │ │ ├── MenuSession.kt │ │ │ ├── MenuSettings.kt │ │ │ ├── icon │ │ │ │ ├── Icon.kt │ │ │ │ ├── IconProperty.kt │ │ │ │ └── Position.kt │ │ │ ├── item │ │ │ │ ├── Item.kt │ │ │ │ ├── Lore.kt │ │ │ │ └── Meta.kt │ │ │ ├── layout │ │ │ │ ├── Layout.kt │ │ │ │ └── MenuLayout.kt │ │ │ └── texture │ │ │ │ ├── Texture.kt │ │ │ │ ├── TextureMeta.kt │ │ │ │ └── TextureType.kt │ │ └── internal │ │ │ ├── command │ │ │ ├── AppearHelper.kt │ │ │ ├── CommandExpression.kt │ │ │ ├── CommandHandler.kt │ │ │ └── impl │ │ │ │ ├── CommandAction.kt │ │ │ │ ├── CommandConvert.kt │ │ │ │ ├── CommandDebug.kt │ │ │ │ ├── CommandItem.kt │ │ │ │ ├── CommandList.kt │ │ │ │ ├── CommandOpen.kt │ │ │ │ ├── CommandReload.kt │ │ │ │ ├── CommandSounds.kt │ │ │ │ ├── CommandTemplate.kt │ │ │ │ └── CommandTest.kt │ │ │ ├── data │ │ │ ├── DataMap.kt │ │ │ ├── Metadata.kt │ │ │ └── NetQuery.kt │ │ │ ├── database │ │ │ ├── Database.kt │ │ │ ├── DatabaseMongodb.kt │ │ │ ├── DatabaseSQL.kt │ │ │ ├── DatabaseSQLite.kt │ │ │ └── PlayerIndex.kt │ │ │ ├── hook │ │ │ ├── HookAbstract.kt │ │ │ ├── HookPlugin.kt │ │ │ ├── ext │ │ │ │ └── HookPlaceholderAPI.kt │ │ │ └── impl │ │ │ │ ├── HookFastScript.kt │ │ │ │ ├── HookFloodgate.kt │ │ │ │ ├── HookHeadDatabase.kt │ │ │ │ ├── HookItemsAdder.kt │ │ │ │ ├── HookOraxen.kt │ │ │ │ ├── HookPlayerPoints.kt │ │ │ │ ├── HookSkinsRestorer.kt │ │ │ │ ├── HookSkulls.kt │ │ │ │ ├── HookTriton.kt │ │ │ │ ├── HookVault.kt │ │ │ │ └── HookZaphkiel.kt │ │ │ ├── inputer │ │ │ ├── Inputer.kt │ │ │ └── inputs │ │ │ │ ├── InputAnvil.kt │ │ │ │ └── InputBook.kt │ │ │ ├── item │ │ │ ├── ItemRepository.kt │ │ │ └── ItemSource.kt │ │ │ ├── listener │ │ │ ├── ListenerBukkitInventory.kt │ │ │ ├── ListenerCommand.kt │ │ │ ├── ListenerItemInteract.kt │ │ │ ├── ListenerJoin.kt │ │ │ └── ListenerQuit.kt │ │ │ ├── migrate │ │ │ ├── config │ │ │ │ └── MigrateConfig.kt │ │ │ └── plugin │ │ │ │ ├── MigrateDeluxeMenus.kt │ │ │ │ └── MigratePlugin.kt │ │ │ ├── script │ │ │ ├── FunctionParser.kt │ │ │ ├── Script.kt │ │ │ ├── StaticParser.kt │ │ │ ├── impl │ │ │ │ ├── KetherData.kt │ │ │ │ ├── KetherItem.kt │ │ │ │ ├── KetherMathCheck.kt │ │ │ │ ├── KetherMenu.kt │ │ │ │ ├── KetherMeta.kt │ │ │ │ ├── KetherMoney.kt │ │ │ │ ├── KetherPoints.kt │ │ │ │ └── KetherVars.kt │ │ │ ├── js │ │ │ │ ├── Assist.kt │ │ │ │ ├── JavaScriptAgent.kt │ │ │ │ └── ScriptFunction.kt │ │ │ └── kether │ │ │ │ ├── BaseAction.kt │ │ │ │ └── EditType.kt │ │ │ └── service │ │ │ ├── Metrics.kt │ │ │ ├── Performance.kt │ │ │ ├── RegisterCommands.kt │ │ │ ├── Shortcuts.kt │ │ │ └── Updater.kt │ │ └── util │ │ ├── Bungees.kt │ │ ├── Hex.kt │ │ ├── Util.kt │ │ └── bukkit │ │ ├── Heads.kt │ │ ├── ItemHelper.kt │ │ └── ItemMatcher.kt │ └── resources │ ├── data │ ├── globalData.yml │ └── itemRepository.yml │ ├── lang │ ├── en_US.yml │ ├── ru_RU.yml │ ├── vi_VN.yml │ ├── zh_CN.yml │ ├── zh_HK.yml │ └── zh_TW.yml │ ├── menus │ ├── Demo-Buttons.yml │ ├── Example.yml │ ├── Profile.yml │ └── shop-example │ │ ├── Shop-Categories.yml │ │ ├── categories │ │ └── Shop-Ores.yml │ │ └── handler │ │ ├── Shop-Handler-Purchase.yml │ │ └── Shop-Handler-Sell.yml │ └── settings.yml └── settings.gradle.kts /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: 2 | - 'http://paypal.me/Arasple' 3 | - 'http://paypal.me/Score2' 4 | - 'https://afdian.net/@Arasple' 5 | - 'https://afdian.net/@Score2' -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Discord server 4 | url: https://discord.gg/Fs6fJN3jXj 5 | about: InsinuateProjects's Discord 6 | - name: TrMenu wiki 7 | url: https://trmenu.docs.insinuate.cn/ 8 | about: Official wiki of TrMenu(Only chinese now) -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/en_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: '🛸 Feature Request' 2 | description: 'Warning: If you don’t follow the prompts to give feedback, this issue may be ignored or closed.' 3 | title: "[Feature]: " 4 | labels: ['💠Enhancement | 增强'] 5 | body: 6 | - type: checkboxes 7 | id: wikis 8 | attributes: 9 | label: '📚 Have you checked the Wiki' 10 | description: 'Often many questions are caused by not checking the Wiki in detail, have you read [Wiki](https://trmenu.docs.insinuate.cn/)?' 11 | options: 12 | - label: 'I have checked the Wiki and determined that this feature does not exist.' 13 | required: true 14 | 15 | - type: checkboxes 16 | id: issues-reviewed 17 | attributes: 18 | label: '🔗 Is there a duplicate issue' 19 | description: 'Some features may have been mentioned by others, have you read it [Issues](https://github.com/InsinuateProjects/TrMenu/issues)?' 20 | options: 21 | - label: 'I have looked through the existing issue and found no duplicate content, or a more detailed description of the existing issue.' 22 | required: true 23 | 24 | - type: textarea 25 | id: description 26 | attributes: 27 | label: '🔍 Detailed description' 28 | description: 'Describe the function clearly, if there is a demo menu configuration file, please provide it in the next option.' 29 | value: | 30 | ``` 31 | 1. ... 32 | 2. ... 33 | 3. ... 34 | ``` 35 | validations: 36 | required: true 37 | 38 | - type: textarea 39 | id: configuration 40 | attributes: 41 | label: '⚙ Configurations' 42 | description: 'Please provide a menu to describe the function as much as possible, please paste it in the relevant configuration section between the lines below.' 43 | value: | 44 | ``` 45 | 46 | ``` 47 | validations: 48 | required: false 49 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/zh_bug_request.yml: -------------------------------------------------------------------------------- 1 | name: '🐞 错误报告' 2 | description: '注意: 未正确根据提示进行反馈错误可能会被忽略或关闭.' 3 | title: "[问题]: " 4 | labels: ['🐞Bug | 问题', '🔍Recurring | 调查中...'] 5 | body: 6 | - type: checkboxes 7 | id: latests 8 | attributes: 9 | label: '🚀 是否已尝试最新的版本' 10 | description: '你的问题, 也许已经被发现并被修复于[最新版](https://github.com/InsinuateProjects/TrMenu/actions)?' 11 | options: 12 | - label: '我已更新 TrMenu 至最新的版本, 并且同样复现该问题.' 13 | required: true 14 | 15 | - type: checkboxes 16 | id: wikis 17 | attributes: 18 | label: '📚 是否已查阅 Wiki' 19 | description: '往往很多问题都是因为没有详细查阅 Wiki, 你是否已阅读 [Wiki](https://trmenu.docs.insinuate.cn/)?' 20 | options: 21 | - label: '我已查阅 Wiki 对于该问题的相关内容, 并确定该问题是存在的.' 22 | required: true 23 | 24 | - type: checkboxes 25 | id: issues 26 | attributes: 27 | label: '🔗 是否存在重复 issue' 28 | description: '很多新错误往往是重复的,你翻阅过吗 [Issues](https://github.com/InsinuateProjects/TrMenu/issues)?' 29 | options: 30 | - label: '我已翻阅现有的 issue 没有发现内容重复, 亦或是对现有 issue 的更详细的描述.' 31 | required: true 32 | 33 | - type: textarea 34 | id: server-info 35 | attributes: 36 | label: '📰 服务端详细信息' 37 | description: '[必须提供] 输入命令 /trmenu debug dump 并将链接中的内容粘贴到下方.' 38 | value: | 39 | ``` 40 | TrMenu Dump Information (Date: xxxx-xx-xx xx:xx:xx) 41 | 42 | | Server OS: xxxx 43 | | Server software: xxxx 44 | | Java version: xxxx 45 | 46 | | TabooLib: x.x.x 47 | | TrMenu: x.x.x 48 | Installed Plugins: 49 | · XXXXXX - x.x.x 50 | · XXXXXX - x.x.x 51 | · XXXXXX - x.x.x 52 | ``` 53 | validations: 54 | required: true 55 | 56 | - type: textarea 57 | id: description 58 | attributes: 59 | label: '🔍 详细的描述' 60 | description: '对该问题清晰地描述, 包括复现的相关步骤.' 61 | value: | 62 | ``` 63 | 1. ... 64 | 2. ... 65 | 3. ... 66 | ``` 67 | validations: 68 | required: true 69 | 70 | - type: textarea 71 | id: server-logs 72 | attributes: 73 | label: '🗄 服务端日志' 74 | description: '如果有任何相关的服务端日志或异常, 请粘贴在下面的 ``` 行之间或上传完整日志文件.' 75 | value: | 76 | ``` 77 | 78 | ``` 79 | validations: 80 | required: false 81 | 82 | - type: textarea 83 | id: configuration 84 | attributes: 85 | label: '⚙ 配置文件' 86 | description: '请尽可能提供存在问题的菜单(部分), 请粘贴在下面的 ``` 行之间相关的配置部分.' 87 | value: | 88 | ``` 89 | 90 | ``` 91 | validations: 92 | required: false 93 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/zh_feature_request.yml: -------------------------------------------------------------------------------- 1 | name: '🛸 功能请求' 2 | description: '注意: 未正确根据提示发布功能请求可能会被忽略或关闭.' 3 | title: "[功能]: " 4 | labels: ['💠Enhancement | 增强'] 5 | body: 6 | - type: checkboxes 7 | id: wikis 8 | attributes: 9 | label: '📚 是否已查阅 Wiki' 10 | description: '往往很多需求都是因为没有详细查阅 Wiki, 你是否已阅读 [Wiki](https://trmenu.docs.insinuate.cn/)?' 11 | options: 12 | - label: '我已查阅 Wiki 并确定没有存在该功能.' 13 | required: true 14 | 15 | - type: checkboxes 16 | id: issues-reviewed 17 | attributes: 18 | label: '🔗 是否存在重复 issue' 19 | description: '有些功能可能已经被别人提到过,你翻阅过吗 [Issues](https://github.com/InsinuateProjects/TrMenu/issues)?' 20 | options: 21 | - label: '我已翻阅现有的 issue 没有发现内容重复, 亦或是对现有 issue 的更详细的描述.' 22 | required: true 23 | 24 | - type: textarea 25 | id: description 26 | attributes: 27 | label: '🔍 详细的描述' 28 | description: '对该功能清晰地描述, 如果有演示菜单配置文件, 请提供在下一个选项.' 29 | value: | 30 | ``` 31 | 1. ... 32 | 2. ... 33 | 3. ... 34 | ``` 35 | validations: 36 | required: true 37 | 38 | - type: textarea 39 | id: configuration 40 | attributes: 41 | label: '⚙ 配置文件' 42 | description: '请尽可能提供用于描述该功能的菜单, 请粘贴在下面的 ``` 行之间相关的配置部分.' 43 | value: | 44 | ``` 45 | 46 | ``` 47 | validations: 48 | required: false 49 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ stable/v3 ] 6 | pull_request: 7 | branches: [ stable/v3 ] 8 | 9 | jobs: 10 | releaseJar: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | - uses: actions/setup-java@v1 15 | with: 16 | java-version: 8 17 | 18 | - name: Cache .gradle/caches 19 | uses: actions/cache@v1 20 | with: 21 | path: ~/.gradle/caches 22 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*') }} 23 | restore-keys: ${{ runner.os }}-gradle- 24 | 25 | - name: Cache .gradle/wrapper 26 | uses: actions/cache@v1 27 | with: 28 | path: ~/.gradle/wrapper 29 | key: ${{ runner.os }}-gradle-wrapper-${{ hashFiles('**/*.gradle') }} 30 | restore-keys: ${{ runner.os }}-gradle-wrapper- 31 | 32 | - name: Grant execute permission for gradlew 33 | run: chmod +x gradlew 34 | 35 | # - name: Build with Gradle 36 | # run: ./gradlew clean build -s 37 | 38 | # 第一次构建 39 | - name: build 40 | id: build_1 41 | run: ./gradlew build 42 | # 第二次构建 43 | - name: build (retry 1) 44 | id: build_2 45 | if: steps.build_1.outcome == 'failure' 46 | run: ./gradlew build 47 | # 第三次构建 48 | - name: build (retry 2) 49 | id: build_3 50 | if: steps.build_2.outcome == 'failure' 51 | run: ./gradlew build 52 | # 第四次构建 53 | - name: build (retry 3) 54 | id: build_4 55 | if: steps.build_3.outcome == 'failure' 56 | run: ./gradlew build 57 | 58 | - name: Upload Artifacts 59 | uses: actions/upload-artifact@v2 60 | with: 61 | name: TrMenu Artifact 62 | path: build/libs/*.jar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # TRMENU LICENSE 2 | Copyright (c) 2021 TrMenu 3 | 4 | --- 5 | 6 | ### Definitions 7 | 8 | - "License" shall mean the terms and conditions for use, reproduction, and distribution 9 | 10 | - "Package" shall mean the files(unless something else is declared) distributed by the author 11 | 12 | - "You" (or "Your") shall mean an individual or Legal Entity 13 | exercising permissions granted by this License. 14 | 15 | --- 16 | 17 | ### Terms 18 | 19 | - #### Refund 20 | By purchasing this plugin, you support this project and its continuous development voluntarily. 21 | No refund. 22 | 23 | - #### Modifications 24 | You can modify original package for only personal non-commercial usage 25 | or have the author's permission. 26 | 27 | - #### Redistribution 28 | You can only use this plugin for your own servers, sharing is forbidden. 29 | You are not allowed to redistribute or resell complete, partial or modified versions of the package 30 | You are not allowed to repost this plugin on anywhere without permission 31 | 32 | - #### Warranty 33 | The package is without warranty of any kind, express or implied, 34 | including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. 35 | In no event shall the authors or copyright holders be liable for any claim, damages or other liability, 36 | whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the software. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ## (Deprecated) TrMenu 4 | 5 | ![](https://attachment.mcbbs.net/data/myattachment/forum/202108/17/142921rll20j5kie5kzk1f.gif) 6 | ![](https://img.shields.io/github/last-commit/TrPlugins/TrMenu?logo=artstation&style=for-the-badge&color=9266CC)![](https://img.shields.io/github/issues/InsinuateProjects/TrMenu?style=for-the-badge&logo=slashdot)![](https://img.shields.io/github/release/TrPlugins/TrMenu?style=for-the-badge&color=00C58E&logo=ionic) 7 | 8 | --- 9 | 10 | **This resource is no longer actively maintained.** -------------------------------------------------------------------------------- /api/action/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.UUID 2 | 3 | val taboolibVersion: String by rootProject 4 | 5 | plugins { 6 | id("io.izzel.taboolib") 7 | } 8 | 9 | taboolib { 10 | description { 11 | name(rootProject.name) 12 | } 13 | install( 14 | "common", 15 | "common-5", 16 | "expansion-javascript", 17 | "module-chat", 18 | "module-configuration", 19 | ) 20 | options( 21 | "skip-minimize", 22 | "keep-kotlin-module", 23 | "skip-taboolib-relocate", 24 | ) 25 | classifier = null 26 | version = taboolibVersion 27 | } 28 | 29 | repositories { 30 | mavenCentral() 31 | mavenLocal() 32 | maven("https://repo.tabooproject.org/repository/releases") 33 | maven("https://hub.spigotmc.org/nexus/content/groups/public/") 34 | } 35 | 36 | dependencies { 37 | api(project(":common")) 38 | 39 | compileOnly("net.md-5:bungeecord-chat:1.18-R0.1-SNAPSHOT") 40 | } 41 | 42 | tasks.tabooRelocateJar { onlyIf { false } } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/base/ActionContents.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.base 2 | 3 | import kotlin.reflect.KProperty 4 | 5 | /** 6 | * TrMenu 7 | * trplugins.menu.api.action.base.ActionContent 8 | * 9 | * @author Score2 10 | * @since 2022/02/13 20:05 11 | */ 12 | class ActionContents : HashMap { 13 | 14 | constructor(defContent: Any? = null) : super() { 15 | defContent ?: return 16 | stringContent(defContent) 17 | } 18 | 19 | constructor(key: String, any: Any) { 20 | this[key] = any 21 | } 22 | 23 | fun stringContent(value: Any? = null): String { 24 | if (value != null) { 25 | this[defContentKey] = value 26 | } 27 | return this[defContentKey]?.toString()!! 28 | } 29 | 30 | override fun toString(): String { 31 | return runCatching { stringContent() }.getOrNull() ?: super.toString() 32 | } 33 | 34 | companion object { 35 | const val defContentKey = "content" 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/base/ActionEntry.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.base 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.submit 5 | import trplugins.menu.api.action.ActionHandle 6 | 7 | /** 8 | * TrMenu 9 | * trplugins.menu.api.action.base.ActionEntry 10 | * 11 | * @author Score2 12 | * @since 2022/02/08 22:11 13 | */ 14 | data class ActionEntry( 15 | val base: ActionBase, 16 | val contents: ActionContents, 17 | var option: ActionBase.Option, 18 | ) { 19 | val handle get() = base.handle 20 | 21 | fun assign(player: ProxyPlayer) { 22 | base.handle.runAction(player, listOf(this)) 23 | } 24 | 25 | fun execute(player: ProxyPlayer) { 26 | val delay = option.evalDelay() 27 | if (!option.evalCondition(player)) return 28 | 29 | val proceed = { option.evalPlayers(player) { base.onExecute(contents, it, player) } } 30 | if (delay > 0) submit(delay = delay) { proceed.invoke() } 31 | else proceed.invoke() 32 | } 33 | 34 | 35 | companion object { 36 | 37 | fun of(handle: ActionHandle, any: List) = 38 | any.flatMap { of(handle, it) } 39 | 40 | fun of(handle: ActionHandle, any: Any): List { 41 | val entries = mutableListOf() 42 | 43 | when (any) { 44 | is Map<*, *> -> { 45 | val entry = any.entries.firstOrNull() ?: return entries 46 | val key = entry.key.toString() 47 | val value = entry.value ?: return entries 48 | val registered = handle.getRegisteredAction(key) 49 | 50 | val actionEntry = registered.ofEntry(value, registered.Option()) 51 | entries.add(actionEntry) 52 | } 53 | else -> { 54 | val loaded = any.toString().split(ActionHandle.actionsBound).map { 55 | val split = it.split(": ", limit = 2) 56 | val string = split.getOrElse(1) { split[0] } 57 | val registered = handle.getRegisteredAction(split[0]) 58 | 59 | val (content, option) = registered.ofOption(string) 60 | registered.ofEntry(content, option) 61 | } 62 | loaded.maxByOrNull { it.option.set.size }?.let { def -> 63 | loaded.forEach { it.option = def.option } 64 | } 65 | entries.addAll(loaded) 66 | } 67 | } 68 | 69 | return entries 70 | } 71 | } 72 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/logic/Break.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.logic 2 | 3 | import trplugins.menu.api.action.ActionHandle 4 | import trplugins.menu.api.action.base.ActionBase 5 | 6 | /** 7 | * TrMenu 8 | * trplugins.menu.api.action.impl.logic.Return 9 | * 10 | * @author Score2 11 | * @since 2022/02/10 22:09 12 | */ 13 | class Break(handle: ActionHandle) : ActionBase(handle) { 14 | override val regex = "return|break".toRegex() 15 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/logic/Delay.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.logic 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | 7 | /** 8 | * TrMenu 9 | * trplugins.menu.api.action.impl.logic.Delay 10 | * 11 | * @author Score2 12 | * @since 2022/02/10 22:09 13 | */ 14 | class Delay(handle: ActionHandle) : ActionBase(handle) { 15 | override val regex = "delay|wait".toRegex() 16 | fun getDelay(player: ProxyPlayer, content: String) = 17 | player.parse(content).toLongOrNull() ?: 0L 18 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/send/Actionbar.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | 8 | /** 9 | * TrMenu 10 | * trplugins.menu.api.action.impl.send.Actionbar 11 | * 12 | * @author Score2 13 | * @since 2022/02/08 21:33 14 | */ 15 | class Actionbar(handle: ActionHandle) : ActionBase(handle) { 16 | 17 | override val regex = "action(bar)?s?".toRegex() 18 | 19 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 20 | player.sendActionBar(contents.stringContent().parseContent(placeholderPlayer)) 21 | } 22 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/send/Chat.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | 8 | /** 9 | * TrMenu 10 | * trplugins.menu.api.action.impl.chat.Chat 11 | * 12 | * @author Score2 13 | * @since 2022/02/14 9:03 14 | */ 15 | class Chat(handle: ActionHandle) : ActionBase(handle) { 16 | 17 | override val regex = "chat|send|say".toRegex() 18 | 19 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 20 | contents.stringContent().parseContentSplited(placeholderPlayer, contents.stringContent()).forEach { 21 | player.chat(it) 22 | } 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/send/Command.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.isPrimaryThread 5 | import taboolib.common.platform.function.submit 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.chat.Command 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 9:03 16 | */ 17 | class Command(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "command|cmd|player|execute".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | { 23 | placeholderPlayer.parseContentSplited(contents.stringContent(), ";").forEach { 24 | player.performCommand(it) 25 | } 26 | }.also { 27 | if (isPrimaryThread) { 28 | it.invoke() 29 | } else { 30 | submit(async = false) { 31 | it.invoke() 32 | } 33 | } 34 | } 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/send/Console.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.console 5 | import taboolib.common.platform.function.isPrimaryThread 6 | import taboolib.common.platform.function.submit 7 | import trplugins.menu.api.action.ActionHandle 8 | import trplugins.menu.api.action.base.ActionBase 9 | import trplugins.menu.api.action.base.ActionContents 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.chat.CommandConsole 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 9:04 17 | */ 18 | class Console(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "console".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | { 24 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { 25 | console().performCommand(it) 26 | } 27 | }.also { 28 | if (isPrimaryThread) { 29 | it.invoke() 30 | } else { 31 | submit(async = false) { 32 | it.invoke() 33 | } 34 | } 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/send/Tell.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | 8 | /** 9 | * TrMenu 10 | * trplugins.menu.api.action.impl.chat.Tell 11 | * 12 | * @author Score2 13 | * @since 2022/02/14 9:05 14 | */ 15 | class Tell(handle: ActionHandle) : ActionBase(handle) { 16 | 17 | override val regex = "tell|message|msg|talk".toRegex() 18 | 19 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 20 | contents.stringContent().parseContentSplited(placeholderPlayer).forEach { 21 | player.sendMessage(it) 22 | } 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/send/Tellraw.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.module.chat.HexColor 5 | import taboolib.module.chat.TellrawJson 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.util.collections.Variables 10 | import trplugins.menu.util.jsonParser 11 | 12 | /** 13 | * TrMenu 14 | * trplugins.menu.api.action.impl.send.Tellraw 15 | * 16 | * @author Score2 17 | * @since 2022/02/14 11:07 18 | */ 19 | class Tellraw(handle: ActionHandle) : ActionBase(handle) { 20 | 21 | override val regex = "(tell(raw)?|json)s?".toRegex() 22 | 23 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 24 | player.sendRawMessage(contents.stringContent().parseContent(placeholderPlayer)) 25 | } 26 | 27 | private val matcher = "<(.+?)>".toRegex() 28 | 29 | override fun readContents(contents: Any): ActionContents { 30 | val raw = contents.toString() 31 | val json: String 32 | if (kotlin.runCatching { jsonParser.parse(raw) }.isSuccess) { 33 | json = raw 34 | } else { 35 | val tellraw = TellrawJson() 36 | 37 | Variables(raw, matcher) { it[1] }.element.forEach { result -> 38 | 39 | if (result.isVariable) { 40 | val splits = result.value.split("@") 41 | tellraw.append(HexColor.translate(splits[0])) 42 | 43 | splits.mapNotNull { 44 | val keyValue = it.split("=", ":", limit = 2) 45 | if (keyValue.size >= 2) 46 | keyValue[0] to keyValue[1] 47 | else null 48 | }.forEach { 49 | val (type, content) = it 50 | when (type.lowercase()) { 51 | "hover" -> tellraw.hoverText(content.replace("\\n", "\n")) 52 | "suggest" -> tellraw.suggestCommand(content) 53 | "command", "execute" -> tellraw.runCommand(content) 54 | "url", "open_url" -> tellraw.openURL(content) 55 | } 56 | } 57 | } else tellraw.append(HexColor.translate(result.value)) 58 | } 59 | json = tellraw.toRawMessage() 60 | } 61 | 62 | return ActionContents(json) 63 | } 64 | 65 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/action/impl/send/Title.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.util.replaceWithOrder 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.util.Regexs 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.send.Title 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 10:32 16 | */ 17 | class Title(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "(send)?-?(sub)?titles?".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | val title: String by contents 23 | val subTitle: String by contents 24 | val fadeIn: Int by contents 25 | val stay: Int by contents 26 | val fadeOut: Int by contents 27 | 28 | player.sendTitle( 29 | placeholderPlayer.parse(title), 30 | placeholderPlayer.parse(subTitle), 31 | fadeIn, 32 | stay, 33 | fadeOut 34 | ) 35 | } 36 | 37 | override fun readContents(contents: Any): ActionContents { 38 | val actionContents = ActionContents() 39 | var content: String = contents.toString() 40 | val replacements = Regexs.SENTENCE.findAll(content).mapIndexed { index, result -> 41 | content = content.replace(result.value, "{$index}") 42 | index to result.groupValues[1].replace("\\s", " ") 43 | }.toMap().values.toTypedArray() 44 | 45 | val split = content.split(" ", limit = 5) 46 | 47 | var title by actionContents 48 | title = split.getOrElse(0) { "" }.replaceWithOrder(*replacements) 49 | var subTitle by actionContents 50 | subTitle = split.getOrElse(1) { "" }.replaceWithOrder(*replacements) 51 | var fadeIn by actionContents 52 | fadeIn = split.getOrNull(2)?.toIntOrNull() ?: 15 53 | var stay by actionContents 54 | stay = split.getOrNull(3)?.toIntOrNull() ?: 20 55 | var fadeOut by actionContents 56 | fadeOut = split.getOrNull(4)?.toIntOrNull() ?: 15 57 | 58 | return actionContents 59 | } 60 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/reaction/ConditionalReaction.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.reaction 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionEntry 6 | 7 | /** 8 | * @author Rubenicos 9 | * @date 2021/11/23 14:59 10 | */ 11 | class ConditionalReaction(handle: ActionHandle, 12 | priority: Int, 13 | private val condition: String, 14 | private val accept: Reactions, 15 | private val deny: Reactions 16 | ) : Reaction(handle, priority) { 17 | 18 | private val hasCondition: Boolean = condition.isNotBlank() 19 | 20 | override fun isEmpty(): Boolean { 21 | return accept.isEmpty() && deny.isEmpty() 22 | } 23 | 24 | override fun getActions(player: ProxyPlayer): List { 25 | return if (evalCondition(player)) accept.getActions(player) 26 | else deny.getActions(player) 27 | } 28 | 29 | fun evalCondition(player: ProxyPlayer): Boolean { 30 | return if (hasCondition) handle.conditionParser.apply(player, condition).asBoolean() 31 | else true 32 | } 33 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/reaction/Reaction.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.reaction 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionEntry 6 | import trplugins.menu.util.conf.Property 7 | 8 | /** 9 | * @author Rubenicos 10 | * @date 2021/11/23 14:59 11 | */ 12 | abstract class Reaction(val handle: ActionHandle, val priority: Int) { 13 | 14 | abstract fun isEmpty(): Boolean 15 | 16 | abstract fun getActions(player: ProxyPlayer): List 17 | 18 | companion object { 19 | fun of(handle: ActionHandle, priority: Int, any: Any): Reaction? { 20 | if (any is String || ((any is Map<*, *>) && any.entries.firstOrNull()?.key.toString().equals("catcher", true))) { 21 | return SingleReaction(handle, priority, ActionEntry.of(handle, any)) 22 | } 23 | 24 | val reaction = Property.asSection(any) ?: return null 25 | val keyPriority = Property.PRIORITY.getKey(reaction) 26 | val keyRequirement = Property.CONDITION.getKey(reaction) 27 | val keyActions = Property.ACTIONS.ofList(reaction) 28 | val keyDenyActions = Property.DENY_ACTIONS.ofList(reaction) 29 | 30 | return ConditionalReaction( 31 | handle, 32 | reaction.getInt(keyPriority, priority), 33 | reaction.getString(keyRequirement, "")!!, 34 | Reactions.ofReaction(handle, keyActions), 35 | Reactions.ofReaction(handle, keyDenyActions) 36 | ) 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/reaction/Reactions.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.reaction 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionEntry 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2021/1/29 17:51 10 | */ 11 | data class Reactions(val handle: ActionHandle, private val reacts: List) { 12 | 13 | fun eval(player: ProxyPlayer): Boolean { 14 | if (isEmpty()) return true 15 | 16 | return handle.runAction(player, getActions(player)) 17 | } 18 | 19 | fun getActions(player: ProxyPlayer): List { 20 | return mutableListOf().run { 21 | reacts.sortedBy { it.priority }.forEach { addAll(it.getActions(player)) } 22 | this 23 | } 24 | } 25 | 26 | fun isEmpty(): Boolean { 27 | return reacts.isEmpty() || reacts.all { it.isEmpty() } 28 | } 29 | 30 | companion object { 31 | fun ofReaction(handle: ActionHandle, any: Any?): Reactions { 32 | val reacts = mutableListOf() 33 | any ?: return Reactions(handle, reacts) 34 | if (any is List<*>) { 35 | var order = 0 36 | any.filterNotNull().forEach { Reaction.of(handle, order++, it)?.let { react -> reacts.add(react) } } 37 | } else Reaction.of(handle, -1, any)?.let { reacts.add(it) } 38 | 39 | return Reactions(handle, reacts) 40 | } 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /api/action/src/main/kotlin/trplugins/menu/api/reaction/SingleReaction.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.reaction 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionEntry 6 | 7 | /** 8 | * @author Rubenicos 9 | * @date 2021/11/23 14:59 10 | */ 11 | class SingleReaction( 12 | handle: ActionHandle, 13 | priority: Int, 14 | private val actions: List 15 | ) : Reaction(handle, priority) { 16 | 17 | override fun isEmpty(): Boolean { 18 | return actions.isEmpty() 19 | } 20 | 21 | override fun getActions(player: ProxyPlayer): List { 22 | return actions 23 | } 24 | } -------------------------------------------------------------------------------- /api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | gradle.buildFinished { 2 | buildDir.deleteRecursively() 3 | } -------------------------------------------------------------------------------- /api/receptacle/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.UUID 2 | 3 | val taboolibVersion: String by rootProject 4 | 5 | plugins { 6 | id("io.izzel.taboolib") 7 | } 8 | 9 | taboolib { 10 | description { 11 | name(rootProject.name) 12 | } 13 | install( 14 | "common", 15 | "module-nms", 16 | "platform-bukkit", 17 | ) 18 | options( 19 | "skip-minimize", 20 | "keep-kotlin-module", 21 | "skip-taboolib-relocate", 22 | ) 23 | classifier = null 24 | version = taboolibVersion 25 | } 26 | 27 | repositories { 28 | mavenCentral() 29 | maven("https://repo.tabooproject.org/repository/releases") 30 | maven("https://repo.codemc.io/repository/nms/") 31 | maven("https://hub.spigotmc.org/nexus/content/groups/public/") 32 | maven("https://repo.opencollab.dev/maven-snapshots/") 33 | } 34 | 35 | dependencies { 36 | compileOnly(project(":common")) 37 | compileOnly("ink.ptms:nms-all:1.0.0") 38 | compileOnly("ink.ptms.core:v11900:11900-minimize:universal") 39 | compileOnly("ink.ptms.core:v11900:11900-minimize:mapped") 40 | compileOnly("org.geysermc.floodgate:api:2.2.0-SNAPSHOT") 41 | compileOnly(fileTree("libs")) 42 | } 43 | 44 | tasks.tabooRelocateJar { onlyIf { false } } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/Receptacle.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle 2 | 3 | import org.bukkit.entity.Player 4 | 5 | /** 6 | * TrMenu 7 | * trplugins.menu.api.receptacle.Receptacle 8 | * 9 | * @author Score2 10 | * @since 2022/03/10 19:28 11 | */ 12 | abstract class Receptacle(val layout: ReceptacleLayout) { 13 | 14 | abstract var title: String 15 | abstract var onOpen: ((player: Player, receptacle: Receptacle) -> Unit) 16 | abstract var onClose: ((player: Player, receptacle: Receptacle) -> Unit) 17 | abstract var onClick: ((player: Player, event: ReceptacleInteractEvent) -> Unit) 18 | 19 | abstract fun getElement(slot: Int): Element? 20 | abstract fun hasElement(slot: Int): Boolean 21 | abstract fun setElement(element: Element? = null, vararg slots: Int, display: Boolean = true) 22 | 23 | abstract fun clear(display: Boolean = true) 24 | abstract fun refresh(slot: Int = -1) 25 | abstract fun open(player: Player) 26 | abstract fun close(sendPacket: Boolean = true) 27 | abstract fun callEventClick(event: ReceptacleInteractEvent) 28 | 29 | 30 | fun setElement(element: Element?, slots: Collection, display: Boolean = true) { 31 | setElement(element, *slots.toIntArray(), display = display) 32 | } 33 | 34 | fun onOpen(handler: (player: Player, receptacle: Receptacle) -> Unit) { 35 | this.onOpen = handler 36 | } 37 | 38 | fun onClose(handler: (player: Player, receptacle: Receptacle) -> Unit) { 39 | this.onClose = handler 40 | } 41 | 42 | fun onClick(clickEvent: (player: Player, event: ReceptacleInteractEvent) -> Unit) { 43 | this.onClick = clickEvent 44 | } 45 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/ReceptacleAPI.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle 2 | 3 | import org.bukkit.entity.Player 4 | import org.bukkit.event.inventory.InventoryType 5 | import org.bukkit.event.inventory.InventoryType.* 6 | import trplugins.menu.api.receptacle.vanilla.window.ChestInventory 7 | import trplugins.menu.api.receptacle.vanilla.window.WindowLayout 8 | import trplugins.menu.api.receptacle.vanilla.window.WindowReceptacle 9 | import java.util.* 10 | 11 | private val viewingReceptacleMap = HashMap>() 12 | 13 | fun buildReceptacle(title: String, row: Int = 1, builder: ChestInventory.() -> Unit): ChestInventory { 14 | return ChestInventory(row, title).also(builder) 15 | } 16 | 17 | fun buildReceptacle(title: String, type: WindowLayout = WindowLayout.GENERIC_9X1, builder: WindowReceptacle.() -> Unit): WindowReceptacle { 18 | return WindowReceptacle(type, title).also(builder) 19 | } 20 | 21 | fun Player.openReceptacle(title: String, row: Int = 1, builder: ChestInventory.() -> Unit) { 22 | buildReceptacle(title, row, builder).open(this) 23 | } 24 | 25 | fun Player.openReceptacle(title: String, type: WindowLayout = WindowLayout.GENERIC_9X1, builder: WindowReceptacle.() -> Unit) { 26 | buildReceptacle(title, type, builder).open(this) 27 | } 28 | 29 | fun Player.getViewingReceptacle(): Receptacle<*>? { 30 | return viewingReceptacleMap[uniqueId] 31 | } 32 | 33 | fun Player.setViewingReceptacle(receptacle: Receptacle<*>?) { 34 | if (receptacle == null) { 35 | viewingReceptacleMap.remove(uniqueId) 36 | } else { 37 | viewingReceptacleMap[uniqueId] = receptacle 38 | } 39 | } 40 | 41 | fun InventoryType.createReceptacle(title: String = defaultTitle): WindowReceptacle { 42 | if (this != CHEST) { 43 | val receptacleType = when (this.name) { 44 | "ENDER_CHEST", "BARREL" -> WindowLayout.GENERIC_9X3 45 | "DISPENSER", "DROPPER" -> WindowLayout.GENERIC_3x3 46 | "ANVIL" -> WindowLayout.ANVIL 47 | "FURNACE" -> WindowLayout.FURNACE 48 | "WORKBENCH", "CRAFTING" -> WindowLayout.CRAFTING 49 | "ENCHANTING" -> WindowLayout.ENCHANTMENT 50 | "BREWING" -> WindowLayout.BREWING_STAND 51 | "MERCHANT" -> WindowLayout.MERCHANT 52 | "BEACON" -> WindowLayout.BEACON 53 | "HOPPER" -> WindowLayout.HOPPER 54 | "SHULKER_BOX" -> WindowLayout.SHULKER_BOX 55 | "BLAST_FURNACE" -> WindowLayout.BLAST_FURNACE 56 | "SMOKER" -> WindowLayout.SMOKER 57 | "LOOM" -> WindowLayout.LOOM 58 | "CARTOGRAPHY" -> WindowLayout.CARTOGRAPHY_TABLE 59 | "GRINDSTONE" -> WindowLayout.GRINDSTONE 60 | "STONECUTTER" -> WindowLayout.STONECUTTER 61 | else -> throw IllegalArgumentException("Unsupported $this") 62 | } 63 | return WindowReceptacle(receptacleType, title) 64 | } 65 | return ChestInventory() 66 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/ReceptacleCloseEvent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.event.ProxyEvent 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2020/12/5 21:42 9 | */ 10 | class ReceptacleCloseEvent(val player: Player, val receptacle: Receptacle) : ProxyEvent() { 11 | 12 | override val allowCancelled: Boolean 13 | get() = false 14 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/ReceptacleInteractEvent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.event.ProxyEvent 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2020/12/5 21:42 9 | */ 10 | class ReceptacleInteractEvent(val player: Player, val receptacle: Receptacle, val receptacleClickType: ReceptacleClickType, val slot: Int) : ProxyEvent() { 11 | 12 | var element: Element? 13 | set(value) = receptacle.setElement(value, slot) 14 | get() = receptacle.getElement(slot) 15 | 16 | fun refresh() { 17 | if (receptacleClickType.isItemMoveable()) { 18 | receptacle.layout.hotBarSlots.forEach { receptacle.refresh(it) } 19 | receptacle.layout.mainInvSlots.forEach { receptacle.refresh(it) } 20 | receptacle.layout.containerSlots.forEach { receptacle.refresh(it) } 21 | } else { 22 | receptacle.refresh(slot) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/ReceptacleLayout.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle 2 | 3 | /** 4 | * TrMenu 5 | * trplugins.menu.api.receptacle.ReceptacleLayout 6 | * 7 | * @author Score2 8 | * @since 2022/03/05 14:31 9 | */ 10 | open class ReceptacleLayout(val slotRange: IntRange) { 11 | 12 | val mainInvSlots by lazy { (slotRange.last + 1..slotRange.last + 27).toList() } 13 | 14 | val hotBarSlots by lazy { (mainInvSlots.last() + 1..mainInvSlots.last() + 9).toList() } 15 | 16 | val containerSlots by lazy { slotRange.toList() } 17 | 18 | val containerSize by lazy { containerSlots.size + 1 } 19 | 20 | val totalSlots by lazy { (0..hotBarSlots.last()).toList() } 21 | 22 | val totalSize by lazy { totalSlots.size } 23 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/hook/HookFloodgate.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle.hook 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.entity.Player 5 | 6 | /** 7 | * TrMenu 8 | * trplugins.menu.api.receptacle.hook.HookFloodgate 9 | * 10 | * @author Score2 11 | * @since 2022/02/19 22:58 12 | */ 13 | class HookFloodgate private constructor() { 14 | 15 | fun isBedrockPlayer(player: Player): Boolean { 16 | // return FloodgateApi.getInstance().isFloodgatePlayer(player.uniqueId) 17 | return false 18 | } 19 | 20 | companion object { 21 | 22 | private var hook: HookFloodgate? = null 23 | 24 | fun isBedrockPlayer(player: Player): Boolean { 25 | if (hook == null) { 26 | Bukkit.getPluginManager().getPlugin("floodgate-bukkit") ?: return false 27 | hook = HookFloodgate() 28 | } 29 | return hook?.isBedrockPlayer(player) ?: false 30 | } 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/provider/PlatformProvider.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle.provider 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.entity.Player 5 | import org.geysermc.floodgate.api.FloodgateApi 6 | 7 | /** 8 | * @author Rubenicos 9 | * @since 2022/05/30 20:36 10 | */ 11 | abstract class PlatformProvider { 12 | 13 | open fun isBedrockPlayer(player: Player): Boolean { 14 | return false 15 | } 16 | 17 | companion object { 18 | 19 | var provider: PlatformProvider? = null 20 | 21 | init { 22 | compute() 23 | } 24 | 25 | fun compute() { 26 | if (provider != null) { 27 | return 28 | } 29 | provider = if (Bukkit.getPluginManager().getPlugin("floodgate-bukkit") != null || Bukkit.getPluginManager().getPlugin("floodgate") != null) { 30 | // Use floodgate api by default 31 | object : PlatformProvider() { 32 | override fun isBedrockPlayer(player: Player): Boolean { 33 | return FloodgateApi.getInstance().isFloodgatePlayer(player.uniqueId) 34 | } 35 | } 36 | } else { 37 | // Use uuid comparator instead 38 | object : PlatformProvider() { 39 | override fun isBedrockPlayer(player: Player): Boolean { 40 | return player.uniqueId.toString().startsWith("00000000-0000-0000") 41 | } 42 | } 43 | } 44 | } 45 | 46 | fun isBedrockPlayer(player: Player): Boolean { 47 | return provider != null && provider?.isBedrockPlayer(player) ?: false 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/vanilla/window/ChestInventory.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle.vanilla.window 2 | 3 | import kotlin.properties.Delegates 4 | 5 | /** 6 | * @author Arasple 7 | * @date 2020/11/29 10:59 8 | */ 9 | class ChestInventory(rows: Int = 3, title: String = "Chest") : WindowReceptacle(WindowLayout.ofRows(rows), title) { 10 | 11 | var rows: Int by Delegates.observable(rows) { _, _, value -> 12 | type = WindowLayout.ofRows(value) 13 | } 14 | } -------------------------------------------------------------------------------- /api/receptacle/src/main/kotlin/trplugins/menu/api/receptacle/vanilla/window/StaticInventory.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.receptacle.vanilla.window 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.entity.Player 5 | import org.bukkit.event.inventory.InventoryType 6 | import org.bukkit.inventory.Inventory 7 | import org.bukkit.inventory.InventoryHolder 8 | import taboolib.library.reflex.Reflex.Companion.getProperty 9 | 10 | object StaticInventory { 11 | 12 | private val inventories = HashMap() 13 | 14 | val Player.staticContainerId get() = inventories[this.name]?.containerId 15 | val Player.staticInventory get() = inventories[this.name]?.inventory 16 | 17 | fun open(player: Player, layout: WindowLayout, title: String) { 18 | val holder = Holder(layout, title) 19 | holder.open(player) 20 | inventories[player.name] = holder 21 | } 22 | 23 | fun close(player: Player) { 24 | player.closeInventory() 25 | inventories.remove(player.name)?.clear() 26 | } 27 | 28 | class Holder(layout: WindowLayout, title: String) : InventoryHolder { 29 | 30 | private val inventory: Inventory 31 | var containerId: Int? = null 32 | private set 33 | 34 | init { 35 | inventory = when (val type = layout.toBukkitType()) { 36 | InventoryType.CHEST -> Bukkit.createInventory(this, layout.slotRange.last + 1, title) 37 | else -> Bukkit.createInventory(this, type, title) 38 | } 39 | } 40 | 41 | override fun getInventory(): Inventory { 42 | return inventory 43 | } 44 | 45 | fun open(player: Player) { 46 | player.openInventory(inventory) 47 | containerId = player.getProperty("entity/containerCounter")!! 48 | } 49 | 50 | fun clear() { 51 | inventory.clear() 52 | containerId = null 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | val taboolibVersion: String by project 2 | 3 | plugins { 4 | id("org.gradle.java") 5 | id("org.gradle.maven-publish") 6 | kotlin("jvm") version "1.8.0" apply false 7 | id("io.izzel.taboolib") version "1.55" apply false 8 | } 9 | 10 | description = "Modern & Advanced Menu-Plugin for Minecraft Servers" 11 | 12 | repositories { 13 | mavenCentral() 14 | maven("https://repo.tabooproject.org/repository/releases") 15 | maven("https://jitpack.io") 16 | } 17 | 18 | tasks.jar { 19 | onlyIf { false } 20 | } 21 | 22 | tasks.build { 23 | doLast { 24 | val plugin = project(":plugin") 25 | val file = file("${plugin.buildDir}/libs").listFiles()?.find { it.endsWith("plugin-$version.jar") } 26 | 27 | file?.copyTo(file("$buildDir/libs/${project.name}-$version.jar"), true) 28 | } 29 | dependsOn(project(":plugin").tasks.build) 30 | } 31 | 32 | subprojects { 33 | apply() 34 | apply(plugin = "org.jetbrains.kotlin.jvm") 35 | apply(plugin = "maven-publish") 36 | 37 | repositories { 38 | mavenCentral() 39 | } 40 | 41 | dependencies { 42 | "compileOnly"(kotlin("stdlib")) 43 | } 44 | tasks.withType { 45 | options.encoding = "UTF-8" 46 | } 47 | configure { 48 | sourceCompatibility = JavaVersion.VERSION_1_8 49 | targetCompatibility = JavaVersion.VERSION_1_8 50 | } 51 | 52 | val archiveName = if (project == rootProject) 53 | rootProject.name.toLowerCase() 54 | else 55 | "${rootProject.name.toLowerCase()}-${project.name.toLowerCase()}" 56 | 57 | val sourceSets = extensions.getByName("sourceSets") as SourceSetContainer 58 | 59 | task("sourcesJar") { 60 | from(sourceSets.named("main").get().allSource) 61 | archiveClassifier.set("sources") 62 | } 63 | 64 | tasks.jar { 65 | exclude("taboolib") 66 | } 67 | 68 | publishing { 69 | repositories { 70 | maven { 71 | url = uri("https://repo.mcage.cn/repository/trplugins/") 72 | credentials { 73 | username = project.findProperty("user").toString() 74 | password = project.findProperty("password").toString() 75 | } 76 | authentication { 77 | create("basic") 78 | } 79 | } 80 | } 81 | publications { 82 | create("library") { 83 | from(components["java"]) 84 | artifactId = archiveName 85 | 86 | artifact(tasks["sourcesJar"]) 87 | 88 | pom { 89 | allprojects.forEach { 90 | repositories.addAll(it.repositories) 91 | } 92 | } 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.UUID 2 | 3 | val taboolibVersion: String by rootProject 4 | 5 | plugins { 6 | id("io.izzel.taboolib") 7 | } 8 | 9 | taboolib { 10 | description { 11 | name(rootProject.name) 12 | } 13 | install( 14 | "common", 15 | "common-5", 16 | "expansion-javascript", 17 | "module-chat", 18 | "module-lang", 19 | "module-configuration", 20 | ) 21 | options( 22 | "skip-minimize", 23 | "keep-kotlin-module", 24 | "skip-taboolib-relocate", 25 | ) 26 | classifier = null 27 | version = taboolibVersion 28 | } 29 | 30 | repositories { 31 | mavenCentral() 32 | maven("https://repo.tabooproject.org/repository/releases") 33 | } 34 | 35 | dependencies { 36 | compileOnly("com.google.code.gson:gson:2.8.7") 37 | compileOnly("com.electronwill.night-config:core:3.6.5") 38 | } 39 | tasks.tabooRelocateJar { onlyIf { false } } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/ClassUtils.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util 2 | 3 | object ClassUtils { 4 | @JvmStatic 5 | val staticClass: Class<*> by lazy { 6 | if (System.getProperty("java.version").contains("1.8.")) 7 | Class.forName("jdk.internal.dynalink.beans.StaticClass") 8 | else 9 | Class.forName("jdk.dynalink.beans.StaticClass") 10 | } 11 | 12 | @JvmStatic 13 | fun staticClass(className: String): Any? { 14 | return try { 15 | staticClass.getMethod("forClass", Class::class.java).invoke(null, Class.forName(className)) 16 | } catch (e: Exception) { 17 | null 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/Cooldown.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util 2 | 3 | class Cooldown { 4 | var plugin: String 5 | val packName: String 6 | val packSeconds: Long 7 | private val data = HashMap() 8 | 9 | constructor(n: String, s: Int) { 10 | packName = n 11 | packSeconds = s.toLong() 12 | plugin = "null" 13 | } 14 | 15 | constructor(n: String, s: Long) { 16 | packName = n 17 | packSeconds = s 18 | plugin = "null" 19 | } 20 | 21 | fun unRegister(player: String) { 22 | data.remove(player) 23 | } 24 | 25 | fun getCooldown(player: String): Long { 26 | return this.getCooldown(player, 0L) 27 | } 28 | 29 | fun getCooldown(player: String, cutSeconds: Long): Long { 30 | return if (!data.containsKey(player)) { 31 | 0L 32 | } else { 33 | val difference = System.currentTimeMillis() + cutSeconds - data[player]!! 34 | if (difference >= packSeconds) 0L else packSeconds - difference 35 | } 36 | } 37 | 38 | fun isCooldown(player: String): Boolean { 39 | return this.isCooldown(player, 0L) 40 | } 41 | 42 | fun isCooldown(player: String, cutSeconds: Long): Boolean { 43 | return if (!data.containsKey(player)) { 44 | data[player] = System.currentTimeMillis() 45 | false 46 | } else if (this.getCooldown(player, cutSeconds) <= 0L) { 47 | data[player] = System.currentTimeMillis() 48 | false 49 | } else { 50 | true 51 | } 52 | } 53 | 54 | fun reset(player: String) { 55 | data.remove(player) 56 | } 57 | 58 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/EvalResult.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/31 11:53 6 | */ 7 | @JvmInline 8 | value class EvalResult(val any: Any? = null) { 9 | 10 | fun asBoolean(def: Boolean = false): Boolean { 11 | return when (any) { 12 | is Boolean -> any 13 | is String -> Regexs.parseBoolean(any) 14 | else -> def || Regexs.parseBoolean(any.toString()) 15 | } 16 | } 17 | 18 | fun asString(): String { 19 | return any.toString() 20 | } 21 | 22 | companion object { 23 | 24 | val TRUE = EvalResult(true) 25 | 26 | val FALSE = EvalResult(false) 27 | 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/JsonUtils.kt: -------------------------------------------------------------------------------- 1 | @file:SuppressWarnings("unchecked") 2 | @file:Suppress("DEPRECATION") 3 | 4 | package trplugins.menu.util 5 | 6 | import com.google.gson.JsonElement 7 | import com.google.gson.JsonParser 8 | 9 | /** 10 | * TrMenu 11 | * trplugins.menu.util.GsonUtils 12 | * 13 | * @author Score2 14 | * @since 2022/02/06 22:33 15 | */ 16 | val jsonParser = JsonParser() 17 | 18 | fun String.parseJson(): JsonElement = jsonParser.parse(this) -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/Regexs.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/24 16:57 6 | */ 7 | object Regexs { 8 | 9 | private val PLACEHOLDER_API = "(%)(.+?)(%)|(?!\\{\")((\\{)(.+?)(}))".toRegex() 10 | val JSON_TEXTURE = "\\{\\s*\"".toRegex() 11 | val ICON_KEY = "`(.+?)`".toRegex() 12 | val SENTENCE = "`(.+?)`".toRegex() 13 | val STRING = "\\{(\\w+)}".toRegex() 14 | 15 | private val TRUE = "true|yes|on".toRegex() 16 | val FALSE = "false|no|off".toRegex() 17 | val BOOLEAN = "true|yes|on|false|no|off".toRegex() 18 | 19 | fun containsPlaceholder(string: String): Boolean { 20 | return PLACEHOLDER_API.find(string) != null 21 | } 22 | 23 | fun parseBoolean(string: String): Boolean { 24 | return string.lowercase().matches(TRUE) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/Reloadable.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util 2 | 3 | /** 4 | * @project TrMenu 5 | * 6 | * @author Score2 7 | * @since 2021/09/30 12:11 8 | */ 9 | internal object UNINITIALIZED_VALUE 10 | 11 | class Reloadable(val initializer: () -> T) : Lazy { 12 | 13 | private var _value: Any? = UNINITIALIZED_VALUE 14 | 15 | fun reload(): T { 16 | val result = initializer() 17 | _value = result 18 | return result 19 | } 20 | 21 | override fun isInitialized() = 22 | _value != UNINITIALIZED_VALUE 23 | 24 | override val value: T 25 | get() { 26 | if (_value != UNINITIALIZED_VALUE) { 27 | @Suppress("UNCHECKED_CAST") 28 | return _value as T 29 | } 30 | return reload() 31 | } 32 | 33 | val get get() = value 34 | 35 | @Suppress("UNCHECKED_CAST") 36 | val getOrNull get() = _value as? T 37 | 38 | } 39 | 40 | fun reloadable(initializer: () -> T) = Reloadable(initializer) -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/Time.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util 2 | 3 | import java.text.SimpleDateFormat 4 | import java.time.Duration 5 | import java.util.* 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2021/2/4 10:58 10 | */ 11 | object Time { 12 | 13 | private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") 14 | 15 | val formatDate: () -> String = { dateFormat.format(System.currentTimeMillis()) } 16 | 17 | /** 18 | * @author Bkm016 19 | */ 20 | fun parseDuration(string: String): Duration { 21 | var dur = string.uppercase(Locale.ENGLISH) 22 | if (!dur.contains("T")) { 23 | if (dur.contains("D")) { 24 | if (dur.contains("H") || dur.contains("M") || dur.contains("S")) dur = dur.replace("D", "DT") 25 | } else if (dur.startsWith("P")) dur = "PT" + dur.substring(1) 26 | else dur = "T$dur" 27 | } 28 | if (!dur.startsWith("P")) dur = "P$dur" 29 | 30 | return Duration.parse(dur) 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/collections/CycleList.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util.collections 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/23 23:15 6 | */ 7 | class CycleList(val elements: List) { 8 | 9 | constructor(vararg element: T) : this(element.toList()) 10 | 11 | private val indexs = mutableMapOf() 12 | 13 | operator fun get(index: Int): T { 14 | return elements[index] 15 | } 16 | 17 | fun isEmpty() = elements.isEmpty() 18 | 19 | fun next(id: Int): T? { 20 | return if (isEmpty()) null else this[cycleIndex(id)] 21 | } 22 | 23 | fun isFinal(id: Int): Boolean { 24 | return currentIndex(id) == elements.size - 1 25 | } 26 | 27 | fun current(id: Int): T? { 28 | return if (isEmpty()) null else this[currentIndex(id)] 29 | } 30 | 31 | private fun currentIndex(id: Int): Int { 32 | return if (isEmpty()) -1 else indexs.computeIfAbsent(id) { Index(elements.size - 1) }.current() 33 | } 34 | 35 | fun cycleIndex(id: Int): Int { 36 | return if (isEmpty()) -1 else indexs.computeIfAbsent(id) { Index(elements.size - 1) }.next() 37 | } 38 | 39 | fun cyclable(): Boolean { 40 | return elements.size > 1 41 | } 42 | 43 | fun reset(id: Int) { 44 | indexs.remove(id) 45 | } 46 | 47 | override fun toString(): String { 48 | return elements.joinToString(", ", "[", "]") 49 | } 50 | 51 | private class Index(private val limit: Int) { 52 | 53 | private var index: Int = -1 54 | 55 | fun current(): Int { 56 | return index.coerceAtLeast(0) 57 | } 58 | 59 | fun next(): Int { 60 | if (index < limit) index++ 61 | else index = 0 62 | 63 | return index 64 | } 65 | 66 | } 67 | 68 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/collections/IndivList.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util.collections 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/23 23:15 6 | */ 7 | class IndivList(val elements: List) { 8 | 9 | init { 10 | elements.sortedBy { it.hashCode() } 11 | } 12 | 13 | private val indexs = mutableMapOf() 14 | 15 | fun isEmpty() = elements.isEmpty() 16 | 17 | operator fun set(id: Int, value: Int) { 18 | indexs[id] = value 19 | } 20 | 21 | operator fun get(id: Int): T? { 22 | // 缓解燃眉之急 23 | return try { 24 | if (isEmpty()) null else elements[getIndex(id)] 25 | } catch (e: ArrayIndexOutOfBoundsException) { 26 | null 27 | } 28 | } 29 | 30 | fun getIndex(id: Int): Int { 31 | return if (isEmpty()) -1 else indexs.computeIfAbsent(id) { -1 } 32 | } 33 | 34 | 35 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/collections/Variables.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util.collections 2 | 3 | /** 4 | * @author Bkm016 5 | * @date 2021/1/31 17:21 6 | */ 7 | class Variables(source: String, regex: Regex, group: (List) -> String = { it[1] }) { 8 | 9 | val element: List = source.toElements(regex, group) 10 | 11 | companion object { 12 | 13 | private fun String.toElements(regex: Regex, group: (List) -> String): List { 14 | val list = mutableListOf() 15 | var index = 0 16 | regex.findAll(this).forEach { 17 | list.add(Element(substring(index, it.range.first))) 18 | list.add(Element(group.invoke(it.groupValues), true)) 19 | index = it.range.last + 1 20 | } 21 | val last = Element(substring(index, length)) 22 | if (last.value.isNotEmpty()) { 23 | list.add(last) 24 | } 25 | return list 26 | } 27 | 28 | } 29 | 30 | class Element(var value: String, var isVariable: Boolean = false) 31 | 32 | 33 | } 34 | -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/concurrent/TaskConcurrent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util.concurrent 2 | 3 | import java.util.concurrent.CompletableFuture 4 | import java.util.concurrent.Executors 5 | import java.util.concurrent.Future 6 | 7 | /** 8 | * @author Score2 9 | * @since 2021/09/28 15:32 10 | */ 11 | class TaskConcurrent(val tasks: List, threads: Int) { 12 | 13 | private val poolExecutor = 14 | Executors.newFixedThreadPool( 15 | if (threads < 1) 1 16 | else if (threads > Runtime.getRuntime().availableProcessors()) 17 | Runtime.getRuntime().availableProcessors() 18 | else threads 19 | )!! 20 | 21 | fun start( 22 | process: (Task) -> Result, 23 | succeed: (List>) -> Unit = {}, 24 | catching: ((Throwable) -> List>)? = null 25 | ): CompletableFuture>> { 26 | val future: CompletableFuture>> = CompletableFuture.supplyAsync { 27 | val tasksFuture = mutableListOf>>() 28 | val tasksResult = mutableListOf>() 29 | tasks.forEach { 30 | tasksFuture.add(poolExecutor.submit> { Pair(it, process.invoke(it)) }) 31 | } 32 | tasksFuture.forEach { 33 | try { 34 | tasksResult.add(it.get()) 35 | } catch (t: Throwable) { 36 | t.printStackTrace() 37 | } 38 | } 39 | tasksResult 40 | } 41 | future.thenAccept(succeed) 42 | catching?.let { future.exceptionally(catching) } 43 | return future 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/file/FileListener.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util.file 2 | 3 | import taboolib.common5.FileWatcher 4 | import java.io.File 5 | 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2020/7/28 11:43 10 | */ 11 | object FileListener { 12 | 13 | private val listening = mutableSetOf() 14 | 15 | fun isListening(file: File): Boolean { 16 | return watcher.hasListener(file) 17 | } 18 | 19 | fun listener(file: File, runnable: () -> Unit) { 20 | watcher.addSimpleListener(file, runnable) 21 | listening.add(file) 22 | } 23 | 24 | fun clear() { 25 | var count = 0 26 | listening.removeIf { 27 | val remove = !it.exists() 28 | if (remove) { 29 | watcher.removeListener(it) 30 | count++ 31 | } 32 | remove 33 | } 34 | if (count > 0) { 35 | println("DEBUG: CLEARED $count unused listeners") 36 | } 37 | } 38 | 39 | // @TFunction.Cancel 40 | fun uninstall() { 41 | watcher.unregisterAll() 42 | } 43 | 44 | val watcher = FileWatcher() 45 | 46 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/net/PasteGG.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util.net 2 | 3 | import taboolib.common.Isolated 4 | import taboolib.common.env.DependencyDownloader 5 | import taboolib.common.env.IO 6 | import trplugins.menu.util.parseJson 7 | import java.net.HttpURLConnection 8 | import java.net.URL 9 | import java.nio.charset.StandardCharsets 10 | import java.text.SimpleDateFormat 11 | import java.util.* 12 | 13 | /** 14 | * @author Arasple 15 | * @date 2021/4/3 9:36 16 | */ 17 | @Isolated 18 | object PasteGG { 19 | 20 | private const val URL = "https://api.paste.gg/v1/pastes" 21 | 22 | @JvmStatic 23 | fun main(args: Array) { 24 | paste("Test", "Description", "Test Content", false, 1000 * 60, { 25 | println("Success: $it") 26 | }, { 27 | println("Failed") 28 | }) 29 | } 30 | 31 | private fun getExpiresDate(lastMills: Long): String { 32 | val tz = TimeZone.getTimeZone("UTC"); 33 | val df = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); 34 | df.timeZone = tz; 35 | return df.format(Date(System.currentTimeMillis() + lastMills)); 36 | } 37 | 38 | private fun paste( 39 | name: String, 40 | description: String, 41 | content: String, 42 | public: Boolean, 43 | expires: Long, 44 | success: (String) -> Unit, 45 | failed: () -> Unit 46 | ) { 47 | try { 48 | val con = URL(URL).openConnection() as HttpURLConnection 49 | val json = 50 | """ 51 | { 52 | "name": "$name", 53 | "description": "$description", 54 | "visibility": "${if (public) "public" else "unlisted"}", 55 | "expires": "${getExpiresDate(expires)}", 56 | "files": [ 57 | { 58 | "name": "$name", 59 | "content": { 60 | "format": "text", 61 | "highlight_language": null, 62 | "value": "$content" 63 | } 64 | } 65 | ] 66 | } 67 | """.trimIndent() 68 | 69 | con.requestMethod = "POST" 70 | con.setRequestProperty("Charset", "UTF-8") 71 | con.doInput = true 72 | con.doOutput = true 73 | con.outputStream.also { it.write(json.toByteArray(StandardCharsets.UTF_8)) } 74 | val source = IO.readFully(con.inputStream, StandardCharsets.UTF_8).parseJson().asJsonObject 75 | 76 | success.invoke(source.toString()) 77 | } catch (e: Throwable) { 78 | e.printStackTrace() 79 | failed.invoke() 80 | } 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /common/src/main/kotlin/trplugins/menu/util/net/Paster.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util.net 2 | 3 | import taboolib.common.env.DependencyDownloader 4 | import taboolib.common.env.IO 5 | import taboolib.common.platform.ProxyCommandSender 6 | import taboolib.common.platform.function.submit 7 | import taboolib.module.lang.sendLang 8 | import trplugins.menu.util.parseJson 9 | import java.net.HttpURLConnection 10 | import java.net.URL 11 | import java.nio.charset.StandardCharsets 12 | 13 | /** 14 | * @author Arasple 15 | * @date 2020/12/19 23:11 16 | */ 17 | object Paster { 18 | 19 | private const val URL = "https://paste.helpch.at/" 20 | 21 | fun paste(sender: ProxyCommandSender, content: String, extension: String = "") { 22 | sender.sendLang("Paster-Processing") 23 | paste( 24 | content, 25 | { sender.sendLang("Paster-Success", "$it.$extension") }, 26 | { sender.sendLang("Paster-Failed") } 27 | ) 28 | } 29 | 30 | private fun paste(content: String, url: (String) -> Unit, failed: () -> Unit) { 31 | submit(async = true) { 32 | try { 33 | val con = URL("${URL}documents").openConnection() as HttpURLConnection 34 | con.requestMethod = "POST" 35 | con.setRequestProperty("Charset", "UTF-8") 36 | con.doInput = true 37 | con.doOutput = true 38 | con.outputStream.also { it.write(content.toByteArray(StandardCharsets.UTF_8)) } 39 | val source = IO.readFully(con.inputStream, StandardCharsets.UTF_8).parseJson().asJsonObject 40 | url(URL + source.get("key").asString) 41 | } catch (e: Throwable) { 42 | e.printStackTrace() 43 | failed.invoke() 44 | } 45 | } 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=me.arasple.mc.trmenu 2 | version=3.1.20 3 | taboolibVersion=6.0.11-10 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsinuateProjects/TrMenu/b45749c36a5e431aa0b2256b50bd58d2c5713459/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /plugin/libs/BossShopPro.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsinuateProjects/TrMenu/b45749c36a5e431aa0b2256b50bd58d2c5713459/plugin/libs/BossShopPro.jar -------------------------------------------------------------------------------- /plugin/libs/DeluxeMenus-1.13.3-Release.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsinuateProjects/TrMenu/b45749c36a5e431aa0b2256b50bd58d2c5713459/plugin/libs/DeluxeMenus-1.13.3-Release.jar -------------------------------------------------------------------------------- /plugin/libs/HeadDatabaseAPI.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsinuateProjects/TrMenu/b45749c36a5e431aa0b2256b50bd58d2c5713459/plugin/libs/HeadDatabaseAPI.jar -------------------------------------------------------------------------------- /plugin/libs/api-itemsadder-3.2.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsinuateProjects/TrMenu/b45749c36a5e431aa0b2256b50bd58d2c5713459/plugin/libs/api-itemsadder-3.2.5.jar -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/MenuType.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api 2 | 3 | import net.md_5.bungee.api.ChatColor.COLOR_CHAR 4 | import taboolib.module.configuration.Type 5 | 6 | /** 7 | * TrMenu 8 | * me.arasple.mc.trmenu.module.display.MenuType 9 | * 10 | * @author Score2 11 | * @since 2021/12/04 11:08 12 | */ 13 | val Type.suffixes get() = when (this) { 14 | Type.YAML -> arrayOf("yml", "yaml") 15 | Type.TOML -> arrayOf("tml", "toml") 16 | Type.JSON -> arrayOf("json") 17 | Type.HOCON -> arrayOf("conf") 18 | else -> arrayOf() 19 | } 20 | 21 | val Type.color get() = when (this) { 22 | Type.YAML -> COLOR_CHAR + "b" 23 | Type.TOML -> COLOR_CHAR + "2" 24 | Type.JSON -> COLOR_CHAR + "6" 25 | Type.HOCON -> COLOR_CHAR + "3" 26 | else -> COLOR_CHAR + "7" 27 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/TrMenuAPI.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api 2 | 3 | import org.bukkit.command.CommandMap 4 | import trplugins.menu.module.display.Menu 5 | import trplugins.menu.module.internal.data.Metadata 6 | import trplugins.menu.util.EvalResult 7 | import trplugins.menu.module.internal.service.Performance 8 | import taboolib.library.kether.LocalizedException 9 | import org.bukkit.entity.Player 10 | import taboolib.common.platform.function.adaptPlayer 11 | import taboolib.common.platform.function.onlinePlayers 12 | import taboolib.common.platform.function.pluginId 13 | import taboolib.module.kether.KetherShell 14 | import java.util.concurrent.CompletableFuture 15 | import java.util.concurrent.TimeUnit 16 | import java.util.concurrent.TimeoutException 17 | 18 | 19 | /** 20 | * @author Arasple 21 | * @date 2021/1/25 9:54 22 | */ 23 | object TrMenuAPI { 24 | 25 | /** 26 | * Get the trplugins.menu through its ID 27 | * 28 | * @return Menu 29 | * @see Menu 30 | */ 31 | fun getMenuById(id: String): Menu? { 32 | return Menu.menus.find { it.id == id } 33 | } 34 | 35 | @JvmStatic 36 | fun eval(player: Player, script: String): CompletableFuture { 37 | Performance.check("Handler:Script:Evaluation") { 38 | return try { 39 | KetherShell.eval(script, namespace = listOf("trmenu")) { 40 | sender = adaptPlayer(player) 41 | rootFrame().variables().run { 42 | Metadata.getMeta(player).data.forEach { (key, value) -> 43 | set(key, value.toString()) 44 | } 45 | } 46 | } 47 | } catch (e: LocalizedException) { 48 | println("§c[TrMenu] §8Unexpected exception while parsing kether shell:") 49 | e.localizedMessage.split("\n").forEach { 50 | println(" §8$it") 51 | } 52 | CompletableFuture.completedFuture(false) 53 | } 54 | } 55 | throw Exception() 56 | } 57 | 58 | @JvmStatic 59 | fun instantKether(player: Player, script: String, timeout: Long = 100): EvalResult { 60 | return try { 61 | EvalResult(eval(player, script).get(timeout, TimeUnit.MILLISECONDS)) 62 | } catch (e: TimeoutException) { 63 | println("§c[TrMenu] §8Timeout while parsing kether shell:") 64 | e.localizedMessage?.split("\n")?.forEach { println(" §8$it") } 65 | EvalResult.FALSE 66 | } 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/func/GiveItem.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.func 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.display.session 10 | import trplugins.menu.util.bukkit.ItemMatcher 11 | 12 | /** 13 | * TrMenu 14 | * trplugins.menu.api.action.impl.func.GiveItem 15 | * 16 | * @author Rubenicos 17 | * @since 2022/02/14 13:16 18 | */ 19 | class GiveItem(handle: ActionHandle) : ActionBase(handle) { 20 | 21 | override val regex = "(give|add)(-)?items?".toRegex() 22 | 23 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 24 | ItemMatcher.eval(contents.stringContent().parseContent(placeholderPlayer), !isParsable(contents.stringContent())).buildItem().forEach { 25 | player.cast().inventory.addItem(it).values.forEach { e -> player.cast().world.dropItem(player.cast().location, e) } 26 | } 27 | player.session().playerItemSlots() 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/func/RepairItem.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.func 2 | 3 | import org.bukkit.Material 4 | import org.bukkit.entity.Player 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.common.platform.ProxyPlayer 7 | import trplugins.menu.api.action.ActionHandle 8 | import trplugins.menu.api.action.base.ActionBase 9 | import trplugins.menu.api.action.base.ActionContents 10 | import trplugins.menu.util.bukkit.ItemHelper 11 | 12 | /** 13 | * TrMenu 14 | * trplugins.menu.api.action.impl.func.RepairItem 15 | * 16 | * @author Rubenicos 17 | * @since 2022/02/14 13:16 18 | */ 19 | class RepairItem(handle: ActionHandle) : ActionBase(handle) { 20 | 21 | override val regex = "repair(-)?items?".toRegex() 22 | 23 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 24 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { 25 | repair(ItemHelper.fromPlayerInv(player.cast().inventory, it)) 26 | } 27 | player.cast().updateInventory() 28 | } 29 | 30 | private fun repair(any: Any?) { 31 | if (any is Array<*>) { 32 | any.forEach { repairItem(it as ItemStack?) } 33 | } else if (any is ItemStack) repairItem(any) 34 | } 35 | 36 | @Suppress("DEPRECATION") 37 | private fun repairItem(item: ItemStack?) { 38 | if (item == null || item.type == Material.AIR || item.type.isBlock || item.type.isEdible || item.type.maxDurability <= 0 || item.durability == (0).toShort()) 39 | return 40 | item.durability = (0).toShort() 41 | } 42 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/func/TakeItem.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.func 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.display.session 9 | import trplugins.menu.util.bukkit.ItemMatcher 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.func.TakeItem 14 | * 15 | * @author Rubenicos 16 | * @since 2022/02/14 13:16 17 | */ 18 | class TakeItem(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "(take|remove)(-)?items?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | ItemMatcher.eval(contents.stringContent().parseContent(placeholderPlayer), !isParsable(contents.stringContent())).takeItem(player.cast()) 24 | player.session().playerItemSlots() 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/hook/AddMoney.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.hook 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.internal.hook.HookPlugin 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.hook.AddMoney 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 14:17 16 | */ 17 | class AddMoney(handle: ActionHandle) : ActionBase(handle) { 18 | override val regex = "(give|add|deposit)-?(money|eco|coin)s?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val amount = contents.stringContent().parseContent(placeholderPlayer).toDoubleOrNull() ?: -1.0 22 | if (amount > 0) { 23 | HookPlugin.getVault().addMoney(player.cast(), amount) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/hook/AddPoint.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.hook 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.internal.hook.HookPlugin 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.hook.AddPoint 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 14:18 16 | */ 17 | class AddPoint(handle: ActionHandle) : ActionBase(handle) { 18 | override val regex = "(give|add|deposit)-?points?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val amount = contents.stringContent().parseContent(placeholderPlayer).toIntOrNull() ?: -1 22 | if (amount > 0) { 23 | HookPlugin.getPlayerPoints().addPoints(player.cast(), amount) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/hook/SetMoney.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.hook 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.internal.hook.HookPlugin 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.hook.SetMoney 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 14:17 16 | */ 17 | class SetMoney(handle: ActionHandle) : ActionBase(handle) { 18 | override val regex = "(set|modify)-?(money|eco|coin)s?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val amount = contents.stringContent().parseContent(placeholderPlayer).toDoubleOrNull() ?: -1.0 22 | if (amount > 0) { 23 | HookPlugin.getVault().setMoney(player.cast(), amount) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/hook/SetPoint.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.hook 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.internal.hook.HookPlugin 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.hook.`SetPoint'` 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 14:18 16 | */ 17 | class SetPoint(handle: ActionHandle) : ActionBase(handle) { 18 | override val regex = "(set|modify)-?points?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val amount = contents.stringContent().parseContent(placeholderPlayer).toIntOrNull() ?: -1 22 | if (amount > 0) { 23 | HookPlugin.getPlayerPoints().setPoints(player.cast(), amount) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/hook/TakeMoney.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.hook 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.internal.hook.HookPlugin 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.hook.TakeMoney 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 14:18 16 | */ 17 | class TakeMoney(handle: ActionHandle) : ActionBase(handle) { 18 | override val regex = "(take|remove|withdraw)-?(money|eco|coin)s?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val amount = contents.stringContent().parseContent(placeholderPlayer).toDoubleOrNull() ?: -1.0 22 | if (amount > 0) { 23 | HookPlugin.getVault().takeMoney(player.cast(), amount) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/hook/TakePoint.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.hook 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.internal.hook.HookPlugin 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.hook.TakePoint 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 14:18 16 | */ 17 | class TakePoint(handle: ActionHandle) : ActionBase(handle) { 18 | override val regex = "(take|remove|withdraw)-?points?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val amount = contents.stringContent().parseContent(placeholderPlayer).toIntOrNull() ?: -1 22 | if (amount > 0) { 23 | HookPlugin.getPlayerPoints().takePoints(player.cast(), amount) 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/Close.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.display.session 8 | 9 | /** 10 | * TrMenu 11 | * trplugins.menu.api.action.impl.inventory.Close 12 | * 13 | * @author Score2 14 | * @since 2022/02/14 11:13 15 | */ 16 | class Close(handle: ActionHandle) : ActionBase(handle) { 17 | 18 | override val regex = "close|shut".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | player.session().close(closePacket = true, updateInventory = true) 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/DelArguments.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.submit 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.display.session 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.receptacle.ClearArgument 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 12:05 16 | */ 17 | class DelArguments(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "(clear|cls|del|rem)-?arg(ument)?s?".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | submit(delay = 3L, async = true) { 23 | player.session().arguments = arrayOf() 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/Open.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.TrMenuAPI 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.api.event.MenuOpenEvent 10 | import trplugins.menu.module.internal.data.Metadata 11 | 12 | /** 13 | * TrMenu 14 | * trplugins.menu.api.action.impl.inventory.Open 15 | * 16 | * @author Score2 17 | * @since 2022/02/14 11:14 18 | */ 19 | class Open(handle: ActionHandle) : ActionBase(handle) { 20 | 21 | override val regex = "opens?|(open)?-?gui|(tr)?menu".toRegex() 22 | 23 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 24 | val args = contents.stringContent().parseContentSplited(placeholderPlayer, " ") 25 | val split = args[0].split(":") 26 | val arguments = if (args.size == 1) arrayOf() else args.toTypedArray().copyOfRange(1, args.size) 27 | val menu = TrMenuAPI.getMenuById(split[0]) ?: return 28 | val page = split.getOrNull(1)?.toIntOrNull() ?: 0 29 | 30 | menu.open(player.cast(), page, MenuOpenEvent.Reason.PLAYER_COMMAND) { 31 | if (!Metadata.byBukkit(player.cast(), "FORCE_ARGS") || arguments.isNotEmpty()) { 32 | if (arguments.isEmpty()) { 33 | it.arguments = it.implicitArguments.clone() 34 | it.implicitArguments = arrayOf() 35 | } else { 36 | it.arguments = arguments 37 | } 38 | } 39 | } 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/Page.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.display.session 8 | import kotlin.math.min 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.inventory.Page 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 11:14 16 | */ 17 | class Page(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "(set|switch)?-?(layout|shape|page)s?".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | val session = player.session() 23 | val menu = session.menu ?: return 24 | val page = min(contents.stringContent().parseContent(placeholderPlayer).toIntOrNull() ?: 0, menu.layout.getSize() - 1) 25 | 26 | menu.page(player.cast(), page) 27 | } 28 | 29 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/Refresh.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.display.session 8 | 9 | /** 10 | * TrMenu 11 | * trplugins.menu.api.action.impl.inventory.Refresh 12 | * 13 | * @author Score2 14 | * @since 2022/02/14 11:15 15 | */ 16 | class Refresh(handle: ActionHandle) : ActionBase(handle) { 17 | 18 | override val regex = "(icon)?-?refresh".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val session = player.session() 22 | val baseContent = contents.stringContent() 23 | 24 | if (baseContent.isBlank() || baseContent.equals("refresh", true)) { 25 | session.activeIcons.forEach { it.onRefresh(session) } 26 | } else { 27 | baseContent.split(";").mapNotNull { session.getIcon(it) }.forEach { it.onRefresh(session) } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/ReloadInventory.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.submit 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.display.session 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.inventory.ReloadInventory 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 11:28 16 | */ 17 | class ReloadInventory(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "(reload|rl)-?inv(entory)?s?".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | submit(delay = 2) { 23 | player.session().playerItemSlots() 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/Reset.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.display.Menu 8 | import trplugins.menu.module.display.session 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.inventory.Reset 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 11:16 16 | */ 17 | class Reset(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "resets?".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | val session = player.session() 23 | 24 | Menu.menus.forEach { 25 | it.icons.forEach { icon -> 26 | icon.onReset(session) 27 | } 28 | } 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/Retype.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.internal.data.Metadata 8 | 9 | /** 10 | * TrMenu 11 | * trplugins.menu.api.action.impl.receptacle.Retype 12 | * 13 | * @author Score2 14 | * @since 2022/02/14 12:18 15 | */ 16 | class Retype(handle: ActionHandle) : ActionBase(handle) { 17 | 18 | override val regex = "re-?(peat|catcher|input|enter|type)s?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | Metadata.setBukkitMeta(player.cast(), "RE_ENTER") 22 | } 23 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/SetAgent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import org.bukkit.Bukkit 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.display.session 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.menu.SetAgent 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 12:23 17 | */ 18 | class SetAgent(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "(set|change)-?agent".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | val agent = Bukkit.getPlayerExact(contents.stringContent().parseContent(placeholderPlayer)) ?: return 24 | 25 | player.session().agent = agent 26 | } 27 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/SetArguments.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.display.session 9 | import trplugins.menu.module.internal.data.Metadata 10 | import trplugins.menu.util.Regexs 11 | import trplugins.menu.util.collections.Variables 12 | 13 | /** 14 | * TrMenu 15 | * trplugins.menu.api.action.impl.menu.SetArguments 16 | * 17 | * @author Score2 18 | * @since 2022/02/14 12:23 19 | */ 20 | class SetArguments(handle: ActionHandle) : ActionBase(handle) { 21 | 22 | override val regex = "set-?arg(ument)?s?".toRegex() 23 | 24 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 25 | val baseContent = contents.stringContent() 26 | val args = Variables(baseContent, Regexs.SENTENCE) { 27 | it[1] 28 | }.element.flatMap { 29 | val v = it.value.parse(placeholderPlayer) 30 | if (it.isVariable) listOf(v) 31 | else v.split(" ") 32 | }.filterNot { it.isBlank() } 33 | 34 | Metadata.setBukkitMeta(player.cast(), "FORCE_ARGS") 35 | player.session().arguments = args.toTypedArray() 36 | } 37 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/SetTitle.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.module.display.session 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.menu.SetTitle 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 12:21 16 | */ 17 | class SetTitle(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "set-?title".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | val session = player.session() 23 | val receptacle = session.receptacle ?: return 24 | 25 | receptacle.title = contents.stringContent().parseContent(placeholderPlayer) 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/SilenceClose.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.display.session 8 | import trplugins.menu.module.internal.data.Metadata 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.inventory.SilenceClose 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 11:15 16 | */ 17 | class SilenceClose(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "(force|silent)-?(close|shut)".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | Metadata.setBukkitMeta(player.cast(), "FORCE_CLOSE") 23 | player.session().close(closePacket = true, updateInventory = true) 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/SilenceOpen.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.internal.data.Metadata 8 | 9 | /** 10 | * TrMenu 11 | * trplugins.menu.api.action.impl.inventory.SilenceOpen 12 | * 13 | * @author Score2 14 | * @since 2022/02/14 11:15 15 | */ 16 | class SilenceOpen(handle: ActionHandle) : ActionBase(handle) { 17 | 18 | val open = Open(handle) 19 | 20 | override val regex = "(force|silent)-?(open|menu)".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | Metadata.setBukkitMeta(player.cast(), "FORCE_OPEN") 24 | open.onExecute(contents, player) 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/menu/Update.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.menu 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.display.session 8 | 9 | /** 10 | * TrMenu 11 | * trplugins.menu.api.action.impl.inventory.Update 12 | * 13 | * @author Score2 14 | * @since 2022/02/14 11:14 15 | */ 16 | class Update(handle: ActionHandle) : ActionBase(handle) { 17 | 18 | override val regex = "(icon)?-?update".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | val session = player.session() 22 | val menuId = session.menu?.id // 缓存菜单id避免打开下一个菜单出现图标覆盖 23 | val baseContent = contents.stringContent() 24 | 25 | if (baseContent.isBlank() || baseContent.equals("update", true)) { 26 | session.activeIcons.forEach { 27 | it.onReset(session) 28 | it.settingItem(session, it.getProperty(session), menuId) 29 | } 30 | } else { 31 | baseContent.split(";").mapNotNull { session.getIcon(it) }.forEach { 32 | it.onReset(session) 33 | it.settingItem(session, it.getProperty(session), menuId) 34 | } 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/metadaa/DelData.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.metadaa 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.internal.data.Metadata 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.metadaa.DelData 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 14:27 17 | */ 18 | class DelData(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "(remove|rem|del)-?datas?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | val data = Metadata.getData(player).data 24 | 25 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { it -> 26 | val regex = Regex(it) 27 | data.keys.filter { it.matches(regex) }.forEach { data.remove(it) } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/metadaa/DelGlobalData.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.metadaa 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.internal.data.Metadata 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.metadaa.DelGlobalData 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 14:28 17 | */ 18 | class DelGlobalData(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "(remove|rem|del)-?(global|g)-?datas?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | val data = Metadata.globalData 24 | 25 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { it -> 26 | val regex = Regex(it) 27 | data.getKeys(true).filter { it.matches(regex) }.forEach { data[it] = null } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/metadaa/DelMeta.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.metadaa 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.internal.data.Metadata 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.metadaa.DelMeta 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 14:29 17 | */ 18 | class DelMeta(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "(remove|rem|del)-?(temp|var(iable)?|meta)s?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | val data = Metadata.getMeta(player).data 24 | 25 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { it -> 26 | val regex = Regex(it) 27 | data.keys.filter { it.matches(regex) }.forEach { data.remove(it) } 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/metadaa/SetData.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.metadaa 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.internal.data.Metadata 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.metadaa.SetData 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 14:28 17 | */ 18 | class SetData(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "set-?datas?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { 24 | val split = it.split(" ", limit = 2) 25 | if (split.size == 2) { 26 | val key = split[0] 27 | val value = split[1] 28 | 29 | Metadata.getData(player)[key] = value 30 | } 31 | } 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/metadaa/SetGlobalData.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.metadaa 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.internal.data.Metadata 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.metadaa.SetGlobalData 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 14:28 17 | */ 18 | class SetGlobalData(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "set-?(global|g)-?datas?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { 24 | val split = it.split(" ", limit = 2) 25 | if (split.size == 2) { 26 | val key = split[0] 27 | val value = split[1] 28 | 29 | Metadata.globalData[key] = value 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/metadaa/SetMeta.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.metadaa 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import trplugins.menu.api.action.ActionHandle 7 | import trplugins.menu.api.action.base.ActionBase 8 | import trplugins.menu.api.action.base.ActionContents 9 | import trplugins.menu.module.internal.data.Metadata 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.metadaa.SetMeta 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 14:29 17 | */ 18 | class SetMeta(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "set-?(temp|var(iable)?|meta)s?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { 24 | val split = it.split(" ", limit = 2) 25 | if (split.size == 2) { 26 | val key = split[0] 27 | val value = split[1] 28 | 29 | Metadata.getMeta(player)[key] = value 30 | // TODO DEBUG 31 | } 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/script/JavaScript.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.script 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.action.ActionHandle 5 | import trplugins.menu.api.action.base.ActionBase 6 | import trplugins.menu.api.action.base.ActionContents 7 | import trplugins.menu.module.display.session 8 | import trplugins.menu.module.internal.script.js.JavaScriptAgent 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.script.JavaScript 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 12:52 16 | */ 17 | class JavaScript(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "((java)?-?script|js)s?".toRegex() 20 | 21 | override fun readContents(contents: Any): ActionContents { 22 | JavaScriptAgent.preCompile(contents.toString()) 23 | return super.readContents(contents) 24 | } 25 | 26 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 27 | JavaScriptAgent.eval(player.session(), contents.stringContent()) 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/script/Kether.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.script 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import trplugins.menu.api.TrMenuAPI 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | 9 | /** 10 | * TrMenu 11 | * trplugins.menu.api.action.impl.script.Kether 12 | * 13 | * @author Score2 14 | * @since 2022/02/14 12:55 15 | */ 16 | class Kether(handle: ActionHandle) : ActionBase(handle) { 17 | 18 | override val regex = "ke(ther)?s?".toRegex() 19 | 20 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 21 | TrMenuAPI.eval(player.cast(), contents.stringContent()) 22 | } 23 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/Bossbar.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.boss.BarColor 5 | import org.bukkit.boss.BarStyle 6 | import taboolib.common.platform.ProxyPlayer 7 | import taboolib.common.platform.function.submit 8 | import taboolib.common.util.replaceWithOrder 9 | import trplugins.menu.api.action.ActionHandle 10 | import trplugins.menu.api.action.base.ActionBase 11 | import trplugins.menu.api.action.base.ActionContents 12 | import trplugins.menu.module.internal.script.FunctionParser 13 | import trplugins.menu.util.Regexs 14 | 15 | /** 16 | * TrMenu 17 | * trplugins.menu.api.action.impl.send.Bossbar 18 | * 19 | * @author Score2 20 | * @since 2022/02/14 12:28 21 | */ 22 | class Bossbar(handle: ActionHandle) : ActionBase(handle) { 23 | 24 | override val regex = "(send)?-?boss(bar)?s?".toRegex() 25 | 26 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 27 | val barContent: String by contents 28 | val color: String by contents 29 | val style: String by contents 30 | val stay: Int by contents 31 | 32 | val bossBar = Bukkit.createBossBar( 33 | FunctionParser.parse(placeholderPlayer.cast(), barContent), 34 | BarColor.valueOf(color), 35 | BarStyle.valueOf(style) 36 | ) 37 | bossBar.addPlayer(player.cast()) 38 | submit(delay = System.currentTimeMillis() + (stay * 50L)) { 39 | bossBar.removePlayer(player.cast()) 40 | } 41 | } 42 | 43 | override fun readContents(contents: Any): ActionContents { 44 | val actionContents = ActionContents() 45 | var content: String = contents.toString() 46 | val replacements = Regexs.SENTENCE.findAll(content).mapIndexed { index, result -> 47 | content = content.replace(result.value, "{$index}") 48 | index to result.groupValues[1].replace("\\s", " ") 49 | }.toMap().values.toTypedArray() 50 | 51 | val split = content.split(" ", limit = 4) 52 | 53 | var barContent by actionContents 54 | barContent = split.getOrElse(0) { "" }.replaceWithOrder(*replacements) 55 | var color by actionContents 56 | color = split.getOrElse(1) { "white" }.replaceWithOrder(*replacements) 57 | var style by actionContents 58 | style = split.getOrElse(2) { "solid" }.replaceWithOrder(*replacements) 59 | var stay by actionContents 60 | stay = split.getOrNull(3)?.toIntOrNull() ?: 15 61 | 62 | return actionContents 63 | } 64 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/CommandOp.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import org.bukkit.Bukkit 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import taboolib.common.platform.function.submit 7 | import trplugins.menu.api.action.ActionHandle 8 | import trplugins.menu.api.action.base.ActionBase 9 | import trplugins.menu.api.action.base.ActionContents 10 | 11 | /** 12 | * TrMenu 13 | * trplugins.menu.api.action.impl.send.CommandOp 14 | * 15 | * @author Score2 16 | * @since 2022/02/14 12:29 17 | */ 18 | class CommandOp(handle: ActionHandle) : ActionBase(handle) { 19 | 20 | override val regex = "op(erator)?s?".toRegex() 21 | 22 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 23 | { 24 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { 25 | player.isOp.let { isOp -> 26 | player.isOp = true 27 | try { 28 | player.performCommand(it) 29 | } catch (e: Throwable) { 30 | e.printStackTrace() 31 | } 32 | player.isOp = isOp 33 | } 34 | } 35 | }.also { 36 | if (Bukkit.isPrimaryThread()) { 37 | it.invoke() 38 | } else { 39 | submit(async = false) { 40 | it.invoke() 41 | } 42 | } 43 | } 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/Connect.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import taboolib.common.platform.ProxyPlayer 4 | import taboolib.common.platform.function.adaptPlayer 5 | import trplugins.menu.api.action.ActionHandle 6 | import trplugins.menu.api.action.base.ActionBase 7 | import trplugins.menu.api.action.base.ActionContents 8 | import trplugins.menu.util.Bungees 9 | 10 | /** 11 | * TrMenu 12 | * trplugins.menu.api.action.impl.send.Connect 13 | * 14 | * @author Score2 15 | * @since 2022/02/14 12:29 16 | */ 17 | class Connect(handle: ActionHandle) : ActionBase(handle) { 18 | 19 | override val regex = "bungee|server|connect".toRegex() 20 | 21 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 22 | Bungees.connect(player.cast(), contents.stringContent().parseContent(placeholderPlayer)) 23 | } 24 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/action/impl/send/Sound.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.action.impl.send 2 | 3 | import org.bukkit.entity.Player 4 | import taboolib.common.platform.ProxyPlayer 5 | import taboolib.common.platform.function.adaptPlayer 6 | import taboolib.library.xseries.XSound 7 | import taboolib.module.lang.sendLang 8 | import trplugins.menu.api.action.ActionHandle 9 | import trplugins.menu.api.action.base.ActionBase 10 | import trplugins.menu.api.action.base.ActionContents 11 | 12 | /** 13 | * TrMenu 14 | * trplugins.menu.api.action.impl.send.Sound 15 | * 16 | * @author Score2 17 | * @since 2022/02/14 12:30 18 | */ 19 | class Sound(handle: ActionHandle) : ActionBase(handle) { 20 | 21 | override val regex = "(play)?-?sounds?".toRegex() 22 | 23 | override fun onExecute(contents: ActionContents, player: ProxyPlayer, placeholderPlayer: ProxyPlayer) { 24 | contents.stringContent().parseContentSplited(placeholderPlayer, ";").forEach { 25 | val split = it.split("-") 26 | if (split.isNotEmpty()) { 27 | val sound: XSound 28 | try { 29 | sound = XSound.valueOf(split[0]) 30 | } catch (t: Throwable) { 31 | player.sendLang("Menu-Action-Sound", it) 32 | return 33 | } 34 | val volume: Float = split.getOrNull(1)?.toFloatOrNull() ?: 1f 35 | val pitch: Float = split.getOrNull(2)?.toFloatOrNull() ?: 1f 36 | sound.play(player.cast(), volume, pitch) 37 | } 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/event/CustomDatabaseEvent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.event 2 | 3 | import trplugins.menu.module.internal.database.Database 4 | import taboolib.platform.type.BukkitProxyEvent 5 | 6 | /** 7 | * @Author sky 8 | * @Since 2020-08-14 14:52 9 | */ 10 | class CustomDatabaseEvent(val name: String, var database: Database? = null) : BukkitProxyEvent() { 11 | 12 | override val allowCancelled: Boolean 13 | get() = false 14 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/event/CustomItemSourceEvent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.event 2 | 3 | import org.bukkit.inventory.ItemStack 4 | import taboolib.platform.type.BukkitProxyEvent 5 | import trplugins.menu.module.display.MenuSession 6 | 7 | class CustomItemSourceEvent( 8 | val name: String, 9 | val id: String, 10 | val session: MenuSession, 11 | var source: ItemStack? = null 12 | ) : 13 | BukkitProxyEvent() { 14 | 15 | override val allowCancelled: Boolean 16 | get() = false 17 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/event/MenuCloseEvent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.event 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import taboolib.platform.type.BukkitProxyEvent 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2021/1/29 17:34 9 | */ 10 | class MenuCloseEvent(val session: MenuSession) : BukkitProxyEvent() -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/event/MenuOpenEvent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.event 2 | 3 | import trplugins.menu.module.display.Menu 4 | import trplugins.menu.module.display.MenuSession 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2021/1/29 17:34 10 | */ 11 | class MenuOpenEvent(val session: MenuSession, val menu: Menu, val page: Int, val reason: Reason = Reason.UNKNOWN) : 12 | BukkitProxyEvent() { 13 | 14 | enum class Reason { 15 | 16 | RELOAD, 17 | 18 | PLAYER_COMMAND, 19 | 20 | CONSOLE, 21 | 22 | BINDING_COMMANDS, 23 | 24 | BINDING_ITEMS, 25 | 26 | BINDING_SHORTCUT, 27 | 28 | UNKNOWN 29 | 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/event/MenuPageChangeEvent.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.event 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import taboolib.platform.type.BukkitProxyEvent 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2021/2/4 11:33 9 | */ 10 | class MenuPageChangeEvent(val session: MenuSession, val from: Int, val to: Int, val override: Boolean) : BukkitProxyEvent() -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/menu/IIcon.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.menu 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import trplugins.menu.module.display.icon.Icon 5 | import trplugins.menu.module.display.icon.IconProperty 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2021/1/24 20:54 10 | * @see Icon 11 | */ 12 | interface IIcon { 13 | 14 | /** 15 | * 为一个会话加载图标功能 16 | * 17 | * @param session 菜单会话 18 | * 19 | */ 20 | fun startup(session: MenuSession) 21 | 22 | /** 23 | * 显示图标属性 24 | */ 25 | fun settingItem(session: MenuSession, icon: IconProperty, lastMenuId: String?) 26 | 27 | /** 28 | * 更新显示属性 & 动画 29 | */ 30 | fun onUpdate(session: MenuSession, frames: Set) 31 | 32 | /** 33 | * 重新计算优先级, 筛选子图标 34 | */ 35 | fun onRefresh(session: MenuSession) 36 | 37 | /** 38 | * 重置会话缓存 39 | */ 40 | fun onReset(session: MenuSession) 41 | 42 | /** 43 | * 取得针对当前会话有效的图标属性 44 | */ 45 | fun getProperty(session: MenuSession): IconProperty 46 | 47 | /** 48 | * 判断该图标是否对该会话可用 49 | */ 50 | fun isAvailable(session: MenuSession): Boolean 51 | 52 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/menu/IItem.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.menu 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import trplugins.menu.module.display.item.Item 5 | import trplugins.menu.module.display.item.Meta 6 | import trplugins.menu.module.display.texture.Texture 7 | import org.bukkit.inventory.ItemStack 8 | import taboolib.platform.util.buildItem 9 | import taboolib.platform.util.isAir 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2021/1/25 13:00 14 | * @see Item 15 | */ 16 | interface IItem { 17 | 18 | /** 19 | * 生成材质物品 20 | */ 21 | fun generate(session: MenuSession, texture: Texture, name: String?, lore: List?, meta: Meta): ItemStack 22 | 23 | /** 24 | * 更新材质 25 | */ 26 | fun updateTexture(session: MenuSession) 27 | 28 | /** 29 | * 更新物品显示名称 30 | */ 31 | fun updateName(session: MenuSession) 32 | 33 | /** 34 | * 更新物品显示 Lore 35 | */ 36 | fun updateLore(session: MenuSession) 37 | 38 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/menu/IManager.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.menu 2 | 3 | import org.bukkit.entity.Player 4 | import trplugins.menu.api.receptacle.vanilla.window.WindowReceptacle 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2020/12/4 22:30 9 | */ 10 | interface IManager { 11 | 12 | fun getViewingReceptacle(player: Player): WindowReceptacle? 13 | 14 | fun setViewingReceptacle(player: Player, receptacle: WindowReceptacle? = null) 15 | 16 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/menu/IPosition.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.menu 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | 5 | /** 6 | * @author Arasple 7 | * @date 2021/1/25 19:17 8 | */ 9 | interface IPosition { 10 | 11 | fun generatePosition(session: MenuSession) 12 | 13 | fun currentPosition(session: MenuSession) 14 | 15 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/menu/ISerializer.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.menu 2 | 3 | import trplugins.menu.module.conf.prop.SerialzeResult 4 | import trplugins.menu.module.display.layout.MenuLayout 5 | import taboolib.module.configuration.Configuration 6 | import java.io.File 7 | 8 | /** 9 | * @author Arasple 10 | * @date 2021/1/25 10:11 11 | */ 12 | interface ISerializer { 13 | 14 | fun serializeMenu(file: File): SerialzeResult 15 | 16 | fun serializeSetting(conf: Configuration): SerialzeResult 17 | 18 | fun serializeLayout(conf: Configuration): SerialzeResult 19 | 20 | fun serializeIcons(conf: Configuration, layout: MenuLayout): SerialzeResult 21 | 22 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/api/menu/ITexture.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.api.menu 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import org.bukkit.inventory.ItemStack 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2021/1/24 11:39 9 | */ 10 | interface ITexture { 11 | 12 | fun generate(session: MenuSession): ItemStack 13 | 14 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/conf/prop/RunningPerformance.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.conf.prop 2 | 3 | /** 4 | * @author Score2 5 | * @since 2021/09/28 16:29 6 | */ 7 | enum class RunningPerformance(val priority: Int) { 8 | HIGH(1), NORMAL(2), LOW(3); 9 | 10 | val pools: Int get() = Runtime.getRuntime().availableProcessors() / priority 11 | 12 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/conf/prop/SerializeError.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.conf.prop 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/25 10:17 6 | */ 7 | @JvmInline 8 | value class SerializeError(val id: Int) { 9 | 10 | companion object { 11 | 12 | val INVALID_FILE = SerializeError(0) 13 | val INVALID_ICON_UNDEFINED_TEXTURE = SerializeError(1) 14 | 15 | fun formatInfo(error: SerializeError): String { 16 | return when (error) { 17 | INVALID_FILE -> "Invalid file {0}. The menu configuration format is not supported" 18 | INVALID_ICON_UNDEFINED_TEXTURE -> "Invalid icon {0}. Icon must have a material texture, even if it is to be set AIR" 19 | else -> "Unknown error." 20 | } 21 | } 22 | 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/conf/prop/SerialzeResult.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.conf.prop 2 | 3 | import taboolib.common.util.replaceWithOrder 4 | import trplugins.menu.module.display.icon.Icon 5 | import trplugins.menu.module.display.layout.MenuLayout 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2021/1/25 10:12 10 | */ 11 | class SerialzeResult( 12 | val type: Type, 13 | var state: State = State.SUCCESS, 14 | val errors: MutableList = mutableListOf(), 15 | var result: Any? = null 16 | ) { 17 | 18 | fun succeed(): Boolean { 19 | return state == State.SUCCESS && result != null 20 | } 21 | 22 | fun submitError(error: SerializeError, vararg args: Any) { 23 | state = State.FAILED 24 | errors.add(SerializeError.formatInfo(error).replaceWithOrder(*args)) 25 | } 26 | 27 | @Suppress("UNCHECKED_CAST") 28 | fun asIcons(): Set { 29 | return (result as List).toSet() 30 | } 31 | 32 | fun asLayout(): MenuLayout { 33 | return result as MenuLayout 34 | } 35 | 36 | enum class State { 37 | 38 | SUCCESS, 39 | FAILED, 40 | IGNORE 41 | 42 | } 43 | 44 | enum class Type { 45 | 46 | MENU, 47 | MENU_SETTING, 48 | MENU_LAYOUT, 49 | ICON, 50 | 51 | } 52 | 53 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/display/icon/IconProperty.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.display.icon 2 | 3 | import taboolib.common.platform.function.adaptPlayer 4 | import trplugins.menu.api.reaction.Reactions 5 | import trplugins.menu.api.receptacle.ReceptacleClickType 6 | import trplugins.menu.module.display.MenuSession 7 | import trplugins.menu.module.display.item.Item 8 | import trplugins.menu.util.Regexs 9 | 10 | /** 11 | * @author Arasple 12 | * @date 2021/1/25 10:53 13 | */ 14 | class IconProperty( 15 | val priority: Int, 16 | val condition: String, 17 | val display: Item, 18 | val action: Map, Reactions> 19 | ) { 20 | 21 | fun isTextureUpdatable(): Boolean { 22 | return display.meta.isDynamic || display.texture.cyclable() || display.texture.elements.any { it.dynamic } 23 | } 24 | 25 | fun isNameUpdatable(): Boolean { 26 | return display.name.cyclable() || display.name.elements.any { Regexs.containsPlaceholder(it) } 27 | } 28 | 29 | fun isLoreUpdatable(): Boolean { 30 | return display.lore.cyclable() || display.lore.elements.any { it -> Regexs.containsPlaceholder(it.lore.joinToString(" ") { it.first }) } 31 | } 32 | 33 | fun handleClick(type: ReceptacleClickType, session: MenuSession) { 34 | val reactions = action.entries 35 | .filter { set -> 36 | set.key.any { it == ReceptacleClickType.ALL || it == ReceptacleClickType.NUMBER_KEY && it.isNumberKeyClick() } || set.key.contains( 37 | type 38 | ) 39 | } 40 | .map { it.value } 41 | 42 | reactions.forEach { it.eval(adaptPlayer(session.viewer)) } 43 | } 44 | 45 | 46 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/display/item/Lore.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.display.item 2 | 3 | import trplugins.menu.api.action.base.ActionBase 4 | import trplugins.menu.module.display.MenuSession 5 | import trplugins.menu.module.internal.script.evalScript 6 | import trplugins.menu.util.collections.Variables 7 | 8 | /** 9 | * @author Arasple 10 | * @date 2021/1/24 18:50 11 | */ 12 | class Lore(lore: List) { 13 | 14 | val lore = lore 15 | .map { 16 | var condition: String? = null 17 | val line = buildString { 18 | Variables(it, ActionBase.OptionType.CONDITION.regex) { it[2] }.element.forEach { element -> 19 | if (element.isVariable) condition = element.value 20 | else append(element.value) 21 | } 22 | } 23 | 24 | line to condition 25 | } 26 | 27 | fun parse(session: MenuSession): List { 28 | val lores = mutableListOf() 29 | lore 30 | .forEach { (line, condition) -> 31 | if (condition == null || session.evalScript(condition).asBoolean()) { 32 | lores.addAll(session.parse(line).split("\\n", "\n")) 33 | } 34 | } 35 | 36 | return lores 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/display/item/Meta.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.display.item 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import trplugins.menu.util.Regexs 5 | import org.bukkit.inventory.ItemFlag 6 | import org.bukkit.inventory.ItemStack 7 | import org.bukkit.inventory.meta.ItemMeta 8 | import taboolib.module.nms.ItemTag 9 | import taboolib.module.nms.getItemTag 10 | import taboolib.platform.util.ItemBuilder 11 | import trplugins.menu.module.internal.script.evalScript 12 | 13 | /** 14 | * @author Arasple 15 | * @date 2021/1/24 18:50 16 | * 显示物品的非动画, 支持动态的属性 17 | */ 18 | class Meta( 19 | private val amount: String, 20 | private val shiny: String, 21 | private val flags: Array, 22 | private val nbt: ItemTag?, 23 | ) { 24 | 25 | private val isAmountDynamic = amount.toIntOrNull() == null 26 | private val isShinyDynamic = !shiny.matches(Regexs.BOOLEAN) 27 | private val isNBTDynamic = nbt != null && Regexs.containsPlaceholder(nbt.toJsonSimplified()) 28 | val isDynamic = isAmountDynamic || isNBTDynamic || isShinyDynamic 29 | 30 | fun amount(session: MenuSession): Int { 31 | return (if (isAmountDynamic) session.parse(amount) else amount).toDoubleOrNull()?.toInt() ?: 1 32 | } 33 | 34 | fun shiny(session: MenuSession, builder: ItemBuilder) { 35 | if ((shiny.toBoolean()) || (isShinyDynamic && session.placeholderPlayer.evalScript(shiny).asBoolean())) { 36 | builder.shiny() 37 | } 38 | return 39 | } 40 | 41 | fun flags(builder: ItemBuilder) { 42 | if (flags.isNotEmpty()) { 43 | builder.flags.addAll(flags) 44 | } 45 | } 46 | 47 | fun nbt(session: MenuSession, itemStack: ItemStack): ItemMeta? { 48 | if (nbt != null && !nbt.isEmpty()) { 49 | val nbt = if (isNBTDynamic) ItemTag.fromLegacyJson(session.parse(nbt.toJson())) else nbt 50 | val tag = ItemTag() 51 | tag.putAll(itemStack.getItemTag()) 52 | tag.putAll(nbt) 53 | tag.saveTo(itemStack) 54 | return itemStack.itemMeta 55 | } 56 | return null 57 | } 58 | 59 | fun hasAmount(): Boolean { 60 | return amount.isNotEmpty() || amount.toIntOrNull() != null 61 | } 62 | 63 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/display/layout/MenuLayout.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.display.layout 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/24 20:54 6 | */ 7 | @JvmInline 8 | value class MenuLayout(internal val layouts: Array) { 9 | 10 | fun search(iconKey: String, pages: List): Map> { 11 | val ps = mutableMapOf>() 12 | 13 | layouts.forEachIndexed { index, layout -> 14 | layout.keys[iconKey]?.let { 15 | ps.computeIfAbsent(index) { mutableSetOf() } 16 | .addAll(it) 17 | } 18 | } 19 | 20 | pages.forEach { ps.computeIfAbsent(it) { mutableSetOf() } } 21 | 22 | return ps 23 | } 24 | 25 | operator fun get(page: Int): Layout { 26 | return layouts[page] 27 | } 28 | 29 | fun getSize(): Int { 30 | return layouts.size 31 | } 32 | 33 | companion object { 34 | 35 | val commonKeys = listOf( 36 | '#', 37 | '-', 38 | '@', 39 | '|', 40 | '=', 41 | 'A', 42 | 'B', 43 | 'C', 44 | 'D', 45 | 'E', 46 | 'F', 47 | 'G', 48 | 'H', 49 | 'I', 50 | 'J', 51 | 'K', 52 | 'L', 53 | 'M', 54 | 'N', 55 | 'O', 56 | 'P', 57 | 'Q', 58 | 'R', 59 | 'S', 60 | 'T', 61 | 'U', 62 | 'V', 63 | 'W', 64 | 'X', 65 | 'Y', 66 | 'Z', 67 | 'a', 68 | 'b', 69 | 'c', 70 | 'd', 71 | 'e', 72 | 'f', 73 | 'g', 74 | 'h', 75 | 'i', 76 | 'j', 77 | 'k', 78 | 'l', 79 | 'm', 80 | 'n', 81 | 'o', 82 | 'p', 83 | 'q', 84 | 'r', 85 | 's', 86 | 't', 87 | 'u', 88 | 'v', 89 | 'w', 90 | 'x', 91 | 'y', 92 | 'z' 93 | ) 94 | 95 | 96 | } 97 | 98 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/display/texture/TextureMeta.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.display.texture 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/24 12:15 6 | * 7 | */ 8 | enum class TextureMeta(val regex: Regex) { 9 | 10 | DATA_VALUE("(?i)[<{]data-?value[:=](.+?)[>}]"), 11 | 12 | MODEL_DATA("(?i)[<{]model-?data[:=](\\d+?)[>}]"), 13 | 14 | LEATHER_DYE("(?i)[<{]dye[:=](\\d{1,3},\\d{1,3},\\d{1,3})[>}]"), 15 | 16 | BANNER_PATTERN("(?i)[<{]banner[:=](.+?)[>}]"); 17 | 18 | constructor(regex: String) : this(regex.toRegex()) 19 | 20 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/display/texture/TextureType.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.display.texture 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/24 11:55 6 | */ 7 | enum class TextureType(val regex: Regex, val group: Int) { 8 | 9 | /** 10 | * Red Stained Glass Pane 11 | * Wool:3 (Data-Value does not support variables here) 12 | */ 13 | NORMAL, 14 | 15 | /** 16 | * {identifier}:{parsedArgument} 17 | * 18 | * e.g. 19 | * head:%player_name% 20 | * head:BlackSky 21 | * 22 | * if the server runs SkinsRestorer and in offline mode, the player head will automatically support 23 | * if argument's length is larger than 64, then identified as custom textued skull 24 | * 25 | * head:eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDRmNDUyZDk5OGVhYmFjNDY0MmM2YjBmZTVhOGY0ZTJlNjczZWRjYWUyYTZkZmQ5ZTZhMmU4NmU3ODZlZGFjMCJ9fX0= 26 | * head:44f452d998eabac4642c6b0fe5a8f4e2e673edcae2a6dfd9e6a2e86e786edac0 27 | * 28 | * Origin Regex [<{]?(player|custom|textured?)?-?(head|skull)[:=]([\\w.%{}]+)[>}]? 29 | */ 30 | HEAD("[<{]?(player|custom|textured?)?-?(head|skull)[:=]([\\S%{}]+)[>}]?", 3), 31 | 32 | /** 33 | * {identifier}:{parsedArgument} 34 | * 35 | * e.g. 36 | * repo:myCustomItem 37 | * repo:%custom_variable_whichreturnstheid% 38 | * 39 | * Its name, lore will be overried if the icon has them 40 | * 41 | */ 42 | REPO("[<{]?repo[:=]([\\w.%]+)[>}]?", 1), 43 | 44 | /** 45 | * {identifier}:{parsedArgument} 46 | * 47 | * e.g. 48 | * source:HDB:random 49 | * source:ORAXEN:itemId 50 | * 51 | */ 52 | SOURCE("[<{]?source[:=](.+)[>}]?", 1), 53 | 54 | /** 55 | * {json Content} 56 | * 57 | * Will be parsed if there contains placeholders 58 | */ 59 | RAW; 60 | 61 | constructor(regex: String = "", group: Int = -1) : this(regex.toRegex(), group) 62 | 63 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/command/AppearHelper.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.command 2 | 3 | @Target(AnnotationTarget.FIELD) 4 | @kotlin.annotation.Retention(AnnotationRetention.RUNTIME) 5 | annotation class AppearHelper -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/command/CommandExpression.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.command 2 | 3 | import taboolib.common.platform.command.SimpleCommandBody 4 | 5 | interface CommandExpression { 6 | 7 | val command: SimpleCommandBody 8 | 9 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/command/impl/CommandAction.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.command.impl 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.command.CommandSender 5 | import taboolib.common.platform.command.subCommand 6 | import taboolib.common.platform.function.adaptPlayer 7 | import taboolib.platform.util.sendLang 8 | import trplugins.menu.TrMenu.actionHandle 9 | import trplugins.menu.api.action.base.ActionEntry 10 | import trplugins.menu.module.internal.command.CommandExpression 11 | import kotlin.system.measureNanoTime 12 | 13 | /** 14 | * @author Arasple 15 | * @date 2021/1/31 10:41 16 | */ 17 | object CommandAction : CommandExpression { 18 | 19 | // trm action [Player] [Action] 20 | override val command = subCommand { 21 | // player 22 | dynamic { 23 | suggestion(uncheck = true) { sender, context -> 24 | Bukkit.getOnlinePlayers().map { it.name } 25 | } 26 | // Action 27 | dynamic { 28 | execute { sender, context, argument -> 29 | val player = context.argument(-1).let { Bukkit.getPlayerExact(it) } 30 | if (player == null || !player.isOnline) { 31 | sender.sendLang("Command-Action-Unknown-Player", context.argument(-1)) 32 | return@execute 33 | } 34 | 35 | val (hidePrint, action) = argument.startsWith("#") to ActionEntry.of(actionHandle, argument.removePrefix("#")) 36 | 37 | measureNanoTime { 38 | actionHandle.runAction(adaptPlayer(player), action).let { 39 | sender.sendMessage("§8[§7Action§8] §7Result: §3$it") 40 | } 41 | }.also { 42 | if (!hidePrint) { 43 | sender.sendMessage("§8[§7Action§8] §7Evaluated §8{$action} §7in §f${it.div(1000000.0)} ms") 44 | } 45 | } 46 | 47 | } 48 | } 49 | } 50 | } 51 | 52 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/command/impl/CommandList.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.command.impl 2 | 3 | import trplugins.menu.module.display.Menu 4 | import trplugins.menu.api.color 5 | import trplugins.menu.module.internal.command.CommandExpression 6 | import org.bukkit.command.CommandSender 7 | import taboolib.common.platform.command.subCommand 8 | import taboolib.platform.util.sendLang 9 | 10 | /** 11 | * @author Arasple 12 | * @date 2021/1/28 20:11 13 | */ 14 | object CommandList : CommandExpression { 15 | 16 | // trm list [filter] 17 | override val command = subCommand { 18 | execute { sender, context, argument -> 19 | find(sender, null) 20 | } 21 | dynamic(optional = true) { 22 | execute { sender, context, argument -> 23 | find(sender, argument) 24 | } 25 | } 26 | } 27 | 28 | private fun find(sender: CommandSender, filter: String?) { 29 | val menus = Menu.menus.filter { filter == null || it.id.contains(filter, true) }.sortedBy { it.id } 30 | 31 | if (menus.isEmpty()) { 32 | sender.sendLang("Command-List-Error", filter ?: "*") 33 | } else { 34 | sender.sendLang("Command-List-Header", menus.size, filter ?: "*") 35 | menus.forEach { 36 | sender.sendLang( 37 | "Command-List-Format", it.id, 38 | it.conf.type.color + it.conf.type.name, 39 | it.settings.title.elements.first(), 40 | it.icons.size 41 | ) 42 | } 43 | } 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/command/impl/CommandReload.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.command.impl 2 | 3 | import trplugins.menu.TrMenu.SETTINGS 4 | import trplugins.menu.module.conf.Loader 5 | import trplugins.menu.module.internal.command.CommandExpression 6 | import org.bukkit.command.CommandSender 7 | import taboolib.common.platform.command.subCommand 8 | import taboolib.platform.util.sendLang 9 | 10 | /** 11 | * @author Arasple 12 | * @date 2021/1/27 11:44 13 | */ 14 | object CommandReload : CommandExpression { 15 | 16 | override val command = subCommand { 17 | execute { sender, _, _ -> 18 | if (Loader.isLoading) { 19 | return@execute sender.sendLang("Menu-Loader-Loading") 20 | } 21 | SETTINGS.reload() 22 | Loader.loadMenus(sender, async = SETTINGS.getBoolean("Options.Async-Load-Menus", true)) 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/command/impl/CommandTest.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.command.impl 2 | 3 | import trplugins.menu.module.internal.command.CommandExpression 4 | import org.bukkit.entity.Player 5 | import org.bukkit.event.inventory.InventoryType 6 | import taboolib.common.platform.command.subCommand 7 | import taboolib.common.platform.function.submit 8 | import taboolib.library.xseries.XMaterial 9 | import trplugins.menu.api.receptacle.vanilla.window.ChestInventory 10 | import trplugins.menu.api.receptacle.createReceptacle 11 | 12 | /** 13 | * @author Arasple 14 | * @date 2021/2/21 13:41 15 | */ 16 | object CommandTest : CommandExpression { 17 | 18 | override val command = subCommand { 19 | // trm test 20 | execute { player, _, _ -> 21 | val chest = InventoryType.CHEST.createReceptacle("Def").also { 22 | it as ChestInventory 23 | it.rows = 3 24 | } 25 | 26 | chest.type.totalSlots.forEach { chest.setElement(XMaterial.values().random().parseItem(), it) } 27 | chest.open(player) 28 | 29 | val task = submit(delay = 20, period = 10, async = false) { 30 | chest.title = (0..20).random().toString() 31 | } 32 | submit(delay = (20 * 20)) { 33 | task.cancel() 34 | } 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/data/DataMap.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.data 2 | 3 | /** 4 | * @author Arasple 5 | * @date 2021/1/27 11:49 6 | */ 7 | @JvmInline 8 | value class DataMap(val data: MutableMap = mutableMapOf()) { 9 | 10 | operator fun set(key: String, value: String) { 11 | data[key] = value 12 | } 13 | 14 | operator fun get(key: String): Any? { 15 | return data[key] 16 | } 17 | 18 | fun remove(key: String) { 19 | data.remove(key) 20 | } 21 | 22 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/data/NetQuery.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.data 2 | 3 | import com.google.common.collect.Maps 4 | import com.google.gson.JsonElement 5 | import com.google.gson.JsonParser 6 | import taboolib.common.platform.function.submit 7 | import java.io.BufferedInputStream 8 | import java.io.ByteArrayOutputStream 9 | import java.net.HttpURLConnection 10 | import java.net.URL 11 | import java.nio.charset.StandardCharsets 12 | 13 | /** 14 | * @author Arasple 15 | * @date 2021/2/3 8:45 16 | */ 17 | class NetQuery(private val url: String, private val span: Int) { 18 | 19 | companion object { 20 | 21 | private val queries = Maps.newConcurrentMap() 22 | 23 | fun query(url: String, span: Int): NetQuery { 24 | return queries.computeIfAbsent(url) { NetQuery(url, span) } 25 | } 26 | 27 | } 28 | 29 | private var lastUpdate = System.currentTimeMillis() 30 | private var updating = false 31 | private var data: String = "" 32 | 33 | private val shouldUpdate: Boolean 34 | get() { 35 | return System.currentTimeMillis() - lastUpdate > span * 1000 36 | } 37 | 38 | init { 39 | update() 40 | } 41 | 42 | fun get(): String { 43 | if (shouldUpdate) update() 44 | return data 45 | } 46 | 47 | fun has(): Boolean { 48 | return data.isNotBlank() 49 | } 50 | 51 | fun asJson(): JsonElement? { 52 | return JsonParser().parse(get()) 53 | } 54 | 55 | fun update() { 56 | if (updating) return 57 | updating = true 58 | 59 | submit(async = true) { 60 | try { 61 | val connection = URL(url).openConnection() as HttpURLConnection 62 | connection.requestMethod = "GET" 63 | connection.setRequestProperty( 64 | "User-Agent", 65 | "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; GTB7.5; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727)" 66 | ) 67 | val inputStream = connection.inputStream 68 | val bufferedInputStream = BufferedInputStream(inputStream) 69 | val stream = ByteArrayOutputStream() 70 | val buf = ByteArray(1024) 71 | var len: Int 72 | while (bufferedInputStream.read(buf).also { len = it } > 0) stream.write(buf, 0, len) 73 | data = String(stream.toByteArray(), StandardCharsets.UTF_8) 74 | lastUpdate = System.currentTimeMillis() 75 | updating = false 76 | } catch (e: Throwable) { 77 | e.printStackTrace() 78 | updating = false 79 | } 80 | } 81 | } 82 | 83 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/database/Database.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.database 2 | 3 | import trplugins.menu.TrMenu 4 | import org.bukkit.entity.Player 5 | import taboolib.module.configuration.Configuration 6 | 7 | /** 8 | * @Author sky 9 | * @Since 2020-08-14 14:38 10 | */ 11 | abstract class Database { 12 | 13 | val index: PlayerIndex 14 | get() = PlayerIndex.of(TrMenu.SETTINGS.getString("Database.Index.Player", "USERNAME")!!) 15 | 16 | fun pull(player: Player): Configuration { 17 | return pull(player, if (index == PlayerIndex.UUID) player.uniqueId.toString() else player.name) 18 | } 19 | 20 | abstract fun pull(player: Player, indexPlayer: String): Configuration 21 | 22 | fun push(player: Player) { 23 | push(player, if (index == PlayerIndex.UUID) player.uniqueId.toString() else player.name) 24 | } 25 | 26 | abstract fun push(player: Player, indexPlayer: String) 27 | 28 | fun release(player: Player) { 29 | release(player, if (index == PlayerIndex.UUID) player.uniqueId.toString() else player.name) 30 | } 31 | 32 | abstract fun release(player: Player, indexPlayer: String) 33 | 34 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/database/DatabaseMongodb.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.database 2 | 3 | import trplugins.menu.TrMenu.SETTINGS 4 | import org.bukkit.entity.Player 5 | import taboolib.module.configuration.Configuration 6 | import taboolib.module.database.bridge.Index 7 | import taboolib.module.database.bridge.createBridgeCollection 8 | 9 | /** 10 | * @Author sky 11 | * @Since 2020-08-14 14:46 12 | */ 13 | class DatabaseMongodb : Database() { 14 | 15 | val collection = createBridgeCollection( 16 | SETTINGS.getString("Database.Type.MongoDB.client") ?: "mongodb://localhost:3307", 17 | SETTINGS.getString("Database.Type.MongoDB.database") ?: "trixey", 18 | SETTINGS.getString("Database.Type.MongoDB.collection") ?: "menu", 19 | Index.valueOf(index.name) 20 | ) 21 | 22 | override fun pull(player: Player, indexPlayer: String): Configuration { 23 | return collection[indexPlayer].also { 24 | if (it.contains("username")) { 25 | it["username"] = player.name 26 | } 27 | } 28 | } 29 | 30 | override fun push(player: Player, indexPlayer: String) { 31 | collection.update(indexPlayer) 32 | } 33 | 34 | override fun release(player: Player, indexPlayer: String) { 35 | collection.release(indexPlayer) 36 | } 37 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/database/DatabaseSQL.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.database 2 | 3 | import trplugins.menu.TrMenu 4 | import org.bukkit.entity.Player 5 | import taboolib.module.configuration.Configuration 6 | import taboolib.module.database.ColumnOptionSQL 7 | import taboolib.module.database.ColumnTypeSQL 8 | import taboolib.module.database.Table 9 | import taboolib.module.database.getHost 10 | import java.util.concurrent.ConcurrentHashMap 11 | 12 | // Almost a total copy from DatabaseSQLite 13 | class DatabaseSQL : Database() { 14 | 15 | private val host = TrMenu.SETTINGS.getHost("Database.Type.SQL") 16 | 17 | val table = Table(TrMenu.SETTINGS.getString("Database.Type.SQL.table", "trmenu_user_data")!!, host) { 18 | add { 19 | name("user") 20 | type(ColumnTypeSQL.VARCHAR, 36) { 21 | options(ColumnOptionSQL.PRIMARY_KEY) 22 | } 23 | } 24 | add { 25 | name("data") 26 | type(ColumnTypeSQL.MEDIUMTEXT) 27 | } 28 | } 29 | 30 | val dataSource = host.createDataSource() 31 | val cache = ConcurrentHashMap() 32 | 33 | init { 34 | table.workspace(dataSource) { createTable() }.run() 35 | } 36 | 37 | override fun pull(player: Player, indexPlayer: String): Configuration { 38 | return cache.computeIfAbsent(indexPlayer) { 39 | table.workspace(dataSource) { 40 | select { where { "user" eq indexPlayer } } 41 | }.firstOrNull { 42 | Configuration.loadFromString(getString("data")) 43 | } ?: Configuration.empty() 44 | } 45 | } 46 | 47 | override fun push(player: Player, indexPlayer: String) { 48 | val file = cache[indexPlayer] ?: return 49 | if (table.workspace(dataSource) { select { where { "user" eq indexPlayer } } }.find()) { 50 | table.workspace(dataSource) { 51 | update { 52 | set("data", file.saveToString()) 53 | where { 54 | "user" eq indexPlayer 55 | } 56 | } 57 | }.run() 58 | } else { 59 | table.workspace(dataSource) { 60 | insert("user", "data") { 61 | value(indexPlayer, file.saveToString()) 62 | } 63 | }.run() 64 | } 65 | } 66 | 67 | override fun release(player: Player, indexPlayer: String) { 68 | cache.remove(indexPlayer) 69 | } 70 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/database/PlayerIndex.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.database 2 | 3 | /** 4 | * @Author Rubenicos 5 | * @Since 2021-11-08 17:27 6 | */ 7 | enum class PlayerIndex { 8 | 9 | UUID, USERNAME; 10 | 11 | companion object { 12 | fun of(type: String): PlayerIndex { 13 | return try { 14 | valueOf(type.uppercase()) 15 | } catch (ignored: Throwable) { 16 | UUID 17 | } 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/HookAbstract.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.plugin.Plugin 5 | import taboolib.common.platform.function.console 6 | import taboolib.module.lang.sendLang 7 | 8 | /** 9 | * @author Arasple 10 | * @date 2021/1/26 22:02 11 | */ 12 | abstract class HookAbstract { 13 | 14 | open val name by lazy { getPluginName() } 15 | 16 | val plugin: Plugin? by lazy { 17 | Bukkit.getPluginManager().getPlugin(name) 18 | } 19 | 20 | val isHooked by lazy { 21 | plugin != null && plugin!!.isEnabled 22 | } 23 | 24 | open fun getPluginName(): String { 25 | return javaClass.simpleName.substring(4) 26 | } 27 | 28 | fun checkHooked(): Boolean { 29 | return if (isHooked) true else false.also { reportAbuse() } 30 | } 31 | 32 | fun reportAbuse() { 33 | console().sendLang("Plugin-Dependency-Abuse", name) 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/HookPlugin.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook 2 | 3 | import taboolib.common.LifeCycle 4 | import taboolib.common.io.runningClasses 5 | import taboolib.common.platform.SkipTo 6 | import taboolib.common.platform.function.console 7 | import taboolib.common.platform.function.info 8 | import taboolib.module.lang.sendLang 9 | import trplugins.menu.module.internal.hook.impl.* 10 | import java.lang.reflect.Modifier 11 | import kotlin.reflect.KClass 12 | 13 | /** 14 | * @author Arasple 15 | * @date 2021/1/26 22:04 16 | */ 17 | @SkipTo(LifeCycle.ENABLE) 18 | object HookPlugin { 19 | 20 | fun printInfo() { 21 | registry.filter { it.isHooked }.forEach { 22 | console().sendLang("Plugin-Dependency-Hooked", it.name) 23 | } 24 | } 25 | 26 | private val registry by lazy { 27 | mutableListOf().also { 28 | runningClasses.forEach { `class` -> 29 | if (Modifier.isAbstract(`class`.modifiers)) return@forEach 30 | if (`class`.superclass != HookAbstract::class.java) return@forEach 31 | 32 | it.add(`class`.asSubclass(HookAbstract::class.java).getConstructor().newInstance()) 33 | } 34 | }.toTypedArray() 35 | } 36 | 37 | @Suppress("UNCHECKED_CAST") 38 | operator fun get(clazz: Class) = registry.find { it.javaClass == clazz } as T 39 | 40 | operator fun get(clazz: KClass) = this[clazz.java] 41 | 42 | fun getHeadDatabase(): HookHeadDatabase { 43 | return get(HookHeadDatabase::class.java) 44 | } 45 | 46 | fun getOraxen(): HookOraxen { 47 | return get(HookOraxen::class.java) 48 | } 49 | 50 | fun getPlayerPoints(): HookPlayerPoints { 51 | return get(HookPlayerPoints::class.java) 52 | } 53 | 54 | fun getSkinsRestorer(): HookSkinsRestorer { 55 | return get(HookSkinsRestorer::class.java) 56 | } 57 | 58 | fun getItemsAdder(): HookItemsAdder { 59 | return get(HookItemsAdder::class.java) 60 | } 61 | 62 | fun getFloodgate(): HookFloodgate { 63 | return get(HookFloodgate::class.java) 64 | } 65 | 66 | fun getVault(): HookVault { 67 | return get(HookVault::class.java) 68 | } 69 | 70 | fun getFastScript(): HookFastScript { 71 | return get(HookFastScript::class.java) 72 | } 73 | 74 | fun getZaphkiel(): HookZaphkiel { 75 | return get(HookZaphkiel::class.java) 76 | } 77 | 78 | fun getTriton(): HookTriton { 79 | return get(HookTriton::class.java) 80 | } 81 | 82 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookFastScript.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import trplugins.menu.module.internal.hook.HookAbstract 4 | //import me.scoretwo.fastscript.FastScript 5 | 6 | /** 7 | * @author Score2 8 | * @date 2021/2/24 22:02 9 | * TODO 3.05 10 | */ 11 | class HookFastScript : HookAbstract() { 12 | 13 | // private val expansionManager get() = FastScript.instance.expansionManager 14 | 15 | // fun getExpansionByNameOrSign(key: String) = expansionManager.getExpansionBySign(key) ?: expansionManager.getExpansionByName(key) 16 | 17 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookFloodgate.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import trplugins.menu.module.internal.hook.HookAbstract 4 | import org.bukkit.entity.Player 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2021/2/4 20:12 9 | */ 10 | class HookFloodgate : HookAbstract() { 11 | 12 | fun isBedrockPlayer(player: Player): Boolean { 13 | // return if (checkHooked()) FloodgateApi.getInstance().isFloodgatePlayer(player.uniqueId) else false 14 | return false 15 | } 16 | 17 | override fun getPluginName(): String { 18 | return "floodgate-bukkit" 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookHeadDatabase.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import trplugins.menu.module.internal.hook.HookAbstract 4 | import me.arcaniax.hdb.api.HeadDatabaseAPI 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.library.xseries.XMaterial 7 | import taboolib.platform.util.buildItem 8 | 9 | /** 10 | * @author Arasple 11 | * @date 2021/1/26 22:04 12 | */ 13 | class HookHeadDatabase : HookAbstract() { 14 | 15 | private val headDatabaseAPI: HeadDatabaseAPI? = if (isHooked) HeadDatabaseAPI() else null 16 | get() { 17 | if (field == null) reportAbuse() 18 | return field 19 | } 20 | 21 | private val empty = buildItem(XMaterial.PLAYER_HEAD) { name = "UNHOOKED_${super.name.uppercase()}" } 22 | 23 | fun getHead(id: String): ItemStack { 24 | return headDatabaseAPI?.getItemHead(id) ?: empty 25 | } 26 | 27 | fun getRandomHead(): ItemStack { 28 | return headDatabaseAPI?.randomHead ?: empty 29 | } 30 | 31 | fun getId(itemStack: ItemStack): String? { 32 | return headDatabaseAPI?.getItemID(itemStack) 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookItemsAdder.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import dev.lone.itemsadder.api.CustomStack 4 | import trplugins.menu.module.internal.hook.HookAbstract 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.library.xseries.XMaterial 7 | import taboolib.platform.util.buildItem 8 | 9 | /** 10 | * @author Arasple 11 | * @date 2021/1/27 11:58 12 | */ 13 | class HookItemsAdder : HookAbstract() { 14 | 15 | private val empty = buildItem(XMaterial.BEDROCK) { name = "UNHOOKED_${super.name.uppercase()}" } 16 | 17 | fun getItem(id: String): ItemStack { 18 | if (checkHooked()) { 19 | return CustomStack.getInstance(id)?.itemStack ?: empty 20 | } 21 | return empty 22 | } 23 | 24 | fun getId(itemStack: ItemStack): String { 25 | if (checkHooked()) { 26 | return CustomStack.byItemStack(itemStack)?.id ?: "UNKNOWN" 27 | } 28 | return "UNHOOKED" 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookOraxen.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import io.th0rgal.oraxen.api.OraxenItems 4 | import trplugins.menu.module.internal.hook.HookAbstract 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.library.xseries.XMaterial 7 | import taboolib.platform.util.buildItem 8 | 9 | /** 10 | * @author Arasple 11 | * @date 2021/1/27 11:58 12 | */ 13 | class HookOraxen : HookAbstract() { 14 | 15 | private val empty = buildItem(XMaterial.BEDROCK) { name = "UNHOOKED_${super.name.uppercase()}" } 16 | 17 | fun getItem(id: String): ItemStack { 18 | if (checkHooked()) { 19 | return OraxenItems.getItemById(id).build() 20 | } 21 | return empty 22 | } 23 | 24 | fun getId(itemStack: ItemStack): String { 25 | if (checkHooked()) { 26 | return OraxenItems.getIdByItem(itemStack) 27 | } 28 | return "UNHOOKED" 29 | } 30 | 31 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookPlayerPoints.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import trplugins.menu.module.internal.hook.HookAbstract 4 | import org.black_ixx.playerpoints.PlayerPoints 5 | import org.black_ixx.playerpoints.PlayerPointsAPI 6 | import org.bukkit.Bukkit 7 | import org.bukkit.OfflinePlayer 8 | import taboolib.common.platform.function.submit 9 | import java.util.concurrent.TimeUnit 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2021/1/26 22:18 14 | */ 15 | class HookPlayerPoints : HookAbstract() { 16 | 17 | private val playerPointsAPI: PlayerPointsAPI? = if (isHooked) (plugin as PlayerPoints).api else null 18 | get() { 19 | if (field == null) reportAbuse() 20 | return field 21 | } 22 | 23 | fun getPoints(player: OfflinePlayer): Int { 24 | return try { 25 | playerPointsAPI?.lookAsync(player.uniqueId)?.get(1, TimeUnit.SECONDS) ?: -1 26 | } catch (t: Throwable) { 27 | playerPointsAPI?.look(player.uniqueId) ?: -1 28 | } 29 | } 30 | 31 | fun setPoints(player: OfflinePlayer, amount: Int) { 32 | try { 33 | playerPointsAPI?.setAsync(player.uniqueId, amount) 34 | } catch (t: Throwable) { 35 | call { playerPointsAPI?.set(player.uniqueId, amount) } 36 | } 37 | } 38 | 39 | fun hasPoints(player: OfflinePlayer, amount: Int): Boolean { 40 | return getPoints(player) >= amount 41 | } 42 | 43 | fun addPoints(player: OfflinePlayer, amount: Int) { 44 | try { 45 | playerPointsAPI?.giveAsync(player.uniqueId, amount) 46 | } catch (t: Throwable) { 47 | call { playerPointsAPI?.give(player.uniqueId, amount) } 48 | } 49 | } 50 | 51 | fun takePoints(player: OfflinePlayer, amount: Int) { 52 | try { 53 | playerPointsAPI?.takeAsync(player.uniqueId, amount) 54 | } catch (t: Throwable) { 55 | call { playerPointsAPI?.take(player.uniqueId, amount) } 56 | } 57 | } 58 | 59 | private fun call(block: () -> Unit) { 60 | if (Bukkit.isPrimaryThread()) { 61 | block.invoke() 62 | } else { 63 | submit(async = false) { block.invoke() } 64 | } 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookSkinsRestorer.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import net.skinsrestorer.api.SkinsRestorerAPI 4 | import trplugins.menu.module.internal.hook.HookAbstract 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2021/1/27 14:12 9 | */ 10 | class HookSkinsRestorer : HookAbstract() { 11 | 12 | private val skinsRestorerAPI: SkinsRestorerAPI? = 13 | if (isHooked) { 14 | SkinsRestorerAPI.getApi() 15 | } else { 16 | null 17 | } 18 | get() { 19 | if (field == null) reportAbuse() 20 | return field 21 | } 22 | 23 | fun getPlayerSkinTexture(name: String): String? { 24 | skinsRestorerAPI?.let { 25 | if (it.getSkinData(name) == null) { 26 | return null 27 | } 28 | 29 | val skinData = it.getSkinData(name) 30 | return skinData.value 31 | } 32 | return null 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookSkulls.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import ca.tweetzy.skulls.Skulls 4 | import ca.tweetzy.skulls.api.SkullsAPI 5 | import trplugins.menu.module.internal.hook.HookAbstract 6 | import trplugins.menu.util.bukkit.Heads 7 | import org.bukkit.inventory.ItemStack 8 | import taboolib.library.xseries.XMaterial 9 | import taboolib.platform.util.buildItem 10 | 11 | /** 12 | * TrMenu 13 | * trmenu.HookSkulls 14 | * 15 | * @author Score2 16 | * @since 2022/01/06 20:57 17 | */ 18 | class HookSkulls : HookAbstract() { 19 | 20 | private val empty = buildItem(XMaterial.PLAYER_HEAD) { name = "UNKNOWN_${super.name.uppercase()}" } 21 | 22 | fun getSkull(id: String): ItemStack { 23 | return SkullsAPI.getSkullItemStack(id.toIntOrNull() ?: 1) ?: empty 24 | } 25 | 26 | fun getRandomSkull(): ItemStack { 27 | return SkullsAPI.getRandomSkull()?.itemStack ?: empty 28 | } 29 | 30 | fun getId(itemStack: ItemStack): String? { 31 | return Skulls.getSkullManager().skulls.find { it.texture == Heads.seekTexture(itemStack) }?.texture 32 | } 33 | 34 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookTriton.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import com.rexcantor64.triton.Triton 4 | import com.rexcantor64.triton.api.players.LanguagePlayer 5 | import org.bukkit.entity.Player 6 | import trplugins.menu.module.internal.hook.HookAbstract 7 | 8 | /** 9 | * @author Rubenicos 10 | * @date 2022/06/01 09:18 11 | */ 12 | class HookTriton : HookAbstract() { 13 | 14 | private val triton: Triton? = if (isHooked) Triton.get() else null 15 | get() { 16 | if (field == null) reportAbuse() 17 | return field 18 | } 19 | 20 | fun getText(player: Player, code: String, args: Array): String? { 21 | val langPlayer: LanguagePlayer = triton?.playerManager?.get(player.uniqueId) ?: return null 22 | return triton?.languageManager?.getText(langPlayer, code, *args) 23 | } 24 | 25 | override fun getPluginName(): String { 26 | return "Triton" 27 | } 28 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookVault.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import trplugins.menu.module.internal.hook.HookAbstract 4 | import net.milkbowl.vault.economy.Economy 5 | import org.bukkit.Bukkit 6 | import org.bukkit.OfflinePlayer 7 | 8 | 9 | /** 10 | * @author Arasple 11 | * @date 2021/2/9 11:45 12 | */ 13 | class HookVault : HookAbstract() { 14 | 15 | private val economyAPI: Economy? = if (isHooked) { 16 | Bukkit.getServer().servicesManager.getRegistration(Economy::class.java)?.provider 17 | } else null 18 | get() { 19 | if (field == null) reportAbuse() 20 | return field 21 | } 22 | 23 | 24 | fun takeMoney(player: OfflinePlayer, money: Double) { 25 | economyAPI?.withdrawPlayer(player, money) 26 | } 27 | 28 | fun addMoney(player: OfflinePlayer, money: Double) { 29 | economyAPI?.depositPlayer(player, money) 30 | } 31 | 32 | fun hasMoney(player: OfflinePlayer, money: Double): Boolean { 33 | return economyAPI?.has(player, money) ?: false 34 | } 35 | 36 | fun getMoney(player: OfflinePlayer): Double { 37 | return economyAPI?.getBalance(player) ?: 0.0 38 | } 39 | 40 | fun setMoney(player: OfflinePlayer, money: Double) { 41 | addMoney(player, money - getMoney(player)) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/hook/impl/HookZaphkiel.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.hook.impl 2 | 3 | import ink.ptms.zaphkiel.ZaphkielAPI 4 | import trplugins.menu.module.internal.hook.HookAbstract 5 | import org.bukkit.entity.Player 6 | import org.bukkit.inventory.ItemStack 7 | import taboolib.library.xseries.XMaterial 8 | import taboolib.platform.util.buildItem 9 | 10 | class HookZaphkiel: HookAbstract() { 11 | 12 | private val empty = buildItem(XMaterial.BEDROCK) { name = "UNHOOKED_${super.name.uppercase()}" } 13 | 14 | private val notFound = buildItem(XMaterial.BEDROCK) { name = "NOT_FOUND_${super.name.uppercase()}" } 15 | 16 | fun getItem(id: String, player: Player? = null): ItemStack { 17 | if (checkHooked()) { 18 | return ZaphkielAPI.getItemStack(id, player) ?: notFound 19 | } 20 | return empty 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/inputer/inputs/InputBook.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.inputer.inputs 2 | 3 | import net.md_5.bungee.api.chat.TextComponent 4 | import org.bukkit.entity.Player 5 | import org.bukkit.event.player.PlayerEditBookEvent 6 | import taboolib.common.platform.event.SubscribeEvent 7 | import taboolib.platform.util.BookBuilder 8 | import taboolib.platform.util.buildBook 9 | import taboolib.platform.util.hasLore 10 | import taboolib.platform.util.takeItem 11 | import java.util.concurrent.ConcurrentHashMap 12 | import java.util.function.Consumer 13 | 14 | /** 15 | * 向玩家发送一本书 16 | * 并捕获该书本的编辑动作 17 | * 18 | * @param player 玩家 19 | * @param display 展示名称 20 | * @param disposable 编辑后销毁 21 | * @param origin 原始内容 22 | * @param catcher 编辑动作 23 | * 24 | * @project TrMenu 25 | * 26 | * @author Score2 27 | * @since 2021/09/30 14:52 28 | */ 29 | class InputBook( 30 | val player: Player, 31 | val display: String, 32 | val disposable: Boolean, 33 | val origin: List, 34 | val catcher: Consumer> 35 | ) { 36 | 37 | private val book = buildBook { 38 | bookPages.add(BookBuilder.Text(java.lang.String.join("\n", origin), true)) 39 | name = "§f$display" 40 | lore.addAll(arrayOf("§0Features Input", if (disposable) "§0Disposable" else "")) 41 | } 42 | 43 | fun open() { 44 | // 移除正在编辑的书本 45 | player.inventory.takeItem(99) { item -> 46 | item.hasLore("Features Input") 47 | } 48 | // 发送书本 49 | player.inventory.addItem(book) 50 | inputBookMap[player.name] = catcher 51 | } 52 | 53 | companion object { 54 | 55 | val inputBookMap: ConcurrentHashMap>> = 56 | ConcurrentHashMap>>() 57 | 58 | @SubscribeEvent 59 | fun e(e: PlayerEditBookEvent) { 60 | val bookLore = e.newBookMeta.lore ?: return 61 | if (bookLore.size > 0 && bookLore[0] == "§0Features Input") { 62 | val consumer = inputBookMap[e.player.name] ?: return 63 | val pages = mutableListOf() 64 | for (page in e.newBookMeta.pages) { 65 | pages.addAll(TextComponent(page).toPlainText().replace("§0", "").split("\n")) 66 | } 67 | consumer.accept(pages) 68 | // 一次性捕获 69 | if (bookLore.size > 1 && bookLore[1] == "§0Disposable") { 70 | inputBookMap.remove(e.player.name) 71 | e.player.inventory.takeItem(99) { item -> 72 | item.hasLore("Features Input") 73 | } 74 | } 75 | } 76 | } 77 | } 78 | 79 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/item/ItemRepository.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.item 2 | 3 | import org.bukkit.Bukkit 4 | import org.bukkit.inventory.ItemStack 5 | import taboolib.common.LifeCycle 6 | import taboolib.common.platform.Awake 7 | import taboolib.common.platform.Schedule 8 | import taboolib.common.platform.function.submit 9 | import taboolib.library.xseries.getItemStack 10 | import taboolib.library.xseries.setItemStack 11 | import taboolib.module.configuration.Config 12 | import taboolib.module.configuration.Configuration 13 | 14 | /** 15 | * @author Arasple 16 | * @date 2020/7/26 8:53 17 | */ 18 | object ItemRepository { 19 | 20 | @Config("data/itemRepository.yml") 21 | private lateinit var data: Configuration 22 | private var writing = false 23 | val itemStacks = mutableMapOf() 24 | 25 | @Schedule(delay = 20 * 60, period = 20 * 60, async = true) 26 | fun saveTask() = save(false) 27 | 28 | @Awake(LifeCycle.DISABLE) 29 | fun cancel() = save(true) 30 | 31 | private fun save(isCanceling: Boolean) { 32 | writing = true 33 | data.getKeys(true).filter { !itemStacks.keys.contains(it) }.forEach { data[it] = null } 34 | itemStacks.forEach { (id, item) -> data.setItemStack(id, item) } 35 | data.saveToFile() 36 | if (!isCanceling) submit(delay = 2L, async = !Bukkit.isPrimaryThread()) { writing = false } 37 | } 38 | 39 | @Schedule(delay = 20) 40 | fun load() { 41 | if (writing) return 42 | val keys = data.getKeys(true).toMutableList() 43 | itemStacks.clear() 44 | keys.removeIf { 45 | data.getItemStack(it)?.let { item -> 46 | itemStacks[it] = item 47 | return@removeIf true 48 | } 49 | false 50 | } 51 | keys.forEach { data[it] = null } 52 | } 53 | 54 | fun getItem(id: String): ItemStack? = itemStacks[id] 55 | 56 | fun hasItem(id: String) = itemStacks.containsKey(id) 57 | 58 | fun addItem(id: String, itemStack: ItemStack) = itemStacks.put(id, itemStack.clone()) 59 | 60 | fun removeItem(id: String) = itemStacks.remove(id) 61 | 62 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/item/ItemSource.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.item 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import trplugins.menu.module.internal.hook.HookPlugin 5 | import trplugins.menu.module.internal.hook.impl.HookSkulls 6 | import trplugins.menu.module.internal.script.js.JavaScriptAgent 7 | import org.bukkit.inventory.ItemStack 8 | import trplugins.menu.api.event.CustomItemSourceEvent 9 | import trplugins.menu.module.internal.script.asItemStack 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2021/1/27 12:04 14 | */ 15 | object ItemSource { 16 | 17 | fun fromSource(session: MenuSession, string: String): ItemStack? { 18 | val identifier = string.split(":", "=", limit = 2) 19 | val name = identifier[0].replace("-", "").uppercase() 20 | val id = identifier[1] 21 | 22 | return when (name) { 23 | "HEADDATABASE", "HDB" -> { 24 | if (id.equals("RANDOM", true)) HookPlugin.getHeadDatabase().getRandomHead() 25 | else HookPlugin.getHeadDatabase().getHead(id) 26 | } 27 | "SKULLS" -> { 28 | if (id.equals("RANDOM", true)) HookPlugin[HookSkulls::class.java].getRandomSkull() 29 | else HookPlugin[HookSkulls::class.java].getSkull(id) 30 | } 31 | "JAVASCRIPT", "JS" -> JavaScriptAgent.eval(session, id).asItemStack() 32 | "ORAXEN" -> HookPlugin.getOraxen().getItem(id) 33 | "ITEMSADDER", "IA" -> HookPlugin.getItemsAdder().getItem(id) 34 | "ZAPHKIEL", "ZL" -> HookPlugin.getZaphkiel().getItem(id) 35 | else -> CustomItemSourceEvent(name, id, session).also { it.call() }.source 36 | } 37 | } 38 | 39 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/listener/ListenerBukkitInventory.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.listener 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import org.bukkit.entity.Player 5 | import org.bukkit.event.entity.PlayerDeathEvent 6 | import org.bukkit.event.inventory.InventoryOpenEvent 7 | import org.bukkit.event.player.PlayerChangedWorldEvent 8 | import taboolib.common.platform.event.EventPriority 9 | import taboolib.common.platform.event.SubscribeEvent 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2020/7/30 11:38 14 | * Fix the Bukkit inventory GUI incompatibility with other plugins 15 | */ 16 | object ListenerBukkitInventory { 17 | 18 | @SubscribeEvent(priority = EventPriority.HIGHEST) 19 | fun e(e: InventoryOpenEvent) { 20 | val player = e.player as Player 21 | 22 | MenuSession.getSession(player).close(closePacket = true, updateInventory = true) 23 | } 24 | 25 | @SubscribeEvent(priority = EventPriority.HIGHEST) 26 | fun e(e: PlayerChangedWorldEvent) { 27 | MenuSession.getSession(e.player).shut() 28 | } 29 | 30 | @SubscribeEvent(priority = EventPriority.HIGHEST) 31 | fun e(e: PlayerDeathEvent) { 32 | MenuSession.getSession(e.entity).shut() 33 | } 34 | 35 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/listener/ListenerCommand.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.listener 2 | 3 | import trplugins.menu.api.event.MenuOpenEvent 4 | import trplugins.menu.module.display.Menu 5 | import org.bukkit.event.player.PlayerCommandPreprocessEvent 6 | import taboolib.common.platform.event.EventPriority 7 | import taboolib.common.platform.event.SubscribeEvent 8 | 9 | 10 | /** 11 | * @author Arasple 12 | * @date 2020/2/29 17:43 13 | */ 14 | object ListenerCommand { 15 | 16 | @SubscribeEvent(priority = EventPriority.HIGHEST, ignoreCancelled = true) 17 | fun onCommand(e: PlayerCommandPreprocessEvent) { 18 | val player = e.player 19 | val message = e.message.removePrefix("/") 20 | 21 | if (message.isNotBlank()) { 22 | Menu.menus.forEach { 23 | val matches = it.settings.matchCommand(it, message) 24 | if (matches != null) { 25 | it.open(player, reason = MenuOpenEvent.Reason.BINDING_COMMANDS) { session -> 26 | session.arguments = matches.toTypedArray() 27 | } 28 | e.isCancelled = true 29 | return 30 | } 31 | } 32 | } 33 | } 34 | 35 | 36 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/listener/ListenerItemInteract.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.listener 2 | 3 | import trplugins.menu.TrMenu 4 | import trplugins.menu.api.event.MenuOpenEvent 5 | import trplugins.menu.module.display.Menu 6 | import trplugins.menu.module.display.MenuSession 7 | import trplugins.menu.util.reloadable 8 | import org.bukkit.event.player.PlayerInteractEvent 9 | import org.bukkit.inventory.EquipmentSlot 10 | import org.bukkit.inventory.Inventory 11 | import taboolib.common.platform.event.EventPriority 12 | import taboolib.common.platform.event.SubscribeEvent 13 | import taboolib.common5.Baffle 14 | import taboolib.module.nms.MinecraftVersion 15 | import java.util.concurrent.TimeUnit 16 | 17 | /** 18 | * @author Arasple 19 | * @date 2021/1/29 17:18 20 | */ 21 | object ListenerItemInteract { 22 | 23 | internal val interactCooldown = reloadable { 24 | Baffle.of(TrMenu.SETTINGS.getLong("Menu.Settings.Bound-Item-Interval", 2000), TimeUnit.MILLISECONDS) 25 | } 26 | 27 | @SubscribeEvent(priority = EventPriority.HIGHEST) 28 | fun onInteract(e: PlayerInteractEvent) { 29 | ListenerItemInteract::interactCooldown.get() 30 | 31 | if (MinecraftVersion.majorLegacy >= 10900 && e.hand == EquipmentSlot.OFF_HAND) return 32 | val player = e.player 33 | val item = e.item ?: return 34 | val session = MenuSession.getSession(player) 35 | 36 | if (player.openInventory.topInventory.holder != (player.inventory as Inventory).holder || session.menu != null) return 37 | if (interactCooldown.value.hasNext(player.name)) { 38 | val menu = Menu.menus.find { it -> it.settings.boundItems.any { it.itemMatches(item, true) } } 39 | if (menu != null) { 40 | e.isCancelled = true 41 | menu.open(player, reason = MenuOpenEvent.Reason.BINDING_ITEMS) 42 | } 43 | } 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/listener/ListenerJoin.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.listener 2 | 3 | import trplugins.menu.module.internal.data.Metadata 4 | import trplugins.menu.util.bukkit.Heads 5 | import org.bukkit.event.player.PlayerJoinEvent 6 | import taboolib.common.platform.event.SubscribeEvent 7 | import taboolib.common.platform.function.submit 8 | 9 | /** 10 | * @author Arasple 11 | * @date 2021/1/27 12:14 12 | */ 13 | object ListenerJoin { 14 | 15 | @SubscribeEvent 16 | fun onJoin(e: PlayerJoinEvent) { 17 | val player = e.player 18 | 19 | submit(async = true) { 20 | // 缓存玩家头颅备用 21 | Heads.getPlayerHead(player.name) 22 | // 加载 Metadata - Data 数据 23 | Metadata.loadData(player) 24 | } 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/listener/ListenerQuit.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.listener 2 | 3 | import trplugins.menu.module.display.Menu 4 | import trplugins.menu.module.display.MenuSession 5 | import trplugins.menu.module.internal.data.Metadata 6 | import org.bukkit.event.player.PlayerQuitEvent 7 | import taboolib.common.platform.event.SubscribeEvent 8 | import taboolib.common.platform.function.submit 9 | import trplugins.menu.api.receptacle.setViewingReceptacle 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2021/1/27 12:14 14 | */ 15 | object ListenerQuit { 16 | 17 | @SubscribeEvent 18 | fun onQuit(e: PlayerQuitEvent) { 19 | val player = e.player 20 | val session = MenuSession.getSession(player) 21 | session.shut() 22 | submit(async = true) { 23 | Metadata.pushData(player) 24 | } 25 | Menu.menus.forEach { 26 | it.icons.forEach { icon -> icon.onReset(session) } 27 | } 28 | MenuSession.removeSession(player) 29 | player.setViewingReceptacle(null) 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/migrate/config/MigrateConfig.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.migrate.config 2 | 3 | abstract class MigrateConfig() { 4 | 5 | abstract fun migrate() 6 | 7 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/migrate/plugin/MigrateDeluxeMenus.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.migrate.plugin 2 | 3 | import com.extendedclip.deluxemenus.menu.Menu 4 | import org.bukkit.event.inventory.InventoryType 5 | import taboolib.module.configuration.Configuration 6 | 7 | /** 8 | * @author Arasp 9 | * @date 2021/2/20 19:07 10 | */ 11 | object MigrateDeluxeMenus : MigratePlugin("DeluxeMenus") { 12 | 13 | override fun migrate() { 14 | Menu.getAllMenus().forEach { 15 | val name = it.menuName 16 | val defUpdate = it.updateInterval 17 | Configuration.empty().run { 18 | 19 | if (it.inventoryType != InventoryType.CHEST) { 20 | this["Type"] = it.name 21 | } 22 | if (it.menuCommands.isNotEmpty()) { 23 | this["Bindings.Commands"] = it.menuCommands 24 | } 25 | it.openHandler 26 | this["Title"] = it.menuTitle 27 | this["Size"] = it.size 28 | this["Icons"] = it.menuItems 29 | 30 | it.menuItems 31 | it.openHandler 32 | it.closeHandler 33 | it.registersCommand() 34 | } 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/migrate/plugin/MigratePlugin.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.migrate.plugin 2 | 3 | import trplugins.menu.module.internal.hook.HookAbstract 4 | 5 | /** 6 | * @author Arasple 7 | * @date 2021/1/27 12:14 8 | */ 9 | abstract class MigratePlugin(override val name: String) : HookAbstract() { 10 | 11 | abstract fun migrate() 12 | 13 | override fun getPluginName(): String { 14 | return name 15 | } 16 | 17 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/Script.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script 2 | 3 | import org.bukkit.entity.Player 4 | import org.bukkit.inventory.ItemStack 5 | import taboolib.common.platform.ProxyPlayer 6 | import trplugins.menu.api.TrMenuAPI 7 | import trplugins.menu.util.EvalResult 8 | import trplugins.menu.module.display.MenuSession 9 | import trplugins.menu.module.display.session 10 | import trplugins.menu.module.internal.script.js.JavaScriptAgent 11 | 12 | /** 13 | * TrMenu 14 | * trmenu.module.internal.script.Script 15 | * 16 | * @author Score2 17 | * @since 2022/01/09 17:48 18 | */ 19 | 20 | fun EvalResult.asItemStack(): ItemStack? { 21 | return any as ItemStack? 22 | } 23 | 24 | // in Condition.Companion 25 | fun MenuSession.evalScript(script: String?): EvalResult { 26 | return placeholderPlayer.evalScript(script) 27 | } 28 | 29 | // in Condition 30 | fun String.evalScript(session: MenuSession): EvalResult { 31 | return if (isEmpty()) EvalResult.TRUE 32 | else session.placeholderPlayer.evalScript(this) 33 | } 34 | 35 | fun ProxyPlayer.evalScript(script: String?) = 36 | cast().evalScript(script) 37 | 38 | fun Player.evalScript(script: String?): EvalResult { 39 | script ?: return EvalResult(null) 40 | val (isJavaScript, js) = JavaScriptAgent.serialize(script) 41 | return if (isJavaScript) JavaScriptAgent.eval(MenuSession.getSession(this), js!!) 42 | else TrMenuAPI.instantKether(this, script) 43 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/StaticParser.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script 2 | 3 | /** 4 | * @project TrMenu 5 | * 6 | * @author Score2 7 | * @since 2021/09/30 0:37 8 | */ 9 | object StaticParser { 10 | 11 | 12 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherData.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.module.internal.data.Metadata 4 | import trplugins.menu.module.internal.script.kether.BaseAction 5 | import trplugins.menu.module.internal.script.kether.EditType 6 | import trplugins.menu.module.internal.script.kether.EditType.* 7 | import taboolib.library.kether.ParsedAction 8 | import taboolib.library.kether.ArgTypes 9 | import taboolib.library.kether.LocalizedException 10 | import taboolib.library.kether.QuestContext 11 | import taboolib.module.kether.KetherParser 12 | import taboolib.module.kether.scriptParser 13 | import java.util.concurrent.CompletableFuture 14 | 15 | /** 16 | * @author Arasple 17 | * @date 2021/1/29 10:17 18 | */ 19 | class KetherData(val type: EditType, private val source: ParsedAction<*>, private val apply: ParsedAction<*>?) : 20 | BaseAction() { 21 | 22 | override fun process(context: QuestContext.Frame): CompletableFuture { 23 | val viewer = context.viewer() 24 | 25 | return context.newFrame(source).run().thenApply { 26 | when (type) { 27 | DEL -> Metadata.getData(viewer).remove(it) 28 | SET -> { 29 | apply?.let { it1 -> 30 | context.newFrame(it1).run().thenApply { apply -> 31 | Metadata.getData(viewer)[it] = apply 32 | } 33 | } 34 | } 35 | GET -> Metadata.getData(viewer)[it] 36 | HAS -> Metadata.getData(viewer).data.containsKey(it) 37 | } 38 | 39 | } 40 | 41 | } 42 | 43 | companion object { 44 | 45 | @KetherParser(["data"], namespace = "trmenu", shared = true) 46 | fun parser() = scriptParser { 47 | val type = when (it.nextToken().lowercase()) { 48 | "del" -> DEL 49 | "set" -> SET 50 | "get" -> GET 51 | else -> throw LocalizedException.of("unknown type") 52 | } 53 | val key = it.next(ArgTypes.ACTION) 54 | it.mark() 55 | KetherData( 56 | type, key, 57 | try { 58 | it.expect("to") 59 | it.next(ArgTypes.ACTION) 60 | } catch (ignored: Exception) { 61 | it.reset() 62 | null 63 | } 64 | ) 65 | } 66 | 67 | } 68 | 69 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherItem.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.module.internal.script.kether.BaseAction 4 | import trplugins.menu.util.bukkit.ItemMatcher 5 | import taboolib.library.kether.ArgTypes 6 | import taboolib.library.kether.ParsedAction 7 | import taboolib.library.kether.QuestContext 8 | import taboolib.module.kether.KetherParser 9 | import taboolib.module.kether.scriptParser 10 | import java.util.concurrent.CompletableFuture 11 | 12 | /** 13 | * @author Arasple 14 | * @date 2021/2/4 15:24 15 | */ 16 | class KetherItem(private val itemMatcher: ParsedAction<*>) : BaseAction() { 17 | 18 | override fun process(context: QuestContext.Frame): CompletableFuture { 19 | return context.newFrame(itemMatcher).run().thenApply { 20 | ItemMatcher.eval(it.toString()).hasItem(context.viewer()) 21 | } 22 | } 23 | 24 | companion object { 25 | 26 | @KetherParser(["item"], namespace = "trmenu", shared = true) 27 | fun parser() = scriptParser { 28 | KetherItem(it.next(ArgTypes.ACTION)) 29 | } 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherMathCheck.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.module.internal.script.kether.BaseAction 4 | import taboolib.library.kether.ArgTypes 5 | import taboolib.library.kether.ParsedAction 6 | import taboolib.library.kether.QuestContext 7 | import taboolib.module.kether.KetherParser 8 | import taboolib.module.kether.scriptParser 9 | import java.util.concurrent.CompletableFuture 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2021/4/2 17:10 14 | * mtc 15 | */ 16 | class KetherMathCheck(val type: Type, val menu: ParsedAction<*>?) : BaseAction() { 17 | 18 | enum class Type { 19 | 20 | INT, 21 | 22 | DOUBLE 23 | 24 | } 25 | 26 | override fun process(context: QuestContext.Frame): CompletableFuture? { 27 | return menu?.let { 28 | context.newFrame(it).run().thenApply { 29 | when (type) { 30 | Type.INT -> it.toIntOrNull() != null 31 | Type.DOUBLE -> it.toDoubleOrNull() != null 32 | } 33 | } 34 | } 35 | } 36 | 37 | companion object { 38 | 39 | @KetherParser(["mathcheck", "mtc"], namespace = "trmenu", shared = true) 40 | fun parser() = scriptParser { 41 | val type = Type.valueOf(it.nextToken().uppercase()) 42 | KetherMathCheck( 43 | type, 44 | it.next(ArgTypes.ACTION) 45 | ) 46 | } 47 | 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherMenu.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.api.TrMenuAPI 4 | import trplugins.menu.api.event.MenuOpenEvent 5 | import trplugins.menu.module.internal.script.kether.BaseAction 6 | import taboolib.library.kether.ArgTypes 7 | import taboolib.library.kether.ParsedAction 8 | import taboolib.library.kether.QuestContext 9 | import taboolib.module.kether.KetherParser 10 | import taboolib.module.kether.scriptParser 11 | import java.util.concurrent.CompletableFuture 12 | import kotlin.math.min 13 | 14 | /** 15 | * @author Arasple 16 | * @date 2021/1/29 10:17 17 | */ 18 | class KetherMenu(val type: Type, val menu: ParsedAction<*>?) : BaseAction() { 19 | 20 | enum class Type { 21 | 22 | OPEN, 23 | 24 | PAGE, 25 | 26 | CLOSE 27 | 28 | } 29 | 30 | override fun process(context: QuestContext.Frame): CompletableFuture { 31 | val viewer = context.viewer() 32 | val session = viewer.session() 33 | 34 | when (type) { 35 | Type.CLOSE -> session?.close(closePacket = true, updateInventory = true) 36 | Type.PAGE -> menu?.let { 37 | context.newFrame(it).run().thenApply { 38 | val menu = session?.menu ?: return@thenApply false 39 | val page = min(it.coerceAtLeast(0), menu.layout.getSize() - 1) 40 | 41 | menu.page(viewer, page) 42 | } 43 | } 44 | Type.OPEN -> menu?.let { 45 | context.newFrame(it).run().thenApply { 46 | TrMenuAPI.getMenuById(it)?.open(context.viewer(), reason = MenuOpenEvent.Reason.CONSOLE) 47 | } 48 | } 49 | } 50 | 51 | return completableFuture 52 | } 53 | 54 | companion object { 55 | 56 | @KetherParser(["menu"], namespace = "trmenu", shared = true) 57 | fun parser() = scriptParser { 58 | val type = Type.valueOf(it.nextToken().uppercase()) 59 | KetherMenu( 60 | type, 61 | if (type != Type.CLOSE) it.next(ArgTypes.ACTION) else null 62 | ) 63 | } 64 | 65 | } 66 | 67 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherMeta.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.module.internal.data.Metadata 4 | import trplugins.menu.module.internal.script.kether.BaseAction 5 | import trplugins.menu.module.internal.script.kether.EditType 6 | import trplugins.menu.module.internal.script.kether.EditType.* 7 | import taboolib.library.kether.ArgTypes 8 | import taboolib.library.kether.LocalizedException 9 | import taboolib.library.kether.ParsedAction 10 | import taboolib.library.kether.QuestContext 11 | import taboolib.module.kether.KetherParser 12 | import taboolib.module.kether.scriptParser 13 | import java.util.concurrent.CompletableFuture 14 | 15 | /** 16 | * @author Arasple 17 | * @date 2021/1/29 10:17 18 | * meta get/del [key] 19 | * meta set [key] to [value] 20 | */ 21 | class KetherMeta(val type: EditType, private val source: ParsedAction<*>, private val apply: ParsedAction<*>?) : 22 | BaseAction() { 23 | 24 | override fun process(context: QuestContext.Frame): CompletableFuture { 25 | val viewer = context.viewer() 26 | 27 | return context.newFrame(source).run().thenApply { 28 | when (type) { 29 | DEL -> Metadata.getMeta(viewer).remove(it) 30 | SET -> { 31 | apply?.let { it1 -> 32 | context.newFrame(it1).run().thenApply { apply -> 33 | Metadata.getMeta(viewer)[it] = apply 34 | } 35 | } 36 | } 37 | GET -> Metadata.getMeta(viewer)[it] 38 | HAS -> Metadata.getMeta(viewer).data.containsKey(it) 39 | } 40 | } 41 | } 42 | 43 | companion object { 44 | 45 | @KetherParser(["meta"], namespace = "trmenu", shared = true) 46 | fun parser() = scriptParser { 47 | 48 | val type = when (it.nextToken().lowercase()) { 49 | "del" -> DEL 50 | "set" -> SET 51 | "get" -> GET 52 | else -> throw LocalizedException.of("unknown type") 53 | } 54 | val key = it.next(ArgTypes.ACTION) 55 | it.mark() 56 | KetherMeta( 57 | type, key, 58 | try { 59 | it.expect("to") 60 | it.next(ArgTypes.ACTION) 61 | } catch (ignored: Exception) { 62 | it.reset() 63 | null 64 | } 65 | ) 66 | } 67 | 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherMoney.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.module.internal.hook.HookPlugin 4 | import trplugins.menu.module.internal.script.kether.BaseAction 5 | import taboolib.library.kether.ArgTypes 6 | import taboolib.library.kether.ParsedAction 7 | import taboolib.library.kether.QuestContext 8 | import taboolib.module.kether.KetherParser 9 | import taboolib.module.kether.scriptParser 10 | import java.util.concurrent.CompletableFuture 11 | 12 | /** 13 | * @author Arasple 14 | * @date 2021/2/4 15:28 15 | */ 16 | class KetherMoney(private val money: ParsedAction<*>) : BaseAction() { 17 | 18 | override fun process(context: QuestContext.Frame): CompletableFuture { 19 | return context.newFrame(money).run().thenApply { 20 | HookPlugin.getVault().hasMoney(context.viewer(), it.toString().toDoubleOrNull() ?: 0.0) 21 | } 22 | } 23 | 24 | companion object { 25 | 26 | @KetherParser(["money", "eco"], namespace = "trmenu", shared = true) 27 | fun parser() = scriptParser { 28 | KetherMoney(it.next(ArgTypes.ACTION)) 29 | } 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherPoints.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.module.internal.hook.HookPlugin 4 | import trplugins.menu.module.internal.script.kether.BaseAction 5 | import taboolib.library.kether.ArgTypes 6 | import taboolib.library.kether.ParsedAction 7 | import taboolib.library.kether.QuestContext 8 | import taboolib.module.kether.KetherParser 9 | import taboolib.module.kether.scriptParser 10 | import java.util.concurrent.CompletableFuture 11 | 12 | /** 13 | * @author Arasple 14 | * @date 2021/2/4 15:28 15 | */ 16 | class KetherPoints(private val points: ParsedAction<*>) : BaseAction() { 17 | 18 | override fun process(context: QuestContext.Frame): CompletableFuture { 19 | return context.newFrame(points).run().thenApply { 20 | HookPlugin.getPlayerPoints().hasPoints(context.viewer(), it.toString().toIntOrNull() ?: 0) 21 | } 22 | } 23 | 24 | companion object { 25 | 26 | @KetherParser(["points"], namespace = "trmenu", shared = true) 27 | fun parser() = scriptParser { 28 | KetherPoints(it.next(ArgTypes.ACTION)) 29 | } 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/impl/KetherVars.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.impl 2 | 3 | import trplugins.menu.module.internal.script.kether.BaseAction 4 | import taboolib.library.kether.ArgTypes 5 | import taboolib.library.kether.ParsedAction 6 | import taboolib.library.kether.QuestContext 7 | import taboolib.module.kether.KetherParser 8 | import taboolib.module.kether.scriptParser 9 | import java.util.concurrent.CompletableFuture 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2021/2/8 21:52 14 | */ 15 | class KetherVars(private val source: ParsedAction<*>) : BaseAction() { 16 | 17 | override fun process(context: QuestContext.Frame): CompletableFuture { 18 | return context.newFrame(source).run().thenApply { 19 | context.viewer().session()?.parse(it.toString().trimIndent()) 20 | } 21 | } 22 | 23 | companion object { 24 | 25 | @KetherParser(["vars", "var"], namespace = "trmenu", shared = true) 26 | fun parser() = scriptParser { 27 | KetherVars(it.next(ArgTypes.ACTION)) 28 | } 29 | 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/js/ScriptFunction.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.js 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import trplugins.menu.util.EvalResult 5 | 6 | /** 7 | * @author Arasple 8 | * @date 2021/2/3 8:34 9 | */ 10 | data class ScriptFunction(val id: String, private val raw: String) { 11 | 12 | private val hasFunction = raw.contains("function") 13 | private val hasReturn = raw.contains("return") 14 | private val basement = if (hasFunction) raw else "function def() { ${if (hasReturn) "" else "return"} $raw } def()" 15 | 16 | fun compile(session: MenuSession, args: List): EvalResult { 17 | val array = "var args = new Array(${args.joinToString("\", \"", "\"", "\"")})" 18 | val content = "$array\n$basement" 19 | 20 | return JavaScriptAgent.eval( 21 | session, 22 | content 23 | ) 24 | } 25 | 26 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/kether/BaseAction.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.kether 2 | 3 | import trplugins.menu.module.display.MenuSession 4 | import org.bukkit.command.CommandSender 5 | import org.bukkit.entity.Player 6 | import taboolib.library.kether.QuestAction 7 | import taboolib.library.kether.QuestContext 8 | import taboolib.module.kether.ScriptContext 9 | import java.util.concurrent.CompletableFuture 10 | 11 | /** 12 | * @author Arasple 13 | * @date 2021/1/29 10:18 14 | */ 15 | abstract class BaseAction : QuestAction() { 16 | 17 | internal val completableFuture: CompletableFuture = CompletableFuture.completedFuture(null) 18 | 19 | fun CommandSender.session(): MenuSession? { 20 | return if (this is Player) MenuSession.getSession(this) else null 21 | } 22 | 23 | fun QuestContext.Frame.viewer(): Player { 24 | return ((this.context() as ScriptContext).sender ?: throw RuntimeException("No viewer found")).cast() 25 | } 26 | 27 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/script/kether/EditType.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.script.kether 2 | 3 | /** 4 | * @author Arasp 5 | * @date 2021/2/24 11:24 6 | */ 7 | enum class EditType { 8 | 9 | DEL, 10 | SET, 11 | GET, 12 | HAS 13 | 14 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/service/Metrics.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.service 2 | 3 | import trplugins.menu.module.display.Menu 4 | import org.bukkit.event.inventory.InventoryType 5 | import taboolib.common.LifeCycle 6 | import taboolib.common.platform.Awake 7 | import taboolib.common.platform.Platform 8 | import taboolib.common.platform.function.pluginVersion 9 | import taboolib.module.metrics.Metrics 10 | import taboolib.module.metrics.charts.* 11 | 12 | /** 13 | * @author Arasple 14 | * @date 2020/3/7 22:15 15 | */ 16 | object Metrics { 17 | 18 | private val B_STATS: Metrics by lazy { Metrics(5742, pluginVersion, Platform.BUKKIT) } 19 | var menuOpenCounts = 0 20 | get() { 21 | val count = field 22 | field = 0 23 | return count 24 | } 25 | 26 | 27 | 28 | @Awake(LifeCycle.INIT) 29 | fun initialization() { 30 | B_STATS.let { metrics -> 31 | metrics.addCustomChart(SingleLineChart("menus") { 32 | Menu.menus.sumOf { menu -> menu.layout.getSize() } 33 | }) 34 | metrics.addCustomChart(SingleLineChart("menu_open_counts") { 35 | menuOpenCounts 36 | }) 37 | 38 | metrics.addCustomChart(AdvancedPie("menu_size") { 39 | val value = mutableMapOf() 40 | 41 | Menu.menus 42 | .flatMap { 43 | it.layout.layouts.filter { it.type == InventoryType.CHEST } 44 | }.forEach { 45 | value[it.rows.toString()] = value.computeIfAbsent(it.rows.toString()) { 0 } + 1 46 | } 47 | 48 | value 49 | }) 50 | 51 | metrics.addCustomChart(AdvancedPie("item_texture") { 52 | val value = mutableMapOf() 53 | 54 | Menu.menus 55 | .flatMap { 56 | val list = it.icons.map { icon -> icon.defIcon.display }.toMutableList() 57 | list.addAll(it.icons.flatMap { icon -> icon.subs.elements.map { sub -> sub.display } }) 58 | list.flatMap { it.texture.elements } 59 | }.forEach { 60 | value[it.type.name] = value.computeIfAbsent(it.type.name) { 0 } + 1 61 | } 62 | 63 | value 64 | }) 65 | 66 | metrics.addCustomChart(AdvancedPie("inventory_type") { 67 | val value = mutableMapOf() 68 | 69 | Menu.menus 70 | .flatMap { 71 | it.layout.layouts.toList() 72 | }.forEach { 73 | value[it.type.name] = value.computeIfAbsent(it.type.name) { 0 } + 1 74 | } 75 | 76 | value 77 | }) 78 | } 79 | } 80 | 81 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/module/internal/service/Performance.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.module.internal.service 2 | 3 | import taboolib.common.platform.ProxyCommandSender 4 | import taboolib.common5.Mirror 5 | 6 | 7 | /** 8 | * @author Arasple 9 | * @date 2021/2/6 19:31 10 | */ 11 | object Performance { 12 | 13 | fun collect(sender: ProxyCommandSender, opt: Mirror.MirrorSettings.() -> Unit = {}): Mirror.MirrorCollect { 14 | return Mirror.report(sender, opt) 15 | } 16 | 17 | @Suppress("DEPRECATION") 18 | inline fun check(id: String, func: () -> Unit) { 19 | Mirror.mirrorData.computeIfAbsent(id) { Mirror.MirrorData() }.define() 20 | func() 21 | Mirror.mirrorData[id]?.finish() 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /plugin/src/main/kotlin/trplugins/menu/util/Bungees.kt: -------------------------------------------------------------------------------- 1 | package trplugins.menu.util 2 | 3 | import trplugins.menu.TrMenu 4 | import org.bukkit.Bukkit 5 | import org.bukkit.entity.Player 6 | import java.io.ByteArrayOutputStream 7 | import java.io.DataOutputStream 8 | import java.io.IOException 9 | 10 | /** 11 | * @author Arasple 12 | * @date 2020/3/8 21:19 13 | */ 14 | object Bungees { 15 | 16 | init { 17 | if (!Bukkit.getMessenger().isOutgoingChannelRegistered(TrMenu.plugin, "BungeeCord")) { 18 | Bukkit.getMessenger().registerOutgoingPluginChannel(TrMenu.plugin, "BungeeCord") 19 | } 20 | } 21 | 22 | fun connect(player: Player, server: String) = sendBungeeData(player, "Connect", server) 23 | 24 | fun sendBungeeData(player: Player, vararg args: String) { 25 | val byteArray = ByteArrayOutputStream() 26 | val out = DataOutputStream(byteArray) 27 | for (arg in args) { 28 | try { 29 | out.writeUTF(arg) 30 | } catch (e: IOException) { 31 | e.printStackTrace() 32 | } 33 | } 34 | player.sendPluginMessage(TrMenu.plugin, "BungeeCord", byteArray.toByteArray()) 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /plugin/src/main/resources/data/globalData.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsinuateProjects/TrMenu/b45749c36a5e431aa0b2256b50bd58d2c5713459/plugin/src/main/resources/data/globalData.yml -------------------------------------------------------------------------------- /plugin/src/main/resources/data/itemRepository.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InsinuateProjects/TrMenu/b45749c36a5e431aa0b2256b50bd58d2c5713459/plugin/src/main/resources/data/itemRepository.yml -------------------------------------------------------------------------------- /plugin/src/main/resources/menus/Demo-Buttons.yml: -------------------------------------------------------------------------------- 1 | Title: 'Demo-Buttons' 2 | 3 | Layout: 4 | - '' 5 | - ' A B C ' 6 | - '' 7 | 8 | Icons: 9 | A: 10 | display: 11 | material: stone 12 | actions: 13 | all: 14 | - 'sound: ENTITY_EXPERIENCE_ORB_PICKUP' 15 | left: 16 | - close 17 | - catcher: 18 | player: 19 | type: CHAT 20 | start: 'tell: &3请输入转账玩家' 21 | cancel: 'tell: &7已取消操作' 22 | end: 23 | - condition: '$ utils.isPlayerOnline(vars("{meta:input}"))' 24 | deny: 25 | - 'tell: &c目标玩家未在线' 26 | - 'return' 27 | money: 28 | type: CHAT 29 | start: 'tell: &a请输入转账金额' 30 | cancel: 'tell: &7已取消操作' 31 | end: 32 | - condition: 'all [ mtc int &input check &input > *0 ]' 33 | actions: 34 | - 'tell: 操作成功' 35 | - 'tell: pay %trmenu_meta_input-player% %trmenu_meta_input-money%' 36 | deny: 37 | - 'tell: &c请输入有效数额' 38 | -------------------------------------------------------------------------------- /plugin/src/main/resources/menus/Profile.yml: -------------------------------------------------------------------------------- 1 | Title: 'Profile: &f{0}' 2 | 3 | Events: 4 | Open: 5 | - condition: '$ utils.isPlayerOnline(vars("{0}"))' 6 | deny: 7 | - 'tell: &7Player &f{0} &7is not online.' 8 | - 'sound: ENTITY_ITEM_BREAK-1-0' 9 | - 'return' 10 | list: 11 | - 'sound: BLOCK_CHEST_OPEN-1-0' 12 | 13 | Bindings: 14 | Commands: 'profiles?' 15 | 16 | Tasks: 17 | profileService: 18 | period: 15 19 | task: 20 | - condition: '$ utils.isPlayerOnline(vars("{0}"))' 21 | action: 'refresh: H;C;L;B;R;Z' 22 | deny: 23 | - 'tell: &7Player &f{0} &7is offline now.' 24 | - 'close' 25 | 26 | Layout: 27 | - '||#||||||' 28 | - '|#H#| |' 29 | - '|RCZ| - |' 30 | - '|#L#| - |' 31 | - '|#B#| |' 32 | - '||#||||||' 33 | 34 | Icons: 35 | 36 | '#': 37 | display: 38 | material: Cyan Stained Glass Pane 39 | 40 | '-': 41 | display: 42 | material: Brown Stained Glass Pane 43 | '|': 44 | display: 45 | material: Black Stained Glass Pane 46 | 47 | 'H': 48 | display: 49 | material: 'source:JS:utils.getEquipment(vars("{0}"), "HEAD")' 50 | icons: 51 | - condition: '$ !utils.hasEquipment(vars("{0}"), "HEAD")' 52 | display: 53 | name: '&3{0}' 54 | material: 'head:{0}' 55 | 56 | 'C': 57 | display: 58 | material: 'source:JS:utils.getEquipment(vars("{0}"), "CHEST")' 59 | icons: 60 | - condition: '$ !utils.hasEquipment(vars("{0}"), "CHEST")' 61 | display: 62 | name: '%server_time_ss%%' 63 | material: Gray Stained Glass Pane 64 | 65 | 'L': 66 | display: 67 | material: 'source:JS:utils.getEquipment(vars("{0}"), "LEGS")' 68 | icons: 69 | - condition: '$ !utils.hasEquipment(vars("{0}"), "LEGS")' 70 | display: 71 | material: Gray Stained Glass Pane 72 | 73 | 'B': 74 | display: 75 | material: 'source:JS:utils.getEquipment(vars("{0}"), "FEET")' 76 | icons: 77 | - condition: '$ !utils.hasEquipment(vars("{0}"), "FEET")' 78 | display: 79 | material: Gray Stained Glass Pane 80 | 81 | 'R': 82 | display: 83 | material: 'source:JS:utils.getEquipment(vars("{0}"), "MAINHAND")' 84 | icons: 85 | - condition: '$ !utils.hasEquipment(vars("{0}"), "MAINHAND")' 86 | display: 87 | material: Gray Stained Glass Pane 88 | 89 | 'Z': 90 | display: 91 | material: 'source:JS:utils.getEquipment(vars("{0}"), "OFFHAND")' 92 | icons: 93 | - condition: '$ !utils.hasEquipment(vars("{0}"), "OFFHAND")' 94 | display: 95 | material: Gray Stained Glass Pane -------------------------------------------------------------------------------- /plugin/src/main/resources/menus/shop-example/Shop-Categories.yml: -------------------------------------------------------------------------------- 1 | Title: 'TrMenu Shop (Example)' 2 | 3 | # 4 | # UI_BUTTON_CLICK 5 | # BLOCK_NOTE_BLOCK_PLING 6 | # 7 | # 8 | 9 | Bindings: 10 | Commands: 11 | - '(?i)shops?-?(guis?)?' 12 | 13 | Layout: 14 | - '#########' 15 | - '| |' 16 | - '| A B C |' 17 | - '| |' 18 | - '#########' 19 | 20 | Events: 21 | Open: 22 | - 'sound: BLOCK_IRON_DOOR_OPEN-1-2' 23 | Close: 24 | - 'sound: BLOCK_IRON_DOOR_CLOSE-1-2' 25 | 26 | Icons: 27 | 28 | '#': 29 | display: 30 | material: gray stained glass pane 31 | name: '&8Shop (Example) by TrMenu' 32 | '|': 33 | display: 34 | material: black stained glas pane 35 | name: '&8Shop (Example) by TrMenu' 36 | 37 | 'A': 38 | update: 10 39 | display: 40 | material: 41 | - 'coal ore' 42 | - 'iron ore' 43 | - 'gold ore' 44 | - 'redstone ore' 45 | - 'diamond ore' 46 | - 'emerald ore' 47 | name: '&a&lORES' 48 | lore: 49 | - '' 50 | - '&7Purchase & Sell ores' 51 | - '' 52 | - '&b➥ &3Click to browse' 53 | actions: 54 | all: 55 | - 'sound: UI_BUTTON_CLICK-1-2' 56 | - 'menu: Shop-Ores' 57 | -------------------------------------------------------------------------------- /plugin/src/main/resources/menus/shop-example/categories/Shop-Ores.yml: -------------------------------------------------------------------------------- 1 | Title: 'Shop-Ores' 2 | 3 | Layout: 4 | - '########<' 5 | - '01234567' 6 | - ' ' 7 | - ' ' 8 | - '#########' 9 | 10 | Events: 11 | Close: 'trplugins.menu: Shop-Categories' 12 | 13 | Icons: 14 | 15 | '#': 16 | display: 17 | material: black stained glass pane 18 | name: '&7Shop (Example) by TrMenu' 19 | '|': 20 | display: 21 | material: cyan stained glass pane 22 | name: '&7Shop (Example) by TrMenu' 23 | 24 | '<': 25 | display: 26 | material: red stained glass pane 27 | name: '&6Return' 28 | actions: 29 | all: 'trplugins.menu: Shop-Categories' 30 | 31 | '0': 32 | display: 33 | material: coal ore 34 | lore: 35 | - '' 36 | - '&8▪ &7Purchase: &e$20.0' 37 | - '&8▪ &7Sell: &2$3.5' 38 | - '' 39 | - '&e➥ &6Left &8| &6Purchase' 40 | - '&e➥ &6Right &8| &6Sell' 41 | actions: 42 | all: 43 | - 'sound: UI_BUTTON_CLICK-1-2' 44 | left: 45 | - 'trplugins.menu: Shop-Handler-Purchase Shop-Ores COAL_ORE 20 1 64' 46 | right: 47 | - 'trplugins.menu: Shop-Handler-Sell Shop-Ores COAL_ORE 3.5 1 64' -------------------------------------------------------------------------------- /plugin/src/main/resources/settings.yml: -------------------------------------------------------------------------------- 1 | Options: 2 | # High, Normal, Low 3 | Running-Performance: Normal 4 | Multi-Thread: true 5 | Async-Load-Menus: true 6 | Bedrock-Static-Inv: false 7 | 8 | Placeholders: 9 | JavaScript-Parse: false 10 | 11 | Database: 12 | # Local: SQLITE 13 | # External: SQL, MONGODB 14 | Method: SQLITE 15 | Type: 16 | SQLite: 17 | file-name: data 18 | table: npc 19 | SQL: 20 | host: localhost 21 | port: 3306 22 | user: root 23 | password: root 24 | database: test 25 | table: trmenu_user_data 26 | MongoDB: 27 | client: 'mongodb://localhost:3307' 28 | database: trixey 29 | collection: trplugins.menu 30 | Index: 31 | # UUID, USERNAME 32 | Player: USERNAME 33 | 34 | Loader: 35 | Menu-Files: 36 | - 'plugins/CustomMenusFolder' 37 | 38 | Menu: 39 | Settings: 40 | Bound-Item-Interval: 2000 41 | Icon: 42 | Inherit: false 43 | Item: 44 | Default-Name-Color: "&7" 45 | Default-Lore-Color: "&7" 46 | Pre-Color: false 47 | 48 | Action: 49 | Inputer: 50 | Cancel-Words: 51 | - 'cancel|quit|end' 52 | - 'q' 53 | Kether: 54 | Allow-Tolerance-Parser: false 55 | 56 | 57 | Shortcuts: 58 | Offhand: [ ] 59 | Sneaking-Offhand: 60 | - condition: 'perm *trmenu.shortcut' 61 | execute: 'open: Example' 62 | deny: 'return' 63 | Right-Click-Player: 'open: Profile' 64 | Sneaking-Right-Click-Player: [ ] 65 | PlayerInventory-Border-Left: [ ] 66 | PlayerInventory-Border-Right: [ ] 67 | PlayerInventory-Border-Middle: [ ] 68 | 69 | RegisterCommands: 70 | openMenus: 71 | aliases: [ ] 72 | permission: null 73 | execute: 74 | - 'tell: &7Argument `example` Required!' 75 | arguments: 76 | example: 'open: example' 77 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "TrMenu" 2 | 3 | include( 4 | ":common", 5 | ":plugin", 6 | 7 | ":api:receptacle", 8 | ":api:action", 9 | 10 | ":module:database", 11 | ":module:migrate", 12 | ) --------------------------------------------------------------------------------