├── .gitattributes ├── .github └── workflows │ ├── javadoc.yml │ ├── main_17.yml │ └── publish_17.yml ├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── libs ├── DungeonPlus-1.3.1.jar ├── FightSystem-1.0.3-api.jar ├── GermPlugin-4.2.9.jar ├── MythicMobs-4.14.2.jar ├── MythicMobs-5.2.0.jar ├── Pouvoir-1.6.7-beta-api.jar ├── ProSkillAPI-R-1.2.7.jar ├── [插件]DragonCore-2.4.7.jar ├── [插件]DragonCore-3.1.0.2.jar ├── patched_1.16.5.jar └── purpur-1.19.2.jar ├── log.md ├── settings.gradle.kts └── src └── main ├── java └── com │ └── skillw │ └── attsystem │ └── util │ └── LoreMap.java ├── kotlin └── com │ └── skillw │ └── attsystem │ ├── AttributeSystem.kt │ ├── api │ ├── AttrAPI.kt │ ├── AttributeSystemAPI.kt │ ├── attribute │ │ ├── Attribute.kt │ │ ├── Mapping.kt │ │ └── compound │ │ │ ├── AttributeData.kt │ │ │ └── AttributeDataCompound.kt │ ├── compiled │ │ ├── CompiledAttrDataCompound.kt │ │ ├── CompiledData.kt │ │ ├── Evalable.kt │ │ └── sub │ │ │ ├── ComplexCompiledData.kt │ │ │ ├── NBTCompiledData.kt │ │ │ └── StringsCompiledData.kt │ ├── equipment │ │ ├── EquipmentData.kt │ │ ├── EquipmentDataCompound.kt │ │ └── EquipmentLoader.kt │ ├── event │ │ ├── AttributeRegisterEvent.kt │ │ ├── AttributeUpdateEvent.kt │ │ ├── ConditionEvent.kt │ │ ├── EquipmentUpdateEvent.kt │ │ ├── HealthRegainEvent.kt │ │ ├── ItemLoadEvent.kt │ │ ├── ItemNBTReadEvent.kt │ │ ├── ItemReadEvent.kt │ │ ├── StringsReadEvent.kt │ │ └── VanillaAttributeUpdateEvent.kt │ ├── manager │ │ ├── AttributeDataManager.kt │ │ ├── AttributeManager.kt │ │ ├── CompileManager.kt │ │ ├── CompiledAttrDataManager.kt │ │ ├── EquipmentDataManager.kt │ │ ├── ReadManager.kt │ │ ├── ReadPatternManager.kt │ │ └── RealizerManager.kt │ └── read │ │ ├── ReadPattern.kt │ │ └── status │ │ ├── NumberStatus.kt │ │ ├── Status.kt │ │ └── StringStatus.kt │ ├── internal │ ├── command │ │ ├── ASCommand.kt │ │ └── sub │ │ │ ├── AttributeStatsCommand.kt │ │ │ └── MirrorCommand.kt │ ├── core │ │ ├── asahi │ │ │ ├── Operator.kt │ │ │ └── prefix │ │ │ │ └── Attribute.kt │ │ ├── attribute │ │ │ ├── ConfigAttributeBuilder.kt │ │ │ └── mapping │ │ │ │ └── DefaultMapping.kt │ │ └── read │ │ │ ├── BaseReadGroup.kt │ │ │ ├── Matcher.kt │ │ │ ├── PatternMatcher.kt │ │ │ ├── StringMatcher.kt │ │ │ ├── num │ │ │ └── NumberReader.kt │ │ │ └── str │ │ │ └── StringReader.kt │ ├── feature │ │ ├── compat │ │ │ ├── dragoncore │ │ │ │ └── EquipmentListener.kt │ │ │ ├── germ │ │ │ │ └── GermListener.kt │ │ │ ├── mythicmobs │ │ │ │ ├── common │ │ │ │ │ ├── DataUpdateV.kt │ │ │ │ │ └── MMVListener.kt │ │ │ │ └── legacy │ │ │ │ │ ├── DataUpdateIV.kt │ │ │ │ │ └── MMIVListener.kt │ │ │ ├── placeholder │ │ │ │ └── PlaceHolderHooker.kt │ │ │ └── pouvoir │ │ │ │ └── AttributePlaceHolder.kt │ │ ├── database │ │ │ └── ASContainer.kt │ │ ├── personal │ │ │ ├── InitialAttrData.kt │ │ │ └── PlayerDataSave.kt │ │ └── realizer │ │ │ ├── HealthRegainRealizer.kt │ │ │ ├── HealthScaleRealizer.kt │ │ │ ├── UpdateRealizer.kt │ │ │ ├── attribute │ │ │ ├── BaseAttributeEntityRealizer.kt │ │ │ └── BaseAttributePlayerRealizer.kt │ │ │ ├── slot │ │ │ ├── EntitySlotRealizer.kt │ │ │ └── PlayerSlotRealizer.kt │ │ │ └── vanilla │ │ │ ├── MaxHealthTaskBuilder.kt │ │ │ └── VanillaAttTaskBuilder.kt │ └── manager │ │ ├── ASConfig.kt │ │ ├── AttributeDataManagerImpl.kt │ │ ├── AttributeManagerImpl.kt │ │ ├── AttributeSystemAPIImpl.kt │ │ ├── CompileManagerImpl.kt │ │ ├── CompiledAttrDataManagerImpl.kt │ │ ├── EquipmentDataManagerImpl.kt │ │ ├── ReadManagerImpl.kt │ │ ├── ReadPatternManagerImpl.kt │ │ └── RealizerManagerImpl.kt │ └── util │ ├── Format.kt │ ├── MapUtils.kt │ ├── StringUtils.kt │ ├── Utils.kt │ └── legacy │ └── Mirror.kt └── resources ├── attributes └── Example.yml ├── config.yml ├── dispatchers └── custom-trigger.yml ├── handlers └── on-attack.yml ├── lang ├── en_US.yml └── zh_CN.yml ├── options.yml ├── reader ├── number │ ├── default.yml │ └── percent.yml └── string │ └── string.yml ├── scripts └── conditions │ ├── attribute.js │ └── slot.js ├── slot.yml └── vanilla.yml /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/workflows/javadoc.yml: -------------------------------------------------------------------------------- 1 | name: javadoc 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | javadoc: 8 | name: javadoc 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: checkout repository 12 | uses: actions/checkout@v2 13 | - name: validate gradle wrapper 14 | uses: gradle/wrapper-validation-action@v1 15 | - name: setup jdk 8.0 16 | uses: actions/setup-java@v2 17 | with: 18 | distribution: adopt 19 | java-version: 8.0 20 | - name: build 21 | run: |- 22 | chmod +x gradlew 23 | ./gradlew dokkaJavadoc 24 | - name: Deploy 25 | uses: moodiest/push-to-branch-action@develop 26 | env: 27 | REPO: self 28 | BRANCH: javadoc 29 | FOLDER: build/dokka/javadoc 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.github/workflows/publish_17.yml: -------------------------------------------------------------------------------- 1 | name: publish_17 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: checkout repository 11 | uses: actions/checkout@v2 12 | - name: validate gradle wrapper 13 | uses: gradle/wrapper-validation-action@v1 14 | - name: setup jdk 8.0 15 | uses: actions/setup-java@v2 16 | with: 17 | distribution: adopt 18 | java-version: 8.0 19 | - name: Cache Gradle packages 20 | uses: actions/cache@v2 21 | with: 22 | path: ~/.gradle/caches 23 | key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle') }} 24 | restore-keys: ${{ runner.os }}-gradle 25 | - name: make gradle wrapper executable 26 | run: chmod +x ./gradlew 27 | - name: Decode 28 | run: | 29 | rm -rf ~/.gradle/ 30 | mkdir ~/.gradle/ 31 | touch ~/.gradle/secring.pgp.base64 32 | echo "${{ secrets.SIGNING_SECRET_KEY_RING_FILE }}" > ~/.gradle/secring.pgp.base64 33 | base64 -d ~/.gradle/secring.pgp.base64 > ~/.gradle/secring.pgp 34 | # 发布到仓库 35 | - name: publish 36 | id: publish_1 37 | continue-on-error: true 38 | env: 39 | NEXUS_USERNAME: ${{ secrets.USERNAME }} 40 | NEXUS_PASSWORD: ${{ secrets.PASSWORD }} 41 | run: ./gradlew publish -Porder=$GITHUB_RUN_NUMBER -Pbuild=$GITHUB_RUN_NUMBER -Pusername=$NEXUS_USERNAME -Ppassword=$NEXUS_PASSWORD -Psigning.keyId=${{secrets.SIGNING_KEY_ID}} -Psigning.password=${{secrets.SIGNING_KEY_PASSWORD}} -Psigning.secretKeyRingFile=$(echo ~/.gradle/secring.pgp) 42 | 43 | # 发布到仓库: 重试-1 44 | - name: publish (retry 1) 45 | id: publish_2 46 | if: steps.publish_1.outcome == 'failure' 47 | continue-on-error: true 48 | env: 49 | NEXUS_USERNAME: ${{ secrets.USERNAME }} 50 | NEXUS_PASSWORD: ${{ secrets.PASSWORD }} 51 | run: ./gradlew publish -Porder=$GITHUB_RUN_NUMBER -Pbuild=$GITHUB_RUN_NUMBER -Pusername=$NEXUS_USERNAME -Ppassword=$NEXUS_PASSWORD -Psigning.keyId=${{secrets.SIGNING_KEY_ID}} -Psigning.password=${{secrets.SIGNING_KEY_PASSWORD}} -Psigning.secretKeyRingFile=$(echo ~/.gradle/secring.pgp) 52 | 53 | # 发布到仓库: 重试-2 54 | - name: publish (retry 2) 55 | id: publish_3 56 | if: steps.publish_2.outcome == 'failure' 57 | continue-on-error: true 58 | env: 59 | NEXUS_USERNAME: ${{ secrets.USERNAME }} 60 | NEXUS_PASSWORD: ${{ secrets.PASSWORD }} 61 | run: ./gradlew publish -Porder=$GITHUB_RUN_NUMBER -Pbuild=$GITHUB_RUN_NUMBER -Pusername=$NEXUS_USERNAME -Ppassword=$NEXUS_PASSWORD -Psigning.keyId=${{secrets.SIGNING_KEY_ID}} -Psigning.password=${{secrets.SIGNING_KEY_PASSWORD}} -Psigning.secretKeyRingFile=$(echo ~/.gradle/secring.pgp) 62 | 63 | # 发布到仓库: 重试-3 64 | - name: publish (retry 3) 65 | id: publish_4 66 | if: steps.publish_3.outcome == 'failure' 67 | env: 68 | NEXUS_USERNAME: ${{ secrets.USERNAME }} 69 | NEXUS_PASSWORD: ${{ secrets.PASSWORD }} 70 | run: ./gradlew publish -Porder=$GITHUB_RUN_NUMBER -Pbuild=$GITHUB_RUN_NUMBER -Pusername=$NEXUS_USERNAME -Ppassword=$NEXUS_PASSWORD -Psigning.keyId=${{secrets.SIGNING_KEY_ID}} -Psigning.password=${{secrets.SIGNING_KEY_PASSWORD}} -Psigning.secretKeyRingFile=$(echo ~/.gradle/secring.pgp) 71 | - name: Auto Close And Release 72 | id: close_and_release 73 | env: 74 | NEXUS_USERNAME: ${{ secrets.USERNAME }} 75 | NEXUS_PASSWORD: ${{ secrets.PASSWORD }} 76 | run: ./gradlew closeAndReleaseRepository -Pusername=$NEXUS_USERNAME -Ppassword=$NEXUS_PASSWORD -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.war 15 | *.nar 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | replay_pid* 24 | /.gradle/ 25 | /build/ 26 | /gradle/ 27 | .idea/runConfigurations.xml 28 | .idea/palantir-java-format.xml 29 | .idea/kotlinc.xml 30 | .idea/inspectionProfiles/Project_Default.xml 31 | .gradle/checksums/sha1-checksums.bin 32 | .gradle/checksums/md5-checksums.bin 33 | .gradle/checksums/checksums.lock 34 | .gradle/buildOutputCleanup/outputFiles.bin 35 | .gradle/buildOutputCleanup/buildOutputCleanup.lock 36 | .gradle/buildOutputCleanup.lock 37 | .gradle/7.0.2/fileHashes/resourceHashesCache.bin 38 | .gradle/7.0.2/fileHashes/fileHashes.lock 39 | .gradle/7.0.2/fileHashes/fileHashes.bin 40 | .gradle/7.0.2/executionHistory/executionHistory.lock 41 | .gradle/7.0.2/executionHistory/executionHistory.bin 42 | .gradle/7.0.2/executionHistory/executionHistory.bin 43 | .gradle/7.0.2/executionHistory/executionHistory.lock 44 | .gradle/7.0.2/fileHashes/fileHashes.bin 45 | .gradle/7.0.2/fileHashes/fileHashes.lock 46 | .gradle/7.0.2/fileHashes/resourceHashesCache.bin 47 | .gradle/buildOutputCleanup/outputFiles.bin 48 | .gradle/buildOutputCleanup/buildOutputCleanup.lock 49 | .gradle/7.0.2/fileHashes/resourceHashesCache.bin 50 | .gradle/7.0.2/fileHashes/resourceHashesCache.bin 51 | .idea 52 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Glom 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AttributeSystem II 2 | 3 | 插件永久免费 4 | 5 | --- 6 | 7 | ## 插件 8 | 9 | | 说明 | 内容 | 10 | |------|------------------------------------| 11 | | 兼容版本 | 1.12.2+ (理论) | 12 | | 硬依赖 | Pouvoir | 13 | | 软依赖 | PlaceholderAPI Mythicmobs SkillAPI | 14 | 15 | ![GitHub Release](https://img.shields.io/github/v/release/Skillw/AttributeSystem) 16 | 17 | 18 | ## 介绍 19 | 20 | **AttributeSystem** 是基于 **TabooLib VI** & **Pouvoir** 编写的一款属性引擎插件 21 | 奉单一职责的宗旨,本引擎仅提供属性 属性读取 属性实现框架,具体属性与功能需要通过 配置 / API 来实现 22 | 23 | **AttributeSystem** 提供包括但不限于以下[**API**](http://doc.skillw.com/attsystem/): 24 | 25 | - AttributeSystemAPI 26 | - AttributeManager 27 | - ConditionManager 28 | - EquipmentDataManager 29 | - AttributeDataManager 30 | - OperationManager 31 | - RealizeManager 32 | - ReadPatternManager 33 | 34 | 你可以通过编写代码/脚本来拓展**AttributeSystem**的诸多功能 35 | 36 | ### 包括但不限于 37 | 38 | #### 属性 (Attribute) 39 | 40 | ```kotlin 41 | Attribute.createAttribute("example", ReadGroup) { 42 | names += "示例属性" 43 | }.register() 44 | ``` 45 | 46 | ```javascript 47 | var Attribute = find('com.skillw.attsystem.api.attribute.Attribute') 48 | var ReadGroup = static('ReadGroup') 49 | 50 | //@Awake(Active) 51 | function regAtt() { 52 | Attribute.createAttribute("example", ReadGroup, (builder) => { 53 | builder.names.add("示例属性") 54 | }).register() 55 | } 56 | ``` 57 | 58 | #### 读取格式 (Read Pattern) 59 | 60 | ```kotlin 61 | @AutoRegister 62 | object MyReadPattern : ReadPattern("my_read_pattern") { 63 | override fun read(string: String, attribute: Attribute, entity: LivingEntity?, slot: String?): Status? { 64 | //code 65 | } 66 | 67 | override fun readNBT(map: Map, attribute: Attribute): Status? { 68 | //code 69 | } 70 | 71 | override fun placeholder(key: String, attribute: Attribute, status: Status, entity: LivingEntity?): Any? { 72 | //code 73 | } 74 | 75 | override fun stat(attribute: Attribute, status: Status, entity: LivingEntity?): TellrawJson { 76 | //code 77 | } 78 | } 79 | ``` 80 | 81 | ```javascript 82 | //@ReadPattern(my_read_pattern) 83 | 84 | function read(string, attribute, entity, slot 85 | ) { 86 | //code 87 | } 88 | 89 | function readNBT(map, attribute) { 90 | //code 91 | } 92 | 93 | function placeholder(key, attribute, status, entity) { 94 | //code 95 | } 96 | 97 | function stat(attribute, status, entity) { 98 | //code 99 | } 100 | ``` 101 | 102 | #### 条件 (Condition) 103 | 104 | ```kotlin 105 | @AutoRegister 106 | object LevelCondition : 107 | BaseCondition("level", setOf("Lv\\.(?\\d+)", "等级限制: (?\\d+)"), ConditionType.ALL) { 108 | override fun condition(slot: String?, entity: LivingEntity?, matcher: Matcher, text: String): Boolean { 109 | entity ?: return true 110 | if (entity !is Player) return true 111 | val level = Coerce.toInteger(matcher.group("value")) 112 | return entity.level >= level 113 | } 114 | } 115 | ``` 116 | 117 | ```javascript 118 | var Coere = static('Coere') 119 | 120 | //@Condition(Level,ALL,Lv\.(?\d+),等级限制: (?\d+)) 121 | function level(slot, entity, matcher, text) { 122 | var hasEntity = entity != "null" 123 | if (!hasEntity) return true 124 | if (!(entity instanceof Player)) { 125 | return true 126 | } 127 | var level = Coerce.toInteger(matcher.group("value")) 128 | return entity.level >= level 129 | } 130 | 131 | ``` 132 | 133 |
134 | 135 | ## Links 136 | 137 | WIKI [www.skillw.com/docs/attsystem/intro](www.skillw.com/docs/attsystem/intro) 138 | 139 | JavaDoc [http://doc.skillw.com/attsystem/](http://doc.skillw.com/attsystem/) 140 | 141 | MCBBS [https://www.mcbbs.net/forum.php?mod=viewthread&tid=1307249](https://www.mcbbs.net/forum.php?mod=viewthread&tid=1307249) 142 | 143 | 爱发电 [https://afdian.net/@glom\_](https://afdian.net/@glom_) 144 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=com.skillw.attsystem 2 | version=2.1.3-alpha -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/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.0.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /libs/DungeonPlus-1.3.1.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/DungeonPlus-1.3.1.jar -------------------------------------------------------------------------------- /libs/FightSystem-1.0.3-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/FightSystem-1.0.3-api.jar -------------------------------------------------------------------------------- /libs/GermPlugin-4.2.9.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/GermPlugin-4.2.9.jar -------------------------------------------------------------------------------- /libs/MythicMobs-4.14.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/MythicMobs-4.14.2.jar -------------------------------------------------------------------------------- /libs/MythicMobs-5.2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/MythicMobs-5.2.0.jar -------------------------------------------------------------------------------- /libs/Pouvoir-1.6.7-beta-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/Pouvoir-1.6.7-beta-api.jar -------------------------------------------------------------------------------- /libs/ProSkillAPI-R-1.2.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/ProSkillAPI-R-1.2.7.jar -------------------------------------------------------------------------------- /libs/[插件]DragonCore-2.4.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/[插件]DragonCore-2.4.7.jar -------------------------------------------------------------------------------- /libs/[插件]DragonCore-3.1.0.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/[插件]DragonCore-3.1.0.2.jar -------------------------------------------------------------------------------- /libs/patched_1.16.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/patched_1.16.5.jar -------------------------------------------------------------------------------- /libs/purpur-1.19.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/libs/purpur-1.19.2.jar -------------------------------------------------------------------------------- /log.md: -------------------------------------------------------------------------------- 1 | Compat with Crackshot -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name="AttributeSystem" -------------------------------------------------------------------------------- /src/main/java/com/skillw/attsystem/util/LoreMap.java: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.util; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | 5 | 6 | public class LoreMap { 7 | 8 | private final TrieNode root = new TrieNode(); 9 | 10 | private final boolean ignorePrefix; 11 | private final boolean ignoreSpace; 12 | private final boolean ignoreColor; 13 | 14 | 15 | public LoreMap(boolean ignoreSpace, boolean ignoreColor, boolean ignorePrefix) { 16 | this.ignoreSpace = ignoreSpace; 17 | this.ignoreColor = ignoreColor; 18 | this.ignorePrefix = ignorePrefix; 19 | } 20 | 21 | 22 | public LoreMap() { 23 | this(true, true, false); 24 | } 25 | 26 | 27 | public void put(String lore, T value) { 28 | lore = lore.replaceAll("&", "§"); 29 | if (this.ignoreSpace) { 30 | lore = lore.replaceAll("\\s", ""); 31 | } 32 | if (this.ignoreColor) { 33 | lore = lore.replaceAll("§.", ""); 34 | } 35 | int depth = 0; 36 | TrieNode current = this.root; 37 | while (depth < lore.length()) { 38 | LoreChar c = new LoreChar(lore.charAt(depth)); 39 | if (current.child.containsKey(c)) { 40 | current = current.child.get(c); 41 | } else { 42 | TrieNode node = new TrieNode(); 43 | node.depth++; 44 | node.pre = current; 45 | current.child.put(c, node); 46 | current = node; 47 | } 48 | if (depth == lore.length() - 1) { 49 | current.obj = value; 50 | } 51 | depth++; 52 | } 53 | } 54 | 55 | public T get(String lore) { 56 | int depth = 0; 57 | if (this.ignoreSpace) { 58 | lore = lore.replaceAll("\\s", ""); 59 | } 60 | if (this.ignoreColor) { 61 | lore = lore.replaceAll("§.", ""); 62 | } 63 | TrieNode current = this.root; 64 | if (this.ignorePrefix) { 65 | while (depth < lore.length()) { 66 | if (this.root.child.containsKey(new LoreChar(lore.charAt(depth)))) { 67 | break; 68 | } 69 | depth++; 70 | } 71 | } 72 | while (depth < lore.length()) { 73 | LoreChar c = new LoreChar(lore.charAt(depth)); 74 | TrieNode node = current.child.get(c); 75 | if (node == null) { 76 | return null; 77 | } 78 | if (node.obj != null) { 79 | if (lore.length() >= depth + 2 && node.child.containsKey(new LoreChar(lore.charAt(depth + 1)))) { 80 | current = node; 81 | depth++; 82 | continue; 83 | } 84 | return node.obj; 85 | } 86 | current = node; 87 | depth++; 88 | } 89 | return null; 90 | } 91 | 92 | public void clear() { 93 | this.root.child.clear(); 94 | } 95 | 96 | 97 | public static class LoreChar { 98 | 99 | private final char c; 100 | 101 | public LoreChar(char c) { 102 | this.c = c; 103 | } 104 | 105 | public char get() { 106 | return this.c; 107 | } 108 | 109 | @Override 110 | public int hashCode() { 111 | return this.c; 112 | } 113 | 114 | @Override 115 | public boolean equals(Object o) { 116 | return (o instanceof LoreChar) && ((LoreChar) o).c == this.c; 117 | } 118 | } 119 | 120 | public class TrieNode { 121 | final ConcurrentHashMap child = new ConcurrentHashMap<>(); 122 | TrieNode pre = null; 123 | T obj = null; 124 | int depth = 0; 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/AttributeSystem.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem 2 | 3 | import com.skillw.attsystem.api.AttributeSystemAPI 4 | import com.skillw.attsystem.api.manager.* 5 | import com.skillw.attsystem.internal.manager.ASConfig 6 | import com.skillw.pouvoir.api.manager.ManagerData 7 | import com.skillw.pouvoir.api.plugin.SubPouvoir 8 | import com.skillw.pouvoir.api.plugin.annotation.PouManager 9 | import org.bukkit.inventory.ItemStack 10 | import taboolib.common.platform.Plugin 11 | import taboolib.common.platform.function.console 12 | import taboolib.common.platform.function.info 13 | import taboolib.module.chat.colored 14 | import taboolib.module.configuration.Config 15 | import taboolib.module.configuration.ConfigFile 16 | import taboolib.module.lang.sendLang 17 | import taboolib.module.nms.ItemTag 18 | import taboolib.module.nms.getItemTag 19 | import taboolib.platform.BukkitPlugin 20 | 21 | object AttributeSystem : Plugin(), SubPouvoir { 22 | 23 | override val key = "AttributeSystem" 24 | override lateinit var managerData: ManagerData 25 | override val plugin by lazy { 26 | BukkitPlugin.getInstance() 27 | } 28 | 29 | /** Configs */ 30 | 31 | @Config("config.yml", autoReload = true) 32 | lateinit var config: ConfigFile 33 | 34 | @Config("slot.yml", autoReload = true) 35 | lateinit var slot: ConfigFile 36 | 37 | @Config("options.yml", autoReload = true) 38 | lateinit var options: ConfigFile 39 | 40 | @Config("vanilla.yml", autoReload = true) 41 | lateinit var vanilla: ConfigFile 42 | /** Managers */ 43 | 44 | @JvmStatic 45 | @PouManager 46 | lateinit var configManager: ASConfig 47 | 48 | @JvmStatic 49 | @PouManager 50 | lateinit var attributeSystemAPI: AttributeSystemAPI 51 | 52 | @JvmStatic 53 | @PouManager 54 | lateinit var readPatternManager: ReadPatternManager 55 | 56 | @JvmStatic 57 | @PouManager 58 | lateinit var attributeManager: AttributeManager 59 | 60 | @JvmStatic 61 | @PouManager 62 | lateinit var attributeDataManager: AttributeDataManager 63 | 64 | @JvmStatic 65 | @PouManager 66 | lateinit var equipmentDataManager: EquipmentDataManager 67 | 68 | @JvmStatic 69 | @PouManager 70 | lateinit var readManager: ReadManager 71 | 72 | @JvmStatic 73 | @PouManager 74 | lateinit var realizerManager: RealizerManager 75 | 76 | @JvmStatic 77 | @PouManager 78 | lateinit var compileManager: CompileManager 79 | 80 | @JvmStatic 81 | @PouManager 82 | lateinit var compiledAttrDataManager: CompiledAttrDataManager 83 | 84 | override fun onLoad() { 85 | load() 86 | } 87 | 88 | override fun onEnable() { 89 | enable() 90 | } 91 | 92 | override fun onActive() { 93 | active() 94 | } 95 | 96 | override fun onDisable() { 97 | disable() 98 | } 99 | 100 | fun debug(string: String) { 101 | if (configManager.debug) { 102 | info(string.colored()) 103 | } 104 | } 105 | 106 | 107 | 108 | fun debugLang(path: String, vararg args: String) { 109 | if (configManager.debug) { 110 | console().sendLang(path, *args) 111 | } 112 | } 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/AttributeSystemAPI.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api 2 | 3 | import com.skillw.pouvoir.api.manager.Manager 4 | import org.bukkit.entity.LivingEntity 5 | import java.util.* 6 | 7 | /** 8 | * Attribute system a p i 9 | * 10 | * @constructor Create empty Attribute system a p i 11 | */ 12 | interface AttributeSystemAPI : Manager { 13 | 14 | /** 15 | * EntityUpdate 16 | * 17 | * 更新实体(装备 属性 原版属性实现) 18 | * 19 | * 建议异步调用 20 | * 21 | * @param entity 实体 22 | */ 23 | fun update(entity: LivingEntity) 24 | 25 | /** 26 | * Remove 27 | * 28 | * 删除一个实体的所有AS数据 29 | * 30 | * @param entity 实体 31 | */ 32 | fun remove(entity: LivingEntity) 33 | 34 | /** 35 | * Remove 36 | * 37 | * 删除一个实体的所有AS数据 38 | * 39 | * @param uuid 实体UUID 40 | */ 41 | fun remove(uuid: UUID) 42 | } 43 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/attribute/Attribute.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.attribute 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.read.ReadPattern 5 | import com.skillw.pouvoir.api.plugin.map.component.Registrable 6 | 7 | /** 8 | * Attribute 9 | * 10 | * @constructor Create Attribute 11 | * @property key 键 12 | * @property names 名称 13 | * @property readPattern 读取格式 14 | * @property priority 优先级 15 | */ 16 | class Attribute private constructor( 17 | override val key: String, 18 | val display: String, 19 | val names: Collection, 20 | val readPattern: ReadPattern<*>, 21 | val priority: Int = 0, 22 | ) : Registrable, Comparable { 23 | override fun compareTo(other: Attribute): Int = if (this.priority == other.priority) 0 24 | else if (this.priority > other.priority) 1 25 | else -1 26 | 27 | /** Entity */ 28 | var entity = true 29 | 30 | /** Release */ 31 | var config = false 32 | 33 | override fun register() { 34 | AttributeSystem.attributeManager.register(this) 35 | } 36 | 37 | var mapping: Mapping? = null 38 | set(value) { 39 | value?.attribute = this 40 | field = value 41 | } 42 | 43 | override fun equals(other: Any?): Boolean { 44 | if (this === other) return true 45 | if (javaClass != other?.javaClass) return false 46 | 47 | other as Attribute 48 | 49 | return key == other.key 50 | } 51 | 52 | override fun hashCode(): Int { 53 | return key.hashCode() 54 | } 55 | 56 | override fun toString(): String { 57 | return "Attribute(key='$key')" 58 | } 59 | 60 | /** 61 | * Builder 62 | * 63 | * @param receiver 64 | * @constructor 65 | * @property key 键 66 | * @property readPattern 读取格式 67 | */ 68 | class Builder(val key: String, private val readPattern: ReadPattern<*>, receiver: Builder.() -> Unit) { 69 | var display: String? = null 70 | 71 | /** Entity */ 72 | var entity = true 73 | 74 | /** Release */ 75 | var release = false 76 | 77 | /** Priority */ 78 | var priority: Int = 0 79 | 80 | /** Names */ 81 | val names = ArrayList() 82 | 83 | var mapping: Mapping? = null 84 | 85 | 86 | init { 87 | receiver.invoke(this) 88 | } 89 | 90 | /** 91 | * Build 92 | * 93 | * @return 94 | */ 95 | fun build(): Attribute { 96 | val att = Attribute(key, display ?: names.first(), names, readPattern, priority) 97 | att.config = release 98 | att.entity = entity 99 | att.mapping = mapping 100 | return att 101 | } 102 | 103 | } 104 | 105 | companion object { 106 | @JvmStatic 107 | fun createAttribute( 108 | key: String, 109 | readPattern: ReadPattern<*>, 110 | init: Builder.() -> Unit, 111 | ): Attribute { 112 | return Builder(key, readPattern, init).build() 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/attribute/Mapping.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.attribute 2 | 3 | import com.skillw.attsystem.api.compiled.CompiledData 4 | import com.skillw.attsystem.api.read.status.Status 5 | import org.bukkit.entity.LivingEntity 6 | 7 | /** 8 | * @className Mapping 9 | * 10 | * @author Glom 11 | * @date 2023/8/5 14:57 Copyright 2023 user. All rights reserved. 12 | */ 13 | abstract class Mapping { 14 | var attribute: Attribute? = null 15 | abstract fun mapping(status: Status<*>, entity: LivingEntity?): CompiledData? 16 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/attribute/compound/AttributeData.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.attribute.compound 2 | 3 | import com.skillw.attsystem.AttributeSystem.attributeManager 4 | import com.skillw.attsystem.api.attribute.Attribute 5 | import com.skillw.attsystem.api.read.status.Status 6 | import com.skillw.pouvoir.api.plugin.map.BaseMap 7 | import org.bukkit.inventory.ItemStack 8 | import taboolib.module.nms.ItemTag 9 | import taboolib.module.nms.ItemTagData 10 | import taboolib.module.nms.getItemTag 11 | import taboolib.module.nms.setItemTag 12 | import java.util.concurrent.ConcurrentHashMap 13 | 14 | 15 | /** 16 | * Attribute data 17 | * 18 | * @constructor Create empty Attribute data 19 | */ 20 | class AttributeData : BaseMap> { 21 | 22 | constructor() 23 | constructor(attributeData: AttributeData) { 24 | this.release = attributeData.release 25 | for (attribute in attributeData.keys) { 26 | this[attribute] = attributeData[attribute]!!.clone() 27 | } 28 | } 29 | 30 | /** Release */ 31 | var release = false 32 | 33 | /** 34 | * Release 35 | * 36 | * 设置为在下次属性更新时释放 37 | * 38 | * @return 自身 39 | */ 40 | fun release(): AttributeData { 41 | this.release = true 42 | return this 43 | } 44 | 45 | /** 46 | * Un release 47 | * 48 | * 设置为不在下次属性更新时释放 49 | * 50 | * @return 自身 51 | */ 52 | fun unRelease(): AttributeData { 53 | this.release = false 54 | return this 55 | } 56 | 57 | /** 58 | * NumberOperation 59 | * 60 | * 作运算操作 61 | * 62 | * @param attribute 属性 63 | * @param status 属性状态 64 | * @return 自身 65 | */ 66 | fun operation(attribute: Attribute, status: Status<*>): AttributeData { 67 | val thisStatus = this[attribute] ?: run { 68 | this.register(attribute, status.clone()) 69 | return this 70 | } 71 | this[attribute] = thisStatus.operation(status) 72 | return this 73 | } 74 | 75 | /** 76 | * NumberOperation 77 | * 78 | * 作运算操作 79 | * 80 | * @param others 属性数据 81 | * @return 自身(运算后) 82 | */ 83 | 84 | @Deprecated("use combine", ReplaceWith("combine(*others)")) 85 | fun operation(vararg others: AttributeData): AttributeData = combine(*others) 86 | 87 | /** 88 | * NumberOperation 89 | * 90 | * 作运算操作 91 | * 92 | * @param others 属性数据 93 | * @return 自身(运算后) 94 | */ 95 | fun combine(vararg others: AttributeData): AttributeData { 96 | for (attributeData in others) { 97 | attributeData.forEach { (attribute, attributeStatus) -> 98 | this.operation(attribute, attributeStatus) 99 | } 100 | } 101 | return this 102 | } 103 | 104 | /** 105 | * To compound 106 | * 107 | * 转换为属性数据集 108 | * 109 | * @param key 键 110 | * @return 属性数据集 111 | */ 112 | fun toCompound(key: String): AttributeDataCompound { 113 | val compound = AttributeDataCompound() 114 | compound.register(key, this) 115 | return compound 116 | } 117 | 118 | 119 | override fun toString(): String { 120 | return serialize().toString() 121 | } 122 | 123 | /** 124 | * Get 125 | * 126 | * @param attributeKey 属性键 127 | * @return 属性状态 128 | */ 129 | operator fun get(attributeKey: String): Status<*>? { 130 | return this[attributeManager[attributeKey] ?: return null] 131 | } 132 | 133 | /** 134 | * Clone 135 | * 136 | * 复制 137 | * 138 | * @return 属性数据 139 | */ 140 | public override fun clone(): AttributeData { 141 | return AttributeData(this) 142 | } 143 | 144 | /** 145 | * To map 146 | * 147 | * 转换为map 148 | * 149 | * @return Map 150 | */ 151 | fun serialize(): MutableMap { 152 | val tag = ConcurrentHashMap() 153 | for ((attribute, status) in this) { 154 | val value = status.serialize() 155 | if (value.isEmpty()) continue 156 | tag[attribute.key] = status.serialize() 157 | } 158 | return tag 159 | } 160 | 161 | /** 162 | * Save 163 | * 164 | * 以"ATTRIBUTE_DATA.键"保存到物品NBT中 165 | * 166 | * @param itemStack 物品 167 | * @param key 键 168 | * @return 物品 169 | */ 170 | fun save(itemStack: ItemStack, key: String): ItemStack { 171 | val tag = itemStack.getItemTag() 172 | if (tag.containsKey("ATTRIBUTE_DATA")) { 173 | val compound = tag["ATTRIBUTE_DATA"]!!.asCompound() 174 | compound[key] = ItemTagData.toNBT(this.serialize()) 175 | tag["ATTRIBUTE_DATA"] = compound 176 | } else { 177 | val compound = ItemTag() 178 | compound[key] = ItemTagData.toNBT(this.serialize()) 179 | tag["ATTRIBUTE_DATA"] = compound 180 | } 181 | return itemStack.setItemTag(tag) 182 | } 183 | 184 | companion object { 185 | 186 | /** 187 | * 用于读取NBT 188 | * 189 | * @param map Map NBT 190 | * @return AttributeData 属性数据 191 | */ 192 | @JvmStatic 193 | fun fromMap(map: Map): AttributeData = 194 | AttributeData().apply { 195 | map.forEach { (attKey, value) -> 196 | val attribute = attributeManager[attKey] ?: return@forEach 197 | val status = 198 | attribute.readPattern.readNBT(value as Map, attribute) ?: return@forEach 199 | register(attribute, status) 200 | } 201 | } 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/compiled/CompiledAttrDataCompound.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.compiled 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 4 | import com.skillw.attsystem.api.compiled.sub.ComplexCompiledData 5 | import com.skillw.attsystem.internal.feature.realizer.attribute.BaseAttributeEntityRealizer.baseEntity 6 | import com.skillw.attsystem.internal.feature.realizer.attribute.BaseAttributePlayerRealizer.basePlayer 7 | import com.skillw.attsystem.util.Utils.mirrorIfDebug 8 | import com.skillw.pouvoir.api.plugin.map.LowerMap 9 | import org.bukkit.configuration.serialization.ConfigurationSerializable 10 | import org.bukkit.entity.LivingEntity 11 | import org.bukkit.entity.Player 12 | 13 | /** 14 | * @className CompiledAttrDataCompound 15 | * 16 | * @author Glom 17 | * @date 2023/8/3 1:13 Copyright 2023 user. All rights reserved. 18 | */ 19 | class CompiledAttrDataCompound(entity: LivingEntity) : LowerMap(), Evalable, 20 | ConfigurationSerializable { 21 | 22 | init { 23 | if (entity is Player) 24 | basePlayer() 25 | else 26 | baseEntity() 27 | } 28 | 29 | override fun eval(entity: LivingEntity?): AttributeDataCompound { 30 | return mirrorIfDebug("compiled-attr-data-eval") { 31 | val result = AttributeDataCompound(entity) 32 | val total = ComplexCompiledData() 33 | forEach { (_, compiledData) -> 34 | total.add(compiledData) 35 | } 36 | val maxLayers = total.layers(1) 37 | result.combine(total.eval(entity)) 38 | repeat(maxLayers) { 39 | result.putAll(total.eval(entity)) 40 | } 41 | result.allToRelease() 42 | } 43 | } 44 | 45 | override fun serialize(): MutableMap { 46 | val children = LinkedHashMap() 47 | this.entries.forEach { (key, data) -> 48 | children[key] = data.serialize() 49 | } 50 | return linkedMapOf( 51 | "CompiledAttrDataCompound" to children 52 | ) 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/compiled/CompiledData.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.compiled 2 | 3 | import com.skillw.pouvoir.api.feature.condition.Condition 4 | import com.skillw.pouvoir.api.feature.condition.ConditionData 5 | import com.skillw.pouvoir.api.plugin.map.KeyMap 6 | import org.bukkit.configuration.serialization.ConfigurationSerializable 7 | import org.bukkit.entity.LivingEntity 8 | 9 | /** 10 | * @className CompiledData 11 | * 12 | * @author Glom 13 | * @date 2023/8/2 18:51 Copyright 2023 user. All rights reserved. 14 | */ 15 | abstract class CompiledData : KeyMap(), Evalable, ConfigurationSerializable { 16 | 17 | 18 | fun putAllCond(other: KeyMap) { 19 | other.forEach { (condition, conditionData) -> 20 | computeIfAbsent(condition) { ConditionData(condition) }.addAll(conditionData) 21 | } 22 | } 23 | 24 | open fun putAll(other: CompiledData) { 25 | putAllCond(other) 26 | } 27 | 28 | open fun condition(entity: LivingEntity?): Boolean { 29 | return values.all { data -> 30 | data.condition(entity) 31 | } 32 | } 33 | 34 | override fun serialize(): MutableMap { 35 | val total = LinkedHashMap() 36 | values.forEach { 37 | total.putAll(it.serialize()) 38 | } 39 | return total 40 | } 41 | 42 | 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/compiled/Evalable.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.compiled 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 4 | import org.bukkit.entity.LivingEntity 5 | 6 | /** 7 | * @className Evalable 8 | * 9 | * @author Glom 10 | * @date 2023/8/3 1:31 Copyright 2023 user. All rights reserved. 11 | */ 12 | fun interface Evalable { 13 | fun eval(entity: LivingEntity?): AttributeDataCompound 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/compiled/sub/ComplexCompiledData.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.compiled.sub 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 4 | import com.skillw.attsystem.api.compiled.CompiledData 5 | import org.bukkit.entity.LivingEntity 6 | 7 | /** 8 | * @className ComplexCompiledData 9 | * 10 | * @author Glom 11 | * @date 2023/8/2 21:25 Copyright 2023 user. All rights reserved. 12 | */ 13 | class ComplexCompiledData : CompiledData() { 14 | private val children = ArrayList() 15 | var base: CompiledData? = null 16 | val addition = AttributeDataCompound() 17 | fun add(compiled: CompiledData) { 18 | if (compiled is NBTCompiledData) { 19 | putAllCond(compiled) 20 | compiled.clear() 21 | } 22 | children.add(compiled) 23 | } 24 | 25 | fun layers(current: Int): Int { 26 | return children.filterIsInstance().maxOfOrNull { it.layers(current + 1) } ?: current 27 | } 28 | 29 | override fun putAll(other: CompiledData) { 30 | super.putAll(other) 31 | if (other is ComplexCompiledData) 32 | combine(other) 33 | } 34 | 35 | fun combine(other: ComplexCompiledData) { 36 | addition.combine(other.addition) 37 | children.addAll(other.children) 38 | } 39 | 40 | override fun clear() { 41 | super.clear() 42 | clearChildren() 43 | addition.clear() 44 | } 45 | 46 | fun clearChildren() { 47 | children.clear() 48 | } 49 | 50 | override fun eval(entity: LivingEntity?): AttributeDataCompound { 51 | if (!condition(entity)) return AttributeDataCompound() 52 | val total = AttributeDataCompound(entity) 53 | base?.eval(entity)?.let { total.combine(it) } 54 | if (addition.isNotEmpty()) { 55 | total.combine(addition.clone()) 56 | } 57 | children.forEach { 58 | total.combine(it.eval(entity)) 59 | } 60 | return total 61 | } 62 | 63 | override fun serialize(): MutableMap { 64 | val total = super.serialize() 65 | 66 | val children = LinkedHashMap() 67 | this.children.forEach { 68 | children.putAll(it.serialize()) 69 | } 70 | return linkedMapOf( 71 | "ComplexCompiledData-${hashCode()}" to linkedMapOf( 72 | "conditions" to total, 73 | "base" to base?.serialize(), 74 | "addition" to addition.serialize(), 75 | "children" to children, 76 | ) 77 | ) 78 | } 79 | 80 | override fun hashCode(): Int { 81 | return super.hashCode() + children.hashCode() + addition.hashCode() 82 | } 83 | 84 | override fun equals(other: Any?): Boolean { 85 | if (this === other) return true 86 | if (other !is ComplexCompiledData) return false 87 | if (!super.equals(other)) return false 88 | 89 | if (children != other.children) return false 90 | return addition == other.addition 91 | } 92 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/compiled/sub/NBTCompiledData.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.compiled.sub 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 4 | import com.skillw.attsystem.api.compiled.CompiledData 5 | import org.bukkit.entity.LivingEntity 6 | 7 | /** 8 | * @className NBTCompiledData 9 | * 10 | * @author Glom 11 | * @date 2023/8/2 21:25 Copyright 2023 user. All rights reserved. 12 | */ 13 | class NBTCompiledData( 14 | attrDataMap: MutableMap = HashMap(), 15 | ) : CompiledData() { 16 | private val condEntries = ArrayList() 17 | private val attrData = AttributeDataCompound.fromMap(attrDataMap) 18 | 19 | /** 20 | * Entry 21 | * 22 | * @constructor Create empty Entry 23 | * @property pathsToDelete 24 | */ 25 | class Entry(val pathsToDelete: Collection) : CompiledData() { 26 | override fun eval(entity: LivingEntity?): AttributeDataCompound { 27 | TODO("Not yet implemented") 28 | } 29 | } 30 | 31 | /** 32 | * Add 33 | * 34 | * @param entry 35 | */ 36 | fun add(entry: Entry) { 37 | if (entry.pathsToDelete.isNotEmpty()) 38 | condEntries += entry 39 | else 40 | putAllCond(entry) 41 | } 42 | 43 | override fun eval(entity: LivingEntity?): AttributeDataCompound { 44 | val clone = attrData.clone() 45 | if (!condition(entity)) { 46 | condEntries.flatMap { it.pathsToDelete }.forEach { clone.removeDeep(it) } 47 | } else { 48 | condEntries.forEach { entry -> 49 | if (!entry.condition(entity)) { 50 | entry.pathsToDelete.forEach { clone.removeDeep(it) } 51 | } 52 | } 53 | } 54 | return clone 55 | } 56 | 57 | override fun serialize(): MutableMap { 58 | val total = super.serialize() 59 | 60 | return linkedMapOf( 61 | "NBTCompiledData-${hashCode()}" to linkedMapOf( 62 | "conditions" to total, 63 | "attrData" to attrData.serialize(), 64 | "entries" to condEntries.map { 65 | linkedMapOf( 66 | "paths" to it.pathsToDelete, 67 | "conditions" to it.serialize() 68 | ) 69 | }, 70 | ) 71 | ) 72 | } 73 | 74 | override fun hashCode(): Int { 75 | return super.hashCode() + condEntries.hashCode() + attrData.hashCode() 76 | } 77 | 78 | override fun equals(other: Any?): Boolean { 79 | if (this === other) return true 80 | if (other !is NBTCompiledData) return false 81 | if (!super.equals(other)) return false 82 | 83 | if (attrData != other.attrData) return false 84 | return condEntries == other.condEntries 85 | } 86 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/compiled/sub/StringsCompiledData.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.compiled.sub 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeData 4 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 5 | import com.skillw.attsystem.api.compiled.CompiledData 6 | import org.bukkit.entity.LivingEntity 7 | 8 | /** 9 | * @className StringsCompiledData 10 | * 11 | * @author Glom 12 | * @date 2023/8/2 21:25 Copyright 2023 user. All rights reserved. 13 | */ 14 | class StringsCompiledData( 15 | val data: AttributeData = AttributeData(), 16 | ) : CompiledData() { 17 | 18 | 19 | override fun putAll(other: CompiledData) { 20 | if (other !is StringsCompiledData) return 21 | data.combine(other.data) 22 | super.putAll(other) 23 | } 24 | 25 | override fun eval(entity: LivingEntity?): AttributeDataCompound { 26 | return AttributeDataCompound().apply { 27 | if (condition(entity)) { 28 | register("STRINGS-ATTRIBUTE", data.clone()) 29 | } 30 | }.allToRelease() 31 | } 32 | 33 | override fun serialize(): MutableMap { 34 | val attrData = data.serialize() 35 | val total = super.serialize() 36 | 37 | return linkedMapOf( 38 | "StringsCompiledData-${hashCode()}" to linkedMapOf( 39 | "conditions" to total, 40 | "attrData" to attrData 41 | ) 42 | ) 43 | } 44 | 45 | override fun hashCode(): Int { 46 | return super.hashCode() + data.hashCode() 47 | } 48 | 49 | override fun equals(other: Any?): Boolean { 50 | if (this === other) return true 51 | if (other !is StringsCompiledData) return false 52 | if (!super.equals(other)) return false 53 | 54 | return data == other.data 55 | } 56 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/equipment/EquipmentData.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.equipment 2 | 3 | import com.skillw.pouvoir.api.plugin.map.LowerMap 4 | import org.bukkit.inventory.ItemStack 5 | import taboolib.module.nms.getItemTag 6 | import java.util.concurrent.ConcurrentHashMap 7 | 8 | /** 9 | * Equipment data 10 | * 11 | * @constructor Create empty Equipment data 12 | */ 13 | class EquipmentData(var compound: EquipmentDataCompound? = null, var source: String? = null) : LowerMap() { 14 | 15 | private val cache = ConcurrentHashMap() 16 | 17 | constructor(other: EquipmentData, release: Boolean) : this() { 18 | this.release = release 19 | for (key in other.keys) { 20 | this[key] = other[key]!!.clone() 21 | } 22 | } 23 | 24 | fun getHead() = get("头盔") ?: get("Head") 25 | fun getChest() = get("胸甲") ?: get("Chest") 26 | fun getLegs() = get("护腿") ?: get("Legs") 27 | fun getFeet() = get("靴子") ?: get("Feet") 28 | fun getHand() = get("主手") ?: get("Hand") 29 | fun getOffHand() = get("副手") ?: get("OffHand") 30 | 31 | 32 | private fun assertValid() { 33 | if (compound == null || source == null) { 34 | error("Operating owner-less EquipmentData! Please register the EquipmentData first!") 35 | } 36 | } 37 | 38 | override fun put(key: String, value: ItemStack): ItemStack? { 39 | assertValid() 40 | return compound?.let { com -> 41 | source?.let { sour -> 42 | com.set(sour, key, value) 43 | } 44 | } 45 | } 46 | 47 | fun uncheckedPut(key: String, value: ItemStack): ItemStack? { 48 | cache[key] = value.getItemTag(false).toString().hashCode() 49 | return super.put(key, value) 50 | } 51 | 52 | 53 | override fun remove(key: String): ItemStack? { 54 | assertValid() 55 | return compound?.let { com -> 56 | source?.let { sour -> 57 | com.removeItem(sour, key) 58 | } 59 | } 60 | } 61 | 62 | internal fun uncheckedRemove(key: String): ItemStack? { 63 | cache.remove(key) 64 | return super.remove(key) 65 | } 66 | 67 | override fun clear() { 68 | assertValid() 69 | compound?.let { com -> 70 | source?.let { sour -> 71 | com.clear(sour) 72 | } 73 | } 74 | } 75 | 76 | internal fun uncheckedClear() { 77 | cache.clear() 78 | super.clear() 79 | } 80 | 81 | override fun putAll(from: Map) { 82 | assertValid() 83 | compound?.let { com -> 84 | source?.let { sour -> 85 | from.forEach { (slot, item) -> 86 | com[sour, slot] = item 87 | } 88 | } 89 | } 90 | } 91 | 92 | 93 | /** 94 | * Clone 95 | * 96 | * @return 97 | */ 98 | fun clone(compound: EquipmentDataCompound?, source: String?): EquipmentData { 99 | val equipmentData = EquipmentData(compound, source) 100 | this.forEach { 101 | equipmentData[it.key] = it.value.clone() 102 | } 103 | return equipmentData 104 | } 105 | 106 | 107 | /** Release */ 108 | var release = false 109 | 110 | /** 111 | * Release 112 | * 113 | * 设置为在下次更新时释放装备数据 114 | * 115 | * @return 116 | */ 117 | fun release(): EquipmentData { 118 | this.release = true 119 | return this 120 | } 121 | 122 | /** 123 | * Un release 124 | * 125 | * 设置为不在下次更新时释放装备数据 126 | * 127 | * @return 128 | */ 129 | fun unRelease(): EquipmentData { 130 | this.release = false 131 | return this 132 | } 133 | 134 | fun free(): EquipmentData { 135 | source = null 136 | compound = null 137 | return this 138 | } 139 | 140 | fun hasChanged(item: ItemStack, slot: String): Boolean { 141 | return item.getItemTag(false).toString().hashCode() != cache[slot] 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/equipment/EquipmentDataCompound.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.equipment 2 | 3 | import com.skillw.attsystem.AttributeSystem.equipmentDataManager 4 | import com.skillw.pouvoir.api.plugin.map.LowerMap 5 | import org.bukkit.entity.LivingEntity 6 | import org.bukkit.inventory.ItemStack 7 | 8 | /** 9 | * Equipment data compound 10 | * 11 | * @constructor Create empty Equipment data compound 12 | */ 13 | class EquipmentDataCompound() : LowerMap() { 14 | /** Entity */ 15 | var entity: LivingEntity? = null 16 | 17 | constructor(entity: LivingEntity) : this() { 18 | this.entity = entity 19 | } 20 | 21 | constructor(compound: EquipmentDataCompound) : this() { 22 | for (source in compound.keys) { 23 | val equipmentData = compound[source] ?: continue 24 | this[source] = equipmentData.clone(compound, source) 25 | } 26 | } 27 | 28 | fun hasChanged(item: ItemStack, source: String, slot: String): Boolean { 29 | val data = get(source) ?: return true 30 | return data.hasChanged(item, slot) 31 | } 32 | 33 | /** 34 | * Set 35 | * 36 | * @param source 键 37 | * @param slot 子键(槽位) 38 | * @param itemStack 物品 39 | * @return 物品 40 | */ 41 | operator fun set(source: String, slot: String, itemStack: ItemStack): ItemStack { 42 | entity?.let { equipmentDataManager.addEquipment(it, source, slot, itemStack) } 43 | return itemStack 44 | } 45 | 46 | override fun put(key: String, value: EquipmentData): EquipmentData? { 47 | return entity?.let { 48 | equipmentDataManager.addEquipData(it, key, value.apply { 49 | compound = this@EquipmentDataCompound 50 | source = key 51 | }) 52 | } 53 | } 54 | 55 | internal fun uncheckedPut(key: String, value: EquipmentData): EquipmentData? { 56 | return super.put(key, value) 57 | } 58 | 59 | 60 | override fun remove(key: String): EquipmentData? { 61 | return entity?.let { equipmentDataManager.removeEquipData(it, key) }?.free() 62 | } 63 | 64 | fun clear(source: String) { 65 | entity?.let { 66 | equipmentDataManager.clearEquipData(it, source) 67 | } 68 | } 69 | 70 | override fun clear() { 71 | entity?.let { 72 | values.forEach(EquipmentData::free) 73 | equipmentDataManager.clearEquipData(it) 74 | } 75 | } 76 | 77 | fun removeItem(source: String, slot: String): ItemStack? { 78 | return entity?.let { equipmentDataManager.removeItem(it, source, slot) } 79 | } 80 | 81 | /** 82 | * Get 83 | * 84 | * @param key 键 85 | * @param subKey 子键(槽位) 86 | * @return 物品 87 | */ 88 | operator fun get(key: String, subKey: String): ItemStack? { 89 | return this[key]?.get(subKey) 90 | } 91 | 92 | internal fun uncheckedClear() { 93 | return super.clear() 94 | } 95 | 96 | internal fun uncheckedRemove(key: String): EquipmentData? { 97 | return super.remove(key) 98 | } 99 | 100 | /** 101 | * Clone 102 | * 103 | * @return 104 | */ 105 | override fun clone(): EquipmentDataCompound { 106 | return EquipmentDataCompound(this) 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/equipment/EquipmentLoader.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.equipment 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.pouvoir.api.plugin.map.component.Registrable 5 | import org.bukkit.entity.LivingEntity 6 | import org.bukkit.inventory.ItemStack 7 | 8 | /** 9 | * @className EquipmentLoader 10 | * 11 | * @author Glom 12 | * @date 2023/1/22 9:46 Copyright 2023 user. All rights reserved. 13 | */ 14 | interface EquipmentLoader : Registrable, Comparable> { 15 | override val key: String 16 | fun filter(entity: LivingEntity): Boolean = false 17 | fun loadEquipment(entity: E): Map 18 | 19 | val priority: Int 20 | 21 | override fun compareTo(other: EquipmentLoader<*>): Int = if (this.priority == other.priority) 0 22 | else if (this.priority > other.priority) 1 23 | else -1 24 | 25 | override fun register() { 26 | AttributeSystem.equipmentDataManager.registerLoader(this as EquipmentLoader) 27 | } 28 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/AttributeRegisterEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.attsystem.api.attribute.Attribute 4 | import taboolib.platform.type.BukkitProxyEvent 5 | 6 | class AttributeRegisterEvent(val attribute: Attribute) : BukkitProxyEvent() -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/AttributeUpdateEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 4 | import org.bukkit.entity.Entity 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | class AttributeUpdateEvent { 8 | /** 9 | * 属性更新前 10 | * 11 | * @property entity 实体 12 | * @property data 属性数据集 13 | */ 14 | class Pre( 15 | val entity: Entity, 16 | val data: AttributeDataCompound, 17 | ) : BukkitProxyEvent() { 18 | override val allowCancelled = false 19 | } 20 | 21 | /** 22 | * 属性更新中 此时新的属性数据已经加载 但属性映射还没有计算 23 | * 24 | * @property entity 实体 25 | * @property data 属性数据集 26 | */ 27 | class Process( 28 | val entity: Entity, 29 | val data: AttributeDataCompound, 30 | ) : BukkitProxyEvent() { 31 | override val allowCancelled = false 32 | 33 | } 34 | 35 | /** 36 | * 属性更新后 完全新的属性数据 属性映射已计算 37 | * 38 | * @property entity 实体 39 | * @property data 属性数据集 40 | */ 41 | class Post( 42 | val entity: Entity, 43 | val data: AttributeDataCompound, 44 | ) : BukkitProxyEvent() { 45 | override val allowCancelled = false 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/ConditionEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.pouvoir.api.feature.condition.BaseCondition 4 | import org.bukkit.entity.LivingEntity 5 | import taboolib.platform.type.BukkitProxyEvent 6 | import java.util.regex.Matcher 7 | 8 | /** 9 | * 条件处理事件 10 | * 11 | * @property condition 条件 12 | * @property entity 实体 13 | * @property matcher 正则匹配器 14 | * @property text 文本 15 | * @property pass 是否通过 16 | */ 17 | class ConditionEvent( 18 | val condition: BaseCondition, 19 | val entity: LivingEntity?, 20 | val matcher: Matcher, 21 | val text: String, 22 | var pass: Boolean = false, 23 | ) : BukkitProxyEvent() 24 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/EquipmentUpdateEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.attsystem.api.equipment.EquipmentDataCompound 4 | import org.bukkit.entity.Entity 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | class EquipmentUpdateEvent { 8 | 9 | /** 10 | * 装备更新前事件 11 | * 12 | * @property entity 实体 13 | * @property data 装备数据集 14 | */ 15 | class Pre( 16 | val entity: Entity, 17 | val data: EquipmentDataCompound, 18 | ) : BukkitProxyEvent() { 19 | 20 | override val allowCancelled = false 21 | } 22 | 23 | 24 | /** 25 | * 装备更新中事件 26 | * 27 | * @property entity 实体 28 | * @property data 装备数据集 29 | */ 30 | class Process( 31 | val entity: Entity, 32 | val data: EquipmentDataCompound, 33 | ) : BukkitProxyEvent() { 34 | 35 | override val allowCancelled = false 36 | } 37 | 38 | 39 | /** 40 | * 装备更新后事件 41 | * 42 | * @property entity 实体 43 | * @property data 装备数据集 44 | */ 45 | class Post( 46 | val entity: Entity, 47 | val data: EquipmentDataCompound, 48 | ) : BukkitProxyEvent() { 49 | 50 | override val allowCancelled = false 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/HealthRegainEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import org.bukkit.entity.Entity 4 | import taboolib.platform.type.BukkitProxyEvent 5 | 6 | /** 7 | * 回血事件 8 | * 9 | * @constructor Create empty Health regain event 10 | * @property entity 实体 11 | * @property amount 回复量 12 | */ 13 | class HealthRegainEvent(val entity: Entity, var amount: Double) : BukkitProxyEvent() -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/ItemLoadEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import org.bukkit.entity.Entity 4 | import org.bukkit.inventory.ItemStack 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | /** 8 | * 加载物品事件 9 | * 10 | * 物品被加载到装备栏时触发 11 | * 12 | * @constructor Create empty Item load event 13 | * @property entity 实体 14 | * @property itemStack 物品 15 | */ 16 | class ItemLoadEvent( 17 | val entity: Entity, 18 | val itemStack: ItemStack, 19 | ) : BukkitProxyEvent() -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/ItemNBTReadEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 4 | import org.bukkit.entity.LivingEntity 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.platform.type.BukkitProxyEvent 7 | 8 | /** 9 | * Item NBT read event 10 | * 11 | * @constructor Create empty Item n b t read event 12 | * @property entity 实体 13 | * @property itemStack 物品 14 | * @property dataCompound 属性数据集 15 | */ 16 | class ItemNBTReadEvent( 17 | val entity: LivingEntity?, 18 | val itemStack: ItemStack, 19 | val dataCompound: AttributeDataCompound, 20 | ) : BukkitProxyEvent() 21 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/ItemReadEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.attsystem.api.compiled.sub.ComplexCompiledData 4 | import org.bukkit.entity.LivingEntity 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.platform.type.BukkitProxyEvent 7 | 8 | /** 9 | * 读取物品事件 10 | * 11 | * @constructor Create empty Item read event 12 | * @property entity 实体 13 | * @property itemStack 物品 14 | * @property compiledData 预编译属性数据 15 | */ 16 | class ItemReadEvent( 17 | val entity: LivingEntity?, 18 | val itemStack: ItemStack, 19 | val compiledData: ComplexCompiledData, 20 | val slot: String?, 21 | ) : BukkitProxyEvent() { 22 | override val allowCancelled = true 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/StringsReadEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.attsystem.api.compiled.CompiledData 4 | import org.bukkit.entity.LivingEntity 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | /** 8 | * 读取字符串属性事件 9 | * 10 | * @constructor Create empty Strings read event 11 | * @property entity 实体 12 | * @property strings 字符串集 13 | * @property compiledData 预编译属性数据 14 | */ 15 | open class StringsReadEvent( 16 | val entity: LivingEntity?, 17 | val strings: Collection, 18 | val compiledData: CompiledData, 19 | ) : BukkitProxyEvent() -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/event/VanillaAttributeUpdateEvent.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.event 2 | 3 | import com.skillw.pouvoir.util.attribute.BukkitAttribute 4 | import org.bukkit.entity.Entity 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | /** 8 | * 原版属性更新后 9 | * 10 | * @property entity 实体 11 | * @property attr 属性 12 | * @property value 属性值 13 | */ 14 | class VanillaAttributeUpdateEvent ( 15 | val entity: Entity, 16 | val attr: BukkitAttribute, 17 | val value: Double, 18 | ) : BukkitProxyEvent() { 19 | override val allowCancelled = false 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/manager/AttributeDataManager.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem.compiledAttrDataManager 4 | import com.skillw.attsystem.api.attribute.compound.AttributeData 5 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 6 | import com.skillw.attsystem.util.Utils.validEntity 7 | import com.skillw.pouvoir.api.manager.Manager 8 | import com.skillw.pouvoir.api.plugin.map.BaseMap 9 | import org.bukkit.entity.LivingEntity 10 | import java.util.* 11 | 12 | /** 13 | * Attribute data manager 14 | * 15 | * @constructor Create empty Attribute data manager 16 | */ 17 | abstract class AttributeDataManager : BaseMap(), Manager { 18 | 19 | /** 20 | * 更新实体的属性数据 21 | * 22 | * @param entity 实体 23 | * @return 属性数据集 24 | */ 25 | abstract fun update(entity: LivingEntity): AttributeDataCompound? 26 | 27 | 28 | /** 29 | * 给实体添加属性数据 30 | * 31 | * @param entity 实体 32 | * @param source 源 33 | * @param attributeData 属性数据 34 | * @return 属性数据 35 | */ 36 | 37 | abstract fun addAttrData( 38 | entity: LivingEntity, source: String, attributeData: AttributeData, 39 | ): AttributeData 40 | 41 | /** 42 | * 给实体添加属性数据 43 | * 44 | * @param uuid UUID 45 | * @param source 源 46 | * @param attributeData 属性数据 47 | * @return 属性数据 48 | */ 49 | 50 | abstract fun addAttrData( 51 | uuid: UUID, source: String, attributeData: AttributeData, 52 | ): AttributeData 53 | 54 | /** 55 | * 给实体添加属性数据 56 | * 57 | * @param entity 实体 58 | * @param source 源 59 | * @param attributes 字符串集(会据此读取出属性数据) 60 | * @param release 是否在下次更新时释放属性数据 61 | * @return 属性数据 62 | */ 63 | @Deprecated("addAttrData", ReplaceWith("addAttrData(entity, key, attributes)")) 64 | fun addAttribute( 65 | entity: LivingEntity, 66 | source: String, 67 | attributes: Collection, 68 | release: Boolean = false, 69 | ): AttributeData? = 70 | compiledAttrDataManager.addCompiledData(entity, source, attributes)?.eval(entity)?.toAttributeData() 71 | 72 | /** 73 | * 给实体添加属性数据 74 | * 75 | * @param entity 实体 76 | * @param source 源 77 | * @param attributeData 属性数据 78 | * @param release 是否在下次更新时释放属性数据 79 | * @return 属性数据 80 | */ 81 | @Deprecated("addAttrData", ReplaceWith("addAttrData(entity, key, attributeData)")) 82 | fun addAttribute( 83 | entity: LivingEntity, source: String, attributeData: AttributeData, 84 | release: Boolean = false, 85 | ): AttributeData = addAttrData(entity, source, attributeData) 86 | 87 | /** 88 | * 给实体添加属性数据 89 | * 90 | * @param uuid UUID 91 | * @param source 源 92 | * @param attributes 字符串集(会据此读取出属性数据) 93 | * @param release 是否在下次更新时释放属性数据 94 | * @return 属性数据 95 | */ 96 | @Deprecated("addAttrData", ReplaceWith("addAttrData(uuid, key, attributes)")) 97 | fun addAttribute( 98 | uuid: UUID, source: String, attributes: Collection, 99 | release: Boolean = false, 100 | ): AttributeData? = uuid.validEntity()?.let { addAttribute(it, source, attributes) } 101 | 102 | /** 103 | * 给实体添加属性数据 104 | * 105 | * @param uuid UUID 106 | * @param source 源 107 | * @param attributeData 属性数据 108 | * @param release 是否在下次更新时释放属性数据 109 | * @return 属性数据 110 | */ 111 | @Deprecated("addAttrData", ReplaceWith("addAttrData(uuid, key, attributeData)")) 112 | fun addAttribute( 113 | uuid: UUID, source: String, attributeData: AttributeData, 114 | release: Boolean = false, 115 | ): AttributeData = addAttrData(uuid, source, attributeData) 116 | 117 | /** 118 | * 根据 源 删除实体的属性数据 119 | * 120 | * @param entity 实体 121 | * @param source 源 122 | */ 123 | @Deprecated("removeAttrData", ReplaceWith("removeAttrData(entity, key)")) 124 | fun removeAttribute(entity: LivingEntity, source: String) = removeAttrData(entity, source) 125 | 126 | /** 127 | * 根据 源 删除实体的属性数据 128 | * 129 | * @param uuid UUID 130 | * @param source 源 131 | */ 132 | @Deprecated("removeAttrData", ReplaceWith("removeAttrData(uuid, key)")) 133 | fun removeAttribute(uuid: UUID, source: String) = removeAttrData(uuid, source) 134 | 135 | /** 136 | * 根据 源 删除实体的属性数据 137 | * 138 | * @param entity 实体 139 | * @param source 源 140 | */ 141 | abstract fun removeAttrData(entity: LivingEntity, source: String): AttributeData? 142 | 143 | /** 144 | * 根据 源 删除实体的属性数据 145 | * 146 | * @param uuid UUID 147 | * @param source 源 148 | */ 149 | abstract fun removeAttrData(uuid: UUID, source: String): AttributeData? 150 | 151 | override fun get(key: UUID): AttributeDataCompound? { 152 | return super.get(key) 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/manager/AttributeManager.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.manager 2 | 3 | import com.skillw.attsystem.api.attribute.Attribute 4 | import com.skillw.pouvoir.api.manager.Manager 5 | import com.skillw.pouvoir.api.plugin.SubPouvoir 6 | import com.skillw.pouvoir.api.plugin.map.LowerKeyMap 7 | import com.skillw.pouvoir.api.plugin.map.LowerMap 8 | import java.io.File 9 | 10 | /** 11 | * Attribute manager 12 | * 13 | * @constructor Create empty Attribute manager 14 | */ 15 | abstract class AttributeManager : LowerKeyMap(), Manager { 16 | 17 | 18 | abstract val nameMap: LowerMap 19 | 20 | /** Attributes (按权重排列) */ 21 | abstract val attributes: List 22 | abstract fun reloadFolder(folder: File) 23 | abstract fun addDataFolders(folder: File) 24 | abstract fun addSubPouvoir(subPouvoir: SubPouvoir) 25 | abstract fun unregister(key: String) 26 | 27 | abstract fun find(text: String): Attribute? 28 | } 29 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/manager/CompileManager.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.manager 2 | 3 | import com.skillw.attsystem.api.attribute.compound.AttributeData 4 | import com.skillw.attsystem.api.compiled.sub.ComplexCompiledData 5 | import com.skillw.attsystem.api.compiled.sub.NBTCompiledData 6 | import com.skillw.attsystem.api.compiled.sub.StringsCompiledData 7 | import com.skillw.pouvoir.api.manager.Manager 8 | import org.bukkit.entity.LivingEntity 9 | 10 | /** 11 | * Condition manager 12 | * 13 | * @constructor Create empty Condition manager 14 | */ 15 | abstract class CompileManager : Manager { 16 | /** 17 | * 构建 NBT预编译属性的构造器 18 | * 19 | * @param entity 实体 20 | * @param nbt NBT 21 | * @param slot 槽位 22 | * @return NBT条件的构造器 23 | */ 24 | abstract fun compile( 25 | entity: LivingEntity?, 26 | nbt: Collection, 27 | slot: String? = null, 28 | ): (MutableMap) -> NBTCompiledData 29 | 30 | 31 | /** 32 | * 构建 字符串预编译属性的构造器 33 | * 34 | * @param entity 实体 35 | * @param string 字符串 36 | * @param slot 槽位 37 | * @return 字符串预编译属性的构造器,若无条件则返回null 38 | */ 39 | abstract fun compile( 40 | entity: LivingEntity?, 41 | string: String, 42 | slot: String? = null, 43 | ): ((AttributeData) -> StringsCompiledData)? 44 | 45 | 46 | /** 47 | * 属性映射 48 | * 49 | * @param entity LivingEntity? 50 | * @return 预编译映射属性的构造器 51 | */ 52 | abstract fun mapping( 53 | entity: LivingEntity?, 54 | ): (AttributeData) -> ComplexCompiledData 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/manager/CompiledAttrDataManager.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.manager 2 | 3 | import com.skillw.attsystem.api.compiled.CompiledAttrDataCompound 4 | import com.skillw.attsystem.api.compiled.CompiledData 5 | import com.skillw.pouvoir.api.manager.Manager 6 | import com.skillw.pouvoir.api.plugin.map.BaseMap 7 | import org.bukkit.entity.LivingEntity 8 | import java.util.* 9 | 10 | /** 11 | * Attribute data manager 12 | * 13 | * @constructor Create empty Attribute data manager 14 | */ 15 | abstract class CompiledAttrDataManager : BaseMap(), Manager { 16 | 17 | /** 18 | * 是否有此预编译数据 19 | * 20 | * @param entity LivingEntity 21 | * @param source String 源 22 | * @return Boolean 23 | */ 24 | abstract fun hasCompiledData(entity: LivingEntity, source: String): Boolean 25 | 26 | 27 | /** 28 | * 是否有此预编译数据 29 | * 30 | * @param uuid UUID 31 | * @param source String 源 32 | * @return Boolean 33 | */ 34 | abstract fun hasCompiledData(uuid: UUID, source: String): Boolean 35 | 36 | 37 | /** 38 | * 给实体添加预编译属性数据 39 | * 40 | * @param entity 实体 41 | * @param source 源 42 | * @param attributes 字符串集(会据此读取出预编译属性数据) 43 | * @return 预编译属性数据 44 | */ 45 | 46 | abstract fun addCompiledData( 47 | entity: LivingEntity, 48 | source: String, 49 | attributes: Collection, slot: String? = null, 50 | ): CompiledData? 51 | 52 | /** 53 | * 给实体添加预编译属性数据 54 | * 55 | * @param entity 实体 56 | * @param source 源 57 | * @param compiledData 预编译属性数据 58 | * @return 预编译属性数据 59 | */ 60 | 61 | abstract fun addCompiledData( 62 | entity: LivingEntity, source: String, compiledData: CompiledData, 63 | ): CompiledData 64 | 65 | /** 66 | * 给实体添加预编译属性数据 67 | * 68 | * @param uuid UUID 69 | * @param source 源 70 | * @param attributes 字符串集(会据此读取出预编译属性数据) 71 | * @return 预编译属性数据 72 | */ 73 | 74 | abstract fun addCompiledData( 75 | uuid: UUID, source: String, attributes: Collection, slot: String? = null, 76 | ): CompiledData? 77 | 78 | /** 79 | * 给实体添加预编译属性数据 80 | * 81 | * @param uuid UUID 82 | * @param source 源 83 | * @param compiledData 预编译属性数据 84 | * @return 预编译属性数据 85 | */ 86 | 87 | abstract fun addCompiledData( 88 | uuid: UUID, source: String, compiledData: CompiledData, 89 | ): CompiledData? 90 | 91 | 92 | /** 93 | * 根据 键(源) 删除实体的预编译属性数据 94 | * 95 | * @param entity 实体 96 | * @param source 键(源) 97 | */ 98 | abstract fun removeCompiledData(entity: LivingEntity, source: String): CompiledData? 99 | 100 | /** 101 | * 根据 键(源) 删除实体的预编译属性数据 102 | * 103 | * @param uuid UUID 104 | * @param source 键(源) 105 | */ 106 | abstract fun removeCompiledData(uuid: UUID, source: String): CompiledData? 107 | 108 | /** 109 | * 删除所有以 所给前缀 为开头的 预编译属性数据 110 | * 111 | * @param uuid UUID 112 | * @param prefix String 前缀 113 | */ 114 | abstract fun removeIfStartWith(uuid: UUID, prefix: String) 115 | 116 | /** 117 | * 删除所有以 所给前缀 为开头的 预编译属性数据 118 | * 119 | * @param entity LivingEntity 120 | * @param prefix String 前缀 121 | */ 122 | abstract fun removeIfStartWith(entity: LivingEntity, prefix: String) 123 | 124 | abstract override fun get(key: UUID): CompiledAttrDataCompound? 125 | } 126 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/manager/ReadManager.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.manager 2 | 3 | import com.skillw.attsystem.api.compiled.CompiledData 4 | import com.skillw.attsystem.api.compiled.sub.NBTCompiledData 5 | import com.skillw.pouvoir.api.manager.Manager 6 | import org.bukkit.entity.LivingEntity 7 | import org.bukkit.inventory.ItemStack 8 | 9 | /** 10 | * ReadManager 11 | * 12 | * @constructor Create empty ReadManager 13 | */ 14 | abstract class ReadManager : Manager { 15 | /** 16 | * 预读取字符串集的属性数据 17 | * 18 | * @param strings 待读取属性的字符串集 19 | * @param entity 实体 20 | * @param slot 槽位(可为null) 21 | * @return 预编译属性数据 (StringsReadEvent事件被取消时返回null) 22 | */ 23 | abstract fun read( 24 | strings: Collection, 25 | entity: LivingEntity? = null, 26 | slot: String? = null, 27 | ): CompiledData? 28 | 29 | /** 30 | * 预读取物品 lore 上的属性 31 | * 32 | * @param itemStack 物品 33 | * @param entity 实体 34 | * @param slot 槽位 35 | * @return 物品LORE属性数据 无lore则返回null 36 | */ 37 | abstract fun readItemLore( 38 | itemStack: ItemStack, entity: LivingEntity? = null, slot: String? = null, 39 | ): CompiledData? 40 | 41 | 42 | /** 43 | * 预读取物品 lore 上的属性 44 | * 45 | * @param itemStacks 物品 46 | * @param entity 实体 47 | * @param slot 槽位 48 | * @return 物品LORE属性数据 49 | */ 50 | abstract fun readItemsLore( 51 | itemStacks: Collection, entity: LivingEntity? = null, slot: String? = null, 52 | ): CompiledData 53 | 54 | /** 55 | * 预读取物品 NBT 上的属性 56 | * 57 | * @param itemStack 物品 58 | * @param entity 实体 59 | * @param slot 槽位 60 | * @return 物品NBT属性数据集 61 | */ 62 | abstract fun readItemNBT( 63 | itemStack: ItemStack, entity: LivingEntity? = null, slot: String? = null, 64 | ): CompiledData? 65 | 66 | /** 67 | * 预读取物品 NBT 上的属性 68 | * 69 | * @param itemStacks 物品 70 | * @param entity 实体 71 | * @param slot 槽位 72 | * @return 物品NBT属性数据集 73 | */ 74 | abstract fun readItemsNBT( 75 | itemStacks: Collection, entity: LivingEntity? = null, slot: String? = null, 76 | ): CompiledData 77 | 78 | 79 | /** 80 | * 预读取物品属性 (lore 与 nbt) 都读 81 | * 82 | * 读取物品的属性数据集(lore & NBT) 83 | * 84 | * 触发ItemReadEvent 85 | * 86 | * @param itemStack 物品 87 | * @param entity 实体 88 | * @param slot 槽位 89 | * @return 预编译属性数据 (ItemReadEvent事件被取消时返回null) 90 | */ 91 | abstract fun readItem( 92 | itemStack: ItemStack, entity: LivingEntity? = null, slot: String? = null, 93 | ): CompiledData? 94 | 95 | 96 | /** 97 | * 预读取物品属性 (lore 与 nbt) 都读 98 | * 99 | * @param itemStacks 物品 100 | * @param entity 实体 101 | * @param slot 槽位 102 | * @return 预编译属性数据 103 | */ 104 | abstract fun readItems( 105 | itemStacks: Collection, entity: LivingEntity? = null, slot: String? = null, 106 | ): CompiledData 107 | 108 | /** 109 | * 预读取属性,格式与NBT一样 110 | * 111 | * @param attrDataMap MutableMap 112 | * @param conditions Collection 113 | * @param entity LivingEntity? 114 | * @param slot String? 115 | * @return CompiledData 116 | */ 117 | 118 | abstract fun readMap( 119 | attrDataMap: MutableMap, 120 | conditions: Collection, 121 | entity: LivingEntity? = null, 122 | slot: String? = null, 123 | ): NBTCompiledData 124 | 125 | /** 126 | * 预编译属性 127 | * 128 | * # map中应包含 129 | * 130 | * ``` 131 | * type: nbt / strings(默认) 132 | * ``` 133 | * 134 | * ## Type-Strings: 135 | * ``` 136 | * attributes: 137 | * - '需要在地面上' 138 | * - '攻击力: 100 / 需要生命值属性: 10' 139 | * ``` 140 | * 141 | * ## Type-NBT: 142 | * ``` 143 | * attributes: 144 | * ababa: 145 | * PhysicalDamage: 146 | * value: 100 147 | * conditions: 148 | * - conditions: 149 | * - key: ground 150 | * status: true 151 | * - conditions: 152 | * - key: attribute 153 | * name: 生命值 154 | * value: 10 155 | * paths: [ "ababa.PhysicalDamage.value" ] 156 | * ``` 157 | * 158 | * 以上两个示例的效果是一模一样的 159 | * 160 | * @param map Map 161 | * @param entity LivingEntity? 162 | * @param slot String? 163 | * @return CompiledData? 读取失败时返回null 164 | */ 165 | 166 | abstract fun readMap( 167 | map: Map, 168 | entity: LivingEntity? = null, 169 | slot: String? = null, 170 | ): CompiledData? 171 | } 172 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/manager/ReadPatternManager.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.manager 2 | 3 | import com.skillw.attsystem.api.read.ReadPattern 4 | import com.skillw.pouvoir.api.manager.Manager 5 | import com.skillw.pouvoir.api.plugin.map.LowerKeyMap 6 | 7 | /** 8 | * Read pattern manager 9 | * 10 | * @constructor Create empty Read pattern manager 11 | */ 12 | abstract class ReadPatternManager : LowerKeyMap>(), Manager {} 13 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/manager/RealizerManager.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 5 | 6 | /** 7 | * Realize manager 8 | * 9 | * @constructor Create empty Realize manager 10 | */ 11 | abstract class RealizerManager : BaseRealizerManager("as-realizer-manager", AttributeSystem) 12 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/read/ReadPattern.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.read 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.attribute.Attribute 5 | import com.skillw.attsystem.api.read.status.Status 6 | import com.skillw.pouvoir.api.feature.operation.Operation 7 | import com.skillw.pouvoir.api.plugin.map.LowerMap 8 | import com.skillw.pouvoir.api.plugin.map.component.Registrable 9 | import org.bukkit.entity.LivingEntity 10 | import taboolib.module.chat.ComponentText 11 | 12 | /** 13 | * Read pattern 14 | * 15 | * 读取格式 16 | * 17 | * 你可以通过拓展该类来实现自己的读取格式 (记得注册) 18 | * 19 | * 对应的属性状态可以用自带的或者自己拓展 20 | * 21 | * 读取时不用考虑是否符合条件 已经处理过了 22 | * 23 | * @constructor Create empty Read pattern 24 | * @property key 读取格式键 25 | */ 26 | abstract class ReadPattern( 27 | override val key: String, 28 | ) : Registrable { 29 | /** 是否在重载时删除 */ 30 | var release = false 31 | 32 | /** 33 | * Status中可能的键 34 | * 35 | * @return Set 36 | */ 37 | abstract fun operations(): LowerMap> 38 | 39 | /** 40 | * Read 41 | * 42 | * 读取单行字符串 43 | * 44 | * @param string 字符串 45 | * @param attribute 属性 46 | * @param entity 实体 47 | * @param slot 槽位 48 | * @return 读取结果-属性状态 49 | */ 50 | abstract fun read( 51 | string: String, 52 | attribute: Attribute, 53 | entity: LivingEntity?, 54 | slot: String?, 55 | ): Status? 56 | 57 | /** 58 | * Read 读取单行字符串 (无槽位) 59 | * 60 | * @param string 字符串 61 | * @param attribute 属性 62 | * @param entity 实体 63 | * @return 读取结果-属性状态 64 | */ 65 | fun read( 66 | string: String, 67 | attribute: Attribute, 68 | entity: LivingEntity?, 69 | ): Status? { 70 | return read(string, attribute, entity, "null") 71 | } 72 | 73 | /** 74 | * Read NBT 75 | * 76 | * @param map NBT 77 | * @param attribute 属性 78 | * @return 读取结果-属性状态 79 | */ 80 | abstract fun readNBT( 81 | map: Map, 82 | attribute: Attribute, 83 | ): Status? 84 | 85 | /** 86 | * Placeholder 87 | * 88 | * 占位符(读取组内部的,会在 %as_att:属性键_占位符键% 生效) 89 | * 90 | * @param key 占位符键 91 | * @param attribute 属性 92 | * @param status 属性状态 93 | * @param entity 实体 94 | * @return 返回值 95 | */ 96 | abstract fun placeholder( 97 | key: String, 98 | attribute: Attribute, 99 | status: Status<*>, 100 | entity: LivingEntity? = null, 101 | ): A? 102 | 103 | /** 104 | * 用于指令统计信息 可以直接返回 TellrawJson() 空对象 105 | * 106 | * @param attribute 属性 107 | * @param status 属性状态 108 | * @param entity 实体 109 | * @return ComponentText 110 | */ 111 | open fun stat( 112 | attribute: Attribute, 113 | status: Status<*>, 114 | entity: LivingEntity?, 115 | ): ComponentText { 116 | return ComponentText.empty() 117 | } 118 | 119 | open fun getTotal(attribute: Attribute, status: Status<*>, entity: LivingEntity?): A? = 120 | placeholder("total", attribute, status, entity) 121 | 122 | open fun getMin(attribute: Attribute, status: Status<*>, entity: LivingEntity?): A? = 123 | placeholder("min", attribute, status, entity) 124 | 125 | open fun getMax(attribute: Attribute, status: Status<*>, entity: LivingEntity?): A? = 126 | placeholder("max", attribute, status, entity) 127 | 128 | override fun register() { 129 | AttributeSystem.readPatternManager.register(this) 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/read/status/NumberStatus.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.read.status 2 | 3 | import com.skillw.pouvoir.api.feature.operation.NumberOperation 4 | import com.skillw.attsystem.internal.core.read.BaseReadGroup 5 | 6 | /** 7 | * Number status 8 | * 9 | * @constructor Create empty Number status 10 | * @property numberReader 11 | */ 12 | class NumberStatus(numberReader: BaseReadGroup) : Status(numberReader) { 13 | 14 | override fun clone(): NumberStatus { 15 | val attributeStatus = NumberStatus(readGroup) 16 | this.forEach { 17 | attributeStatus.register(it.key, it.value) 18 | } 19 | return attributeStatus 20 | } 21 | 22 | 23 | /** 24 | * NumberOperation 25 | * 26 | * @param status 属性状态 27 | * @param operation 运算操作 28 | * @return 运算结果(自身) 29 | */ 30 | fun operation(status: NumberStatus, operation: NumberOperation): NumberStatus { 31 | for (key in status.keys) { 32 | if (this.containsKey(key)) { 33 | this.register(key, operation.operate(get(key)!!, status[key]!!).toDouble()) 34 | } else { 35 | this.register(key, status[key]!!) 36 | } 37 | } 38 | return this 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/read/status/Status.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.read.status 2 | 3 | import com.skillw.attsystem.api.attribute.Attribute 4 | import com.skillw.attsystem.internal.core.read.BaseReadGroup 5 | import com.skillw.pouvoir.api.feature.operation.Operation 6 | import com.skillw.pouvoir.api.plugin.map.LowerMap 7 | import org.bukkit.entity.LivingEntity 8 | 9 | /** 10 | * Status 11 | * 12 | * @constructor Create empty Status 13 | */ 14 | abstract class Status(val readGroup: BaseReadGroup) : LowerMap() { 15 | open fun operation(status: Status<*>): Status { 16 | status as? Status ?: return this 17 | for (key in status.keys) { 18 | if (this.containsKey(key)) { 19 | this.register( 20 | key, 21 | readGroup.operations()[key]?.operate(get(key) ?: continue, status[key] ?: continue) 22 | ?: continue 23 | ) 24 | } else { 25 | this.register(key, status[key] ?: continue) 26 | } 27 | } 28 | return this 29 | } 30 | 31 | open fun getTotal(attribute: Attribute, entity: LivingEntity): A? = readGroup.getTotal(attribute, this, entity) 32 | open fun getMin(attribute: Attribute, entity: LivingEntity?): A? = readGroup.getMin(attribute, this, entity) 33 | open fun getMax(attribute: Attribute, entity: LivingEntity?): A? = readGroup.getMax(attribute, this, entity) 34 | 35 | /** 36 | * NumberOperation 37 | * 38 | * 做运算 39 | * 40 | * @param key (捕获组)键 41 | * @param value (捕获组)值 42 | * @param operation 运算操作 43 | * @return 运算结果(自身) 44 | */ 45 | open fun operation(key: String, value: A, operation: Operation): Status { 46 | if (this.containsKey(key)) { 47 | this.register(key, operation.operate(get(key) ?: return this, value)) 48 | } else { 49 | this.register(key, value) 50 | } 51 | return this 52 | } 53 | 54 | /** 55 | * Serialize 56 | * 57 | * @return 序列化结果 58 | */ 59 | open fun serialize(): MutableMap { 60 | return HashMap(this) 61 | } 62 | 63 | /** 64 | * Clone 65 | * 66 | * @return 复制结果 67 | */ 68 | public abstract override fun clone(): Status 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/api/read/status/StringStatus.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.api.read.status 2 | 3 | import com.skillw.attsystem.internal.core.read.BaseReadGroup 4 | 5 | /** 6 | * Number status 7 | * 8 | * @constructor Create empty Number status 9 | * @property numberReader 10 | */ 11 | class StringStatus(numberReader: BaseReadGroup) : Status(numberReader) { 12 | override fun clone(): StringStatus { 13 | val attributeStatus = StringStatus(readGroup) 14 | this.forEach { 15 | attributeStatus.register(it.key, it.value) 16 | } 17 | return attributeStatus 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/command/ASCommand.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.command 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.internal.command.sub.AttributeStatsCommand 5 | import com.skillw.attsystem.internal.command.sub.MirrorCommand 6 | import com.skillw.attsystem.internal.manager.ASConfig 7 | import com.skillw.pouvoir.util.soundClick 8 | import com.skillw.pouvoir.util.soundFail 9 | import com.skillw.pouvoir.util.soundSuccess 10 | import org.bukkit.Bukkit 11 | import org.bukkit.entity.Player 12 | import taboolib.common.platform.ProxyCommandSender 13 | import taboolib.common.platform.command.CommandBody 14 | import taboolib.common.platform.command.CommandHeader 15 | import taboolib.common.platform.command.mainCommand 16 | import taboolib.common.platform.command.subCommand 17 | import taboolib.common.platform.function.pluginVersion 18 | import taboolib.module.chat.colored 19 | import taboolib.module.lang.sendLang 20 | 21 | @CommandHeader(name = "as", permission = "as.command") 22 | object ASCommand { 23 | internal fun ProxyCommandSender.soundSuccess() { 24 | (this.origin as? Player?)?.soundSuccess() 25 | } 26 | 27 | internal fun ProxyCommandSender.soundFail() { 28 | (this.origin as? Player?)?.soundFail() 29 | } 30 | 31 | internal fun ProxyCommandSender.soundClick() { 32 | (this.origin as? Player?)?.soundClick() 33 | } 34 | 35 | @CommandBody 36 | val main = mainCommand { 37 | execute { sender, _, _ -> 38 | sender.sendLang("command-info") 39 | sender.soundSuccess() 40 | } 41 | incorrectCommand { sender, _, _, _ -> 42 | sender.sendLang("wrong-command") 43 | sender.soundFail() 44 | } 45 | incorrectSender { sender, _ -> 46 | sender.sendLang("wrong-sender") 47 | sender.soundFail() 48 | } 49 | } 50 | 51 | @CommandBody(permission = "as.command.help") 52 | val help = subCommand { 53 | execute { sender, _, _ -> 54 | sender.soundSuccess() 55 | sender.sendLang("command-info") 56 | } 57 | } 58 | 59 | @CommandBody(permission = "as.command.debug") 60 | val debug = subCommand { 61 | execute { sender, _, _ -> 62 | sender.soundSuccess() 63 | ASConfig.debugMode = !ASConfig.debugMode 64 | sender.sendLang("command-debug-${if (ASConfig.debugMode) "on" else "off"}") 65 | } 66 | } 67 | 68 | @CommandBody(permission = "as.command.info") 69 | val info = subCommand { 70 | execute { sender, _, _ -> 71 | sender.soundSuccess() 72 | sender.sendMessage("&aAttributeSystem &9v$pluginVersion &6By Glom_".colored()) 73 | } 74 | } 75 | 76 | @CommandBody(permission = "as.command.reload") 77 | val reload = subCommand { 78 | execute { sender, _, _ -> 79 | sender.soundSuccess() 80 | AttributeSystem.reload() 81 | sender.sendLang("command-reload") 82 | } 83 | } 84 | 85 | @CommandBody(permission = "as.command.disable") 86 | val disable = subCommand { 87 | dynamic { 88 | execute { sender, _, argument -> 89 | sender.soundFail() 90 | if (argument != "confirm") return@execute 91 | Bukkit.getScheduler().cancelTasks(AttributeSystem.plugin) 92 | Bukkit.getPluginManager().disablePlugin(AttributeSystem.plugin) 93 | sender.sendLang("command-disable") 94 | } 95 | } 96 | execute { sender, _, _ -> 97 | sender.soundFail() 98 | sender.sendLang("command-disable-warning") 99 | } 100 | } 101 | 102 | @CommandBody(permission = "as.command.report") 103 | val report = MirrorCommand.report 104 | 105 | @CommandBody(permission = "as.command.clear") 106 | val clear = MirrorCommand.clear 107 | 108 | @CommandBody(permission = "as.command.stats") 109 | val stats = AttributeStatsCommand.stats 110 | @CommandBody(permission = "as.command.data") 111 | val data = AttributeStatsCommand.data 112 | 113 | @CommandBody(permission = "as.command.stats") 114 | val itemstats = AttributeStatsCommand.itemstats 115 | 116 | @CommandBody(permission = "as.command.stats") 117 | val entitystats = AttributeStatsCommand.entitystats 118 | } 119 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/command/sub/MirrorCommand.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.command.sub 2 | 3 | import com.skillw.attsystem.internal.command.ASCommand.soundSuccess 4 | import com.skillw.attsystem.util.legacy.Mirror 5 | import taboolib.common.platform.ProxyCommandSender 6 | import taboolib.common.platform.command.subCommand 7 | import taboolib.common.platform.function.submitAsync 8 | import taboolib.module.lang.sendLang 9 | 10 | object MirrorCommand { 11 | val report = subCommand { 12 | execute { sender, _, _ -> 13 | sender.soundSuccess() 14 | submitAsync { Mirror.report(sender) } 15 | } 16 | } 17 | 18 | val clear = subCommand { 19 | execute { sender, _, _ -> 20 | sender.soundSuccess() 21 | sender.sendLang("command-clear") 22 | Mirror.mirrorData.clear() 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/asahi/Operator.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.asahi 2 | 3 | import com.skillw.asahi.api.annotation.AsahiGetter 4 | import com.skillw.asahi.api.annotation.AsahiSetter 5 | import com.skillw.asahi.api.member.context.AsahiContext 6 | import com.skillw.attsystem.api.AttrAPI.attribute 7 | import com.skillw.attsystem.api.attribute.Attribute 8 | import com.skillw.attsystem.api.attribute.compound.AttributeData 9 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 10 | import com.skillw.attsystem.api.read.status.Status 11 | import com.skillw.attsystem.internal.core.read.BaseReadGroup 12 | import com.skillw.attsystem.internal.feature.compat.pouvoir.AttributePlaceHolder 13 | 14 | /** 15 | * @className Operator 16 | * 17 | * @author Glom 18 | * @date 2023/1/23 17:07 Copyright 2023 user. All rights reserved. 19 | */ 20 | 21 | @AsahiGetter 22 | object DataGetter : AsahiContext.Getter("attribute-data", 1) { 23 | 24 | override fun AsahiContext.filter(key: String): Boolean { 25 | return key.contains(".") && getOrigin(key.split(".")[0]) is AttributeDataCompound 26 | } 27 | 28 | override fun AsahiContext.getValue(key: String): Any? { 29 | val varKey = key.split(".")[0] 30 | val data = getOrigin(varKey) 31 | val subKeys = key.substringAfter("$varKey.").split(".") 32 | return when (data) { 33 | is AttributeDataCompound -> { 34 | val attribute = attribute(subKeys[0]) ?: return null 35 | val params = subKeys.toMutableList().apply { removeFirst() } 36 | AttributePlaceHolder.get(data, attribute, params) 37 | } 38 | 39 | else -> null 40 | } 41 | } 42 | } 43 | 44 | @AsahiSetter 45 | object DataSetter : AsahiContext.Setter("attribute-data", 1) { 46 | 47 | override fun AsahiContext.filter(key: String): Boolean { 48 | return key.contains(".") && getOrigin(key.split(".")[0]) is AttributeDataCompound 49 | } 50 | 51 | 52 | private fun AttributeDataCompound.put( 53 | source: String, 54 | attribute: Attribute, 55 | data: Status<*>, 56 | ) { 57 | 58 | } 59 | 60 | override fun AsahiContext.setValue(key: String, value: Any?): Any? { 61 | val varKey = key.split(".")[0] 62 | val data = getOrigin(varKey) 63 | val subKeys = key.substringAfter("$varKey.").split(".") 64 | return when (data) { 65 | is AttributeDataCompound -> { 66 | when (subKeys.size) { 67 | 0 -> { 68 | return null 69 | } 70 | 71 | 1 -> { 72 | val source = subKeys[0] 73 | data[source] = AttributeData.fromMap(value as Map) 74 | } 75 | 76 | 2 -> { 77 | val source = subKeys[0] 78 | val attribute = attribute(subKeys[1]) ?: return null 79 | val status = 80 | attribute.readPattern.readNBT(value as Map, attribute) as Status<*> 81 | data.computeIfAbsent(source) { AttributeData() }[attribute] = status 82 | 83 | } 84 | 85 | else -> { 86 | val source = subKeys[0] 87 | val attribute = attribute(subKeys[1]) ?: return null 88 | if (attribute.readPattern !is BaseReadGroup<*>) return null 89 | val matcher = subKeys[2] 90 | value ?: (data[source, attribute] as? Status)?.remove(matcher) 91 | value?.let { (data[source, attribute] as? Status)?.set(matcher, it) } 92 | 93 | } 94 | 95 | } 96 | } 97 | 98 | else -> null 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/asahi/prefix/Attribute.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.asahi.prefix 2 | 3 | import com.skillw.asahi.api.annotation.AsahiPrefix 4 | import com.skillw.asahi.api.prefixParser 5 | import com.skillw.asahi.api.quest 6 | import com.skillw.asahi.api.quester 7 | import com.skillw.attsystem.api.AttrAPI.addAttribute 8 | import com.skillw.attsystem.api.AttrAPI.getAttrData 9 | import com.skillw.attsystem.api.AttrAPI.read 10 | import com.skillw.attsystem.api.AttrAPI.readItem 11 | import com.skillw.attsystem.api.AttrAPI.readItemLore 12 | import com.skillw.attsystem.api.AttrAPI.readItemNBT 13 | import com.skillw.attsystem.api.AttrAPI.removeAttribute 14 | import com.skillw.attsystem.api.AttrAPI.updateAttr 15 | import com.skillw.attsystem.api.attribute.compound.AttributeData 16 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 17 | import org.bukkit.entity.LivingEntity 18 | import org.bukkit.inventory.ItemStack 19 | import taboolib.module.nms.ItemTagData 20 | import taboolib.module.nms.getItemTag 21 | 22 | 23 | @AsahiPrefix(["attr"]) 24 | private fun attr() = prefixParser { 25 | when (val type = next()) { 26 | "data" -> { 27 | val entity = if (expect("of")) quest() else quester { selector() } 28 | result { 29 | entity.get().getAttrData() 30 | } 31 | } 32 | 33 | "read" -> { 34 | val list = quest>() 35 | val slot = if (expect("slot")) quest() else quester { null } 36 | result { list.get().map { it.toString() }.read(selectorSafely(), slot.get()) } 37 | } 38 | 39 | "readItem" -> { 40 | val item = quest() 41 | val slot = if (expect("slot")) quest() else quester { null } 42 | result { item.get().readItem(selectorSafely(), slot.get()) } 43 | } 44 | 45 | "readLore" -> { 46 | val item = quest() 47 | val slot = if (expect("slot")) quest() else quester { null } 48 | result { item.get().readItemLore(selectorSafely(), slot.get()) } 49 | } 50 | 51 | "readNBT" -> { 52 | val item = quest() 53 | val slot = if (expect("slot")) quest() else quester { null } 54 | result { item.get().readItemNBT(selectorSafely(), slot.get()) } 55 | } 56 | 57 | "add" -> { 58 | val key = quest() 59 | val attributeData = quest() 60 | result { selector().addAttribute(key.get(), attributeData.get()) } 61 | } 62 | 63 | "remove" -> { 64 | val key = quest() 65 | result { selector().removeAttribute(key.toString()) } 66 | } 67 | 68 | 69 | "addItemAttr" -> { 70 | val key = quest() 71 | val attributeData = quest() 72 | result { 73 | selector().let { 74 | it.getItemTag().apply { 75 | putDeep("ATTRIBUTE_DATA.${key.get()}", ItemTagData.toNBT(attributeData.get().serialize())) 76 | saveTo(it) 77 | } 78 | } 79 | } 80 | } 81 | 82 | "addItemAttrs" -> { 83 | val compound = quest() 84 | result { 85 | selector().let { 86 | compound.get().saveTo(it) 87 | } 88 | } 89 | } 90 | 91 | "removeItemAttr" -> { 92 | val key = quest() 93 | result { 94 | selector().let { 95 | it.getItemTag().apply { 96 | removeDeep("ATTRIBUTE_DATA.${key.get()}") 97 | saveTo(it) 98 | } 99 | } 100 | } 101 | } 102 | 103 | "update" -> { 104 | result { 105 | selector().updateAttr() 106 | } 107 | } 108 | 109 | else -> { 110 | error("Invalid Attr token $type") 111 | } 112 | } 113 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/attribute/ConfigAttributeBuilder.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.attribute 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.attribute.Attribute 5 | import com.skillw.attsystem.api.attribute.Mapping 6 | import com.skillw.attsystem.api.read.ReadPattern 7 | import com.skillw.attsystem.internal.core.attribute.mapping.DefaultMapping 8 | import com.skillw.pouvoir.api.plugin.`object`.BaseObject 9 | import com.skillw.pouvoir.util.toMap 10 | import org.bukkit.Bukkit 11 | import org.bukkit.configuration.ConfigurationSection 12 | import taboolib.common.platform.function.console 13 | import taboolib.common5.Coerce 14 | import taboolib.module.lang.sendLang 15 | import taboolib.platform.util.sendLang 16 | 17 | class ConfigAttributeBuilder( 18 | override val key: String, 19 | override val priority: Int, 20 | private val display: String? = null, 21 | private val names: List, 22 | private val readPattern: ReadPattern<*>, 23 | private val isEntity: Boolean, 24 | private val mapping: Mapping?, 25 | ) : BaseObject { 26 | override fun register() { 27 | AttributeSystem.attributeManager.register( 28 | Attribute.createAttribute(key, readPattern) { 29 | release = true 30 | this@ConfigAttributeBuilder.display?.let { display = it } 31 | priority = this@ConfigAttributeBuilder.priority 32 | entity = this@ConfigAttributeBuilder.isEntity 33 | names.addAll(this@ConfigAttributeBuilder.names) 34 | this@ConfigAttributeBuilder.mapping?.let { mapping = it } 35 | } 36 | ) 37 | } 38 | 39 | companion object { 40 | @JvmStatic 41 | fun deserialize(section: ConfigurationSection): ConfigAttributeBuilder? { 42 | try { 43 | val attKey = section.name 44 | val priority = Coerce.toInteger(section["priority"].toString()) 45 | val display = section["display"]?.toString() 46 | val names = if (section.contains("names")) section.getStringList("names") else listOf(attKey) 47 | val isEntity = (section["include-entity"]?.toString()?.lowercase() ?: "true") == "true" 48 | val readPatternKey = 49 | section.getString("read-group")?.lowercase() ?: section.getString("read-pattern")?.lowercase() 50 | ?: "default" 51 | val readPattern = 52 | AttributeSystem.readPatternManager[readPatternKey] 53 | if (readPattern == null) { 54 | console().sendLang("invalid-read-pattern", attKey, readPatternKey) 55 | return null 56 | } 57 | val map = section.getConfigurationSection("mapping")?.toMap() 58 | val mapping = map?.let { DefaultMapping(it) } 59 | return ConfigAttributeBuilder(attKey, priority, display, names, readPattern, isEntity, mapping) 60 | } catch (e: Throwable) { 61 | Bukkit.getConsoleSender().sendLang("error.attribute-load", section["key"].toString()) 62 | e.printStackTrace() 63 | } 64 | return null 65 | } 66 | } 67 | 68 | override fun serialize(): MutableMap { 69 | return linkedMapOf( 70 | "priority" to priority, 71 | "names" to names, 72 | "read-group" to readPattern 73 | ) 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/attribute/mapping/DefaultMapping.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.attribute.mapping 2 | 3 | import com.skillw.attsystem.AttributeSystem.readManager 4 | import com.skillw.attsystem.api.attribute.Mapping 5 | import com.skillw.attsystem.api.compiled.CompiledData 6 | import com.skillw.attsystem.api.read.status.Status 7 | import com.skillw.attsystem.util.MapUtils.replaceThenCalc 8 | import org.bukkit.entity.LivingEntity 9 | 10 | /** 11 | * @className DefaultMapping 12 | * 13 | * @author Glom 14 | * @date 2023/8/5 15:35 Copyright 2023 user. All rights reserved. 15 | */ 16 | class DefaultMapping(val map: Map) : Mapping() { 17 | override fun mapping(status: Status<*>, entity: LivingEntity?): CompiledData? { 18 | attribute ?: return null 19 | val replacement = 20 | (status as? Status<*>)?.readGroup?.run { 21 | placeholderKeys.associate { "<${it}>" to placeholder(it, attribute!!, status, entity).toString() } 22 | } ?: return null 23 | val mapping = map.replaceThenCalc(replacement, entity) as Map 24 | return readManager.readMap(mapping, entity) 25 | } 26 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/read/Matcher.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.read 2 | 3 | import com.skillw.pouvoir.api.feature.operation.Operation 4 | import com.skillw.pouvoir.api.plugin.map.component.Keyable 5 | 6 | /** 7 | * @className Matcher 8 | * 9 | * @author Glom 10 | * @date 2022/8/7 22:36 Copyright 2022 user. All rights reserved. 11 | */ 12 | class Matcher(override val key: String, val operation: Operation) : Keyable, Operation by operation -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/read/PatternMatcher.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.read 2 | 3 | import java.util.regex.Pattern 4 | 5 | /** 6 | * @className `PatternMatcher'` 7 | * 8 | * @author Glom 9 | * @date 2022/8/7 22:55 Copyright 2022 user. All rights reserved. 10 | */ 11 | data class PatternMatcher(val pattern: Pattern, val set: Set>) -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/read/StringMatcher.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.read 2 | 3 | /** 4 | * @className `PatternMatcher'` 5 | * 6 | * @author Glom 7 | * @date 2022/8/7 22:55 Copyright 2022 user. All rights reserved. 8 | */ 9 | data class StringMatcher(val string: String, val set: Set>) -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/read/num/NumberReader.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.read.num 2 | 3 | import com.skillw.attsystem.api.attribute.Attribute 4 | import com.skillw.attsystem.api.read.status.NumberStatus 5 | import com.skillw.attsystem.api.read.status.Status 6 | import com.skillw.attsystem.internal.core.read.BaseReadGroup 7 | import com.skillw.attsystem.internal.manager.ASConfig.numberPattern 8 | import com.skillw.pouvoir.util.calculateDouble 9 | import org.bukkit.entity.LivingEntity 10 | import taboolib.common5.Coerce 11 | import taboolib.common5.cdouble 12 | 13 | 14 | /** 15 | * Number reader 数字读取组 16 | * 17 | * 是AttributeSystem默认的读取格式实现,用于读取数字属性 18 | * 19 | * @param key 20 | * @param matchers 捕获组 21 | * @param patternStrings 正则表达式 22 | * @param placeholders 占位符 23 | * @constructor 24 | */ 25 | open class NumberReader( 26 | key: String, 27 | matchers: Map, 28 | patternStrings: List, 29 | placeholders: Map, 30 | ) : BaseReadGroup(key, matchers, patternStrings, placeholders, numberPattern) { 31 | 32 | override fun read(string: String, attribute: Attribute, entity: LivingEntity?, slot: String?): NumberStatus? { 33 | 34 | val status = NumberStatus(this) 35 | var temp = string 36 | attribute.names.forEach { 37 | if (temp.contains(it)) temp = temp.replace(it, "{name}") 38 | } 39 | patternList@ for ((pattern, matchers) in patterns) { 40 | val matcher = pattern.matcher(temp) 41 | if (!matcher.find()) continue 42 | matchers.forEach { usedMatcher -> 43 | val key = usedMatcher.key 44 | val valueStr = matcher.group(key) 45 | Coerce.asDouble(valueStr).ifPresent { 46 | status.operation(key, it, usedMatcher.operation) 47 | } 48 | } 49 | break@patternList 50 | } 51 | return status 52 | } 53 | 54 | override fun readNBT(map: Map, attribute: Attribute): NumberStatus { 55 | return NumberStatus(this).apply { 56 | putAll(map.mapValues { it.value.cdouble }) 57 | } 58 | } 59 | 60 | override fun onPlaceholder( 61 | key: String, 62 | attribute: Attribute, 63 | status: Status, 64 | entity: LivingEntity?, 65 | ): Double? { 66 | return replacePlaceholder(key, status, entity)?.calculateDouble() 67 | } 68 | 69 | 70 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/core/read/str/StringReader.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.core.read.str 2 | 3 | import com.skillw.attsystem.api.attribute.Attribute 4 | import com.skillw.attsystem.api.read.status.Status 5 | import com.skillw.attsystem.api.read.status.StringStatus 6 | import com.skillw.attsystem.internal.core.read.BaseReadGroup 7 | import org.bukkit.entity.LivingEntity 8 | 9 | /** 10 | * String reader 11 | * 12 | * 是AttributeSystem默认的读取格式实现,用于读取字符串属性 13 | * 14 | * @param key 15 | * @param matchers 捕获组 16 | * @param patternStrings 正则表达式 17 | * @param placeholders 占位符 18 | * @constructor 19 | */ 20 | class StringReader( 21 | key: String, 22 | matchers: Map, 23 | patternStrings: List, 24 | placeholders: Map, 25 | ) : BaseReadGroup(key, matchers, patternStrings, placeholders) { 26 | 27 | override fun read(string: String, attribute: Attribute, entity: LivingEntity?, slot: String?): StringStatus? { 28 | val attributeStatus = StringStatus(this) 29 | var temp = string 30 | attribute.names.forEach { 31 | if (temp.contains(it)) temp = temp.replaceFirst(it, "{name}") 32 | } 33 | patternList@ for ((pattern, matchers) in patterns) { 34 | val matcher = pattern.matcher(temp) 35 | if (!matcher.find()) continue 36 | matchers.forEach { usedMatcher -> 37 | val key = usedMatcher.key 38 | val valueStr = matcher.group(key) 39 | attributeStatus.operation(key, valueStr, usedMatcher.operation) 40 | } 41 | break@patternList 42 | } 43 | return attributeStatus 44 | } 45 | 46 | override fun readNBT(map: Map, attribute: Attribute): StringStatus { 47 | return StringStatus(this).apply { 48 | putAll(map.mapValues { it.value.toString() }) 49 | } 50 | } 51 | 52 | override fun onPlaceholder( 53 | key: String, 54 | attribute: Attribute, 55 | status: Status, 56 | entity: LivingEntity?, 57 | ): String? { 58 | return replacePlaceholder(key, status, entity) 59 | } 60 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/dragoncore/EquipmentListener.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.dragoncore 2 | 3 | import com.skillw.attsystem.AttributeSystem.equipmentDataManager 4 | import com.skillw.attsystem.api.event.EquipmentUpdateEvent 5 | import com.skillw.attsystem.internal.feature.realizer.UpdateRealizer.updateSync 6 | import com.skillw.attsystem.internal.manager.ASConfig.dragonCore 7 | import eos.moe.dragoncore.api.SlotAPI 8 | import eos.moe.dragoncore.api.event.PlayerSlotUpdateEvent 9 | import eos.moe.dragoncore.config.Config.slotSettings 10 | import org.bukkit.entity.Player 11 | import org.bukkit.inventory.ItemStack 12 | import taboolib.common.platform.Ghost 13 | import taboolib.common.platform.event.SubscribeEvent 14 | import java.util.concurrent.ConcurrentHashMap 15 | 16 | object EquipmentListener { 17 | private val cacheSlots: (Player) -> Map? by lazy { 18 | runCatching { 19 | val method = SlotAPI::class.java.getDeclaredMethod("getCacheAllSlotItem", Player::class.java) 20 | return@lazy { player -> 21 | (method.invoke(null, player) as? Map?)?.filter { it.key != null && it.value != null } as Map? 22 | } 23 | }.getOrElse { 24 | val method = SlotAPI::class.java.getDeclaredMethod("getCacheAllSlot", String::class.java) 25 | return@lazy { player -> 26 | ( method.invoke(null, player.name) as? Map?)?.filter { it.key != null && it.value != null } as Map? 27 | } 28 | } 29 | } 30 | 31 | @Ghost 32 | @SubscribeEvent(bind = "eos.moe.dragoncore.api.SlotAPI") 33 | fun e(event: EquipmentUpdateEvent.Pre) { 34 | val player = event.entity as? Player ?: return 35 | if (!dragonCore) return 36 | val cache = cacheSlots(player) 37 | val attributeItems = cache?.let { ConcurrentHashMap(it) } ?: return 38 | attributeItems.keys.filter { key -> 39 | !slotSettings.containsKey(key) || !slotSettings[key]!!.isAttribute 40 | }.forEach(attributeItems::remove) 41 | equipmentDataManager.addEquipData(player, "Dragon-Core", attributeItems) 42 | } 43 | 44 | @Ghost 45 | @SubscribeEvent 46 | fun e(event: PlayerSlotUpdateEvent) { 47 | event.player.updateSync(0) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/germ/GermListener.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.germ 2 | 3 | import com.germ.germplugin.api.GermSlotAPI 4 | import com.skillw.attsystem.api.event.EquipmentUpdateEvent 5 | import com.skillw.attsystem.internal.manager.ASConfig 6 | import com.skillw.attsystem.internal.manager.ASConfig.germ 7 | import org.bukkit.entity.Player 8 | import taboolib.common.platform.event.SubscribeEvent 9 | import taboolib.platform.util.isNotAir 10 | 11 | object GermListener { 12 | @SubscribeEvent 13 | fun load(event: EquipmentUpdateEvent.Pre) { 14 | val player = event.entity 15 | if (!germ || player !is Player) return 16 | val compound = event.data 17 | compound.remove("Germ-Equipment") 18 | val map = GermSlotAPI.getGermSlotIdentitysAndItemStacks(player, ASConfig.germSlots) 19 | map.filter { it.value.isNotAir() }.forEach { 20 | compound["Germ-Equipment", it.key] = it.value 21 | } 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/mythicmobs/common/DataUpdateV.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.mythicmobs.common 2 | 3 | import com.skillw.attsystem.api.AttrAPI.updateAttr 4 | import com.skillw.pouvoir.util.isAlive 5 | import io.lumine.mythic.api.skills.INoTargetSkill 6 | import io.lumine.mythic.api.skills.SkillMetadata 7 | import io.lumine.mythic.api.skills.SkillResult 8 | import io.lumine.mythic.core.logging.MythicLogger 9 | import org.bukkit.entity.LivingEntity 10 | import taboolib.module.nms.getI18nName 11 | 12 | /** 13 | * @className AttributeDamageIV 14 | * 15 | * @author Glom 16 | * @date 2022/7/11 17:14 Copyright 2022 user. All rights reserved. 17 | */ 18 | internal object DataUpdateV : INoTargetSkill { 19 | override fun cast(data: SkillMetadata): SkillResult { 20 | val target = data.caster.entity.bukkitEntity 21 | if (target !is LivingEntity || !target.isAlive()) return SkillResult.CONDITION_FAILED 22 | target.updateAttr() 23 | MythicLogger.debug( 24 | MythicLogger.DebugLevel.MECHANIC, 25 | "+ DataUpdate Mechanic fired for {0}", 26 | target.getI18nName() 27 | ) 28 | return SkillResult.SUCCESS 29 | } 30 | 31 | 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/mythicmobs/common/MMVListener.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.mythicmobs.common 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.AttrAPI.read 5 | import com.skillw.attsystem.api.AttrAPI.updateSync 6 | import io.lumine.mythic.bukkit.events.MythicMechanicLoadEvent 7 | import io.lumine.mythic.bukkit.events.MythicMobSpawnEvent 8 | import org.bukkit.entity.LivingEntity 9 | import taboolib.common.platform.Ghost 10 | import taboolib.common.platform.event.SubscribeEvent 11 | import taboolib.common.platform.function.submit 12 | 13 | internal object MMVListener { 14 | @Ghost 15 | @SubscribeEvent 16 | fun onMythicMechanicLoad(event: MythicMechanicLoadEvent) { 17 | when (event.mechanicName.lowercase()) { 18 | in listOf("att-update", "attupdate") -> { 19 | event.register(DataUpdateV) 20 | } 21 | } 22 | } 23 | 24 | @Ghost 25 | @SubscribeEvent 26 | fun onMythicMobsSpawn(event: MythicMobSpawnEvent) { 27 | val entity = event.entity as? LivingEntity ?: return 28 | val attributes = event.mob.type.config.getStringList("Attributes") 29 | if (!attributes.isNullOrEmpty()) 30 | submit(delay = 5) { 31 | attributes.read(entity)?.let { 32 | AttributeSystem.compiledAttrDataManager[entity.uniqueId]?.register( 33 | "MYTHIC-BASE-ATTRIBUTE", 34 | it 35 | ) 36 | } 37 | entity.updateSync() 38 | entity.health = entity.maxHealth 39 | } 40 | } 41 | 42 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/mythicmobs/legacy/DataUpdateIV.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.mythicmobs.legacy 2 | 3 | import com.skillw.attsystem.api.AttrAPI.update 4 | import com.skillw.pouvoir.util.isAlive 5 | import io.lumine.xikage.mythicmobs.io.MythicLineConfig 6 | import io.lumine.xikage.mythicmobs.logging.MythicLogger 7 | import io.lumine.xikage.mythicmobs.skills.INoTargetSkill 8 | import io.lumine.xikage.mythicmobs.skills.SkillMechanic 9 | import io.lumine.xikage.mythicmobs.skills.SkillMetadata 10 | import org.bukkit.entity.LivingEntity 11 | import taboolib.module.nms.getI18nName 12 | 13 | /** 14 | * @className AttributeDamageIV 15 | * 16 | * @author Glom 17 | * @date 2022/7/11 17:14 Copyright 2022 user. All rights reserved. 18 | */ 19 | internal class DataUpdateIV(skill: String, mlc: MythicLineConfig) : SkillMechanic(skill, mlc), INoTargetSkill { 20 | override fun cast(data: SkillMetadata): Boolean { 21 | val target = data.caster.entity.bukkitEntity 22 | if (target !is LivingEntity || !target.isAlive()) return false 23 | target.update() 24 | MythicLogger.debug( 25 | MythicLogger.DebugLevel.MECHANIC, 26 | "+ DataUpdate Mechanic fired for {0}", 27 | target.getI18nName() 28 | ) 29 | return true 30 | } 31 | 32 | 33 | } 34 | 35 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/mythicmobs/legacy/MMIVListener.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.mythicmobs.legacy 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.AttrAPI.read 5 | import com.skillw.attsystem.api.AttrAPI.updateSync 6 | import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMechanicLoadEvent 7 | import io.lumine.xikage.mythicmobs.api.bukkit.events.MythicMobSpawnEvent 8 | import org.bukkit.entity.LivingEntity 9 | import taboolib.common.platform.Ghost 10 | import taboolib.common.platform.event.SubscribeEvent 11 | import taboolib.common.platform.function.submit 12 | 13 | internal object MMIVListener { 14 | @Ghost 15 | @SubscribeEvent 16 | fun onMythicMechanicLoad(event: MythicMechanicLoadEvent) { 17 | when (event.mechanicName.lowercase()) { 18 | 19 | in listOf("att-update", "attupdate") -> { 20 | event.register(DataUpdateIV(event.config.line, event.config)) 21 | } 22 | } 23 | } 24 | 25 | @Ghost 26 | @SubscribeEvent 27 | fun onMythicMobsSpawn(event: MythicMobSpawnEvent) { 28 | val entity = event.entity as? LivingEntity ?: return 29 | val attributes = event.mob.type.config.getStringList("Attributes") 30 | if (attributes.isNullOrEmpty()) 31 | return 32 | attributes.read(entity)?.let { 33 | AttributeSystem.compiledAttrDataManager[entity.uniqueId]?.register( 34 | "MYTHIC-BASE-ATTRIBUTE", 35 | it 36 | ) 37 | } 38 | submit(delay = 5) { 39 | attributes.read(entity)?.let { 40 | AttributeSystem.compiledAttrDataManager[entity.uniqueId]?.register( 41 | "MYTHIC-BASE-ATTRIBUTE", 42 | it 43 | ) 44 | } 45 | entity.updateSync() 46 | entity.health = entity.maxHealth 47 | } 48 | } 49 | 50 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/placeholder/PlaceHolderHooker.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.placeholder 2 | 3 | import com.skillw.pouvoir.Pouvoir 4 | import org.bukkit.entity.Player 5 | import taboolib.platform.compat.PlaceholderExpansion 6 | 7 | object PlaceHolderHooker : PlaceholderExpansion { 8 | 9 | override val identifier: String = "as" 10 | 11 | override fun onPlaceholderRequest(player: Player?, args: String): String { 12 | return Pouvoir.placeholderManager.replace(player, "%as_$args%") 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/compat/pouvoir/AttributePlaceHolder.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.compat.pouvoir 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.AttributeSystem.attributeManager 5 | import com.skillw.attsystem.AttributeSystem.compiledAttrDataManager 6 | import com.skillw.attsystem.AttributeSystem.equipmentDataManager 7 | import com.skillw.attsystem.api.AttrAPI.getAttrData 8 | import com.skillw.attsystem.api.attribute.Attribute 9 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 10 | import com.skillw.attsystem.api.compiled.sub.ComplexCompiledData 11 | import com.skillw.pouvoir.api.feature.placeholder.PouPlaceHolder 12 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 13 | import org.bukkit.entity.LivingEntity 14 | 15 | @AutoRegister 16 | object AttributePlaceHolder : PouPlaceHolder("as", AttributeSystem) { 17 | 18 | fun get( 19 | data: AttributeDataCompound, 20 | attribute: Attribute, 21 | params: List, 22 | ): String { 23 | return when (params.size) { 24 | 0 -> 25 | data.getAttrValue(attribute)?.toString() 26 | 27 | 1 -> { 28 | data.getAttrValue(attribute, params[0])?.toString() 29 | } 30 | 31 | 2 -> { 32 | data.getStatus(attribute)?.get(params[1])?.toString() 33 | } 34 | 35 | else -> 36 | "0.0" 37 | } ?: "0.0" 38 | } 39 | 40 | fun placeholder(params: String, entity: LivingEntity, attrData: AttributeDataCompound): String { 41 | val lower = params.lowercase().replace(":", "_") 42 | val uuid = entity.uniqueId 43 | val strings = if (lower.contains("_")) lower.split("_").toMutableList() else mutableListOf(lower) 44 | when (strings[0]) { 45 | "att" -> { 46 | val attribute = attributeManager[strings[1]] 47 | attribute?.also { 48 | strings.removeAt(0) 49 | strings.removeAt(0) 50 | return get(attrData, attribute, strings) 51 | } 52 | } 53 | 54 | "equipment" -> { 55 | strings.removeAt(0) 56 | if (strings.size < 3) return "0.0" 57 | val source = strings[0] 58 | val slot = strings[1] 59 | val attKey = strings[2] 60 | strings.removeAt(0) 61 | strings.removeAt(0) 62 | strings.removeAt(0) 63 | val attribute = attributeManager[attKey] ?: return "0.0" 64 | val sourceKey = equipmentDataManager.getSource(source, slot) 65 | val compiledData = compiledAttrDataManager[uuid]?.get(sourceKey) ?: ComplexCompiledData() 66 | val itemAttrData = compiledData.eval(entity) 67 | return get(itemAttrData, attribute, strings) 68 | } 69 | } 70 | return "0.0" 71 | } 72 | 73 | override fun onPlaceHolderRequest(params: String, entity: LivingEntity, def: String): String { 74 | return placeholder(params, entity, entity.getAttrData() ?: return "NULL_DATA") 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/database/ASContainer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.database 2 | 3 | import com.skillw.attsystem.internal.manager.ASConfig 4 | import com.skillw.pouvoir.Pouvoir.databaseManager 5 | import com.skillw.pouvoir.api.feature.database.UserBased 6 | import taboolib.common.LifeCycle 7 | import taboolib.common.platform.Awake 8 | 9 | internal object ASContainer : UserBased { 10 | @JvmStatic 11 | val holder by lazy { 12 | databaseManager.containerHolder(ASConfig.databaseConfig) 13 | } 14 | 15 | @JvmStatic 16 | lateinit var container: UserBased 17 | 18 | @Awake(LifeCycle.ENABLE) 19 | fun loadContainer() { 20 | kotlin.runCatching { 21 | container = (holder?.container("as_data", true) as? UserBased?)!! 22 | }.let { 23 | if (it.isFailure) 24 | taboolib.common.platform.function.warning("AttributeSystem User Container Initialization Failed!") 25 | } 26 | } 27 | 28 | override fun get(user: String, key: String): String? { 29 | return container[user, key] 30 | } 31 | 32 | override fun delete(user: String, key: String) { 33 | return container.delete(user, key) 34 | } 35 | 36 | override fun set(user: String, key: String, value: String?) { 37 | container[user, key] = value 38 | } 39 | 40 | override fun contains(user: String, key: String): Boolean { 41 | return container.contains(user, key) 42 | } 43 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/personal/InitialAttrData.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.personal 2 | 3 | import com.google.gson.GsonBuilder 4 | import com.skillw.attsystem.AttributeSystem.attributeDataManager 5 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 6 | import com.skillw.attsystem.internal.feature.database.ASContainer 7 | import com.skillw.pouvoir.api.plugin.map.component.Keyable 8 | import com.skillw.pouvoir.util.decodeFromString 9 | import com.skillw.pouvoir.util.encodeJson 10 | import org.bukkit.entity.Player 11 | import taboolib.common.util.unsafeLazy 12 | import java.util.* 13 | 14 | /** 15 | * @className InitialAttrData 16 | * 17 | * @author Glom 18 | * @date 2023/8/1 18:07 Copyright 2023 user. All rights reserved. 19 | */ 20 | class InitialAttrData(override val key: UUID, val compound: AttributeDataCompound = AttributeDataCompound()) : 21 | Keyable { 22 | companion object { 23 | private val gson by unsafeLazy { 24 | GsonBuilder().create() 25 | } 26 | 27 | @JvmStatic 28 | fun deserialize(uuid: UUID, str: String): InitialAttrData? { 29 | 30 | return InitialAttrData( 31 | uuid, 32 | AttributeDataCompound.fromMap(gson.fromJson>(str, Map::class.java) ?: return null) 33 | ) 34 | } 35 | 36 | @JvmStatic 37 | fun fromPlayer(player: Player): InitialAttrData { 38 | return InitialAttrData(player.uniqueId, attributeDataManager[player.uniqueId] ?: AttributeDataCompound()) 39 | } 40 | 41 | @JvmStatic 42 | internal fun pushAttrData(player: Player) { 43 | ASContainer[player.uniqueId.toString(), "initial-attr-data"] = fromPlayer(player).serialize() 44 | } 45 | 46 | @JvmStatic 47 | internal fun pullAttrData(uuid: UUID): InitialAttrData? { 48 | val data = ASContainer[uuid.toString(), "initial-attr-data"] ?: return null 49 | if (data == "null") return null 50 | return deserialize(uuid, data) 51 | } 52 | } 53 | 54 | fun serialize(): String { 55 | return gson.toJson(compound.mapValues { it.value.serialize() }) 56 | } 57 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/personal/PlayerDataSave.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.personal 2 | 3 | import org.bukkit.event.player.PlayerQuitEvent 4 | import taboolib.common.platform.event.EventPriority 5 | import taboolib.common.platform.event.SubscribeEvent 6 | 7 | private object PlayerUpdate { 8 | 9 | @SubscribeEvent(EventPriority.LOWEST) 10 | fun quit(event: PlayerQuitEvent) { 11 | val player = event.player 12 | InitialAttrData.pushAttrData(player) 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/HealthRegainRealizer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.AttributeSystem.attributeDataManager 5 | import com.skillw.attsystem.AttributeSystem.attributeSystemAPI 6 | import com.skillw.attsystem.api.event.HealthRegainEvent 7 | import com.skillw.attsystem.internal.manager.ASConfig.fightSystem 8 | import com.skillw.attsystem.util.Utils.validEntity 9 | import com.skillw.fightsystem.api.FightAPI.isFighting 10 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 11 | import com.skillw.pouvoir.api.feature.realizer.component.ScheduledRealizer 12 | import com.skillw.pouvoir.api.feature.realizer.component.Switchable 13 | import com.skillw.pouvoir.api.feature.realizer.component.Valuable 14 | import com.skillw.pouvoir.api.feature.realizer.component.Vanillable 15 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 16 | import org.bukkit.entity.LivingEntity 17 | import org.bukkit.event.entity.EntityRegainHealthEvent 18 | import taboolib.common.platform.event.SubscribeEvent 19 | import taboolib.common.util.unsafeLazy 20 | import taboolib.common5.cbool 21 | import kotlin.math.min 22 | 23 | @AutoRegister 24 | internal object HealthRegainRealizer : ScheduledRealizer("health-regain"), Switchable, Vanillable, Valuable { 25 | override val file by lazy { 26 | AttributeSystem.options.file!! 27 | } 28 | override val manager: BaseRealizerManager by unsafeLazy { 29 | AttributeSystem.realizerManager 30 | } 31 | override val defaultPeriod: Long = 10 32 | override val defaultEnable: Boolean 33 | get() = false 34 | override val defaultValue: String 35 | get() = "0" 36 | override val defaultVanilla: Boolean 37 | get() = true 38 | private val disableInFight: Boolean 39 | get() = config["disable-in-fighting"].cbool 40 | 41 | @SubscribeEvent 42 | fun onVanillaRegain(event: EntityRegainHealthEvent) { 43 | if (!isEnableVanilla()) { 44 | event.isCancelled = true 45 | return 46 | } 47 | val regainEvent = HealthRegainEvent(event.entity, event.amount) 48 | regainEvent.call() 49 | event.amount = regainEvent.amount 50 | } 51 | 52 | @Suppress("DEPRECATION") 53 | private fun LivingEntity.regain(amount: Double) { 54 | val maxHealth = maxHealth 55 | if (health >= maxHealth) return 56 | val event = HealthRegainEvent(this, amount).apply { call() } 57 | if (event.isCancelled) return 58 | val result = min(maxHealth, health + event.amount) 59 | health = result 60 | } 61 | 62 | override fun task() { 63 | for (uuid in attributeDataManager.keys) { 64 | val entity = uuid.validEntity() 65 | if (entity == null || !entity.isValid || entity.isDead) { 66 | attributeSystemAPI.remove(uuid) 67 | continue 68 | } 69 | if (disableInFight && fightSystem && entity.isFighting()) return 70 | entity.regain(value(entity)) 71 | } 72 | } 73 | 74 | override fun whenEnable() { 75 | refreshTask() 76 | } 77 | 78 | override fun whenDisable() { 79 | cancelTask() 80 | } 81 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/HealthScaleRealizer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizer 5 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 6 | import com.skillw.pouvoir.api.feature.realizer.component.Awakeable 7 | import com.skillw.pouvoir.api.feature.realizer.component.Switchable 8 | import com.skillw.pouvoir.api.feature.realizer.component.Valuable 9 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 10 | import org.bukkit.Bukkit 11 | import org.bukkit.entity.Player 12 | import org.bukkit.event.player.PlayerJoinEvent 13 | import org.bukkit.event.player.PlayerRespawnEvent 14 | import taboolib.common.platform.Ghost 15 | import taboolib.common.platform.event.SubscribeEvent 16 | import taboolib.common.util.unsafeLazy 17 | 18 | @AutoRegister 19 | internal object HealthScaleRealizer : BaseRealizer("health-scale"), Awakeable, Switchable, Valuable { 20 | 21 | override val file by lazy { 22 | AttributeSystem.options.file!! 23 | } 24 | override val manager: BaseRealizerManager by unsafeLazy { 25 | AttributeSystem.realizerManager 26 | } 27 | override val defaultEnable: Boolean 28 | get() = true 29 | override val defaultValue: String 30 | get() = "20" 31 | 32 | 33 | private fun realize(player: Player) { 34 | with(player) { 35 | if (isEnable()) { 36 | isHealthScaled = true 37 | healthScale = value(this) 38 | } else { 39 | isHealthScaled = false 40 | } 41 | } 42 | } 43 | 44 | @SubscribeEvent 45 | fun onPlayerJoin(event: PlayerJoinEvent) { 46 | realize(event.player) 47 | } 48 | 49 | @Ghost 50 | @SubscribeEvent 51 | fun onPlayerReborn(event: PlayerRespawnEvent) { 52 | realize(event.player) 53 | } 54 | 55 | 56 | override fun onReload() { 57 | Bukkit.getServer().onlinePlayers.forEach(::realize) 58 | } 59 | 60 | override fun whenEnable() { 61 | onReload() 62 | } 63 | 64 | override fun whenDisable() { 65 | onDisable() 66 | } 67 | 68 | override fun onDisable() { 69 | Bukkit.getServer().onlinePlayers.forEach { 70 | it.isHealthScaled = false 71 | } 72 | } 73 | 74 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/UpdateRealizer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer 2 | 3 | import com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent 4 | import com.skillw.attsystem.AttributeSystem 5 | import com.skillw.attsystem.AttributeSystem.attributeDataManager 6 | import com.skillw.attsystem.AttributeSystem.realizerManager 7 | import com.skillw.attsystem.api.AttrAPI.update 8 | import com.skillw.attsystem.internal.manager.AttributeSystemAPIImpl.remove 9 | import com.skillw.attsystem.util.Utils.validEntity 10 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 11 | import com.skillw.pouvoir.api.feature.realizer.component.ScheduledRealizer 12 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 13 | import org.bukkit.entity.LivingEntity 14 | import org.bukkit.entity.Player 15 | import org.bukkit.event.entity.EntityDeathEvent 16 | import org.bukkit.event.inventory.InventoryClickEvent 17 | import org.bukkit.event.inventory.InventoryCloseEvent 18 | import org.bukkit.event.player.* 19 | import org.spigotmc.event.player.PlayerSpawnLocationEvent 20 | import taboolib.common.platform.event.OptionalEvent 21 | import taboolib.common.platform.event.SubscribeEvent 22 | import taboolib.common.platform.function.submit 23 | import taboolib.common.util.unsafeLazy 24 | import taboolib.common5.Baffle 25 | import taboolib.common5.clong 26 | import java.util.concurrent.TimeUnit 27 | 28 | @AutoRegister 29 | internal object UpdateRealizer : ScheduledRealizer("update", true) { 30 | override val file by lazy { 31 | AttributeSystem.options.file!! 32 | } 33 | override val manager: BaseRealizerManager by unsafeLazy { 34 | realizerManager 35 | } 36 | override val defaultPeriod: Long = 10 37 | 38 | override fun task() { 39 | for (uuid in attributeDataManager.keys) { 40 | val entity = uuid.validEntity() 41 | if (entity == null || !entity.isValid || entity.isDead) { 42 | if (entity !is Player) 43 | remove(uuid) 44 | continue 45 | } 46 | entity.update() 47 | } 48 | realizerManager.executeSyncTasks() 49 | } 50 | 51 | @SubscribeEvent(bind = "com.destroystokyo.paper.event.entity.EntityRemoveFromWorldEvent") 52 | fun onEntityDead(optionalEvent: OptionalEvent) { 53 | val event = optionalEvent.get() 54 | val entity = event.entity 55 | AttributeSystem.attributeSystemAPI.remove(entity.uniqueId) 56 | } 57 | 58 | 59 | @SubscribeEvent 60 | fun onEntityDead(event: EntityDeathEvent) { 61 | val entity = event.entity 62 | if (entity !is Player) { 63 | AttributeSystem.attributeSystemAPI.remove(entity.uniqueId) 64 | } 65 | } 66 | 67 | 68 | private var baffle = Baffle.of(20, TimeUnit.MILLISECONDS) 69 | 70 | override fun onEnable() { 71 | onReload() 72 | } 73 | 74 | override fun onReload() { 75 | super.onReload() 76 | baffle.resetAll() 77 | baffle = Baffle.of(config.getOrDefault("baffle", 20).clong, TimeUnit.MILLISECONDS) 78 | } 79 | 80 | internal fun LivingEntity.updateSync(delay: Long = 0) { 81 | if (baffle.hasNext(name)) { 82 | submit(delay = delay) { 83 | update() 84 | } 85 | } 86 | } 87 | 88 | @SubscribeEvent 89 | fun join(event: PlayerJoinEvent) { 90 | event.player.updateSync(1) 91 | } 92 | 93 | @SubscribeEvent 94 | fun respawn(event: PlayerRespawnEvent) { 95 | event.player.updateSync(1) 96 | } 97 | 98 | @SubscribeEvent 99 | fun spawnLocation(event: PlayerSpawnLocationEvent) { 100 | 101 | event.player.updateSync(1) 102 | } 103 | 104 | @SubscribeEvent(ignoreCancelled = true) 105 | fun pickupItem(event: PlayerPickupItemEvent) { 106 | event.player.updateSync(1) 107 | } 108 | 109 | @SubscribeEvent(ignoreCancelled = true) 110 | fun itemHeld(event: PlayerItemHeldEvent) { 111 | event.player.updateSync(1) 112 | } 113 | 114 | @SubscribeEvent(ignoreCancelled = true) 115 | fun dropItem(event: PlayerDropItemEvent) { 116 | event.player.updateSync(1) 117 | } 118 | 119 | @SubscribeEvent(ignoreCancelled = true) 120 | fun swapHandItems(event: PlayerSwapHandItemsEvent) { 121 | event.player.updateSync(1) 122 | } 123 | 124 | 125 | @SubscribeEvent(ignoreCancelled = true) 126 | fun click(event: InventoryClickEvent) { 127 | val player = event.whoClicked as Player 128 | player.updateSync(1) 129 | } 130 | 131 | @SubscribeEvent(ignoreCancelled = true) 132 | fun close(event: InventoryCloseEvent) { 133 | val player = event.player as Player 134 | player.updateSync(1) 135 | } 136 | 137 | @SubscribeEvent 138 | fun quit(event: PlayerQuitEvent) { 139 | val player = event.player 140 | AttributeSystem.attributeSystemAPI.remove(player.uniqueId) 141 | baffle.reset(player.name) 142 | } 143 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/attribute/BaseAttributeEntityRealizer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer.attribute 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.AttrAPI.read 5 | import com.skillw.attsystem.api.AttrAPI.update 6 | import com.skillw.attsystem.api.compiled.CompiledAttrDataCompound 7 | import com.skillw.attsystem.api.compiled.sub.ComplexCompiledData 8 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizer 9 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 10 | import com.skillw.pouvoir.api.feature.realizer.component.Awakeable 11 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 12 | import com.skillw.pouvoir.util.isAlive 13 | import org.bukkit.entity.LivingEntity 14 | import org.bukkit.event.entity.EntitySpawnEvent 15 | import taboolib.common.platform.event.SubscribeEvent 16 | import taboolib.common.util.asList 17 | import taboolib.common.util.unsafeLazy 18 | import taboolib.common5.cbool 19 | import taboolib.module.configuration.util.asMap 20 | 21 | /** 22 | * @className BaseAttributePlayerRealizer 23 | * 24 | * Ӧ�ý��� basic attribute�ġ��� 25 | * 26 | * @author Glom 27 | * @date 2023/1/6 7:05 Copyright 2022 user. All rights reserved. 28 | */ 29 | @AutoRegister 30 | object BaseAttributeEntityRealizer : BaseRealizer("base-attribute-entity"), Awakeable { 31 | override val file by lazy { 32 | AttributeSystem.options.file!! 33 | } 34 | override val manager: BaseRealizerManager by unsafeLazy { 35 | AttributeSystem.realizerManager 36 | } 37 | 38 | val type 39 | get() = config["type"]?.toString()?.lowercase() ?: "strings" 40 | val attrData 41 | get() = config["attributes"] 42 | val conditions 43 | get() = config["conditions"] 44 | val onSpawn 45 | get() = config["on-spawn"]?.cbool ?: true 46 | 47 | private const val KEY = "BASIC-ATTRIBUTE" 48 | 49 | var baseData: ComplexCompiledData = ComplexCompiledData() 50 | 51 | 52 | override fun onEnable() { 53 | onReload() 54 | } 55 | 56 | override fun onActive() { 57 | onReload() 58 | } 59 | 60 | override fun onReload() { 61 | val base = when (type) { 62 | "nbt" -> { 63 | val attrData = attrData.asMap().entries.associate { it.key to it.value!! }.toMutableMap() 64 | val conditions = conditions as? List? ?: emptyList() 65 | AttributeSystem.readManager.readMap(attrData, conditions) 66 | } 67 | 68 | else -> attrData?.asList()?.read() 69 | } 70 | baseData.base = base 71 | } 72 | 73 | fun CompiledAttrDataCompound.baseEntity(): CompiledAttrDataCompound { 74 | this[KEY] = baseData 75 | return this 76 | } 77 | 78 | @SubscribeEvent 79 | fun entity(event: EntitySpawnEvent) { 80 | if(!onSpawn) return 81 | val entity = event.entity 82 | if(entity.isAlive()) 83 | (entity as LivingEntity).update() 84 | } 85 | 86 | 87 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/attribute/BaseAttributePlayerRealizer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer.attribute 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.AttrAPI.read 5 | import com.skillw.attsystem.api.compiled.CompiledAttrDataCompound 6 | import com.skillw.attsystem.api.compiled.sub.ComplexCompiledData 7 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizer 8 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 9 | import com.skillw.pouvoir.api.feature.realizer.component.Awakeable 10 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 11 | import taboolib.common.util.asList 12 | import taboolib.common.util.unsafeLazy 13 | import taboolib.module.configuration.util.asMap 14 | 15 | /** 16 | * @className BaseAttributePlayerRealizer 17 | * 18 | * Ӧ�ý��� basic attribute�ġ��� 19 | * 20 | * @author Glom 21 | * @date 2023/1/6 7:05 Copyright 2022 user. All rights reserved. 22 | */ 23 | @AutoRegister 24 | object BaseAttributePlayerRealizer : BaseRealizer("base-attribute-player"), Awakeable { 25 | 26 | override val file by lazy { 27 | AttributeSystem.options.file!! 28 | } 29 | override val manager: BaseRealizerManager by unsafeLazy { 30 | AttributeSystem.realizerManager 31 | } 32 | val type 33 | get() = config["type"]?.toString()?.lowercase() ?: "strings" 34 | val attrData 35 | get() = config["attributes"] 36 | val conditions 37 | get() = config["conditions"] 38 | 39 | private const val KEY = "BASIC-ATTRIBUTE" 40 | 41 | var baseData: ComplexCompiledData = ComplexCompiledData() 42 | 43 | 44 | override fun onEnable() { 45 | onReload() 46 | } 47 | 48 | override fun onActive() { 49 | onReload() 50 | } 51 | 52 | override fun onReload() { 53 | val base = when (type) { 54 | "nbt" -> { 55 | val attrData = attrData.asMap().entries.associate { it.key to it.value!! }.toMutableMap() 56 | val conditions = conditions as? List? ?: emptyList() 57 | AttributeSystem.readManager.readMap(attrData, conditions) 58 | } 59 | 60 | else -> attrData?.asList()?.read() 61 | } 62 | baseData.base = base 63 | } 64 | 65 | fun CompiledAttrDataCompound.basePlayer(): CompiledAttrDataCompound { 66 | this[KEY] = baseData 67 | return this 68 | } 69 | 70 | 71 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/slot/EntitySlotRealizer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer.slot 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.equipment.EquipmentLoader 5 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizer 6 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 7 | import com.skillw.pouvoir.api.feature.realizer.component.Awakeable 8 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 9 | import com.skillw.pouvoir.api.plugin.map.LowerMap 10 | import org.bukkit.entity.LivingEntity 11 | import org.bukkit.inventory.ItemStack 12 | import taboolib.common.platform.function.console 13 | import taboolib.common.util.unsafeLazy 14 | import taboolib.module.lang.sendLang 15 | import taboolib.type.BukkitEquipment 16 | 17 | @AutoRegister 18 | object EntitySlotRealizer : BaseRealizer("entity"), Awakeable { 19 | private val slots = LowerMap() 20 | override val file by lazy { 21 | AttributeSystem.slot.file!! 22 | } 23 | override val manager: BaseRealizerManager by unsafeLazy { 24 | AttributeSystem.realizerManager 25 | } 26 | 27 | override fun onEnable() { 28 | onReload() 29 | } 30 | 31 | override fun onReload() { 32 | slots.clear() 33 | for (key in config.keys) { 34 | val slot = config[key].toString() 35 | val type = kotlin.runCatching { BukkitEquipment.fromString(slot) }.getOrNull() 36 | type ?: console().sendLang("equipment-type-error", key) 37 | type ?: continue 38 | slots.register(key, type) 39 | } 40 | slots.putAll( 41 | mapOf( 42 | "头盔" to BukkitEquipment.HEAD, 43 | "胸甲" to BukkitEquipment.CHEST, 44 | "护腿" to BukkitEquipment.LEGS, 45 | "靴子" to BukkitEquipment.FEET, 46 | "主手" to BukkitEquipment.HAND, 47 | "副手" to BukkitEquipment.OFF_HAND 48 | ) 49 | ) 50 | } 51 | 52 | @AutoRegister 53 | object NormalEquipmentLoader : EquipmentLoader { 54 | 55 | override val key: String = "default" 56 | 57 | override val priority: Int = 1000 58 | 59 | override fun loadEquipment(entity: LivingEntity): Map { 60 | val items = HashMap() 61 | for ((key, equipmentType) in slots) { 62 | items[key] = equipmentType.getItem(entity) 63 | } 64 | return items 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/slot/PlayerSlotRealizer.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer.slot 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.equipment.EquipmentLoader 5 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizer 6 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 7 | import com.skillw.pouvoir.api.feature.realizer.component.Awakeable 8 | import com.skillw.pouvoir.api.plugin.annotation.AutoRegister 9 | import com.skillw.pouvoir.api.plugin.map.LowerKeyMap 10 | import com.skillw.pouvoir.api.plugin.map.component.Registrable 11 | import org.bukkit.entity.LivingEntity 12 | import org.bukkit.entity.Player 13 | import org.bukkit.inventory.ItemStack 14 | import taboolib.common.util.unsafeLazy 15 | import taboolib.common5.Coerce 16 | import taboolib.common5.cint 17 | import taboolib.platform.util.hasLore 18 | import taboolib.type.BukkitEquipment 19 | 20 | @AutoRegister 21 | object PlayerSlotRealizer : BaseRealizer("player"), Awakeable { 22 | private val slots = LowerKeyMap() 23 | override val file by lazy { 24 | AttributeSystem.slot.file!! 25 | } 26 | override val manager: BaseRealizerManager by unsafeLazy { 27 | AttributeSystem.realizerManager 28 | } 29 | 30 | override fun onEnable() { 31 | onReload() 32 | } 33 | 34 | override fun onReload() { 35 | slots.clear() 36 | for (key in config.keys) { 37 | val value = config[key] 38 | val slot: String 39 | var require: String? = null 40 | if (value is Map<*, *>) { 41 | val section = value as Map 42 | slot = section["slot"].toString() 43 | require = section["require"]?.toString() 44 | } else { 45 | slot = value.toString() 46 | } 47 | slots.register(PlayerSlot(key, slot.uppercase(), require)) 48 | } 49 | 50 | setOf( 51 | PlayerSlot("头盔", "HEAD"), 52 | PlayerSlot("胸甲", "CHEST"), 53 | PlayerSlot("护腿", "LEGS"), 54 | PlayerSlot("靴子", "FEET"), 55 | PlayerSlot("主手", "HAND"), 56 | PlayerSlot("副手", "OFFHAND") 57 | ).forEach(slots::register) 58 | } 59 | 60 | 61 | @AutoRegister 62 | object PlayerEquipmentLoader : EquipmentLoader { 63 | 64 | override val key: String = "default" 65 | 66 | override val priority: Int = 999 67 | 68 | override fun filter(entity: LivingEntity): Boolean { 69 | return entity is Player 70 | } 71 | 72 | override fun loadEquipment(entity: Player): Map { 73 | val items = HashMap() 74 | for ((slot, playerSlot) in slots) { 75 | items[slot] = playerSlot.getItem(entity) 76 | } 77 | return items 78 | } 79 | } 80 | 81 | /** 82 | * Player slot 83 | * 84 | * @constructor Create empty Player slot 85 | * @property key 槽位键 86 | * @property slot 槽位 ( BukkitEquipment 或 数字) 87 | */ 88 | data class PlayerSlot(override val key: String, val slot: String, val require: String? = null) : 89 | Registrable { 90 | /** Bukkit equipment */ 91 | val equipment: BukkitEquipment? = 92 | if (!Coerce.asInteger(slot).isPresent) 93 | BukkitEquipment.fromString(slot) 94 | ?: Coerce.toEnum(slot, BukkitEquipment::class.java) 95 | else null 96 | 97 | fun getSlot(player: Player): Int { 98 | return if (slot == "held") player.inventory.heldItemSlot else slot.cint 99 | } 100 | 101 | fun getItem(player: Player): ItemStack? { 102 | return (if (equipment == null) { 103 | player.inventory.getItem(getSlot(player)) 104 | } else { 105 | equipment.getItem(player) 106 | }).let { 107 | if (require != null && it?.hasLore(require) != true) null else it 108 | } 109 | } 110 | 111 | override fun register() { 112 | slots.register(key, this) 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/vanilla/MaxHealthTaskBuilder.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer.vanilla 2 | 3 | import com.skillw.attsystem.api.event.VanillaAttributeUpdateEvent 4 | import com.skillw.attsystem.internal.manager.ASConfig 5 | import com.skillw.pouvoir.util.attribute.BukkitAttribute 6 | import com.skillw.pouvoir.util.attribute.clear 7 | import com.skillw.pouvoir.util.attribute.getAttribute 8 | import com.sucy.skill.SkillAPI 9 | import com.sucy.skill.api.player.PlayerClass 10 | import org.bukkit.entity.LivingEntity 11 | import org.bukkit.entity.Player 12 | import taboolib.common5.Coerce 13 | import taboolib.module.nms.MinecraftVersion 14 | 15 | internal object MaxHealthTaskBuilder : VanillaAttTaskBuilder("max-health", BukkitAttribute.MAX_HEALTH) { 16 | 17 | val default 18 | get() = Coerce.toDouble(config["default"]) 19 | 20 | private val isLegacy by lazy { 21 | MinecraftVersion.majorLegacy <= 11300 22 | } 23 | 24 | 25 | private fun getSkillAPIHealth(player: Player): Int { 26 | return if (ASConfig.skillAPI) SkillAPI.getPlayerData(player).classes.stream() 27 | .mapToInt { aClass: PlayerClass -> aClass.health.toInt() }.sum() else 0 28 | } 29 | 30 | 31 | override fun newTask(entity: LivingEntity): (() -> Unit)? { 32 | val uuid = entity.uniqueId 33 | var value = value(entity) 34 | val vanilla = isEnableVanilla() 35 | if (entity is Player && isLegacy) { 36 | value += default 37 | } 38 | if (entity is Player && (isLegacy || vanilla)) { 39 | value += getSkillAPIHealth(entity).toDouble() 40 | } 41 | if (!changed(uuid, value)) return null 42 | val modifier = genModifier(value) 43 | return if (entity !is Player || (!isLegacy && vanilla)) { 44 | { 45 | entity.getAttribute(attribute)?.run { 46 | if (!isEnableVanilla()) clear() 47 | else removeModifier(modifier) 48 | addModifier(modifier) 49 | VanillaAttributeUpdateEvent(entity, BukkitAttribute.MAX_HEALTH, if(isEnableVanilla()) value + 20 else value).call() 50 | } 51 | } 52 | } else { 53 | if (value <= 0.0) { 54 | taboolib.common.platform.function.warning("Max Health value must bigger than 0.0! $entity $value") 55 | return null 56 | } 57 | { 58 | entity.apply { 59 | getAttribute(BukkitAttribute.MAX_HEALTH)?.apply { 60 | clear() 61 | } 62 | maxHealth = value 63 | VanillaAttributeUpdateEvent(entity, BukkitAttribute.MAX_HEALTH, value).call() 64 | } 65 | } 66 | } 67 | } 68 | 69 | override fun unrealize(entity: LivingEntity) { 70 | super.unrealize(entity) 71 | entity.maxHealth = default 72 | } 73 | 74 | override fun onDisable() { 75 | 76 | } 77 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/feature/realizer/vanilla/VanillaAttTaskBuilder.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.feature.realizer.vanilla 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.AttributeSystem.realizerManager 5 | import com.skillw.attsystem.api.event.VanillaAttributeUpdateEvent 6 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizer 7 | import com.skillw.pouvoir.api.feature.realizer.BaseRealizerManager 8 | import com.skillw.pouvoir.api.feature.realizer.component.* 9 | import com.skillw.pouvoir.util.attribute.BukkitAttribute 10 | import com.skillw.pouvoir.util.attribute.clear 11 | import com.skillw.pouvoir.util.attribute.getAttribute 12 | import org.bukkit.Bukkit 13 | import org.bukkit.attribute.AttributeModifier 14 | import org.bukkit.entity.LivingEntity 15 | import taboolib.common.LifeCycle 16 | import taboolib.common.platform.Awake 17 | import taboolib.common.util.unsafeLazy 18 | import java.util.* 19 | 20 | internal open class VanillaAttTaskBuilder(key: String, val attribute: BukkitAttribute) : BaseRealizer(key), Switchable, 21 | Vanillable, Valuable, Sync, Awakeable { 22 | override val file by lazy { 23 | AttributeSystem.vanilla.file!! 24 | } 25 | override val manager: BaseRealizerManager by unsafeLazy { 26 | realizerManager 27 | } 28 | protected val realizeKey = "realizer-vanilla-$key" 29 | 30 | override val defaultEnable: Boolean 31 | get() = false 32 | override val defaultValue: String 33 | get() = "0" 34 | override val defaultVanilla: Boolean 35 | get() = true 36 | 37 | 38 | private val valuesCache = WeakHashMap() 39 | 40 | protected fun changed(uuid: UUID, value: Double): Boolean = 41 | synchronized(valuesCache) { 42 | val current = valuesCache[uuid] 43 | return if (current != value) { 44 | valuesCache[uuid] = value 45 | true 46 | } else { 47 | false 48 | } 49 | } 50 | 51 | 52 | override fun newTask(entity: LivingEntity): (() -> Unit)? { 53 | val uuid = entity.uniqueId 54 | val value = value(entity) 55 | if (!changed(uuid, value) || entity.getAttribute(attribute) == null) return null 56 | val modifier = genModifier(value) 57 | return { 58 | entity.getAttribute(attribute)?.run { 59 | if (!isEnableVanilla()) clear() 60 | else removeModifier(modifier) 61 | addModifier(modifier) 62 | VanillaAttributeUpdateEvent(entity,this@VanillaAttTaskBuilder.attribute, if(isEnableVanilla()) value + 20 else value).call() 63 | } 64 | } 65 | } 66 | 67 | protected fun genModifier(value: Double): AttributeModifier { 68 | return AttributeModifier(ATTRIBUTE_UUID, "AS-${attribute.name}", value, AttributeModifier.Operation.ADD_NUMBER) 69 | } 70 | 71 | open fun unrealize(entity: LivingEntity) { 72 | entity.getAttribute(attribute)?.run { 73 | removeModifier(genModifier(0.0)) 74 | } 75 | } 76 | 77 | companion object { 78 | private val ATTRIBUTE_UUID = UUID.nameUUIDFromBytes("AS_ATTRIBUTE".toByteArray()) 79 | 80 | @Awake(LifeCycle.LOAD) 81 | fun autoRegister() { 82 | MaxHealthTaskBuilder.register() 83 | BukkitAttribute.values().filter { it != BukkitAttribute.MAX_HEALTH }.forEach { att -> 84 | att.toBukkit()?.let { VanillaAttTaskBuilder(att.normalizeName, att).register() } 85 | } 86 | } 87 | } 88 | 89 | 90 | override fun whenDisable() { 91 | Bukkit.getServer().worlds.forEach { world -> 92 | world.entities.filterIsInstance().forEach(::unrealize) 93 | } 94 | } 95 | 96 | override fun onDisable() { 97 | Bukkit.getServer().worlds.forEach { world -> 98 | world.entities.filterIsInstance().forEach(::unrealize) 99 | } 100 | } 101 | 102 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/ASConfig.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.AttrAPI 5 | import com.skillw.pouvoir.Pouvoir 6 | import com.skillw.pouvoir.api.feature.operation.Operation 7 | import com.skillw.pouvoir.api.manager.ConfigManager 8 | import com.skillw.pouvoir.api.plugin.map.DataMap 9 | import com.skillw.pouvoir.util.static 10 | import com.skillw.pouvoir.util.toMap 11 | import org.bukkit.Bukkit 12 | import org.spigotmc.AsyncCatcher 13 | import taboolib.common.platform.Platform 14 | import taboolib.common.platform.function.console 15 | import taboolib.common.platform.function.getDataFolder 16 | import taboolib.module.lang.asLangText 17 | import taboolib.module.metrics.charts.SingleLineChart 18 | import java.io.File 19 | import java.util.function.Function 20 | import java.util.regex.Pattern 21 | 22 | object ASConfig : ConfigManager(AttributeSystem) { 23 | override val priority = 0 24 | 25 | val ignores: List 26 | get() = this["config"].getStringList("options.read.ignores") 27 | 28 | var lineConditionPattern: Pattern = Pattern.compile("options.condition.line-condition.format") 29 | 30 | private val lineConditionFormat: String 31 | get() = this["config"].getString("options.condition.line-condition.format") ?: "\\/(?.*)" 32 | val lineConditionSeparator: String 33 | get() = this["config"].getString("options.condition.line-condition.separator") ?: "," 34 | 35 | val databaseConfig: DataMap 36 | get() = DataMap().also { it.putAll(this["config"].getConfigurationSection("database")!!.toMap()) } 37 | 38 | 39 | override fun onLoad() { 40 | AsyncCatcher.enabled = false 41 | createIfNotExists( 42 | "dispatchers", "custom-trigger.yml" 43 | ) 44 | createIfNotExists( 45 | "handlers", "on-attack.yml" 46 | ) 47 | createIfNotExists("reader", "number/default.yml", "number/percent.yml", "string/string.yml") 48 | createIfNotExists( 49 | "attributes", 50 | "Example.yml" 51 | ) 52 | createIfNotExists( 53 | "scripts", 54 | "conditions/slot.js", 55 | "conditions/attribute.js", 56 | ) 57 | //兼容2.1.0-beta及之前的脚本 58 | mapOf( 59 | "com.skillw.attsystem.internal.core.operation.num.Operation" to "com.skillw.pouvoir.api.feature.operation.Operation" 60 | ).forEach(Pouvoir.scriptEngineManager::relocate) 61 | 62 | Pouvoir.scriptEngineManager.globalVariables.let { 63 | it["AttrAPI"] = AttrAPI::class.java.static() 64 | it["AttributeSystem"] = AttributeSystem::class.java.static() 65 | it["operation"] = Function> { name -> 66 | AttrAPI.operation(name) 67 | } 68 | } 69 | } 70 | 71 | override fun onEnable() { 72 | onReload() 73 | val metrics = 74 | taboolib.module.metrics.Metrics(14465, AttributeSystem.plugin.description.version, Platform.BUKKIT) 75 | metrics.addCustomChart(SingleLineChart("attributes") { 76 | AttributeSystem.attributeManager.attributes.size 77 | }) 78 | metrics.addCustomChart(SingleLineChart("read_patterns") { 79 | AttributeSystem.readPatternManager.size 80 | }) 81 | Pouvoir.triggerHandlerManager.addSubPouvoir(AttributeSystem) 82 | } 83 | 84 | 85 | override fun subReload() { 86 | lineConditionPattern = Pattern.compile(lineConditionFormat) 87 | Pouvoir.scriptManager.addScriptDir(scripts) 88 | completeYaml("config.yml") 89 | } 90 | 91 | val germSlots: List 92 | get() { 93 | return this["slot"].getStringList("germ-slots") 94 | } 95 | val germ by lazy { 96 | Bukkit.getPluginManager().isPluginEnabled("GermPlugin") 97 | } 98 | val dragonCore by lazy { 99 | Bukkit.getPluginManager().isPluginEnabled("DragonCore") 100 | } 101 | 102 | val skillAPI by lazy { 103 | Bukkit.getPluginManager().isPluginEnabled("SkillAPI") || Bukkit.getPluginManager() 104 | .isPluginEnabled("ProSkillAPI") 105 | } 106 | val fightSystem by lazy { 107 | Bukkit.getPluginManager().isPluginEnabled("FightSystem") 108 | } 109 | 110 | private val scripts = File(getDataFolder(), "scripts") 111 | 112 | var debugMode: Boolean = false 113 | 114 | val debug: Boolean 115 | get() = debugMode || this["config"].getBoolean("options.debug") 116 | const val numberPattern: String = "(?((?<=\\()(\\+|\\-)?(\\d+(?:(\\.\\d+))?)(?=\\)))|((\\+|\\-)?(\\d+(?:(\\.\\d+))?)))" 117 | 118 | val statsTitle: String 119 | get() = console().asLangText("stats-title") 120 | val statsStatus 121 | get() = console().asLangText("stats-status") 122 | val statusAttributeFormat 123 | get() = console().asLangText("stats-attribute-format") 124 | 125 | val statusNone 126 | get() = console().asLangText("stats-status-none") 127 | 128 | val statusValue 129 | get() = console().asLangText("stats-status-value") 130 | 131 | val statusPlaceholder 132 | get() = console().asLangText("stats-status-placeholder") 133 | 134 | val statusPlaceholderValue 135 | get() = console().asLangText("stats-status-placeholder-value") 136 | 137 | val statsEnd: String 138 | get() = console().asLangText("stats-end") 139 | 140 | 141 | @JvmStatic 142 | fun debug(debug: () -> Unit) { 143 | if (this.debug) { 144 | debug.invoke() 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/AttributeDataManagerImpl.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.AttributeSystem.attributeDataManager 5 | import com.skillw.attsystem.AttributeSystem.compileManager 6 | import com.skillw.attsystem.AttributeSystem.compiledAttrDataManager 7 | import com.skillw.attsystem.api.attribute.compound.AttributeData 8 | import com.skillw.attsystem.api.attribute.compound.AttributeDataCompound 9 | import com.skillw.attsystem.api.event.AttributeUpdateEvent 10 | import com.skillw.attsystem.api.manager.AttributeDataManager 11 | import com.skillw.attsystem.internal.feature.personal.InitialAttrData.Companion.pullAttrData 12 | import com.skillw.attsystem.util.Utils.validEntity 13 | import com.skillw.pouvoir.util.isAlive 14 | import org.bukkit.entity.LivingEntity 15 | import java.util.* 16 | 17 | object AttributeDataManagerImpl : AttributeDataManager() { 18 | override val key = "AttributeDataManager" 19 | override val priority: Int = 3 20 | override val subPouvoir = AttributeSystem 21 | 22 | override fun get(key: UUID): AttributeDataCompound? { 23 | return uncheckedGet(key) ?: pullAttrData(key)?.compound 24 | } 25 | 26 | private fun uncheckedGet(key: UUID): AttributeDataCompound? { 27 | return super.get(key) 28 | } 29 | 30 | override fun update(entity: LivingEntity): AttributeDataCompound? { 31 | if (!entity.isAlive()) return null 32 | val uuid = entity.uniqueId 33 | var attrData = 34 | uncheckedGet(uuid)?.clone() ?: AttributeDataCompound(entity).also { this[uuid] = it } 35 | //PRE 36 | val preEvent = 37 | AttributeUpdateEvent.Pre(entity, attrData) 38 | preEvent.call() 39 | attrData = preEvent.data 40 | attrData.release() 41 | //PROCESS 42 | 43 | compiledAttrDataManager[uuid]?.apply { 44 | attrData.combine(eval(entity)) 45 | } 46 | 47 | val process = 48 | AttributeUpdateEvent.Process(entity, attrData) 49 | process.call() 50 | attrData = process.data 51 | this[uuid] = attrData 52 | attrData.init() 53 | 54 | attrData.combine(compileManager.mapping(entity)(attrData.toAttributeData()).eval(entity).allToRelease()) 55 | 56 | //AFTER 57 | val postEvent = 58 | AttributeUpdateEvent.Post(entity, attrData) 59 | postEvent.call() 60 | attrData = postEvent.data 61 | this[uuid] = attrData 62 | return attrData 63 | } 64 | 65 | override fun addAttrData( 66 | entity: LivingEntity, 67 | source: String, 68 | attributeData: AttributeData, 69 | 70 | ): AttributeData { 71 | if (!entity.isAlive()) { 72 | return attributeData 73 | } 74 | val uuid = entity.uniqueId 75 | if (attributeDataManager.containsKey(uuid)) { 76 | attributeDataManager[uuid]!!.register(source, attributeData) 77 | } else { 78 | val compound = AttributeDataCompound() 79 | compound.register(source, attributeData) 80 | attributeDataManager.register(uuid, compound) 81 | } 82 | return attributeData 83 | } 84 | 85 | override fun addAttrData(uuid: UUID, source: String, attributeData: AttributeData): AttributeData { 86 | return uuid.validEntity()?.let { addAttrData(it, source, attributeData) } ?: AttributeData() 87 | } 88 | 89 | override fun removeAttrData(entity: LivingEntity, source: String): AttributeData? { 90 | if (!entity.isAlive()) return null 91 | return attributeDataManager[entity.uniqueId]?.run { 92 | remove(source) 93 | } 94 | } 95 | 96 | override fun removeAttrData(uuid: UUID, source: String): AttributeData? { 97 | return uuid.validEntity()?.let { removeAttrData(it, source) } 98 | } 99 | 100 | 101 | override fun put(key: UUID, value: AttributeDataCompound): AttributeDataCompound? { 102 | return super.put(key, value)?.apply { entity = key.validEntity() } 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/AttributeManagerImpl.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.attribute.Attribute 5 | import com.skillw.attsystem.api.event.AttributeRegisterEvent 6 | import com.skillw.attsystem.api.manager.AttributeManager 7 | import com.skillw.attsystem.internal.core.attribute.ConfigAttributeBuilder 8 | import com.skillw.attsystem.internal.manager.ASConfig.debug 9 | import com.skillw.pouvoir.api.plugin.SubPouvoir 10 | import com.skillw.pouvoir.api.plugin.map.BaseMap 11 | import com.skillw.pouvoir.api.plugin.map.LowerMap 12 | import com.skillw.pouvoir.util.loadMultiply 13 | import com.skillw.pouvoir.util.loadYaml 14 | import com.skillw.pouvoir.util.put 15 | import com.skillw.pouvoir.util.read.StrTrie 16 | import com.skillw.pouvoir.util.safe 17 | import taboolib.common.platform.function.console 18 | import taboolib.common5.FileWatcher 19 | import taboolib.module.lang.sendLang 20 | import java.io.File 21 | import java.util.concurrent.CopyOnWriteArrayList 22 | 23 | object AttributeManagerImpl : AttributeManager() { 24 | override val key = "AttributeManager" 25 | override val priority: Int = 2 26 | override val subPouvoir = AttributeSystem 27 | private val fileWatcher = FileWatcher(20) 28 | private val dataFolders = HashSet() 29 | private val fileToKeys = BaseMap>() 30 | private val folderToKeys = BaseMap>() 31 | private val nameTrie = StrTrie() 32 | 33 | 34 | override val nameMap = LowerMap() 35 | 36 | override val attributes: MutableList by lazy { 37 | CopyOnWriteArrayList() 38 | } 39 | 40 | override fun find(text: String): Attribute? { 41 | return nameTrie.parse(text).result 42 | } 43 | 44 | override fun addSubPouvoir(subPouvoir: SubPouvoir) { 45 | val folder = subPouvoir.plugin.dataFolder 46 | addDataFolders(folder) 47 | subPouvoir.managerData.onReload { 48 | reloadFolder(folder) 49 | } 50 | } 51 | 52 | override fun onEnable() { 53 | addSubPouvoir(AttributeSystem) 54 | onReload() 55 | } 56 | 57 | override fun reloadFolder(folder: File) { 58 | dataFolders.add(folder) 59 | folderToKeys[folder]?.forEach(::unregister) 60 | loadMultiply( 61 | File(folder, "attributes"), ConfigAttributeBuilder::class.java 62 | ).forEach { 63 | val (builder, file) = it 64 | safe { builder.register() } 65 | fileToKeys.put(file, builder.key) 66 | folderToKeys.put(folder, builder.key) 67 | } 68 | } 69 | 70 | private fun reloadFile(file: File) { 71 | fileToKeys[file]?.let { 72 | it.forEach(::unregister) 73 | fileToKeys.remove(file) 74 | val yaml = runCatching { file.loadYaml() }.getOrNull() ?: return 75 | yaml.apply { 76 | getKeys(false).forEach { key -> 77 | ConfigAttributeBuilder.deserialize(getConfigurationSection(key)!!)?.register() 78 | fileToKeys.put(file, key) 79 | } 80 | } 81 | } 82 | } 83 | 84 | private fun refreshFileListener(todo: () -> Unit) { 85 | fileToKeys.keys.forEach(fileWatcher::removeListener) 86 | fileToKeys.clear() 87 | todo() 88 | fileToKeys.keys.forEach { file -> 89 | fileWatcher.addSimpleListener(file) { 90 | reloadFile(file) 91 | } 92 | } 93 | } 94 | 95 | override fun addDataFolders(folder: File) { 96 | dataFolders.add(folder) 97 | onReload() 98 | } 99 | 100 | override fun onReload() { 101 | this.entries.filter { it.value.config }.forEach { this.remove(it.key); } 102 | attributes.removeIf { it.config } 103 | this.nameMap.entries.filter { it.value.config }.forEach { nameMap.remove(it.key) } 104 | refreshFileListener { 105 | dataFolders.forEach(::reloadFolder) 106 | } 107 | } 108 | 109 | override fun put(key: String, value: Attribute): Attribute? { 110 | attributes.removeIf { it.key == key } 111 | attributes.add(value) 112 | attributes.sort() 113 | 114 | nameMap[key] = value 115 | nameTrie.put(key, value) 116 | value.names.forEach { 117 | nameMap[it] = value 118 | nameTrie.put(it, value) 119 | } 120 | debug { 121 | console().sendLang( 122 | "attribute-register", 123 | value.display, 124 | value.priority 125 | ) 126 | } 127 | AttributeRegisterEvent(value).call() 128 | return super.put(key, value) 129 | } 130 | 131 | override fun unregister(key: String) { 132 | remove(key)?.apply { 133 | names.forEach(nameMap::remove) 134 | debug { 135 | console().sendLang( 136 | "attribute-unregister", 137 | display, 138 | priority 139 | ) 140 | } 141 | } 142 | } 143 | 144 | override operator fun get(key: String): Attribute? { 145 | val lower = key.lowercase() 146 | return super.get(lower) ?: nameMap[lower] 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/AttributeSystemAPIImpl.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.AttributeSystemAPI 5 | import com.skillw.attsystem.util.Utils.mirrorIfDebug 6 | import com.skillw.pouvoir.util.isAlive 7 | import org.bukkit.entity.LivingEntity 8 | import java.util.* 9 | 10 | object AttributeSystemAPIImpl : AttributeSystemAPI { 11 | 12 | override val key = "AttributeSystemAPI" 13 | override val priority: Int = 100 14 | override val subPouvoir = AttributeSystem 15 | 16 | override fun update(entity: LivingEntity) { 17 | if (!entity.isAlive()) return 18 | mirrorIfDebug("update-entity") { 19 | mirrorIfDebug("update-equipment") { 20 | AttributeSystem.equipmentDataManager.update(entity) 21 | } 22 | mirrorIfDebug("update-attribute") { 23 | AttributeSystem.attributeDataManager.update(entity) 24 | } 25 | mirrorIfDebug("realize") { 26 | AttributeSystem.realizerManager.realize(entity) 27 | } 28 | } 29 | } 30 | 31 | 32 | override fun remove(entity: LivingEntity) { 33 | this.remove(entity.uniqueId) 34 | } 35 | 36 | 37 | override fun remove(uuid: UUID) { 38 | AttributeSystem.attributeDataManager.remove(uuid) 39 | AttributeSystem.equipmentDataManager.remove(uuid) 40 | AttributeSystem.compiledAttrDataManager.remove(uuid) 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/CompileManagerImpl.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.attribute.compound.AttributeData 5 | import com.skillw.attsystem.api.compiled.sub.ComplexCompiledData 6 | import com.skillw.attsystem.api.compiled.sub.NBTCompiledData 7 | import com.skillw.attsystem.api.compiled.sub.StringsCompiledData 8 | import com.skillw.attsystem.api.manager.CompileManager 9 | import com.skillw.pouvoir.Pouvoir.conditionManager 10 | import org.bukkit.entity.LivingEntity 11 | 12 | object CompileManagerImpl : CompileManager() { 13 | override val key = "CompileManager" 14 | override val priority: Int = 7 15 | override val subPouvoir = AttributeSystem 16 | override fun compile( 17 | entity: LivingEntity?, 18 | nbt: Collection, 19 | slot: String?, 20 | ): (MutableMap) -> NBTCompiledData { 21 | return { attrDataMap -> 22 | val total = NBTCompiledData(attrDataMap) 23 | for (condCompound in nbt) { 24 | condCompound as? Map ?: continue 25 | val paths = condCompound["paths"] as? List ?: continue 26 | val entry = NBTCompiledData.Entry(paths) 27 | val conditions = condCompound["conditions"] as? List> ?: continue 28 | conditionManager.matchConditions(conditions, slot).forEach(entry::register) 29 | total.add(entry) 30 | } 31 | total 32 | } 33 | 34 | } 35 | 36 | override fun compile( 37 | entity: LivingEntity?, 38 | string: String, 39 | slot: String?, 40 | ): ((AttributeData) -> StringsCompiledData)? { 41 | val matches = conditionManager.matchConditions(string, slot) 42 | return if (matches.isNotEmpty()) 43 | { data -> 44 | StringsCompiledData(data).apply { 45 | matches.forEach(this::register) 46 | } 47 | } 48 | else null 49 | } 50 | 51 | override fun mapping(entity: LivingEntity?): (AttributeData) -> ComplexCompiledData = { data -> 52 | ComplexCompiledData().apply { 53 | data.forEach { (attribute, status) -> 54 | attribute.mapping?.mapping(status, entity)?.also(this::add) 55 | } 56 | } 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/CompiledAttrDataManagerImpl.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.AttributeSystem.readManager 5 | import com.skillw.attsystem.api.compiled.CompiledAttrDataCompound 6 | import com.skillw.attsystem.api.compiled.CompiledData 7 | import com.skillw.attsystem.api.manager.CompiledAttrDataManager 8 | import com.skillw.attsystem.util.Utils.validEntity 9 | import org.bukkit.entity.LivingEntity 10 | import java.util.* 11 | 12 | object CompiledAttrDataManagerImpl : CompiledAttrDataManager() { 13 | override val key = "CompiledAttrDataManager" 14 | override val priority: Int = 2 15 | override val subPouvoir = AttributeSystem 16 | override fun hasCompiledData(entity: LivingEntity, source: String): Boolean { 17 | return hasCompiledData(entity.uniqueId, source) 18 | } 19 | 20 | override fun hasCompiledData(uuid: UUID, source: String): Boolean { 21 | return get(uuid)?.containsKey(source) == true 22 | } 23 | 24 | override fun addCompiledData( 25 | entity: LivingEntity, 26 | source: String, 27 | attributes: Collection, 28 | slot: String?, 29 | ): CompiledData? { 30 | return this.addCompiledData(entity.uniqueId, source, attributes, slot) 31 | } 32 | 33 | override fun addCompiledData( 34 | entity: LivingEntity, 35 | source: String, 36 | compiledData: CompiledData, 37 | ): CompiledData { 38 | val uuid = entity.uniqueId 39 | this.computeIfAbsent(uuid) { CompiledAttrDataCompound(entity) }.register(source, compiledData) 40 | return compiledData 41 | } 42 | 43 | override fun addCompiledData( 44 | uuid: UUID, 45 | source: String, 46 | attributes: Collection, 47 | slot: String?, 48 | ): CompiledData? { 49 | return readManager.read(attributes, uuid.validEntity(), slot)?.let { 50 | this.addCompiledData( 51 | uuid, 52 | source, 53 | it 54 | ) 55 | } 56 | } 57 | 58 | override fun addCompiledData(uuid: UUID, source: String, compiledData: CompiledData): CompiledData? { 59 | return uuid.validEntity()?.let { addCompiledData(it, source, compiledData) } 60 | } 61 | 62 | override fun removeCompiledData(entity: LivingEntity, source: String): CompiledData? { 63 | return removeCompiledData(entity.uniqueId, source) 64 | } 65 | 66 | override fun removeCompiledData(uuid: UUID, source: String): CompiledData? { 67 | return this[uuid]?.run { 68 | remove(source) 69 | } 70 | } 71 | 72 | override fun removeIfStartWith(entity: LivingEntity, prefix: String) { 73 | return removeIfStartWith(entity.uniqueId, prefix) 74 | } 75 | 76 | override fun get(key: UUID): CompiledAttrDataCompound? { 77 | val entity = key.validEntity() ?: return null 78 | return computeIfAbsent(key) { CompiledAttrDataCompound(entity) } 79 | } 80 | 81 | override fun removeIfStartWith(uuid: UUID, prefix: String) { 82 | val lower = prefix.lowercase() 83 | this[uuid]?.run { 84 | filterKeys { it.startsWith(lower) }.map { it.key }.forEach(this::remove) 85 | } 86 | } 87 | 88 | 89 | } 90 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/ReadManagerImpl.kt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Skillw/AttributeSystem/f7c948c2becde0e972e16d9a598d40fea3f69731/src/main/kotlin/com/skillw/attsystem/internal/manager/ReadManagerImpl.kt -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/ReadPatternManagerImpl.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.AttributeSystem 4 | import com.skillw.attsystem.api.manager.ReadPatternManager 5 | import com.skillw.attsystem.internal.core.read.BaseReadGroup 6 | import com.skillw.attsystem.internal.manager.ASConfig.debug 7 | import com.skillw.pouvoir.util.loadMultiply 8 | import taboolib.common.platform.function.console 9 | import taboolib.module.lang.sendLang 10 | import java.io.File 11 | 12 | object ReadPatternManagerImpl : ReadPatternManager() { 13 | override val key = "ReadPatternManager" 14 | override val priority: Int = 1 15 | override val subPouvoir = AttributeSystem 16 | 17 | 18 | override fun onEnable() { 19 | onReload() 20 | } 21 | 22 | override fun onReload() { 23 | this.entries.filter { it.value.release }.forEach { (key, _) -> 24 | this.remove(key)?.also { 25 | debug { 26 | console().sendLang( 27 | "group-reader-unregister", 28 | key, 29 | it.operations().map { operation -> operation.key } 30 | ) 31 | } 32 | } 33 | } 34 | loadMultiply( 35 | File(AttributeSystem.plugin.dataFolder, "reader"), BaseReadGroup::class.java 36 | ).forEach { 37 | debug { 38 | console().sendLang( 39 | "group-reader-register", 40 | it.key.key.lowercase(), 41 | it.key.operations().map { operation -> operation.key }) 42 | } 43 | it.key.release = true 44 | it.key.register() 45 | } 46 | } 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/internal/manager/RealizerManagerImpl.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.internal.manager 2 | 3 | import com.skillw.attsystem.api.manager.RealizerManager 4 | import taboolib.common.LifeCycle 5 | import taboolib.common.platform.Awake 6 | 7 | object RealizerManagerImpl : RealizerManager() { 8 | override val priority: Int = 999 9 | 10 | @Awake(LifeCycle.DISABLE) 11 | fun disable() { 12 | onDisable() 13 | } 14 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/util/Format.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.util 2 | 3 | import java.text.NumberFormat 4 | 5 | object Format { 6 | @JvmStatic 7 | val format: NumberFormat by lazy { 8 | val numberFormat = NumberFormat.getInstance() 9 | numberFormat.isGroupingUsed = false 10 | numberFormat 11 | } 12 | 13 | 14 | @JvmStatic 15 | fun format(number: Number): String { 16 | return format.format(number) 17 | } 18 | 19 | fun Number.real(): String { 20 | return format.format(this) 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/util/MapUtils.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.util 2 | 3 | import com.skillw.pouvoir.util.calculateInline 4 | import com.skillw.pouvoir.util.replacement 5 | import org.bukkit.entity.LivingEntity 6 | import taboolib.module.nms.ItemTag 7 | import taboolib.module.nms.ItemTagData 8 | import taboolib.module.nms.ItemTagList 9 | import taboolib.module.nms.ItemTagType 10 | 11 | object MapUtils { 12 | 13 | @JvmStatic 14 | fun MutableMap.removeDeep(path: String) { 15 | val splits = path.split(".") 16 | if (splits.isEmpty()) { 17 | this.remove(path) 18 | return 19 | } 20 | var compound = this 21 | var temp: MutableMap 22 | for (node in splits) { 23 | if (node.equals(splits.last(), ignoreCase = true)) { 24 | compound.remove(node) 25 | } 26 | compound[node].also { temp = ((it as MutableMap?) ?: return) } 27 | compound = temp 28 | } 29 | } 30 | 31 | @JvmStatic 32 | internal fun ItemTag.toMutableMap(strList: List = emptyList()): MutableMap { 33 | val map = HashMap() 34 | for (it in this) { 35 | val key = it.key 36 | if (strList.contains(key)) continue 37 | val value = it.value.obj() 38 | map[key] = value 39 | } 40 | return map 41 | } 42 | 43 | @JvmStatic 44 | internal fun ItemTagList.toList(): List { 45 | return map { it.obj() } 46 | } 47 | 48 | @Suppress("IMPLICIT_CAST_TO_ANY") 49 | @JvmStatic 50 | internal fun ItemTagData.obj(): Any { 51 | val value = when (this.type) { 52 | ItemTagType.BYTE -> this.asByte() 53 | ItemTagType.SHORT -> this.asShort() 54 | ItemTagType.INT -> this.asInt() 55 | ItemTagType.LONG -> this.asLong() 56 | ItemTagType.FLOAT -> this.asFloat() 57 | ItemTagType.DOUBLE -> this.asDouble() 58 | ItemTagType.STRING -> this.asString() 59 | ItemTagType.BYTE_ARRAY -> this.asByteArray() 60 | ItemTagType.INT_ARRAY -> this.asIntArray() 61 | ItemTagType.COMPOUND -> this.asCompound() 62 | ItemTagType.LIST -> this.asList() 63 | else -> this.asString() 64 | } 65 | return when (value) { 66 | is ItemTag -> { 67 | value.toMutableMap() 68 | } 69 | 70 | is ItemTagList -> { 71 | val list = ArrayList() 72 | value.forEach { 73 | list.add(it.obj()) 74 | } 75 | list 76 | } 77 | 78 | else -> value 79 | } 80 | } 81 | 82 | internal fun T.replaceThenCalc(replacement: Map, entity: LivingEntity?): Any { 83 | return when (this) { 84 | is Map<*, *> -> { 85 | val map = HashMap() 86 | forEach { (key, value) -> 87 | key ?: return@forEach 88 | value ?: return@forEach 89 | map[key.toString()] = value.replaceThenCalc(replacement, entity) 90 | } 91 | map 92 | } 93 | 94 | is List<*> -> { 95 | val list = ArrayList() 96 | mapNotNull { it }.forEach { 97 | list.add(it.replaceThenCalc(replacement, entity)) 98 | } 99 | list 100 | } 101 | 102 | is String -> replacement(replacement).calculateInline(entity) 103 | 104 | else -> this 105 | } 106 | } 107 | 108 | 109 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/util/StringUtils.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.util 2 | 3 | import org.bukkit.Material 4 | import taboolib.library.xseries.XMaterial 5 | 6 | object StringUtils { 7 | @JvmStatic 8 | fun String.material(): Material? { 9 | val xMaterial = XMaterial.matchXMaterial(this) 10 | return if (xMaterial.isPresent) { 11 | xMaterial.get().parseMaterial() 12 | } else { 13 | Material.matchMaterial(this) 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/util/Utils.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.util 2 | 3 | import com.skillw.attsystem.AttributeSystem.attributeSystemAPI 4 | import com.skillw.attsystem.internal.manager.ASConfig 5 | import com.skillw.attsystem.util.legacy.mirrorNow 6 | import com.skillw.pouvoir.taboolib.module.nms.MinecraftVersion 7 | import com.skillw.pouvoir.util.livingEntity 8 | import org.bukkit.entity.LivingEntity 9 | import taboolib.common.platform.function.submit 10 | import taboolib.common.platform.service.PlatformExecutor 11 | import java.util.* 12 | 13 | object Utils { 14 | @JvmStatic 15 | fun UUID.validEntity(): LivingEntity? { 16 | 17 | return livingEntity() ?: run { 18 | attributeSystemAPI.remove(this) 19 | null 20 | } 21 | } 22 | 23 | @JvmStatic 24 | fun mirrorIfDebug(id: String, func: () -> T): T { 25 | return if (ASConfig.debug) { 26 | mirrorNow(id, func) 27 | } else { 28 | func() 29 | } 30 | } 31 | 32 | 33 | @JvmStatic 34 | fun adaptive( 35 | now: Boolean = false, 36 | delay: Long = 0, 37 | period: Long = 0, 38 | executor: PlatformExecutor.PlatformTask.() -> Unit, 39 | ): PlatformExecutor.PlatformTask { 40 | MinecraftVersion 41 | return submit(now, true, delay, period, executor) 42 | } 43 | 44 | 45 | } -------------------------------------------------------------------------------- /src/main/kotlin/com/skillw/attsystem/util/legacy/Mirror.kt: -------------------------------------------------------------------------------- 1 | package com.skillw.attsystem.util.legacy 2 | 3 | import taboolib.common.platform.ProxyCommandSender 4 | import taboolib.common.platform.function.pluginId 5 | import taboolib.common.util.replaceWithOrder 6 | import java.math.BigDecimal 7 | import java.math.RoundingMode 8 | import java.util.* 9 | import java.util.concurrent.CompletableFuture 10 | import java.util.concurrent.ConcurrentHashMap 11 | 12 | fun mirrorNow(id: String, func: () -> T): T { 13 | val time = System.nanoTime() 14 | return func().also { 15 | Mirror.mirrorData.computeIfAbsent(id) { Mirror.MirrorData() }.finish(time) 16 | } 17 | } 18 | 19 | fun mirrorFuture(id: String, func: Mirror.MirrorFuture.() -> Unit): CompletableFuture { 20 | val mf = Mirror.MirrorFuture().also(func) 21 | mf.future.thenApply { 22 | Mirror.mirrorData.computeIfAbsent(id) { Mirror.MirrorData() }.finish(mf.time) 23 | } 24 | return mf.future 25 | } 26 | 27 | object Mirror { 28 | 29 | val mirrorData = ConcurrentHashMap() 30 | 31 | fun report(sender: ProxyCommandSender, func: MirrorSettings.() -> Unit = {}): MirrorCollect { 32 | val options = MirrorSettings().also(func) 33 | val collect = MirrorCollect(options, "/", "/") 34 | mirrorData.forEach { mirror -> 35 | var point = collect 36 | mirror.key.split(":").forEach { 37 | point = point.sub.computeIfAbsent(it) { _ -> MirrorCollect(options, mirror.key, it) } 38 | } 39 | } 40 | collect.print(sender, collect.getTotal(), 0) 41 | return collect 42 | } 43 | 44 | class MirrorSettings { 45 | 46 | var childFormat = "§c[$pluginId] §8{0}§f{1} §8count({2})§c avg({3}ms) §7{4}ms ~ {5}ms §8··· §7{6}%" 47 | var parentFormat = "§c[$pluginId] §8{0}§7{1} §8count({2})§c avg({3}ms) §7{4}ms ~ {5}ms §8··· §7{6}%" 48 | } 49 | 50 | class MirrorFuture { 51 | 52 | internal val time = System.nanoTime() 53 | internal val future = CompletableFuture() 54 | 55 | fun finish(any: T) { 56 | future.complete(any) 57 | } 58 | } 59 | 60 | class MirrorCollect(val opt: MirrorSettings, val key: String, val path: String, val sub: MutableMap = TreeMap()) { 61 | 62 | fun getTotal(): BigDecimal { 63 | var total = mirrorData[key]?.timeTotal ?: BigDecimal.ZERO 64 | sub.values.forEach { 65 | total = total.add(it.getTotal()) 66 | } 67 | return total 68 | } 69 | 70 | fun print(sender: ProxyCommandSender, all: BigDecimal, space: Int) { 71 | val prefix = "${"···".repeat(space)}${if (space > 0) " " else ""}" 72 | val total = getTotal() 73 | val data = mirrorData[key] 74 | if (data != null) { 75 | val count = data.count 76 | val avg = data.getAverage() 77 | val min = data.getLowest() 78 | val max = data.getHighest() 79 | val format = if (sub.isEmpty()) opt.childFormat else opt.parentFormat 80 | sender.sendMessage(format.replaceWithOrder(prefix, path, count, avg, min, max, percent(all, total))) 81 | } 82 | sub.values.map { 83 | it to percent(all, it.getTotal()) 84 | }.sortedByDescending { 85 | it.second 86 | }.forEach { 87 | it.first.print(sender, all, if (data != null) space + 1 else space) 88 | } 89 | } 90 | 91 | fun percent(all: BigDecimal, total: BigDecimal): Double { 92 | return if (all.toDouble() == 0.0) 0.0 else total.divide(all, 2, RoundingMode.HALF_UP).multiply(BigDecimal("100")).toDouble() 93 | } 94 | } 95 | 96 | class MirrorData { 97 | 98 | internal var count = 0L 99 | internal var time = 0L 100 | internal var timeTotal = BigDecimal.ZERO 101 | internal var timeLatest = BigDecimal.ZERO 102 | internal var timeLowest = BigDecimal.ZERO 103 | internal var timeHighest = BigDecimal.ZERO 104 | 105 | init { 106 | reset() 107 | } 108 | 109 | fun define(): MirrorData { 110 | time = System.nanoTime() 111 | return this 112 | } 113 | 114 | fun finish(): MirrorData { 115 | return finish(time) 116 | } 117 | 118 | fun finish(startTime: Long): MirrorData { 119 | val stopTime = System.nanoTime() 120 | timeLatest = BigDecimal((stopTime - startTime) / 1000000.0).setScale(2, RoundingMode.HALF_UP) 121 | timeTotal = timeTotal.add(timeLatest) 122 | if (timeLatest.compareTo(timeHighest) == 1) { 123 | timeHighest = timeLatest 124 | } 125 | if (timeLatest.compareTo(timeLowest) == -1) { 126 | timeLowest = timeLatest 127 | } 128 | count++ 129 | return this 130 | } 131 | 132 | fun reset(): MirrorData { 133 | count = 0 134 | timeTotal = BigDecimal.ZERO 135 | timeLatest = BigDecimal.ZERO 136 | timeLowest = BigDecimal.ZERO 137 | timeHighest = BigDecimal.ZERO 138 | return this 139 | } 140 | 141 | fun getTotal(): Double { 142 | return timeTotal.toDouble() 143 | } 144 | 145 | fun getLatest(): Double { 146 | return timeLatest.toDouble() 147 | } 148 | 149 | fun getHighest(): Double { 150 | return timeHighest.toDouble() 151 | } 152 | 153 | fun getLowest(): Double { 154 | return timeLowest.toDouble() 155 | } 156 | 157 | fun getAverage(): Double { 158 | return if (count == 0L) 0.0 else timeTotal.divide(BigDecimal.valueOf(count), 2, RoundingMode.HALF_UP).toDouble() 159 | } 160 | } 161 | } -------------------------------------------------------------------------------- /src/main/resources/attributes/Example.yml: -------------------------------------------------------------------------------- 1 | # 在这里的属性 重载即可注册 2 | # AttributeSystem没有脚本属性, 3 | # 在AttributeSystem里,属性与其功能的实现是完全分开的 4 | # 你可以通过修改各种公式乃至自定义机制,注册脚本监听器来实现属性的功能 5 | #ID 6 | ExampleAtt: 7 | #权重 不填默认0 8 | priority: 1 9 | #是否会计算到实体属性上 不填默认true 10 | include-entity: true 11 | #展示名 不填默认names的第一个 12 | display: "示例属性" 13 | #名称 不填默认是key 14 | names: 15 | - "示例属性" 16 | - "示例属性2" 17 | - "示例属性3" 18 | #读取组 不填默认Default 19 | read-pattern: default 20 | #属性映射 21 | mapping: 22 | type: strings 23 | #后面可以通过 <占位符公式id> 调用本属性读取组的占位符公式 24 | attributes: 25 | - "移动速度: {{ * 10}}" 26 | 27 | #快速声明一个属性 28 | 快速属性: { } 29 | 30 | 31 | #下面是字符串属性,感兴趣的可以看看 32 | StringAtt: 33 | names: [ "唯一字符串属性" ] 34 | read-pattern: StrSkip 35 | 36 | StringAppendAtt: 37 | names: [ "拼接字符串属性" ] 38 | read-pattern: StrAppend 39 | 40 | RomenAtt: 41 | names: [ "罗马数字" ] 42 | read-pattern: StrRoman -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | database: 2 | type: sqlite 3 | # sqlite的path 4 | path: plugins/AttributeSystem/database.db 5 | enable: false 6 | host: localhost 7 | port: 3306 8 | user: root 9 | password: root 10 | database: root 11 | table: my_database 12 | #每10分钟同步一次 (tick) 13 | user-container-sync-time: 12000 14 | options: 15 | debug: false 16 | read: 17 | #当行中有这些之一时,忽略此行属性 18 | ignores: 19 | - "//" 20 | - "§-" 21 | condition: 22 | line-condition: 23 | #单行条件的格式 24 | #解析: 25 | # \/ '\'用来转义, : 属性和单行条件之间的分隔符 26 | # (?.*) : 单行条件们 27 | # 例: 攻击力: 100/Lv.100,职业: 巫师 28 | format: '\/(?.*)' 29 | #每个单行条件间的分隔符 30 | separator: "," 31 | # 移至Pouvoir 32 | # operation: 33 | # string-append-separator: ", " 34 | 35 | -------------------------------------------------------------------------------- /src/main/resources/dispatchers/custom-trigger.yml: -------------------------------------------------------------------------------- 1 | custom entity fight: 2 | triggers: [ entity damage by entity ] 3 | context: 4 | attacker: "@event damager" 5 | defender: "@event entity" 6 | namespaces: [ bukkit ] 7 | pre-handle: |- 8 | print attack! 9 | if check &attacker !type LivingEntity || &defender !type LivingEntity then exit 10 | if check &attacker type Player then { 11 | &attacker message '你在打东西! 爱来自 plugins/AttributeSystem/dispatchers/custom-trigger.yml' 12 | } 13 | post-handle: 14 | type: js 15 | content: |- 16 | print(" entity damage by entity 处理完了! 爱来自 plugins/AttributeSystem/dispatchers/custom-trigger.yml") 17 | exception: |- 18 | warning '触发器 custom entity fight 处理失败! 具体报错请看后台! 爱来自 plugins/AttributeSystem/dispatchers/custom-trigger.yml' 19 | -------------------------------------------------------------------------------- /src/main/resources/handlers/on-attack.yml: -------------------------------------------------------------------------------- 1 | #on-attack: 2 | # triggers: [ custom entity fight ] 3 | # namespaces: [ bukkit ] 4 | # when: 5 | # - if: "check &attacker name; == 'Neige'" 6 | # goto: main1 7 | # - else: main 8 | # context: 9 | # attackerData: attr data of &attacker 10 | # defenderData: attr data of &defender 11 | # functions: 12 | # main: |- 13 | # set addition_damage to math &attackerData.攻击力.value - &defenderData.防御力.value 14 | # damage &defender &addition_damage 15 | # particle REDSTONE at @defender eyeLocation; { 16 | # 'range' = 100 17 | # count = 1000 18 | # data = particleData dust [ color [ 255 255 235 ] in 1.0 ] 19 | # } 20 | # main1: |- 21 | # tell all 'Neige 打人了!' 22 | -------------------------------------------------------------------------------- /src/main/resources/lang/en_US.yml: -------------------------------------------------------------------------------- 1 | prefix: '&d[&9AttributeSystem&d] ' 2 | equipment-type-error: '&d[&9AttributeSystem&d] &6{0} &cis not a slot type!' 3 | 4 | command-reload: '&d[&9AttributeSystem&d] &aReloaded!' 5 | command-info: 6 | - '&f&m─&6&m──────────────────────────────────&6&f&m─' 7 | - ' &9Command List:' 8 | - ' &6/as' 9 | - ' &d- &ehelp &5—— &aShow help.' 10 | - ' &d- &edebug &5—— &aDebug mode.' 11 | - ' &d- &einfo &5—— &aShow info.' 12 | - ' &d- &estats (Player) &5—— &aShow the stats.' 13 | - ' &d- &eitemstats [Player] [key] [slot] &5—— &aShow the stats of a item&e.' 14 | - ' &d- &eentitystats &5—— &aShow the stats of the entity you look at.' 15 | - ' &d- &epersonal [Type] [Sub Type] &5—— &aSet where does the info show.' 16 | - ' &d- &ereport &5—— &aCheck Mirror Data.' 17 | - ' &d- &eclear &5—— &aClear Mirror Data.' 18 | - ' &d- &ereload &5—— &aReload.' 19 | - '&f&m─&6&m──────────────────────────────────&6&f&m─' 20 | command-personal: '&d[&9AttributeSystem&d] &eYour &6{0} &eis changed to &b{1} &e!' 21 | command-valid-player: '&d[&9AttributeSystem&d] &cThe player &6{0} &cdosen t exist!' 22 | command-valid-item: '&d[&9AttributeSystem&d] &cThe item is not exists!' 23 | command-valid-entity: '&d[&9AttributeSystem&d] &cYou have to look at a Entity!' 24 | command-disable-warning: '&d[&9AttributeSystem&d] &cAre you sure to disable &9AttributeSystem &c? Type &6/as disable confirm &cif you really wanna disable it! &4:(' 25 | command-disable: '&d[&9AttributeSystem&d] &cYou disabled &9AttributeSystem &c!Please stop the server then delete this plugin &4:(' 26 | command-debug-on: '&d[&9AttributeSystem&d] &aTurn on &bDebug Mode&a.' 27 | command-debug-off: '&d[&9AttributeSystem&d] &cTurn off &bDebug Mode&c.' 28 | 29 | 30 | fight-in: '&d[&9AttributeSystem&d] &eInto fighting!' 31 | fight-out: '&d[&9AttributeSystem&d] &eOut of fighting!' 32 | 33 | 34 | disable-damage-type: '&d[&9AttributeSystem&d] &cYou can t attack with &6{0} &c!' 35 | wrong-command: '&d[&9AttributeSystem&d] &cWrong command!' 36 | wrong-sender: '&d[&9AttributeSystem&d] &cWrong sender!' 37 | command-clear: '&d[&9AttributeSystem&d] &aMirrorData has been cleared!' 38 | 39 | group-reader-register: '&d[&9AttributeSystem&d] &aRead Group &6{0} &7[&f{1}&7] &ahas been registered!' 40 | group-reader-unregister: '&d[&9AttributeSystem&d] &cRead Group &6{0} &7[&f{1}&7] &chas been unregistered!' 41 | attribute-register: '&d[&9AttributeSystem&d] &aAttribute &6{0} &7[&f{1}&7] &ahas been registered!' 42 | attribute-unregister: '&d[&9AttributeSystem&d] &cAttribute &6{0} &7[&f{1}&7] &chas been unregistered!' 43 | 44 | #annotation-read-pattern-register: '&d[&9AttributeSystem&d] &aRead Pattern &6{0} &ahas been registered!' 45 | #annotation-read-pattern-unregister: '&d[&9AttributeSystem&d] &cRead Pattern &6{0} &chas been unregistered!' 46 | #annotation-message-type-register: '&d[&9AttributeSystem&d] &aMessage Type &6{0} &ahas been registered!' 47 | #annotation-message-type-unregister: '&d[&9AttributeSystem&d] &cMessage Type &6{0} &chas been unregistered!' 48 | 49 | stats-title: ' &f&m─&7&m─────────&f&m─&fAttribute Status&f&m─&7&m─────────&f&m─' 50 | stats-attribute-format: '&7 &7{name} &f>&7>&8> &c{value} ' 51 | stats-status: 'Status:' 52 | stats-status-value: '{key} = {value}' 53 | stats-status-none: 'None' 54 | stats-status-placeholder: 'Placeholder:' 55 | stats-status-placeholder-value: '{key} = {value}' 56 | stats-end: ' &f&m─&7&m───────────────────────────&7&f&m─' 57 | 58 | fight-info: "&b&lFight Info:" 59 | fight-info-key: "&6Fight Key: &4{0}" 60 | fight-info-attacker: "&7Attacker: &c{0}" 61 | fight-info-defender: "&7Defender: &c{0}" 62 | fight-info-damage-type: " &8-> &eDamageType: &6{0}" 63 | fight-info-mechanic: " &7- &5Machine: &c{0}" 64 | fight-info-mechanic-return: " &5return: &6{0}" 65 | fight-info-usable-vars: " &7- &dUsable variables:" 66 | fight-info-message: " &7- &dMessage:" 67 | fight-info-result: "&7Result: &c{0}" 68 | 69 | error-read-group: '&d[&9AttributeSystem&d] &cAn error occurred while loading NumberReader &6{0} &c!' 70 | error-read-group-cause: '&d[&9AttributeSystem&d] &cCause: &f{0}' 71 | invalid-read-pattern: '&d[&9AttributeSystem&d] &cThe ReadPattern &b{1} &cof Attribute &6{0} &cdoes not exist!' 72 | invalid-damage-type: '&d[&9AttributeSystem&d] &cThe DamageType is null in &6{0}&c!' 73 | invalid-mechanic: '&d[&9AttributeSystem&d] &cThe Mechanic is null in &6{0}&c!' 74 | invalid-attribute: '&d[&9AttributeSystem&d] &cThe Attribute is null! &6{0}' 75 | 76 | read-restrict-numeric: "&d[&9AttributeSystem&d] &cThe value &d{0} &cin &6{1} &cmust be a Numeric!" 77 | 78 | type-TITLE: 'Title' 79 | type-ACTION-BAR: 'ActionBar' 80 | type-CHAT: 'Chat' 81 | type-HOLO: 'Holo text' 82 | type-DISABLE: 'Swichable' 83 | 84 | attacking-message-type: 'Attacking MessageType' 85 | defensive-message-type: 'Defensive MessageType' 86 | health-regain-type: 'Health Regain MessageType' -------------------------------------------------------------------------------- /src/main/resources/lang/zh_CN.yml: -------------------------------------------------------------------------------- 1 | prefix: '&d[&9属性系统&d] ' 2 | equipment-type-error: '&d[&9属性系统&d] &6{0} &c不是槽位类型!' 3 | 4 | command-reload: '&d[&9属性系统&d] &a插件已重载成功!' 5 | command-info: 6 | - '&f&m─&6&m──────────────────────────────────&6&f&m─' 7 | - ' &9指令列表:' 8 | - ' &6/as' 9 | - ' &d- &ehelp &5—— &a插件帮助.' 10 | - ' &d- &edebug &5—— &a开启调试模式.' 11 | - ' &d- &einfo &5—— &a显示插件信息.' 12 | - ' &d- &estats (玩家名) &5—— &a显示属性统计.' 13 | - ' &d- &eitemstats [玩家名] [key] [slot] &5—— &a显示物品的属性统计&e.' 14 | - ' &d- &eentitystats &5—— &a显示你所看向的实体的属性统计' 15 | - ' &d- &ereport &5—— &a查看耗时数据' 16 | - ' &d- &eclear &5—— &a清除耗时数据' 17 | - ' &d- &ereload &5—— &a重载插件' 18 | - '&f&m─&6&m──────────────────────────────────&6&f&m─' 19 | command-valid-player: '&d[&9属性系统&d] &c玩家 &6{0} &c不存在!' 20 | command-valid-item: '&d[&9属性系统&d] &c物品不存在!' 21 | command-valid-entity: '&d[&9属性系统&d] &c你必须看向一个实体!' 22 | command-disable-warning: '&d[&9属性系统&d] &c你确定要关闭 &9属性系统 &c吗? 这将导致其所有属性实现失效!如果你确定要关闭,请输入 &6/as disable confirm &c! &4:(' 23 | command-disable: '&d[&9属性系统&d] &c你关闭了 &9属性系统 &c!请重启服务器并删除插件! &4:(' 24 | command-debug-on: '&d[&9属性系统&d] &a你开启了 &b调试模式&a.' 25 | command-debug-off: '&d[&9属性系统&d] &c你关闭了 &b调试模式&c.' 26 | fight-in: '&d[&9属性系统&d] &e你已进入战斗状态!' 27 | fight-out: '&d[&9属性系统&d] &e你已离开战斗状态!' 28 | 29 | 30 | disable-damage-type: '&d[&9属性系统&d] &6{0} &c已被禁止普攻!' 31 | wrong-command: '&d[&9属性系统&d] &c你是不是输错指令啦!' 32 | wrong-sender: '&d[&9属性系统&d] &c控制台不能发送此指令!' 33 | command-clear: '&d[&9属性系统&d] &a耗时数据已清楚!' 34 | 35 | group-reader-register: '&d[&9属性系统&d] &a读取组 &6{0} &7[&f{1}&7] &a注册成功!' 36 | group-reader-unregister: '&d[&9属性系统&d] &c读取组 &6{0} &7[&f{1}&7] &c注销成功!' 37 | attribute-register: '&d[&9属性系统&d] &a属性 &6{0} &7[&f{1}&7] &a注册成功!' 38 | attribute-unregister: '&d[&9属性系统&d] &c属性 &6{0} &7[&f{1}&7] &c注销成功!' 39 | 40 | 41 | #annotation-read-pattern-register: '&d[&9属性系统&d] &a读取模式 &6{0} &a注册成功!' 42 | #annotation-read-pattern-unregister: '&d[&9属性系统&d] &c读取模式 &6{0} &c注销成功!' 43 | #annotation-message-type-register: '&d[&9属性系统&d] &a消息类型 &6{0} &a注册成功!' 44 | #annotation-message-type-unregister: '&d[&9属性系统&d] &c消息类型 &6{0} &c注销成功!' 45 | 46 | stats-title: ' &f&m─&7&m─────────&f&m─&f属性统计&f&m─&7&m─────────&f&m─' 47 | stats-attribute-format: '&7 &7{name} &f>&7>&8> &c{value} &7点' 48 | stats-status: '属性(捕获组)状态:' 49 | stats-status-value: '{key} = {value}' 50 | stats-status-none: '无' 51 | stats-status-placeholder: '占位符:' 52 | stats-status-placeholder-value: '{key} = {value}' 53 | stats-end: ' &f&m─&7&m───────────────────────────&7&f&m─' 54 | 55 | 56 | 57 | error-read-group: '&d[&9属性系统&d] &c加载读取组 &6{0} &c时发生了错误!' 58 | error-read-group-cause: '&d[&9属性系统&d] &c原因: &f{0}' 59 | invalid-read-pattern: '&d[&9属性系统&d] &c属性 &6{0} &c的读取格式 &b{1} &c不存在!!' 60 | invalid-attribute: '&d[&9属性系统&d] &c属性不存在! &6{0}' 61 | 62 | read-restrict-numeric: "&d[&9属性系统&d] &c在 &6{1} &c中的值 &d{0} &c必须是一个数字!" 63 | 64 | -------------------------------------------------------------------------------- /src/main/resources/options.yml: -------------------------------------------------------------------------------- 1 | base-attribute-player: 2 | # strings / nbt 3 | type: strings 4 | attributes: 5 | - "生命恢复: 0.1" 6 | - "攻击速度: 1.5" 7 | - "命中几率: 100(%)" 8 | - "攻击距离: 2.7" 9 | - "暴击伤害: 150(%)" 10 | base-attribute-entity: 11 | #当实体生成的时候,是否自动添加这些属性 12 | on-spawn: true 13 | # strings / nbt 14 | type: strings 15 | attributes: 16 | - "命中几率: 100(%)" 17 | #生命值缩放 18 | health-scale: 19 | enable: true 20 | value: 20 21 | health-regain: 22 | #默认每10tick(0.5s)恢复一次生命值 (见 period) 23 | #为了方便实现"每秒回血" %as_att:HealthRegain% /s 故将值除以二 24 | enable: true 25 | vanilla: true 26 | #每多少tick 恢复一次生命 27 | period: 10 28 | #战斗时间禁生命恢复系统 29 | disable-in-fighting: false 30 | value: "%as_att:HealthRegain% / 2" 31 | update: 32 | #属性更新任务周期 (tick) 33 | period: 10 34 | #由事件驱动的玩家更新最低间隔 (ms) 35 | #为了防止玩家高频更新属性 36 | baffle: 20 -------------------------------------------------------------------------------- /src/main/resources/reader/number/default.yml: -------------------------------------------------------------------------------- 1 | Default: 2 | type: number 3 | matchers: 4 | #左边是捕获组id 右边是运算操作 5 | #捕获组id只能包含 a-z A-Z 0-9 6 | #运算操作: 7 | #- plus 加 8 | #- max 取最大 9 | #- min 取最小 10 | #- reduce 减 11 | #- scalar 乘 12 | percentMax: plus 13 | percentMin: plus 14 | valueMin: plus 15 | valueMax: plus 16 | percent: plus 17 | value: plus 18 | valueAddition: plus 19 | percentAddition: plus 20 | mul: scalar 21 | #匹配模式(正则) 22 | #从上到下先后匹配 23 | #特殊字符要转义 24 | #捕获组id只能包含 a-z A-Z 0-9 25 | patterns: 26 | # 攻击力: 11-23 % 27 | - "{name}.*?-.*?%" 28 | # 攻击力: 10-20 29 | - "{name}.*?-" 30 | # 攻击力: 10 (+20) % 31 | - "{name}.*?.*?\\(\\).*?%" 32 | # 攻击力: 10 % 33 | - "{name}.*?.*?%" 34 | # 攻击力*10 35 | - "{name}.*?\\*.*?" 36 | # 攻击力: 100 (+50) 37 | - "{name}.*?.*?\\(\\)" 38 | # 攻击力: 100 / 攻击力 100 39 | - "{name}.*?" 40 | # 100 攻击力 +100 41 | - ".*?{name}.*?" 42 | # 100 攻击力 43 | - ".*?{name}" 44 | #变量(PAPI / PouPAPI) 45 | #调用变量格式: %as_att:属性ID_下面的id% 46 | placeholders: 47 | #占位符id 48 | # 可通过 %as_att:属性id_占位符id 调用% 49 | #可带入捕获组 与 其他 占位符 的值 50 | #优先带入捕获组的 51 | # total min max 必须写 52 | total: "( + + {random to }) * {calculate '(1+( + /100 + {random to } /100))'} * { if check == 0 then 1 else }" 53 | scalar: 54 | value: 55 | percent: + /100 56 | valueMin: 57 | valueMax: 58 | percentMin: /100 59 | percentMax: /100 60 | valueRandom: + {random to } 61 | percentRandom: (/100 + {random to }/100) 62 | original: 63 | #total: "( )*( 1 + () ) * { if check == 0 then 1 else }" 64 | #min: "( + + )*( 1 + () ) " 65 | #max: "( + + )*( 1 + () )" 66 | #mul: 67 | #value: + 68 | #percent: ( + ) /100 69 | #valueMin: + 70 | #valueMax: + 71 | #percentMin: ( + ) /100 72 | #percentMax: ( + ) /100 73 | #valueRandom: + + {random to } 74 | #percentRandom: (( + ()/100) + {random to }/100) -------------------------------------------------------------------------------- /src/main/resources/reader/number/percent.yml: -------------------------------------------------------------------------------- 1 | Percent: 2 | type: number 3 | matchers: 4 | percentMax: plus 5 | percentMin: plus 6 | percent: plus 7 | percentAddition: plus 8 | patterns: 9 | # 暴击率: 10-60(% 10 | - "{name}.*?-" 11 | # 暴击率: 50 (+10) (%) 12 | - "{name}.*?.*?\\(\\)" 13 | # 暴击率: 50(%) 14 | - "{name}.*?" 15 | placeholders: 16 | # total min max 必须写 17 | total: "" 18 | min: "( + ) /100" 19 | max: "( + ) /100" 20 | percent: ( + ) /100 21 | percentMin: /100 22 | percentMax: /100 23 | percentRandom: ( + + {random to })/100 24 | -------------------------------------------------------------------------------- /src/main/resources/reader/string/string.yml: -------------------------------------------------------------------------------- 1 | StrSkip: 2 | type: string 3 | matchers: 4 | value: skip 5 | patterns: 6 | # 唯一字符串属性: 好耶 7 | - "{name}(:|:)?\\s*?(?.*)" 8 | placeholders: 9 | total: 10 | value: 11 | StrAppend: 12 | type: string 13 | matchers: 14 | value: append 15 | patterns: 16 | # 拼接字符串属性: 好耶 17 | - "{name}(:|:)?\\s*?(?.*)" 18 | placeholders: 19 | total: 20 | value: 21 | StrRoman: 22 | type: string 23 | matchers: 24 | roman: roman_num 25 | patterns: 26 | # 罗马数字: IV 27 | - "{name}(:|:)?\\s*?(?[IVXLCDM]+)" 28 | placeholders: 29 | total: 30 | romanNum: 31 | -------------------------------------------------------------------------------- /src/main/resources/scripts/conditions/attribute.js: -------------------------------------------------------------------------------- 1 | //@Condition() 2 | 3 | // load("plugins/Pouvoir/scripts/core/basic.js"); 4 | 5 | Coerce = static("Coerce"); 6 | 7 | key = "attribute"; 8 | names = ["需要(?.*)属性: (?\\d+)"]; 9 | 10 | function parameters(matcher, text) { 11 | const name = matcher.group("name"); 12 | const value = Coerce.toDouble(matcher.group("value")); 13 | return mapOf({ name: name, value: value }); 14 | } 15 | 16 | function condition(entity, map) { 17 | if (entity == null) return true; 18 | var name = map.get("name"); 19 | var value = map.get("value"); 20 | const compound = AttrAPI.getAttrData(entity); 21 | return compound == null || compound.getAttrValue(name, "total") >= value; 22 | } 23 | -------------------------------------------------------------------------------- /src/main/resources/scripts/conditions/slot.js: -------------------------------------------------------------------------------- 1 | //@Condition() 2 | 3 | key = "slot"; 4 | 5 | names = ["槽位: (?.*)"]; 6 | 7 | function parameters(matcher, text) { 8 | var requiredSlot = matcher.group("slot"); 9 | return mapOf({ required: requiredSlot }); 10 | } 11 | 12 | function condition(entity, map) { 13 | if (entity == null) return true; 14 | // 槽位会自动初始化到参数中 15 | const slot = map.get("slot"); 16 | const required = map.get("required"); 17 | if (slot == null || required == null) return true; 18 | return slot.equalsIgnoreCase(required); 19 | } 20 | -------------------------------------------------------------------------------- /src/main/resources/slot.yml: -------------------------------------------------------------------------------- 1 | #左ID 右槽位 2 | player: { } 3 | #左AS内部槽位key 右原版槽位 4 | # 2.1.0-beta 后已内置 5 | # "头盔": "HEAD" 6 | # "胸甲": "CHEST" 7 | # "护腿": "LEGS" 8 | # "靴子": "FEET" 9 | # "主手": "HAND" 10 | # "副手": "OFFHAND" 11 | #读取槽位20的装备 以20th为id存入装备栏 12 | # "20th": "20" 13 | #这样写可以给放到槽位的装备加限制: 14 | # "20th": 15 | # slot: 20 16 | # require: "槽位: 饰品" 17 | entity: { } 18 | # 2.1.0-beta 后已内置 19 | # "头盔": "HEAD" 20 | # "胸甲": "CHEST" 21 | # "护腿": "LEGS" 22 | # "靴子": "FEET" 23 | # "主手": "HAND" 24 | # "副手": "OFFHAND" 25 | # 萌芽槽位 26 | germ-slots: 27 | - "example" 28 | -------------------------------------------------------------------------------- /src/main/resources/vanilla.yml: -------------------------------------------------------------------------------- 1 | #支持 PAPI/PPAPI 字符串内联函数 2 | #会影响实体的原版属性 / 其它属性 3 | #支持任何原版属性,例如飞行速度FlySpeed 4 | #fly-speed: 5 | # enable: true 6 | # vanilla: true 7 | # value: %as_att:FlySpeed% 8 | max-health: 9 | enable: true 10 | vanilla: true 11 | #玩家默认血量 12 | default: 20 13 | value: "%as_att:MaxHealth%" 14 | movement-speed: 15 | enable: true 16 | vanilla: true 17 | value: "%as_att:MovementSpeed% / 2250" 18 | knockback-resistance: 19 | #击退抗性 20 | enable: true 21 | vanilla: true 22 | value: "%as_att:Resistance%" 23 | #下面这些只支持玩家 24 | attack-speed: 25 | #单位为 攻击次数/s 26 | enable: true 27 | vanilla: true 28 | value: "%as_att:AttackSpeed%" 29 | luck: 30 | enable: true 31 | vanilla: true 32 | value: "%as_att:Luck%" --------------------------------------------------------------------------------