├── .gitignore ├── LICENSE ├── README.md ├── build.gradle.kts ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── plugin └── build.gradle.kts ├── project ├── build.gradle.kts ├── common-impl │ ├── build.gradle.kts │ └── src │ │ └── main │ │ ├── kotlin │ │ └── ink │ │ │ └── ptms │ │ │ └── zaphkiel │ │ │ └── impl │ │ │ ├── DefaultItemHandler.kt │ │ │ ├── DefaultItemLoader.kt │ │ │ ├── DefaultItemManager.kt │ │ │ ├── DefaultItemSerializer.kt │ │ │ ├── DefaultItemUpdater.kt │ │ │ ├── DefaultZapAPI.kt │ │ │ ├── Translator.kt │ │ │ ├── feature │ │ │ ├── ItemCooldown.kt │ │ │ ├── ItemDataMapping.kt │ │ │ ├── ItemDurability.kt │ │ │ ├── ItemMenu.kt │ │ │ ├── hook │ │ │ │ ├── AttributePlusHook.kt │ │ │ │ └── MythicHook.kt │ │ │ └── kether │ │ │ │ ├── ActionBuilder.kt │ │ │ │ ├── ActionCooldown.kt │ │ │ │ ├── ActionIt.kt │ │ │ │ ├── ActionItem.kt │ │ │ │ ├── ActionMythic.kt │ │ │ │ ├── ActionPotion.kt │ │ │ │ ├── ActionZaphkiel.kt │ │ │ │ └── Extensions.kt │ │ │ ├── internal │ │ │ ├── ItemBuilder.kt │ │ │ ├── ItemListener.kt │ │ │ └── ItemUpdater.kt │ │ │ ├── item │ │ │ ├── Config.kt │ │ │ ├── DefaultDisplay.kt │ │ │ ├── DefaultGroup.kt │ │ │ ├── DefaultItem.kt │ │ │ ├── DefaultItemEvent.kt │ │ │ ├── DefaultItemStream.kt │ │ │ ├── DefaultItemStreamGenerated.kt │ │ │ ├── DefaultSerializedItem.kt │ │ │ ├── DefaultStructureList.kt │ │ │ └── DefaultStructureSingle.kt │ │ │ └── meta │ │ │ ├── MetaAttribute.kt │ │ │ ├── MetaCanDestroy.kt │ │ │ ├── MetaCanPlaceOn.kt │ │ │ ├── MetaColor.kt │ │ │ ├── MetaCustomModelData.kt │ │ │ ├── MetaData.kt │ │ │ ├── MetaEnchantment.kt │ │ │ ├── MetaIcon.kt │ │ │ ├── MetaItemFlag.kt │ │ │ ├── MetaKey.kt │ │ │ ├── MetaNative.kt │ │ │ ├── MetaPotion.kt │ │ │ ├── MetaShiny.kt │ │ │ ├── MetaSkull.kt │ │ │ ├── MetaSpawner.kt │ │ │ ├── MetaTiphareth.kt │ │ │ ├── MetaUnbreakable.kt │ │ │ └── MetaUnique.kt │ │ └── resources │ │ ├── config.yml │ │ ├── display │ │ └── def.yml │ │ ├── generator │ │ └── def.yml │ │ └── item │ │ └── def.yml ├── common │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── ink │ │ └── ptms │ │ └── zaphkiel │ │ ├── ZapAPI.kt │ │ ├── Zaphkiel.kt │ │ ├── annotation │ │ ├── Equal.kt │ │ ├── LegacyName.kt │ │ ├── Locked.kt │ │ ├── Printable.kt │ │ └── UseWarning.kt │ │ ├── api │ │ ├── Display.kt │ │ ├── DisplayProduct.kt │ │ ├── Group.kt │ │ ├── Item.kt │ │ ├── ItemEvent.kt │ │ ├── ItemHandler.kt │ │ ├── ItemKey.kt │ │ ├── ItemLoader.kt │ │ ├── ItemManager.kt │ │ ├── ItemSerializer.kt │ │ ├── ItemSignal.kt │ │ ├── ItemStream.kt │ │ ├── ItemUpdater.kt │ │ ├── JsonContainer.kt │ │ ├── Model.kt │ │ ├── SerializedItem.kt │ │ ├── StructureList.kt │ │ ├── StructureSingle.kt │ │ └── event │ │ │ ├── Alias.kt │ │ │ ├── Editable.kt │ │ │ ├── ItemBuildEvent.kt │ │ │ ├── ItemEvent.kt │ │ │ ├── ItemGiveEvent.kt │ │ │ ├── ItemReleaseEvent.kt │ │ │ └── PluginReloadEvent.kt │ │ ├── impl │ │ └── item │ │ │ └── Extensions.kt │ │ └── item │ │ └── meta │ │ └── Meta.kt ├── module-bukkit │ ├── build.gradle.kts │ └── src │ │ └── main │ │ └── kotlin │ │ └── ink │ │ └── ptms │ │ └── zaphkiel │ │ └── ZaphkielCommand.kt └── module-legacy-api │ ├── build.gradle.kts │ └── src │ └── main │ └── kotlin │ └── ink │ └── ptms │ └── zaphkiel │ └── ZaphkielAPI.kt └── settings.gradle.kts /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle 2 | .idea 3 | build 4 | bin -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zaphkiel 2 | 3 | 不是很好用的物品库,Gradle 写的很混乱,因学业繁忙暂无时间优化。 4 | 5 | ## Building 6 | 7 | * [Gradle](https://gradle.org/) - Dependency Management 8 | 9 | The GradleWrapper in included in this project. 10 | 11 | **Windows:** 12 | 13 | ``` 14 | gradlew.bat clean build 15 | ``` 16 | 17 | **macOS/Linux:** 18 | 19 | ``` 20 | ./gradlew clean build 21 | ``` 22 | 23 | Build artifacts should be found in `./build/libs` folder. -------------------------------------------------------------------------------- /build.gradle.kts: -------------------------------------------------------------------------------- 1 | @file:Suppress("PropertyName", "SpellCheckingInspection") 2 | 3 | import io.izzel.taboolib.gradle.* 4 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 5 | 6 | plugins { 7 | java 8 | id("io.izzel.taboolib") version "2.0.20" 9 | id("org.jetbrains.kotlin.jvm") version "1.8.22" 10 | } 11 | 12 | subprojects { 13 | apply() 14 | apply(plugin = "io.izzel.taboolib") 15 | apply(plugin = "org.jetbrains.kotlin.jvm") 16 | 17 | // TabooLib 配置 18 | taboolib { 19 | env { 20 | install(Basic, Bukkit, BukkitUtil, BukkitNMS, BukkitNMSUtil, BukkitUI, BukkitHook) 21 | install(Database, Kether, DatabasePlayer, Jexl) 22 | install(CommandHelper) 23 | } 24 | version { taboolib = "6.2.0-beta30" } 25 | } 26 | 27 | // 全局仓库 28 | repositories { 29 | mavenLocal() 30 | mavenCentral() 31 | } 32 | // 全局依赖 33 | dependencies { 34 | compileOnly("org.apache.commons:commons-lang3:3.12.0") 35 | compileOnly("com.google.guava:guava:30.1.1-jre") 36 | compileOnly("com.google.code.gson:gson:2.8.8") 37 | compileOnly("ink.ptms.core:v11904:11904:mapped") 38 | compileOnly("ink.ptms.core:v11200:11200") 39 | compileOnly(kotlin("stdlib")) 40 | } 41 | 42 | // 编译配置 43 | java { 44 | withSourcesJar() 45 | sourceCompatibility = JavaVersion.VERSION_1_8 46 | targetCompatibility = JavaVersion.VERSION_1_8 47 | } 48 | tasks.withType { 49 | options.encoding = "UTF-8" 50 | } 51 | tasks.withType { 52 | kotlinOptions { 53 | jvmTarget = "1.8" 54 | freeCompilerArgs = listOf("-Xjvm-default=all", "-Xextended-compiler-checks") 55 | } 56 | } 57 | } 58 | 59 | gradle.buildFinished { 60 | buildDir.deleteRecursively() 61 | } -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group=ink.ptms.zaphkiel 2 | version=2.0.31 -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TabooLib/zaphkiel/491767067d396a49fcc914cfc779fb19246354b8/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.3.3-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /plugin/build.gradle.kts: -------------------------------------------------------------------------------- 1 | dependencies { 2 | taboo("ink.ptms:um:1.0.1") 3 | } 4 | 5 | taboolib { 6 | description { 7 | name(rootProject.name) 8 | contributors { 9 | name("坏黑") 10 | } 11 | } 12 | relocate("ink.ptms.um", "ink.ptms.zaphkiel.um") 13 | } 14 | 15 | tasks { 16 | jar { 17 | // 构件名 18 | archiveFileName.set("${rootProject.name}-${archiveFileName.get().substringAfter('-')}") 19 | // 打包子项目源代码 20 | rootProject.subprojects.forEach { from(it.sourceSets["main"].output) } 21 | } 22 | } -------------------------------------------------------------------------------- /project/build.gradle.kts: -------------------------------------------------------------------------------- 1 | gradle.buildFinished { 2 | buildDir.deleteRecursively() 3 | } -------------------------------------------------------------------------------- /project/common-impl/build.gradle.kts: -------------------------------------------------------------------------------- 1 | taboolib { subproject = true } 2 | 3 | dependencies { 4 | compileOnly(project(":project:common")) 5 | compileOnly("ink.ptms:nms-all:1.0.0") 6 | compileOnly("ink.ptms.core:v11802:11802-minimize:mapped") 7 | compileOnly("ink.ptms.core:v11802:11802-minimize:universal") 8 | compileOnly("ink.ptms:Sandalphon:1.4.1") 9 | compileOnly("public:AttributePlus:3.2.6") 10 | compileOnly("public:HeadDatabase:1.3.0") 11 | compileOnly("public:Tiphareth:1.0.0") 12 | compileOnly("ink.ptms:um:1.0.1") 13 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/DefaultItemHandler.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl 2 | 3 | import ink.ptms.zaphkiel.api.Item 4 | import ink.ptms.zaphkiel.api.ItemHandler 5 | import ink.ptms.zaphkiel.api.ItemStream 6 | import ink.ptms.zaphkiel.impl.item.DefaultItemStream 7 | import org.bukkit.inventory.ItemStack 8 | import taboolib.module.nms.ItemTag 9 | import taboolib.platform.util.isAir 10 | 11 | /** 12 | * Zaphkiel 13 | * ink.ptms.zaphkiel.impl.DefaultItemHandler 14 | * 15 | * @author 坏黑 16 | * @since 2022/7/23 16:10 17 | */ 18 | class DefaultItemHandler : ItemHandler { 19 | 20 | override fun read(item: ItemStack): ItemStream { 21 | if (item.isAir()) { 22 | error("Could not read empty item.") 23 | } 24 | return DefaultItemStream(item) 25 | } 26 | 27 | override fun getItem(item: ItemStack): Item? { 28 | return read(item).takeIf { it.isExtension() }?.getZaphkielItem() 29 | } 30 | 31 | override fun getItemId(item: ItemStack): String? { 32 | return read(item).takeIf { it.isExtension() }?.getZaphkielId() 33 | } 34 | 35 | override fun getItemData(item: ItemStack): ItemTag? { 36 | return read(item).takeIf { it.isExtension() }?.getZaphkielData() 37 | } 38 | 39 | override fun getItemUniqueData(item: ItemStack): ItemTag? { 40 | return read(item).takeIf { it.isExtension() }?.getZaphkielUniqueData() 41 | } 42 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/DefaultItemLoader.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl 2 | 3 | import ink.ptms.zaphkiel.api.* 4 | import ink.ptms.zaphkiel.api.event.PluginReloadEvent 5 | import ink.ptms.zaphkiel.impl.item.DefaultDisplay 6 | import ink.ptms.zaphkiel.impl.item.DefaultGroup 7 | import ink.ptms.zaphkiel.impl.item.DefaultItem 8 | import ink.ptms.zaphkiel.item.meta.Meta 9 | import taboolib.common.platform.function.getDataFolder 10 | import taboolib.common.platform.function.info 11 | import taboolib.common.platform.function.releaseResourceFile 12 | import taboolib.library.configuration.ConfigurationSection 13 | import taboolib.library.reflex.Reflex.Companion.invokeConstructor 14 | import taboolib.module.configuration.Configuration 15 | import taboolib.module.configuration.Type 16 | import java.io.File 17 | 18 | /** 19 | * Zaphkiel 20 | * ink.ptms.zaphkiel.impl.DefaultItemLoader 21 | * 22 | * @author 坏黑 23 | * @since 2022/7/23 16:15 24 | */ 25 | class DefaultItemLoader : ItemLoader { 26 | 27 | val folderItem = File(getDataFolder(), "item") 28 | val folderDisplay = File(getDataFolder(), "display") 29 | 30 | val itemManager: DefaultItemManager 31 | get() = DefaultZapAPI.instance.defaultItemManager 32 | 33 | fun reload() { 34 | // 释放默认物品文件 35 | if (!folderItem.exists()) { 36 | releaseResourceFile("item/def.yml") 37 | } 38 | if (!folderDisplay.exists()) { 39 | releaseResourceFile("display/def.yml") 40 | } 41 | // 重新加载 42 | reloadDisplay() 43 | reloadItem() 44 | } 45 | 46 | fun reloadItem() { 47 | itemManager.clearItem() 48 | // 加载模型 49 | loadModelFromFile(folderItem).forEach { itemManager.registerModel(it) } 50 | // 加载物品 51 | folderItem.listFiles()?.forEach { loadItemFromFile(it).forEach { itemManager.registerItem(it) } } 52 | // 提示 53 | info("Loaded ${itemManager.registeredItem.size} items (${itemManager.registeredModel.size} models)") 54 | PluginReloadEvent.Item().call() 55 | } 56 | 57 | fun reloadDisplay() { 58 | itemManager.clearDisplay() 59 | // 加载展示方案 60 | loadDisplayFromFile(folderDisplay).forEach { itemManager.registerDisplay(it) } 61 | // 从物品文件夹中加载的展示方案 62 | loadDisplayFromFile(folderItem, fromItemFile = true).forEach { itemManager.registerDisplay(it) } 63 | // 提示 64 | info("Loaded ${itemManager.registeredDisplay.size} display plans") 65 | PluginReloadEvent.Display().call() 66 | } 67 | 68 | override fun loadItemFromFile(file: File): List { 69 | return loadItemFromFile(file, null, 0) 70 | } 71 | 72 | fun loadItemFromFile(file: File, parent: Group?, level: Int): List { 73 | val items = arrayListOf() 74 | // 如果是文件夹,递归加载 75 | if (file.isDirectory) { 76 | val group = DefaultGroup.NO_GROUP.copy(name = file.nameWithoutExtension, level = level, parent = parent) 77 | // 注册组 78 | itemManager.registerGroup(group) 79 | // 加载物品 80 | file.listFiles()?.forEach { items += loadItemFromFile(it, group, level + 1) } 81 | } 82 | // 如果是 yml 文件,加载物品 83 | else if (file.extension == "yml") { 84 | val conf = Configuration.loadFromFile(file) 85 | // 加载物品组 86 | val group = if (conf.contains("__group__")) { 87 | // 自定组 88 | DefaultGroup(file.nameWithoutExtension, file, conf.getConfigurationSection("__group__")!!, level = level, parent = parent) 89 | } else { 90 | // 默认组 91 | DefaultGroup.NO_GROUP.copy(name = file.nameWithoutExtension, level = level, parent = parent) 92 | } 93 | // 注册组 94 | itemManager.registerGroup(group) 95 | // 加载物品 96 | conf.getKeys(false).filter { !it.endsWith("$") && it != "__group__" }.forEach { 97 | try { 98 | items += DefaultItem(conf.getConfigurationSection(it)!!, group = group) 99 | } catch (t: Throwable) { 100 | t.printStackTrace() 101 | } 102 | } 103 | } 104 | return items 105 | } 106 | 107 | override fun loadModelFromFile(file: File): List { 108 | val models = arrayListOf() 109 | // 如果是文件夹,递归加载 110 | if (file.isDirectory) { 111 | file.listFiles()?.forEach { models += loadModelFromFile(it) } 112 | } 113 | // 如果是 yml 文件,加载模型 114 | else if (file.extension == "yml") { 115 | val conf = Configuration.loadFromFile(file) 116 | // 加载模型 117 | conf.getKeys(false).filter { it.endsWith("$") }.forEach { key -> 118 | models += Model(key.substring(0, key.length - 1), conf.getConfigurationSection(key)!!) 119 | } 120 | } 121 | return models 122 | } 123 | 124 | override fun loadDisplayFromFile(file: File, fromItemFile: Boolean): List { 125 | val display = arrayListOf() 126 | // 如果是文件夹,递归加载 127 | if (file.isDirectory) { 128 | file.listFiles()?.forEach { display += loadDisplayFromFile(it, fromItemFile) } 129 | } 130 | // 如果是 yml 文件,加载展示方案 131 | else if (file.extension == "yml") { 132 | val conf = Configuration.loadFromFile(file) 133 | // 如果是从物品文件夹中加载,那么会将所有不包含 display 节点的物品视为 "以特殊形式加载的" 展示方案 134 | conf.getKeys(false).forEach { 135 | if (fromItemFile && (it.endsWith("$") || conf.contains("$it.display"))) { 136 | return@forEach 137 | } 138 | display += DefaultDisplay(conf.getConfigurationSection(it)!!) 139 | } 140 | } 141 | return display 142 | } 143 | 144 | override fun loadMetaFromSection(root: ConfigurationSection): List { 145 | val itemManager = DefaultZapAPI.instance.defaultItemManager 146 | val copy = Configuration.empty(Type.YAML) 147 | return root.getConfigurationSection("meta")?.getKeys(false)?.mapNotNull { id -> 148 | // 调整 !! 结尾字段 149 | if (id.endsWith("!!")) { 150 | copy["meta.${id.substring(0, id.length - 2)}"] = root["meta.$id"] 151 | } else { 152 | copy["meta.$id"] = root["meta.$id"] 153 | } 154 | val locked: Boolean 155 | val metaClass = if (id.endsWith("!!")) { 156 | locked = true 157 | itemManager.registeredMeta[id.substring(0, id.length - 2)] 158 | } else { 159 | locked = false 160 | itemManager.registeredMeta[id] 161 | } ?: return@mapNotNull null 162 | val meta: Meta = metaClass.invokeConstructor(copy) 163 | meta.locked = locked 164 | meta 165 | }?.toMutableList() ?: ArrayList() 166 | } 167 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/DefaultItemManager.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl 2 | 3 | import ink.ptms.zaphkiel.api.* 4 | import ink.ptms.zaphkiel.api.event.ItemGiveEvent 5 | import ink.ptms.zaphkiel.impl.meta.MetaKey 6 | import ink.ptms.zaphkiel.item.meta.Meta 7 | import org.bukkit.entity.Player 8 | import org.bukkit.inventory.ItemStack 9 | import taboolib.common.io.runningClassMapInJar 10 | import taboolib.platform.util.giveItem 11 | 12 | /** 13 | * Zaphkiel 14 | * ink.ptms.zaphkiel.impl.DefaultItemManager 15 | * 16 | * @author 坏黑 17 | * @since 2022/7/23 16:15 18 | */ 19 | class DefaultItemManager : ItemManager { 20 | 21 | val registeredItem = HashMap() 22 | 23 | val registeredModel = HashMap() 24 | 25 | val registeredDisplay = HashMap() 26 | 27 | val registeredGroup = HashMap() 28 | 29 | @Suppress("UNCHECKED_CAST") 30 | val registeredMeta: MutableMap> = runningClassMapInJar 31 | .values 32 | .filter { it.hasAnnotation(MetaKey::class.java) } 33 | .associateBy { c -> c.getAnnotation(MetaKey::class.java).property("value", "") } 34 | .mapValues { it.value.toClass() as Class } 35 | .toMutableMap() 36 | 37 | fun clearItem() { 38 | registeredItem.clear() 39 | registeredModel.clear() 40 | registeredGroup.clear() 41 | } 42 | 43 | fun clearDisplay() { 44 | registeredDisplay.clear() 45 | } 46 | 47 | override fun giveItem(player: Player, item: Item, amount: Int): Boolean { 48 | val event = ItemGiveEvent(player, item.build(player), amount).also { it.call() } 49 | if (!event.isCancelled) { 50 | val itemStack = event.itemStream.rebuildToItemStack(player) 51 | // 物品最大堆叠数量 52 | val maxStackSize = itemStack.maxStackSize 53 | // 计算需要发送的次数 54 | val times = event.amount / maxStackSize 55 | val remainder = event.amount % maxStackSize 56 | // 发送整数倍的最大堆叠数量 57 | repeat(times) { 58 | player.giveItem(itemStack.clone().also { it.amount = maxStackSize }) 59 | } 60 | // 发送剩余数量 61 | if (remainder > 0) { 62 | player.giveItem(itemStack.clone().also { it.amount = remainder }) 63 | } 64 | return true 65 | } 66 | return false 67 | } 68 | 69 | override fun giveItem(player: Player, name: String, amount: Int): Boolean { 70 | return giveItem(player, getItem(name) ?: return false, amount) 71 | } 72 | 73 | override fun getItem(name: String): Item? { 74 | return registeredItem[name] 75 | } 76 | 77 | override fun getItemMap(): Map { 78 | return registeredItem 79 | } 80 | 81 | override fun getModel(name: String): Model? { 82 | return registeredModel[name] 83 | } 84 | 85 | override fun getModelMap(): Map { 86 | return registeredModel 87 | } 88 | 89 | override fun getDisplay(name: String): Display? { 90 | return registeredDisplay[name] 91 | } 92 | 93 | override fun getDisplayMap(): Map { 94 | return registeredDisplay 95 | } 96 | 97 | override fun getGroup(name: String): Group? { 98 | return registeredGroup[name] 99 | } 100 | 101 | override fun getGroupMap(): Map { 102 | return registeredGroup 103 | } 104 | 105 | override fun getMeta(name: String): Class? { 106 | return registeredMeta[name] 107 | } 108 | 109 | override fun getMetaMap(): Map> { 110 | return registeredMeta 111 | } 112 | 113 | override fun registerItem(item: Item) { 114 | registeredItem[item.id] = item 115 | } 116 | 117 | override fun unregisterItem(item: Item) { 118 | registeredItem.remove(item.id) 119 | } 120 | 121 | override fun registerModel(model: Model) { 122 | registeredModel[model.id] = model 123 | } 124 | 125 | override fun unregisterModel(model: Model) { 126 | registeredModel.remove(model.id) 127 | } 128 | 129 | override fun registerDisplay(display: Display) { 130 | registeredDisplay[display.id] = display 131 | } 132 | 133 | override fun unregisterDisplay(display: Display) { 134 | registeredDisplay.remove(display.id) 135 | } 136 | 137 | override fun registerGroup(group: Group) { 138 | registeredGroup[group.name] = group 139 | } 140 | 141 | override fun unregisterGroup(group: Group) { 142 | registeredGroup.remove(group.name) 143 | } 144 | 145 | override fun registerMeta(meta: Class) { 146 | registeredMeta[meta.getAnnotation(MetaKey::class.java).value] = meta 147 | } 148 | 149 | override fun unregisterMeta(meta: Class) { 150 | registeredMeta.remove(meta.getAnnotation(MetaKey::class.java).value) 151 | } 152 | 153 | override fun generateItem(id: String, player: Player?): ItemStream? { 154 | return registeredItem[id]?.build(player) 155 | } 156 | 157 | override fun generateItemStack(id: String, player: Player?): ItemStack? { 158 | return registeredItem[id]?.build(player)?.toItemStack(player) 159 | } 160 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/DefaultItemSerializer.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl 2 | 3 | import com.google.gson.JsonObject 4 | import com.google.gson.JsonParser 5 | import ink.ptms.zaphkiel.Zaphkiel 6 | import ink.ptms.zaphkiel.api.ItemKey 7 | import ink.ptms.zaphkiel.api.ItemSerializer 8 | import ink.ptms.zaphkiel.api.ItemStream 9 | import ink.ptms.zaphkiel.api.SerializedItem 10 | import ink.ptms.zaphkiel.impl.item.DefaultItemStream 11 | import ink.ptms.zaphkiel.impl.item.DefaultSerializedItem 12 | import ink.ptms.zaphkiel.impl.meta.MetaUnique 13 | import org.apache.commons.lang3.time.DateFormatUtils 14 | import org.bukkit.inventory.ItemStack 15 | import taboolib.library.xseries.XMaterial 16 | import taboolib.library.xseries.parseToItemStack 17 | import taboolib.module.nms.ItemTag 18 | import taboolib.module.nms.ItemTagData 19 | import taboolib.module.nms.ItemTagSerializer 20 | import taboolib.platform.util.isAir 21 | 22 | /** 23 | * Zaphkiel 24 | * ink.ptms.zaphkiel.impl.DefaultItemSerializer 25 | * 26 | * @author 坏黑 27 | * @since 2022/7/23 16:28 28 | */ 29 | class DefaultItemSerializer : ItemSerializer { 30 | 31 | val air = DefaultSerializedItem("minecraft:air", 1, null, null) 32 | 33 | override fun serialize(itemStack: ItemStack): SerializedItem { 34 | return if (itemStack.isAir()) air else serialize(Zaphkiel.api().getItemHandler().read(itemStack)) 35 | } 36 | 37 | override fun serialize(itemStream: ItemStream): SerializedItem { 38 | return if (itemStream.isVanilla()) { 39 | DefaultSerializedItem("minecraft:${XMaterial.matchXMaterial(itemStream.sourceItem).name.lowercase()}", itemStream.sourceItem.amount, null, null) 40 | } else { 41 | DefaultSerializedItem( 42 | itemStream.getZaphkielId(), 43 | itemStream.sourceItem.amount, 44 | itemStream.getZaphkielData().takeIf { it.isNotEmpty() }?.let { ItemTagSerializer.serializeData(it).asJsonObject }, 45 | itemStream.getZaphkielUniqueData()?.let { 46 | DefaultSerializedItem.UniqueData(it["player"]?.asString(), it["date"]!!.asLong(), it["uuid"]!!.asString()) 47 | } 48 | ) 49 | } 50 | } 51 | 52 | override fun deserialize(json: String): ItemStream { 53 | return deserialize(JsonParser.parseString(json).asJsonObject) 54 | } 55 | 56 | override fun deserialize(json: JsonObject): ItemStream { 57 | if (json["id"] == null) { 58 | error("id is null") 59 | } 60 | val id = json["id"]!!.asString 61 | return if (id.startsWith("minecraft:")) { 62 | DefaultItemStream(id.substring("minecraft:".length).parseToItemStack().also { it.amount = json["amount"]?.asInt ?: 1 }) 63 | } else { 64 | deserialize( 65 | DefaultSerializedItem( 66 | json["id"]!!.asString, 67 | json["amount"]?.asInt ?: 1, 68 | json["data"]?.asJsonObject, 69 | json["unique"]?.asJsonObject?.let { 70 | DefaultSerializedItem.UniqueData(it["player"]?.asString, it["date"]!!.asLong, it["uuid"]!!.asString) 71 | } 72 | ) 73 | ) 74 | } 75 | } 76 | 77 | override fun deserialize(item: SerializedItem): ItemStream { 78 | return if (item.id.startsWith("minecraft:")) { 79 | DefaultItemStream(item.id.substring("minecraft:".length).parseToItemStack().also { it.amount = item.amount }) 80 | } else { 81 | val itemStream = Zaphkiel.api().getItemManager().generateItem(item.id) ?: error("item not found: ${item.id}") 82 | val data = item.data 83 | if (data != null) { 84 | itemStream.getZaphkielCompound()!![ItemKey.DATA.key] = ItemTagSerializer.deserializeData(data) 85 | } 86 | val unique = item.uniqueData 87 | if (unique != null) { 88 | itemStream.getZaphkielCompound()!![ItemKey.UNIQUE.key] = ItemTag().also { 89 | // 如果存在玩家信息,将会在物品签名中添加玩家信息 90 | if (unique.player != null) { 91 | it["player"] = ItemTagData(unique.player!!) 92 | } 93 | // 添加构建时间和格式化时间 94 | it["date"] = ItemTagData(unique.date) 95 | it["date-formatted"] = ItemTagData(DateFormatUtils.format(unique.date, MetaUnique.FORMAT)) 96 | it["uuid"] = ItemTagData(unique.uuid) 97 | } 98 | } 99 | itemStream.sourceItem.amount = item.amount 100 | itemStream 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/DefaultItemUpdater.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl 2 | 3 | import ink.ptms.zaphkiel.api.ItemSignal 4 | import ink.ptms.zaphkiel.api.ItemStream 5 | import ink.ptms.zaphkiel.api.ItemUpdater 6 | import ink.ptms.zaphkiel.api.event.ItemBuildEvent 7 | import ink.ptms.zaphkiel.impl.item.DefaultItemStream 8 | import org.bukkit.entity.Player 9 | import org.bukkit.inventory.Inventory 10 | import org.bukkit.inventory.ItemStack 11 | import taboolib.platform.util.isAir 12 | 13 | /** 14 | * Zaphkiel 15 | * ink.ptms.zaphkiel.impl.DefaultItemUpdater 16 | * 17 | * @author 坏黑 18 | * @since 2022/7/23 16:15 19 | */ 20 | class DefaultItemUpdater : ItemUpdater { 21 | 22 | override fun checkUpdate(player: Player?, inventory: Inventory) { 23 | (0 until inventory.size).forEach { i -> 24 | val item = inventory.getItem(i) 25 | if (item.isAir()) { 26 | return@forEach 27 | } 28 | val rebuild = checkUpdate(player, item) 29 | if (ItemSignal.UPDATE_CHECKED in rebuild.signal) { 30 | rebuild.toItemStack(player) 31 | } 32 | } 33 | } 34 | 35 | override fun checkUpdate(player: Player?, item: ItemStack): ItemStream { 36 | if (item.isAir()) { 37 | error("air") 38 | } 39 | val itemStream = DefaultItemStream(item) 40 | if (itemStream.isVanilla()) { 41 | return itemStream 42 | } 43 | val event = ItemBuildEvent.CheckUpdate(player, itemStream, itemStream.isOutdated()) 44 | return if (event.call()) { 45 | // 使用 ItemStream#rebuild 方法会生成新的 ItemStreamGenerated 实例 46 | // 将会重新生成物品名称与描述,产生更多的计算 47 | // 现在看来 nameLock、loreLock 这种设计并不是特别出色 48 | // 在 1.6.1 版本时想过移除,但是没有意义 49 | itemStream.signal += ItemSignal.UPDATE_CHECKED 50 | itemStream.getZaphkielItem().build(player, itemStream) 51 | } else { 52 | itemStream 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/DefaultZapAPI.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl 2 | 3 | import ink.ptms.zaphkiel.ZapAPI 4 | import ink.ptms.zaphkiel.Zaphkiel 5 | import ink.ptms.zaphkiel.api.* 6 | import org.bukkit.Bukkit 7 | import org.bukkit.event.player.PlayerJoinEvent 8 | import org.bukkit.event.player.PlayerQuitEvent 9 | import taboolib.common.LifeCycle 10 | import taboolib.common.io.newFile 11 | import taboolib.common.platform.Awake 12 | import taboolib.common.platform.event.SubscribeEvent 13 | import taboolib.common.platform.function.getDataFolder 14 | import taboolib.common.util.unsafeLazy 15 | import taboolib.expansion.releaseDataContainer 16 | import taboolib.expansion.setupDataContainer 17 | import taboolib.expansion.setupPlayerDatabase 18 | import taboolib.module.configuration.Config 19 | import taboolib.module.configuration.Configuration 20 | 21 | /** 22 | * Zaphkiel 23 | * ink.ptms.zaphkiel.impl.DefaultZapAPI 24 | * 25 | * @author 坏黑 26 | * @since 2022/7/23 16:07 27 | */ 28 | class DefaultZapAPI : ZapAPI { 29 | 30 | val defaultItemHandler = DefaultItemHandler() 31 | val defaultItemManager = DefaultItemManager() 32 | val defaultItemUpdater = DefaultItemUpdater() 33 | val defaultItemLoader = DefaultItemLoader() 34 | val defaultItemSerializer = DefaultItemSerializer() 35 | 36 | override fun getItemHandler(): ItemHandler { 37 | return defaultItemHandler 38 | } 39 | 40 | override fun getItemManager(): ItemManager { 41 | return defaultItemManager 42 | } 43 | 44 | override fun getItemUpdater(): ItemUpdater { 45 | return defaultItemUpdater 46 | } 47 | 48 | override fun getItemLoader(): ItemLoader { 49 | return defaultItemLoader 50 | } 51 | 52 | override fun getItemSerializer(): ItemSerializer { 53 | return defaultItemSerializer 54 | } 55 | 56 | override fun reload() { 57 | config.reload() 58 | // 重载物品 59 | defaultItemLoader.reload() 60 | // 更新玩家背包 61 | Bukkit.getOnlinePlayers().forEach { defaultItemUpdater.checkUpdate(it, it.inventory) } 62 | } 63 | 64 | companion object { 65 | 66 | @Config 67 | lateinit var config: Configuration 68 | private set 69 | 70 | val instance by unsafeLazy { DefaultZapAPI() } 71 | 72 | @Awake(LifeCycle.LOAD) 73 | private fun onLoad() { 74 | Zaphkiel.register(instance) 75 | } 76 | 77 | @Awake(LifeCycle.ENABLE) 78 | private fun onEnable() { 79 | if (config.getBoolean("Database.enable")) { 80 | setupPlayerDatabase(config.getConfigurationSection("Database")!!, "${config.getString("prefix")}_2") 81 | } else { 82 | setupPlayerDatabase(newFile(getDataFolder(), "data.db")) 83 | } 84 | instance.reload() 85 | } 86 | 87 | @SubscribeEvent 88 | private fun onJoin(e: PlayerJoinEvent) { 89 | e.player.setupDataContainer() 90 | } 91 | 92 | @SubscribeEvent 93 | private fun onQuit(e: PlayerQuitEvent) { 94 | e.player.releaseDataContainer() 95 | } 96 | } 97 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/Translator.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl 2 | 3 | import taboolib.common.platform.function.warning 4 | import taboolib.library.configuration.ConfigurationSection 5 | import taboolib.module.nms.ItemTag 6 | import taboolib.module.nms.ItemTagData 7 | import taboolib.module.nms.ItemTagList 8 | import java.util.regex.Pattern 9 | 10 | object Translator { 11 | 12 | private val regex = Pattern.compile("\\d+s")!! 13 | 14 | fun fromItemTag(any: Any): Any { 15 | return when (any) { 16 | is ItemTag -> any.map { i -> i.key to fromItemTag(i.value) }.toMap() 17 | is ItemTagList -> any.map { i -> fromItemTag(i) }.toList() 18 | is ItemTagData -> any.unsafeData() 19 | else -> any 20 | } 21 | } 22 | 23 | fun toItemTag(nbtList: ItemTagList, list: List<*>): ItemTagList { 24 | list.forEach { obj -> 25 | val base = toItemTag(obj) 26 | if (base == null) { 27 | warning("Invalid Type: " + obj + " [" + obj!!.javaClass.simpleName + "]") 28 | return@forEach 29 | } 30 | nbtList.add(base) 31 | } 32 | return nbtList 33 | } 34 | 35 | fun toItemTag(nbt: ItemTag, section: ConfigurationSection): ItemTag { 36 | section.getKeys(false).forEach { key -> 37 | val data = section[key] 38 | val base: ItemTagData? 39 | if (data is ConfigurationSection) { 40 | base = toItemTag(ItemTag(), section.getConfigurationSection(key)!!) 41 | } else { 42 | base = toItemTag(data) 43 | if (base == null) { 44 | warning("Invalid Type: " + data + " [" + data!!.javaClass.simpleName + "]") 45 | return@forEach 46 | } 47 | } 48 | if (key.endsWith("!!")) { 49 | nbt[key.substring(0, key.length - 2)] = base 50 | } else { 51 | nbt[key] = base 52 | } 53 | } 54 | return nbt 55 | } 56 | 57 | fun toItemTag(obj: Any?): ItemTagData? { 58 | return when (obj) { 59 | is String -> if (regex.matcher(obj.toString()).matches()) { 60 | toItemTag(java.lang.Short.valueOf(obj.toString().substring(0, obj.toString().length - 1))) 61 | } else { 62 | ItemTagData(obj.toString()) 63 | } 64 | is Int -> ItemTagData(obj) 65 | is Double -> ItemTagData(obj) 66 | is Float -> ItemTagData(obj) 67 | is Short -> ItemTagData(obj) 68 | is Long -> ItemTagData(obj) 69 | is Byte -> ItemTagData(obj) 70 | is List<*> -> toItemTag(ItemTagList(), (obj as List<*>?)!!) 71 | is Map<*, *> -> { 72 | val nbtCompound = ItemTag() 73 | obj.forEach { (key, value) -> nbtCompound.put(key.toString(), toItemTag(value)) } 74 | nbtCompound 75 | } 76 | is ConfigurationSection -> { 77 | val nbtCompound = ItemTag() 78 | obj.getValues(false).forEach { (key, value) -> nbtCompound.put(key, toItemTag(value)) } 79 | nbtCompound 80 | } 81 | else -> ItemTagData("Error: " + obj!!) 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/ItemCooldown.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature 2 | 3 | import ink.ptms.zaphkiel.api.ItemStream 4 | import org.bukkit.entity.Player 5 | import taboolib.common5.clong 6 | import taboolib.expansion.getDataContainer 7 | 8 | /** 9 | * 判断物品是否在冷却 10 | * @param player 绑定到玩家(可选参数) 11 | */ 12 | fun ItemStream.isItemInCooldown(player: Player? = null): Boolean { 13 | return getItemInCooldown(player) > 0 14 | } 15 | 16 | /** 17 | * 设置物品冷却 18 | * @param gameTick 游戏刻 19 | * @param player 绑定到玩家(可选参数) 20 | */ 21 | fun ItemStream.setItemInCooldown(gameTick: Int, player: Player? = null) { 22 | val nextTime = System.currentTimeMillis() + (gameTick * 50L) 23 | if (player != null) { 24 | player.getDataContainer()["cooldown.${getZaphkielId()}"] = nextTime 25 | } else { 26 | getZaphkielData().putDeep("cooldown.${getZaphkielId()}", nextTime) 27 | } 28 | } 29 | 30 | /** 31 | * 获得物品的剩余冷却时间 32 | * @param player 绑定到玩家(可选参数) 33 | */ 34 | fun ItemStream.getItemInCooldown(player: Player? = null): Long { 35 | val time = if (player != null) { 36 | player.getDataContainer()["cooldown.${getZaphkielId()}"].clong 37 | } else { 38 | getZaphkielData().getDeep("cooldown.${getZaphkielId()}")?.asLong() ?: 0 39 | } 40 | return time - System.currentTimeMillis() 41 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/ItemDataMapping.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature 2 | 3 | import ink.ptms.zaphkiel.api.event.ZapDisplayGenerateEvent 4 | import taboolib.common.platform.event.SubscribeEvent 5 | import taboolib.module.kether.KetherShell 6 | import taboolib.module.kether.ScriptOptions 7 | import taboolib.module.nms.ItemTag 8 | 9 | /** 10 | * Zaphkiel 11 | * ink.ptms.zaphkiel.impl.feature.ItemDataMapping 12 | * 13 | * @author 坏黑 14 | * @since 2023/6/13 23:40 15 | */ 16 | internal object ItemDataMapping { 17 | 18 | @SubscribeEvent 19 | fun onDisplay(e: ZapDisplayGenerateEvent) { 20 | val dataMapper = e.item.dataMapper 21 | if (dataMapper.isEmpty()) { 22 | return 23 | } 24 | // 获取所有数据 25 | val deepValues = e.itemStream.getZaphkielData().deepValues() 26 | // 处理所有映射 27 | e.item.dataMapper.forEach { (k, v) -> 28 | val data = KetherShell.eval(v, ScriptOptions.new { 29 | sandbox() 30 | detailError() 31 | namespace(listOf("zaphkiel-mapping")) 32 | set("@ItemMappingData", deepValues[k]) 33 | vars(deepValues) 34 | if (e.player != null) sender(e.player!!) 35 | }).getNow(null) 36 | // 有效数据 37 | if (data != null) { 38 | // 添加到名字 39 | e.addName(k, data) 40 | // 添加到描述 41 | if (data is List<*>) { 42 | data.filterNotNull().forEach { e.addLore(k, it) } 43 | } else { 44 | e.addLore(k, data) 45 | } 46 | } 47 | } 48 | } 49 | 50 | fun ItemTag.deepValues(node: String = ""): Map { 51 | val map = mutableMapOf() 52 | forEach { (k, v) -> 53 | if (v is ItemTag) { 54 | map.putAll(v.deepValues("$node$k.")) 55 | } else { 56 | map["$node$k"] = v.unsafeData() 57 | } 58 | } 59 | return map 60 | } 61 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/ItemDurability.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.api.ItemSignal 5 | import ink.ptms.zaphkiel.api.ItemStream 6 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 7 | import ink.ptms.zaphkiel.api.event.PluginReloadEvent 8 | import ink.ptms.zaphkiel.impl.DefaultZapAPI 9 | import ink.ptms.zaphkiel.impl.item.DefaultItemStream 10 | import org.bukkit.Bukkit 11 | import org.bukkit.Material 12 | import org.bukkit.Particle 13 | import org.bukkit.Sound 14 | import org.bukkit.entity.Player 15 | import org.bukkit.event.player.PlayerItemBreakEvent 16 | import org.bukkit.event.player.PlayerItemDamageEvent 17 | import org.bukkit.inventory.ItemStack 18 | import taboolib.common.LifeCycle 19 | import taboolib.common.platform.Awake 20 | import taboolib.common.platform.event.EventPriority 21 | import taboolib.common.platform.event.SubscribeEvent 22 | import taboolib.common.platform.function.submitAsync 23 | import taboolib.common.util.random 24 | import taboolib.common5.Coerce 25 | import taboolib.common5.util.createBar 26 | import taboolib.library.xseries.parseToMaterial 27 | import taboolib.module.nms.ItemTagData 28 | import taboolib.module.nms.getItemTag 29 | 30 | /** 31 | * @author sky 32 | * @since 2019-12-16 21:46 33 | */ 34 | object ItemDurability { 35 | 36 | var durability: String? = null 37 | var durabilitySymbol: List? = null 38 | 39 | fun createBar(current: Int, max: Int, display: String = durability!!, symbol: List = durabilitySymbol!!, scale: Int = -1): String { 40 | val percent = Coerce.format((current / max.toDouble()) * 100).toString() 41 | return if (scale == -1) { 42 | display.replace("%symbol%", (1..max).joinToString("") { i -> 43 | if (current >= i) "§f${symbol.getOrElse(0) { "" }}" else "§7${symbol.getOrElse(1) { "" }}" 44 | }) 45 | } else { 46 | val empty = "§7${symbol.getOrElse(1) { "" }}" 47 | val full = "§f${symbol.getOrElse(0) { "" }}" 48 | display.replace("%symbol%", createBar(empty, full, scale, current / max.toDouble())) 49 | }.replace("%current%", current.toString()).replace("%max%", max.toString()).replace("%percent%", percent) 50 | } 51 | 52 | @SubscribeEvent 53 | private fun onRelease(e: ItemReleaseEvent) { 54 | val max = e.itemStream.getZaphkielData()["durability"] ?: return 55 | val current = e.itemStream.getZaphkielData()["durability_current"] ?: return 56 | val sync = e.itemStream.getZaphkielItem().config.getBoolean("meta.durability.synchronous", true) 57 | if (sync) { 58 | val percent = current.asDouble() / max.asDouble() 59 | val durability = e.itemStream.sourceItem.type.maxDurability 60 | e.data = (durability - (durability * percent)).toInt() 61 | } 62 | } 63 | 64 | @SubscribeEvent 65 | private fun onReleaseDisplay(e: ItemReleaseEvent.Display) { 66 | val max = e.itemStream.getZaphkielData()["durability"] ?: return 67 | val cur = e.itemStream.getZaphkielData()["durability_current"] ?: ItemTagData(max.asInt()) 68 | val root = e.itemStream.getZaphkielItem().config.getConfigurationSection("meta.durability") 69 | // 获取耐久表示格式 70 | val displayFormat = root?.getString("display") ?: durability ?: return 71 | if (displayFormat == "none") { 72 | return 73 | } 74 | // 获取耐久表示符号 75 | val displaySymbol = if (root?.contains("display-symbol") == true) { 76 | listOf(root.getString("display-symbol.0")!!, root.getString("display-symbol.1")!!) 77 | } else { 78 | durabilitySymbol!! 79 | } 80 | val bar = createBar(cur.asInt(), max.asInt(), displayFormat, displaySymbol, root?.getInt("scale", -1) ?: -1) 81 | e.addName("durability", bar) 82 | e.addName("DURABILITY", bar) 83 | e.addLore("durability", bar) 84 | e.addLore("DURABILITY", bar) 85 | } 86 | 87 | @SubscribeEvent 88 | private fun onReloadItem(e: PluginReloadEvent.Item) { 89 | reload() 90 | } 91 | 92 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 93 | private fun onDamage(e: PlayerItemDamageEvent) { 94 | val itemStream = DefaultItemStream(e.item) 95 | if (itemStream.isExtension()) { 96 | // 如果物品有自定义耐久度,则取消原版耐久度 97 | if (itemStream.getZaphkielData().containsKey("durability")) { 98 | e.isCancelled = true 99 | } 100 | // 执行脚本 101 | itemStream.getZaphkielItem().invokeScript(listOf("on_damage", "onDamage"), e, itemStream) 102 | } 103 | } 104 | 105 | @Awake(LifeCycle.ACTIVE) 106 | fun reload() { 107 | durability = DefaultZapAPI.config.getString("Durability.display")!! 108 | durabilitySymbol = arrayListOf( 109 | DefaultZapAPI.config.getString("Durability.display-symbol.0")!!, 110 | DefaultZapAPI.config.getString("Durability.display-symbol.1")!! 111 | ) 112 | } 113 | } 114 | 115 | /** 116 | * 获取物品最大耐久度 117 | */ 118 | fun ItemStream.getMaxDurability(): Int { 119 | return (getZaphkielData()["durability"] ?: ItemTagData(-1)).asInt() 120 | } 121 | 122 | /** 123 | * 获取物品当前耐久度 124 | */ 125 | fun ItemStream.getCurrentDurability(): Int { 126 | val max = getZaphkielData()["durability"] ?: return -1 127 | return (getZaphkielData()["durability_current"] ?: ItemTagData(max.asInt())).asInt() 128 | } 129 | 130 | /** 131 | * 扣除耐久度 132 | */ 133 | fun ItemStream.damageItem(value: Int, player: Player? = null, broken: Boolean = true): Boolean { 134 | return repairItem(-value, player, broken) 135 | } 136 | 137 | /** 138 | * 恢复耐久度 139 | */ 140 | fun ItemStream.repairItem(value: Int, player: Player? = null, broken: Boolean = true): Boolean { 141 | val data = getZaphkielData() 142 | val max = data["durability"] ?: return true 143 | val current = data["durability_current"] ?: ItemTagData(max.asInt()) 144 | val currentLatest = (current.asInt() + value).coerceIn(0..max.asInt()) 145 | return when { 146 | // 耐久度大于 0 147 | currentLatest > 0 -> { 148 | signal += ItemSignal.DURABILITY_CHANGED 149 | data["durability_current"] = ItemTagData(currentLatest) 150 | true 151 | } 152 | // 允许被破坏 153 | broken -> { 154 | signal += ItemSignal.DURABILITY_DESTROYED 155 | // 残骸 156 | val remains = getZaphkielItem().config.getString("meta.durability.remains") 157 | if (remains != null) { 158 | val replace = remains.split("~") 159 | // 获取替换后的物品 160 | val replaceItem = if (replace[0].startsWith("minecraft:")) { 161 | ItemStack(replace[0].substring("minecraft:".length).parseToMaterial()) 162 | } else { 163 | Zaphkiel.api().getItemManager().generateItemStack(replace[0], player) ?: ItemStack(Material.STONE) 164 | } 165 | sourceItem.type = replaceItem.type 166 | sourceItem.itemMeta = replaceItem.itemMeta 167 | sourceItem.durability = Coerce.toShort(replace.getOrNull(1) ?: "0") 168 | sourceCompound.clear() 169 | sourceCompound.putAll(replaceItem.getItemTag()) 170 | } else { 171 | val itemStack = sourceItem.clone() 172 | if (player != null) { 173 | Bukkit.getPluginManager().callEvent(PlayerItemBreakEvent(player, sourceItem)) 174 | // 播放特效 175 | submitAsync(delay = 1) { 176 | // 如果物品有耐久度,则播放破碎声音 177 | if (itemStack.type.maxDurability > 0) { 178 | player.playSound(player.location, Sound.ENTITY_ITEM_BREAK, 1f, random(0.5, 1.5).toFloat()) 179 | } 180 | player.world.spawnParticle(Particle.ITEM_CRACK, player.location.add(0.0, 1.0, 0.0), 15, 0.0, 0.0, 0.0, 0.1, itemStack) 181 | } 182 | } 183 | sourceItem.amount = 0 184 | } 185 | false 186 | } 187 | else -> false 188 | } 189 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/ItemMenu.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("DuplicatedCode") 2 | 3 | package ink.ptms.zaphkiel.impl.feature 4 | 5 | import ink.ptms.zaphkiel.Zaphkiel 6 | import ink.ptms.zaphkiel.api.Group 7 | import ink.ptms.zaphkiel.api.Item 8 | import ink.ptms.zaphkiel.impl.internal.ItemListener.onClick 9 | import org.bukkit.Sound 10 | import org.bukkit.entity.Player 11 | import org.bukkit.inventory.ItemFlag 12 | import org.bukkit.inventory.ItemStack 13 | import org.bukkit.inventory.meta.ItemMeta 14 | import taboolib.library.xseries.XMaterial 15 | import taboolib.module.ui.openMenu 16 | import taboolib.module.ui.type.Linked 17 | import taboolib.module.ui.type.PageableChest 18 | import taboolib.platform.util.Slots 19 | import taboolib.platform.util.buildItem 20 | import taboolib.platform.util.modifyLore 21 | import taboolib.platform.util.modifyMeta 22 | 23 | /** 24 | * 打开组菜单 25 | */ 26 | fun Player.openGroupMenu(parent: Group? = null) { 27 | // 播放音效 28 | playSound(location, Sound.UI_BUTTON_CLICK, 1f, 2f) 29 | // 打开页面 30 | openMenu>("Zaphkiel Items (Page %p)") { 31 | rows(6) 32 | slots(Slots.CENTER) 33 | elements { 34 | val items = arrayListOf() 35 | // 获取当前层级下的所有组 36 | items += Zaphkiel.api().getItemManager().getGroupMap().values.filter { it.parent == parent }.map { MenuItem.of(it) } 37 | // 如果存在父组,则获取组内所有物品 38 | if (parent != null) { 39 | items += parent.getItems().map { MenuItem.of(it) } 40 | } 41 | items 42 | } 43 | // 生成物品 44 | onGenerate { _, element, _, _ -> element.icon() } 45 | // 点击 46 | onClick { event, element -> element.click(event.clicker) } 47 | // 翻页 48 | setNextPage(51) { _, hasNextPage -> 49 | if (hasNextPage) { 50 | buildItem(XMaterial.SPECTRAL_ARROW) { name = "§7Next" } 51 | } else { 52 | buildItem(XMaterial.ARROW) { name = "§8Next" } 53 | } 54 | } 55 | setPreviousPage(47) { _, hasPreviousPage -> 56 | if (hasPreviousPage) { 57 | buildItem(XMaterial.SPECTRAL_ARROW) { name = "§7Previous" } 58 | } else { 59 | buildItem(XMaterial.ARROW) { name = "§8Previous" } 60 | } 61 | } 62 | } 63 | } 64 | 65 | interface MenuItem { 66 | 67 | fun icon(): ItemStack 68 | 69 | fun click(player: Player) 70 | 71 | companion object { 72 | 73 | fun of(item: Item) = object : MenuItem { 74 | 75 | override fun icon(): ItemStack { 76 | return item.buildItemStack().modifyMeta { 77 | // 修改描述 78 | modifyLore { 79 | add("") 80 | add("§7ID: ${item.id}") 81 | } 82 | // 隐藏标签 83 | addItemFlags(*ItemFlag.values()) 84 | } 85 | } 86 | 87 | override fun click(player: Player) { 88 | item.giveItemOrDrop(player) 89 | } 90 | } 91 | 92 | fun of(group: Group) = object : MenuItem { 93 | 94 | override fun icon(): ItemStack { 95 | return group.display 96 | } 97 | 98 | override fun click(player: Player) { 99 | player.openGroupMenu(group) 100 | } 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/hook/AttributePlusHook.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.hook 2 | 3 | import ink.ptms.zaphkiel.impl.item.toItemStream 4 | import org.bukkit.entity.Player 5 | import org.serverct.ersha.api.AttributeAPI 6 | import org.serverct.ersha.attribute.data.AttributeData 7 | import taboolib.common.platform.event.OptionalEvent 8 | import taboolib.common.platform.event.SubscribeEvent 9 | import taboolib.library.reflex.Reflex.Companion.getProperty 10 | import taboolib.common5.Coerce 11 | import taboolib.platform.util.isAir 12 | import taboolib.type.BukkitEquipment 13 | 14 | internal object AttributePlusHook { 15 | 16 | @SubscribeEvent(bind = "org.serverct.ersha.api.event.AttrUpdateAttributeEvent\$After") 17 | fun e1(e: OptionalEvent) { 18 | val attributeData = e.source.getProperty("attributeData")!! 19 | val sourceEntity = attributeData.sourceEntity 20 | if (sourceEntity is Player) { 21 | val attrData = AttributeAPI.getAttrData(sourceEntity) 22 | val items = BukkitEquipment.values().mapNotNull { it.getItem(sourceEntity) } 23 | items.forEachIndexed { index, item -> 24 | AttributeAPI.takeSourceAttribute(attrData, "Zaphkiel.$index") 25 | if (item.isAir()) { 26 | return 27 | } 28 | val itemStream = item.toItemStream() 29 | if (itemStream.isVanilla()) { 30 | return 31 | } 32 | val attribute = itemStream.getZaphkielData()["attribute-plus"]?.asCompound() ?: return 33 | val map = HashMap>() 34 | attribute.forEach { (key, data) -> 35 | val args = data.asString().split("-") 36 | map[key] = arrayOf(Coerce.toDouble(args[0]), Coerce.toDouble(args.getOrElse(1) { args[0] })) 37 | } 38 | AttributeAPI.addSourceAttribute(attrData, "Zaphkiel.$index", map, false) 39 | } 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/hook/MythicHook.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.hook 2 | 3 | import ink.ptms.um.event.MobDeathEvent 4 | import ink.ptms.um.event.MobSpawnEvent 5 | import ink.ptms.zaphkiel.Zaphkiel 6 | import org.bukkit.Material 7 | import org.bukkit.entity.LivingEntity 8 | import org.bukkit.entity.Player 9 | import org.bukkit.inventory.ItemStack 10 | import taboolib.common.platform.event.SubscribeEvent 11 | import taboolib.common.platform.function.submit 12 | import taboolib.common.util.random 13 | import taboolib.common5.Coerce 14 | import taboolib.library.configuration.ConfigurationSection 15 | import taboolib.type.BukkitEquipment 16 | 17 | /** 18 | * Zaphkiel 19 | * ink.ptms.zaphkiel.module.compat.MythicHook 20 | * 21 | * @author sky 22 | * @since 2021/5/24 11:47 上午 23 | */ 24 | internal object MythicHook { 25 | 26 | @SubscribeEvent 27 | fun onSpawn(e: MobSpawnEvent) { 28 | val mob = e.mob ?: return 29 | val section = mob.config.getConfigurationSection("Zaphkiel.equipments") ?: return 30 | submit(delay = 5) { 31 | MythicUtil.equipment(section, mob.entity as? LivingEntity ?: return@submit) 32 | } 33 | } 34 | 35 | @SubscribeEvent 36 | fun onDeath(e: MobDeathEvent) { 37 | e.mob.config.getStringList("Zaphkiel.drops").forEach { 38 | val args = it.split(" ") 39 | if (args.size == 3 && !random(Coerce.toDouble(args[2]))) { 40 | return@forEach 41 | } 42 | val item = Zaphkiel.api().getItemManager().generateItemStack(args[0], e.killer as? Player) ?: return@forEach 43 | val amount = args.getOrElse(1) { "1" }.split("-").map { a -> Coerce.toInteger(a) } 44 | item.amount = random(amount[0], amount.getOrElse(1) { amount[0] }) 45 | e.drop.add(item) 46 | } 47 | } 48 | 49 | object MythicUtil { 50 | 51 | fun equipment(equipment: ConfigurationSection?, entity: LivingEntity) { 52 | equipment?.getValues(false)?.forEach { (slot, item) -> 53 | val itemStack = if (item.toString() == "air") { 54 | ItemStack(Material.AIR) 55 | } else { 56 | Zaphkiel.api().getItemManager().generateItemStack(item.toString()) ?: ItemStack(Material.AIR) 57 | } 58 | val equipments = BukkitEquipment.fromString(slot) 59 | if (equipments != null) { 60 | equipments.setItem(entity, itemStack) 61 | equipments.setItemDropChance(entity, 0f) 62 | } 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/ActionBuilder.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import ink.ptms.zaphkiel.api.event.Editable 4 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 5 | import org.bukkit.event.Cancellable 6 | import org.bukkit.event.Event 7 | import taboolib.common5.cint 8 | import taboolib.library.xseries.parseToMaterial 9 | import taboolib.module.kether.KetherParser 10 | import taboolib.module.kether.actionNow 11 | import taboolib.module.kether.combinationParser 12 | import taboolib.module.kether.scriptParser 13 | 14 | @KetherParser(["cancel"], namespace = "zaphkiel") 15 | private fun parserCancel() = scriptParser { 16 | actionNow { 17 | val e = itemEvent() 18 | if (e is Cancellable) { 19 | e.isCancelled = true 20 | } 21 | } 22 | } 23 | 24 | @KetherParser(["preset", "build"], namespace = "zaphkiel-build") 25 | private fun parserPreset() = combinationParser { 26 | it.group(symbol(), text(), command("to", then = text()).option()).apply(it) { action, a1, a2 -> 27 | now { 28 | when (action) { 29 | // 名称 30 | "name" -> { 31 | a2 ?: error("missing value for preset name $a1") 32 | val itemEvent = itemEvent() 33 | if (itemEvent is Editable) { 34 | itemEvent.addName(a1, a2) 35 | } else { 36 | error("It cannot be modified in this event") 37 | } 38 | } 39 | // 描述 40 | "lore" -> { 41 | a2 ?: error("missing value for preset name $a1") 42 | val itemEvent = itemEvent() 43 | if (itemEvent is Editable) { 44 | itemEvent.addLore(a1, a2) 45 | } else { 46 | error("It cannot be modified in this event") 47 | } 48 | } 49 | // 图标(材质) 50 | "icon", "material" -> itemEvent().icon = a1.parseToMaterial() 51 | // 附加值 52 | "data", "damage" -> itemEvent().data = a1.cint 53 | // 其他 54 | else -> error("unknown preset action $action") 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/ActionCooldown.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import ink.ptms.zaphkiel.impl.feature.getItemInCooldown 4 | import ink.ptms.zaphkiel.impl.feature.isItemInCooldown 5 | import ink.ptms.zaphkiel.impl.feature.setItemInCooldown 6 | import org.bukkit.entity.Player 7 | import taboolib.common5.Coerce 8 | import taboolib.library.kether.ArgTypes 9 | import taboolib.library.kether.ParsedAction 10 | import taboolib.module.kether.* 11 | import java.util.concurrent.CompletableFuture 12 | 13 | /** 14 | * cooldown check for item 15 | * cooldown check for player 16 | * cooldown set 100 17 | * cooldown set 100 for player 18 | */ 19 | @KetherParser(["cooldown"], namespace = "zaphkiel", shared = true) 20 | private fun parser() = scriptParser { 21 | it.switch { 22 | case("check") { 23 | try { 24 | it.mark() 25 | it.expects("by", "at", "for", "with") 26 | Check(it.expects("player", "item") == "player") 27 | } catch (ignored: Throwable) { 28 | it.reset() 29 | Check(false) 30 | } 31 | } 32 | case("time") { 33 | try { 34 | it.mark() 35 | it.expects("by", "at", "for", "with") 36 | Time(it.expects("player", "item") == "player") 37 | } catch (ignored: Throwable) { 38 | it.reset() 39 | Time(false) 40 | } 41 | } 42 | case("set") { 43 | val gameTick = it.next(ArgTypes.ACTION) 44 | try { 45 | it.mark() 46 | it.expects("by", "at", "for", "with") 47 | Set(gameTick, it.expects("player", "item") == "player") 48 | } catch (ignored: Throwable) { 49 | it.reset() 50 | Set(gameTick, false) 51 | } 52 | } 53 | } 54 | } 55 | 56 | class Check(val byPlayer: Boolean) : ScriptAction() { 57 | 58 | override fun run(frame: ScriptFrame): CompletableFuture { 59 | val viewer = frame.script().sender?.castSafely() ?: error("No player selected.") 60 | return if (byPlayer) { 61 | CompletableFuture.completedFuture(frame.itemStream().isItemInCooldown(viewer)) 62 | } else { 63 | CompletableFuture.completedFuture(frame.itemStream().isItemInCooldown()) 64 | } 65 | } 66 | } 67 | 68 | class Time(val byPlayer: Boolean) : ScriptAction() { 69 | 70 | override fun run(frame: ScriptFrame): CompletableFuture { 71 | val viewer = frame.script().sender?.castSafely() ?: error("No player selected.") 72 | return if (byPlayer) { 73 | CompletableFuture.completedFuture(frame.itemStream().getItemInCooldown(viewer)) 74 | } else { 75 | CompletableFuture.completedFuture(frame.itemStream().getItemInCooldown()) 76 | } 77 | } 78 | } 79 | 80 | class Set(val gameTick: ParsedAction<*>, val byPlayer: Boolean) : ScriptAction() { 81 | 82 | override fun run(frame: ScriptFrame): CompletableFuture { 83 | val viewer = frame.script().sender?.castSafely() ?: error("No player selected.") 84 | frame.newFrame(gameTick).run().thenAccept { 85 | if (byPlayer) { 86 | CompletableFuture.completedFuture(frame.itemStream().setItemInCooldown(Coerce.toInteger(it), viewer)) 87 | } else { 88 | CompletableFuture.completedFuture(frame.itemStream().setItemInCooldown(Coerce.toInteger(it))) 89 | } 90 | } 91 | return CompletableFuture.completedFuture(null) 92 | } 93 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/ActionIt.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import taboolib.module.kether.KetherParser 4 | import taboolib.module.kether.actionNow 5 | import taboolib.module.kether.script 6 | import taboolib.module.kether.scriptParser 7 | 8 | @KetherParser(["it"], namespace = "zaphkiel-mapping") 9 | private fun parserIt() = scriptParser { 10 | actionNow { script()["@ItemMappingData"] } 11 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/ActionItem.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import ink.ptms.zaphkiel.api.ItemSignal 4 | import ink.ptms.zaphkiel.impl.Translator 5 | import ink.ptms.zaphkiel.impl.feature.damageItem 6 | import ink.ptms.zaphkiel.impl.feature.getCurrentDurability 7 | import ink.ptms.zaphkiel.impl.feature.getMaxDurability 8 | import ink.ptms.zaphkiel.impl.feature.repairItem 9 | import org.bukkit.entity.Player 10 | import taboolib.module.kether.* 11 | import taboolib.module.nms.ItemTagData 12 | 13 | /** 14 | * item durability 15 | * item max-durability 16 | * item consume 17 | * item repair 1 18 | * item damage 1 19 | * item update 20 | * item data key 21 | * item data key to 1 22 | * item data key to ~ 23 | */ 24 | @KetherParser(["item", "zitem"]) 25 | private fun parserItem() = scriptParser { 26 | it.switch { 27 | case("durability") { 28 | actionNow { itemStream().getCurrentDurability() } 29 | } 30 | case("max-durability", "max_durability") { 31 | actionNow { itemStream().getMaxDurability() } 32 | } 33 | case("consume") { 34 | actionNow { itemStream().sourceItem.amount-- } 35 | } 36 | case("repair") { 37 | val value = it.nextParsedAction() 38 | actionTake { 39 | run(value).int { value -> itemStream().repairItem(value, script().sender?.castSafely()) } 40 | } 41 | } 42 | case("damage") { 43 | val value = it.nextParsedAction() 44 | actionTake { 45 | run(value).int { value -> itemStream().damageItem(value, script().sender?.castSafely()) } 46 | } 47 | } 48 | // 更新 49 | // 下次检查时更新,不是立即更新 50 | case("update") { 51 | actionNow { itemStream().signal.add(ItemSignal.UPDATE_CHECKED) } 52 | } 53 | // 数据 54 | case("data") { 55 | val key = it.nextParsedAction() 56 | val value = try { 57 | it.mark() 58 | expect("to") 59 | it.nextParsedAction() 60 | } catch (_: Throwable) { 61 | it.reset() 62 | null 63 | } 64 | actionFuture { f -> 65 | run(key).str { key -> 66 | // 获取 67 | if (value == null) { 68 | val unsafeData = itemStream().getZaphkielData().getDeep(key)?.unsafeData() 69 | f.complete(if (unsafeData != null) Translator.fromItemTag(unsafeData) else null) 70 | } 71 | // 设置 72 | else if (key != "~") { 73 | run(value).str { value -> f.complete(itemStream().getZaphkielData().putDeep(key, ItemTagData.toNBT(value))) } 74 | } 75 | // 移除 76 | else { 77 | itemStream().getZaphkielData().removeDeep(key) 78 | f.complete(null) 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/ActionMythic.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import ink.ptms.um.Mythic 4 | import org.bukkit.entity.Player 5 | import taboolib.module.kether.KetherParser 6 | import taboolib.module.kether.combinationParser 7 | import taboolib.module.kether.script 8 | 9 | /** 10 | * mm cast-skill 'message{m="我是傻逼"}' 11 | */ 12 | @Suppress("SpellCheckingInspection") 13 | @KetherParser(["mm"], namespace = "zaphkiel", shared = true) 14 | private fun parser() = combinationParser { 15 | it.group(symbol(), text()).apply(it) { action, a1 -> 16 | when (action) { 17 | // 释放既能 18 | "castskill", "cast-skill" -> { 19 | val skillMachine = Mythic.API.getSkillMechanic(a1) 20 | val skillTrigger = Mythic.API.getSkillTrigger("API") 21 | now { 22 | val caster = script().sender?.castSafely() ?: error("No player selected.") 23 | skillMachine?.execute(skillTrigger, caster, caster) 24 | } 25 | } 26 | // 其他 27 | else -> error("Unknown action $action") 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/ActionPotion.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import org.bukkit.entity.Player 4 | import org.bukkit.potion.PotionEffect 5 | import org.bukkit.potion.PotionEffectType 6 | import taboolib.common.platform.function.submit 7 | import taboolib.library.kether.ParsedAction 8 | import taboolib.module.kether.* 9 | import java.util.concurrent.CompletableFuture 10 | 11 | /** 12 | * effect give SPEED 10 10 13 | */ 14 | @KetherParser(["potion"], namespace = "zaphkiel", shared = true) 15 | private fun parser() = scriptParser { 16 | it.switch { 17 | case("give") { Give(it.nextParsedAction(), it.nextParsedAction(), it.nextParsedAction()) } 18 | case("remove") { Remove(it.nextParsedAction()) } 19 | case("clear") { Clear() } 20 | } 21 | } 22 | 23 | class Give(val name: ParsedAction<*>, val duration: ParsedAction<*>, val amplifier: ParsedAction<*>) : ScriptAction() { 24 | 25 | override fun run(frame: ScriptFrame): CompletableFuture { 26 | val viewer = frame.script().sender?.castSafely() ?: error("No player selected.") 27 | frame.run(name).str { name -> 28 | frame.run(duration).int { duration -> 29 | frame.run(amplifier).int { amplifier -> 30 | val effectType = PotionEffectType.getByName(name.uppercase()) 31 | if (effectType != null) { 32 | submit { viewer.addPotionEffect(PotionEffect(effectType, duration, amplifier)) } 33 | } 34 | } 35 | } 36 | } 37 | return CompletableFuture.completedFuture(null) 38 | } 39 | } 40 | 41 | class Remove(val name: ParsedAction<*>) : ScriptAction() { 42 | 43 | override fun run(frame: ScriptFrame): CompletableFuture { 44 | val viewer = frame.script().sender?.castSafely() ?: error("No player selected.") 45 | frame.run(name).str { name -> 46 | val effectType = PotionEffectType.getByName(name.uppercase()) 47 | if (effectType != null) { 48 | submit { viewer.removePotionEffect(effectType) } 49 | } 50 | } 51 | return CompletableFuture.completedFuture(null) 52 | } 53 | } 54 | 55 | class Clear : ScriptAction() { 56 | 57 | override fun run(frame: ScriptFrame): CompletableFuture { 58 | val viewer = frame.script().sender?.castSafely() ?: error("No player selected.") 59 | submit { viewer.activePotionEffects.toList().forEach { viewer.removePotionEffect(it.type) } } 60 | return CompletableFuture.completedFuture(null) 61 | } 62 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/ActionZaphkiel.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import org.bukkit.entity.Player 5 | import taboolib.module.kether.KetherParser 6 | import taboolib.module.kether.combinationParser 7 | import taboolib.module.kether.script 8 | 9 | /** 10 | * zaphkiel give item 11 | * zaphkiel give item 1 12 | * zaphkiel take item 13 | */ 14 | @KetherParser(["zaphkiel"], shared = true) 15 | private fun parser() = combinationParser { 16 | it.group(symbol(), text().and(int().option().defaultsTo(1))).apply(it) { action, (id, amount) -> 17 | now { 18 | val viewer = script().sender?.castSafely() ?: error("No player selected.") 19 | val item = Zaphkiel.api().getItemManager().getItem(id) ?: error("unknown item $id") 20 | when (action) { 21 | "take" -> item.takeItem(viewer, amount) 22 | "give" -> item.giveItemOrDrop(viewer, amount) 23 | "has", "check" -> item.hasItem(viewer, amount) 24 | else -> error("Unknown action: $action") 25 | } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/feature/kether/Extensions.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.feature.kether 2 | 3 | import ink.ptms.zaphkiel.api.ItemStream 4 | import org.bukkit.event.Event 5 | import taboolib.module.kether.ScriptFrame 6 | 7 | fun ScriptFrame.itemStream(): ItemStream { 8 | return variables().get("@ItemStream").orElse(null) as? ItemStream ?: error("No item-stream selected.") 9 | } 10 | 11 | fun ScriptFrame.itemEvent(): T { 12 | return variables().get("@ItemEvent").orElse(null) ?: error("No event selected.") 13 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/internal/ItemBuilder.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.internal 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.api.ItemSignal 5 | import ink.ptms.zaphkiel.api.event.ItemBuildEvent 6 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 7 | import ink.ptms.zaphkiel.impl.item.DefaultItemStreamGenerated 8 | import taboolib.common.platform.event.SubscribeEvent 9 | import taboolib.common.reflect.Reflex.Companion.invokeConstructor 10 | import taboolib.common.util.unsafeLazy 11 | import taboolib.module.chat.colored 12 | import taboolib.module.configuration.Configuration 13 | import taboolib.module.configuration.Type 14 | 15 | /** 16 | * @author sky 17 | * @since 2019-12-26 9:53 18 | */ 19 | internal object ItemBuilder { 20 | 21 | val dropMeta by unsafeLazy { 22 | Zaphkiel.api().getItemManager().getMetaMap().map { it.value.invokeConstructor(Configuration.empty(Type.YAML)) }.associateBy { it.id } 23 | } 24 | 25 | @SubscribeEvent 26 | fun onBuildPost(e: ItemBuildEvent.Post) { 27 | e.itemStream.dropMeta.forEach { 28 | dropMeta[it]?.drop(e.player, e.itemStream.sourceCompound) 29 | } 30 | e.item.meta.forEach { 31 | if (it.locked || ItemSignal.UPDATE_CHECKED !in e.itemStream.signal) { 32 | it.build(e.player, e.itemStream.sourceCompound) 33 | } 34 | } 35 | e.itemStream.setZaphkielMetaHistory(e.item.meta.map { it.id }) 36 | } 37 | 38 | @SubscribeEvent 39 | fun onRelease(e: ItemReleaseEvent) { 40 | val itemStream = e.itemStream 41 | itemStream.dropMeta.forEach { 42 | val meta = dropMeta[it] 43 | if (meta != null) { 44 | meta.drop(e) 45 | meta.drop(e.itemMeta) 46 | } 47 | } 48 | e.item.meta.forEach { 49 | if (it.locked || ItemSignal.UPDATE_CHECKED !in itemStream.signal) { 50 | it.build(e) 51 | it.build(e.itemMeta) 52 | } 53 | } 54 | if (itemStream is DefaultItemStreamGenerated) { 55 | var display = Zaphkiel.api().getItemManager().getDisplay(e.item.display) 56 | if (display != null) { 57 | // 展示方案替换事件 58 | display = ItemReleaseEvent.SelectDisplay(e.itemStream, display, e.player).also { it.call() }.display 59 | // 描述替换事件 60 | val event = ItemReleaseEvent.Display(itemStream, itemStream.name, itemStream.lore, e.player) 61 | event.call() 62 | val product = display.build(event.name, event.lore) 63 | e.itemMeta.setDisplayName(product.name?.colored() ?: "") 64 | e.itemMeta.lore = product.lore.colored() 65 | } else { 66 | e.itemMeta.setDisplayName("§c${e.item.id}") 67 | e.itemMeta.lore = listOf("", "§4NO DISPLAY PLAN") 68 | } 69 | } else { 70 | if (e.item.iconLocked) { 71 | e.icon = e.item.icon.type 72 | e.data = e.item.icon.durability.toInt() 73 | } 74 | if (e.item.nameLocked || e.item.loreLocked) { 75 | var display = Zaphkiel.api().getItemManager().getDisplay(e.item.display) 76 | if (display != null) { 77 | display = ItemReleaseEvent.SelectDisplay(e.itemStream, display, e.player).also { it.call() }.display 78 | val event = ItemReleaseEvent.Display(itemStream, e.item.name.toMutableMap(), e.item.lore.toMutableMap(), e.player) 79 | event.call() 80 | val product = display.build(event.name, event.lore) 81 | if (e.item.nameLocked) { 82 | e.itemMeta.setDisplayName(product.name?.colored() ?: "") 83 | } 84 | if (e.item.loreLocked) { 85 | e.itemMeta.lore = product.lore.colored() 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/internal/ItemListener.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.internal 2 | 3 | import ink.ptms.zaphkiel.api.ItemStream 4 | import ink.ptms.zaphkiel.api.event.ItemBuildEvent 5 | import ink.ptms.zaphkiel.api.event.ItemEvent 6 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 7 | import ink.ptms.zaphkiel.impl.item.toItemStream 8 | import org.bukkit.Bukkit 9 | import org.bukkit.entity.Player 10 | import org.bukkit.event.block.Action 11 | import org.bukkit.event.block.BlockBreakEvent 12 | import org.bukkit.event.entity.EntityDamageByEntityEvent 13 | import org.bukkit.event.inventory.ClickType 14 | import org.bukkit.event.inventory.InventoryClickEvent 15 | import org.bukkit.event.player.* 16 | import org.bukkit.inventory.EquipmentSlot 17 | import taboolib.common.platform.Schedule 18 | import taboolib.common.platform.event.EventPriority 19 | import taboolib.common.platform.event.SubscribeEvent 20 | import taboolib.platform.util.attacker 21 | import taboolib.platform.util.isAir 22 | import taboolib.platform.util.isNotAir 23 | 24 | /** 25 | * @author sky 26 | * @since 2020-04-20 12:37 27 | */ 28 | internal object ItemListener { 29 | 30 | @Schedule(period = 100, async = true) 31 | fun onAsyncTick() { 32 | Bukkit.getOnlinePlayers().forEach { 33 | it.inventory.filter { item -> item.isNotAir() }.forEach { item -> 34 | val event = ItemEvent.AsyncTick(item.toItemStream(), it) 35 | event.call() 36 | if (event.save) { 37 | event.itemStream.rebuildToItemStack(it) 38 | } 39 | } 40 | } 41 | } 42 | 43 | @SubscribeEvent 44 | fun onBuildPre(e: ItemBuildEvent.Pre) { 45 | e.itemStream.getZaphkielItem().invokeScript(listOf("on_build", "onBuild"), e.player, e, e.itemStream, "zaphkiel-build") 46 | } 47 | 48 | @SubscribeEvent 49 | fun onRelease(e: ItemReleaseEvent) { 50 | e.itemStream.getZaphkielItem().invokeScript(listOf("on_release", "onRelease"), e.player, e, e.itemStream, "zaphkiel-build") 51 | } 52 | 53 | @SubscribeEvent 54 | fun onReleaseDisplay(e: ItemReleaseEvent.Display) { 55 | e.itemStream.getZaphkielItem().invokeScript(listOf("on_release_display", "onReleaseDisplay"), e.player, e, e.itemStream, "zaphkiel-build") 56 | } 57 | 58 | @SubscribeEvent 59 | fun onAttack(e: EntityDamageByEntityEvent) { 60 | val attacker = e.attacker 61 | if (attacker is Player && attacker.itemInHand.isNotAir()) { 62 | val itemStream = attacker.itemInHand.toItemStream() 63 | if (itemStream.isExtension()) { 64 | itemStream.getZaphkielItem().invokeScript(listOf("on_attack", "onAttack"), attacker, e, itemStream) 65 | } 66 | } 67 | } 68 | 69 | @SubscribeEvent 70 | fun onJoin(e: PlayerJoinEvent) { 71 | e.player.onSelect() 72 | } 73 | 74 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 75 | fun onChangeWorld(e: PlayerChangedWorldEvent) { 76 | e.player.onSelect() 77 | } 78 | 79 | /** 80 | * 当玩家物品发生损坏时 81 | * 触发事件 82 | */ 83 | @SubscribeEvent(ignoreCancelled = true) 84 | fun onBreak(e: PlayerItemBreakEvent) { 85 | val itemStream = e.brokenItem.toItemStream() 86 | if (itemStream.isExtension()) { 87 | itemStream.getZaphkielItem().invokeScript(listOf("on_item_break", "onItemBreak"), e, itemStream) 88 | } 89 | } 90 | 91 | /** 92 | * 当玩家消耗物品时 93 | * 触发事件及脚本 94 | */ 95 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 96 | fun onConsume(e: PlayerItemConsumeEvent) { 97 | val itemStack = e.item 98 | if (itemStack.isAir()) { 99 | return 100 | } 101 | val itemStream = itemStack.toItemStream() 102 | if (itemStream.isExtension()) { 103 | // 触发事件 104 | ItemEvent.Consume(itemStream, e).also { it.call() } 105 | // 执行脚本 106 | itemStream.getZaphkielItem().invokeScript(listOf("on_consume", "onConsume"), e, itemStream) 107 | // 更新物品 108 | if (e.item == e.player.inventory.itemInMainHand) { 109 | e.player.inventory.setItemInMainHand(itemStack) 110 | } else { 111 | e.player.inventory.setItemInOffHand(itemStack) 112 | } 113 | } 114 | } 115 | 116 | /** 117 | * 当玩家与空气或方块发生交互时 118 | * 触发事件及脚本 119 | */ 120 | @SubscribeEvent 121 | fun onInteract(e: PlayerInteractEvent) { 122 | if (e.item.isAir()) { 123 | return 124 | } 125 | val itemStream = e.item!!.toItemStream() 126 | if (itemStream.isVanilla()) { 127 | return 128 | } 129 | // 触发事件 130 | val event = ItemEvent.Interact(itemStream, e) 131 | if (event.call()) { 132 | if (event.save) { 133 | event.itemStream.rebuildToItemStack(e.player) 134 | } 135 | // 执行脚本 136 | when (e.action) { 137 | // 左键 138 | Action.LEFT_CLICK_AIR, Action.LEFT_CLICK_BLOCK -> { 139 | itemStream.getZaphkielItem().invokeScript(listOf("on_left_click", "onLeftClick"), e, itemStream) 140 | } 141 | // 右键 142 | Action.RIGHT_CLICK_AIR, Action.RIGHT_CLICK_BLOCK -> { 143 | itemStream.getZaphkielItem().invokeScript(listOf("on_right_click", "onRightClick"), e, itemStream) 144 | } 145 | // 其他 146 | else -> {} 147 | } 148 | } 149 | } 150 | 151 | /** 152 | * 当玩家与实体发生交互时 153 | * 触发事件及脚本 154 | */ 155 | @SubscribeEvent 156 | fun onInteractAtEntity(e: PlayerInteractEntityEvent) { 157 | if (e.player.inventory.itemInMainHand.isNotAir() && e.hand == EquipmentSlot.HAND) { 158 | val itemStream = e.player.inventory.itemInMainHand.toItemStream() 159 | if (itemStream.isVanilla()) { 160 | return 161 | } 162 | val event = ItemEvent.InteractEntity(itemStream, e) 163 | if (event.call()) { 164 | if (event.save) { 165 | event.itemStream.rebuildToItemStack(e.player) 166 | } 167 | itemStream.getZaphkielItem().invokeScript(listOf("on_right_click_entity", "onRightClickEntity"), e, itemStream) 168 | } 169 | } 170 | } 171 | 172 | /** 173 | * 当玩家切换副手时 174 | * 触发脚本 175 | */ 176 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 177 | fun onSwap(e: PlayerSwapHandItemsEvent) { 178 | if (e.offHandItem.isNotAir()) { 179 | val itemStream = e.offHandItem!!.toItemStream() 180 | if (itemStream.isExtension()) { 181 | itemStream.getZaphkielItem().invokeScript(listOf("on_swap_to_offhand", "onSwapToOffhand"), e, itemStream) 182 | } 183 | } 184 | if (e.mainHandItem.isNotAir()) { 185 | val itemStream = e.mainHandItem!!.toItemStream() 186 | if (itemStream.isExtension()) { 187 | itemStream.getZaphkielItem().invokeScript(listOf("on_swap_to_mainhand", "onSwapToMainHand"), e, itemStream) 188 | } 189 | } 190 | } 191 | 192 | /** 193 | * 当玩家破坏方块时 194 | * 触发脚本 195 | */ 196 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 197 | fun onBreak(e: BlockBreakEvent) { 198 | if (e.player.inventory.itemInMainHand.isAir()) { 199 | return 200 | } 201 | val itemStream = e.player.inventory.itemInMainHand.toItemStream() 202 | if (itemStream.isExtension()) { 203 | itemStream.getZaphkielItem().invokeScript(listOf("on_block_break", "onBlockBreak"), e.player, e, itemStream) 204 | } 205 | } 206 | 207 | /** 208 | * 当玩家破坏方块时(Sandalphon) 209 | * 触发脚本 210 | */ 211 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 212 | fun onBreak(e: ink.ptms.sandalphon.module.impl.blockmine.event.BlockBreakEvent) { 213 | if (e.player.inventory.itemInMainHand.isAir()) { 214 | return 215 | } 216 | val itemStream = e.player.inventory.itemInMainHand.toItemStream() 217 | if (itemStream.isExtension()) { 218 | itemStream.getZaphkielItem().invokeScript(listOf("on_block_break", "onBlockBreak"), e.player, e, itemStream) 219 | } 220 | } 221 | 222 | /** 223 | * 当玩家丢弃物品时 224 | * 触发事件及脚本 225 | */ 226 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 227 | fun onDrop(e: PlayerDropItemEvent) { 228 | if (e.itemDrop.itemStack.isNotAir()) { 229 | val itemStream = e.itemDrop.itemStack.toItemStream() 230 | if (itemStream.isVanilla()) { 231 | return 232 | } 233 | val event = ItemEvent.Drop(itemStream, e) 234 | event.call() 235 | if (event.save) { 236 | e.itemDrop.itemStack = event.itemStream.rebuildToItemStack(e.player) 237 | } 238 | // 若脚本修改物品则写回事件 239 | itemStream.getZaphkielItem().invokeScript(listOf("on_drop", "onDrop"), e.player, e, itemStream)?.thenAccept { 240 | if (it != null) { 241 | e.itemDrop.itemStack = it.itemStack 242 | } 243 | } 244 | } 245 | } 246 | 247 | /** 248 | * 当玩家捡起物品时 249 | * 触发事件及脚本 250 | */ 251 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 252 | fun onPickup(e: PlayerPickupItemEvent) { 253 | if (e.item.itemStack.isNotAir()) { 254 | val itemStream = e.item.itemStack.toItemStream() 255 | if (itemStream.isVanilla()) { 256 | return 257 | } 258 | val event = ItemEvent.Pick(itemStream, e).call() 259 | // 2023/10/21 移除物品捡起事件中修改物品的功能 260 | // if (event.save) { 261 | // e.item.itemStack = event.itemStream.rebuildToItemStack(e.player) 262 | // } 263 | // 若脚本修改物品则写回事件 264 | itemStream.getZaphkielItem().invokeScript(listOf("on_pick", "on_pickup", "onPick", "onPickUp"), e.player, e, itemStream)?.thenAccept { 265 | // if (it != null) { 266 | // e.item.itemStack = it.itemStack 267 | // } 268 | } 269 | } 270 | } 271 | 272 | /** 273 | * 当玩家在背包中点击物品时 274 | * 触发事件 275 | */ 276 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 277 | fun onClick(e: InventoryClickEvent) { 278 | val itemStreamCurrent = if (e.currentItem.isNotAir()) e.currentItem!!.toItemStream() else null 279 | var itemStreamButton: ItemStream? = null 280 | if (e.click == ClickType.NUMBER_KEY) { 281 | val hotbarButton = e.whoClicked.inventory.getItem(e.hotbarButton) 282 | if (hotbarButton.isNotAir()) { 283 | itemStreamButton = hotbarButton.toItemStream() 284 | } 285 | } 286 | if (itemStreamCurrent == null && itemStreamButton == null) { 287 | return 288 | } 289 | val event = ItemEvent.InventoryClick(itemStreamCurrent, itemStreamButton, e) 290 | if (event.call()) { 291 | if (event.saveCurrent && itemStreamCurrent != null) { 292 | itemStreamCurrent.rebuildToItemStack(e.whoClicked as Player) 293 | } 294 | if (event.saveButton && itemStreamButton != null) { 295 | itemStreamButton.rebuildToItemStack(e.whoClicked as Player) 296 | } 297 | } 298 | } 299 | 300 | private fun Player.onSelect() { 301 | inventory.filter { it.isNotAir() }.forEach { 302 | val event = ItemEvent.Select(it.toItemStream(), this) 303 | event.call() 304 | if (event.save) { 305 | event.itemStream.rebuildToItemStack(this@onSelect) 306 | } 307 | } 308 | } 309 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/internal/ItemUpdater.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.internal 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.api.ItemSignal 5 | import org.bukkit.Bukkit 6 | import org.bukkit.entity.Player 7 | import org.bukkit.event.inventory.InventoryOpenEvent 8 | import org.bukkit.event.player.PlayerDropItemEvent 9 | import org.bukkit.event.player.PlayerJoinEvent 10 | import org.bukkit.event.player.PlayerPickupItemEvent 11 | import org.bukkit.event.player.PlayerRespawnEvent 12 | import taboolib.common.platform.Schedule 13 | import taboolib.common.platform.event.EventPriority 14 | import taboolib.common.platform.event.OptionalEvent 15 | import taboolib.common.platform.event.SubscribeEvent 16 | import taboolib.common.platform.function.submitAsync 17 | 18 | /** 19 | * @author sky 20 | * @since 2019-12-16 10:40 21 | */ 22 | private object ItemUpdater { 23 | 24 | /** 25 | * 每 100 tick 更新一次背包(异步更新) 26 | */ 27 | @Schedule(period = 100, async = true) 28 | fun tick() { 29 | Bukkit.getOnlinePlayers().forEach { player -> Zaphkiel.api().getItemUpdater().checkUpdate(player, player.inventory) } 30 | } 31 | 32 | /** 33 | * 进入游戏时更新背包(同步更新) 34 | */ 35 | @SubscribeEvent 36 | fun onJoin(e: PlayerJoinEvent) { 37 | Zaphkiel.api().getItemUpdater().checkUpdate(e.player, e.player.inventory) 38 | } 39 | 40 | /** 41 | * 复活时更新背包(同步更新) 42 | */ 43 | @SubscribeEvent 44 | fun onRespawn(e: PlayerRespawnEvent) { 45 | Zaphkiel.api().getItemUpdater().checkUpdate(e.player, e.player.inventory) 46 | } 47 | 48 | /** 49 | * 丢弃物品时更新物品(同步更新) 50 | */ 51 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 52 | fun onDrop(e: PlayerDropItemEvent) { 53 | val itemStream = Zaphkiel.api().getItemUpdater().checkUpdate(e.player, e.itemDrop.itemStack) 54 | if (ItemSignal.UPDATE_CHECKED in itemStream.signal) { 55 | e.itemDrop.itemStack = itemStream.toItemStack(e.player) 56 | } 57 | } 58 | 59 | /** 60 | * 捡起物品时更新物品(同步更新) 61 | */ 62 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 63 | fun onPickup(e: PlayerPickupItemEvent) { 64 | val itemStream = Zaphkiel.api().getItemUpdater().checkUpdate(e.player, e.item.itemStack) 65 | if (ItemSignal.UPDATE_CHECKED in itemStream.signal) { 66 | e.item.itemStack = itemStream.toItemStack(e.player) 67 | } 68 | } 69 | 70 | /** 71 | * 打开箱子时更新物品(异步更新) 72 | */ 73 | @SubscribeEvent(priority = EventPriority.MONITOR, ignoreCancelled = true) 74 | fun onOpen(e: InventoryOpenEvent) { 75 | kotlin.runCatching { 76 | if (e.inventory.location != null) { 77 | submitAsync { Zaphkiel.api().getItemUpdater().checkUpdate(e.player as Player, e.inventory) } 78 | } 79 | } 80 | } 81 | 82 | /** 83 | * 读取玩家数据时更新背包(同步更新) 84 | */ 85 | @SubscribeEvent(bind = "cc.bukkitPlugin.pds.events.PlayerDataLoadCompleteEvent") 86 | fun onLoad(e: OptionalEvent) { 87 | val player = e.read("player")!! 88 | Zaphkiel.api().getItemUpdater().checkUpdate(player, player.inventory) 89 | } 90 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/Config.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("SpellCheckingInspection") 2 | 3 | package ink.ptms.zaphkiel.impl.item 4 | 5 | import ink.ptms.zaphkiel.api.Item 6 | import ink.ptms.zaphkiel.api.ItemEvent 7 | import org.bukkit.Material 8 | import org.bukkit.inventory.ItemStack 9 | import taboolib.common.util.asList 10 | import taboolib.library.configuration.ConfigurationSection 11 | import taboolib.library.xseries.parseToXMaterial 12 | import taboolib.module.chat.colored 13 | 14 | internal fun parseIcon(config: ConfigurationSection): ItemStack { 15 | val node = if (config.contains("icon!!")) "icon!!" else "icon" 16 | return config.getString(node, "STONE")!!.parseToXMaterial().parseItem() ?: ItemStack(Material.STONE) 17 | } 18 | 19 | internal fun parseName(config: ConfigurationSection): MutableMap { 20 | val map = HashMap() 21 | val node = if (config.contains("name!!")) "name!!" else "name" 22 | val name = config.getConfigurationSection(node) ?: return HashMap() 23 | name.getKeys(false).forEach { key -> 24 | map[key] = config.getString("$node.$key")!! 25 | } 26 | return map 27 | } 28 | 29 | internal fun parseLore(config: ConfigurationSection): MutableMap> { 30 | val map = HashMap>() 31 | val node = if (config.contains("lore!!")) "lore!!" else "lore" 32 | val lore = config.getConfigurationSection(node) ?: return HashMap() 33 | val autowrap = lore.getInt("~autowrap") 34 | lore["~autowrap"] = null 35 | lore.getKeys(false).forEach { key -> 36 | var list = if (config.isList("$node.$key")) config.getStringList("$node.$key") else mutableListOf( 37 | config.getString("$node.$key")!! 38 | ) 39 | list = list.flatMap { it.split('\n') } 40 | list = if (autowrap > 0) list.split(autowrap).toMutableList() else list 41 | map[key] = list.toMutableList() 42 | } 43 | return map 44 | } 45 | 46 | internal fun parseEvent(item: Item, config: ConfigurationSection): MutableMap { 47 | val map = HashMap() 48 | val event = config.getConfigurationSection("event") ?: return HashMap() 49 | event.getKeys(false).forEach { key -> 50 | if (key.endsWith("!!")) { 51 | val substring = key.substring(0, key.length - 2) 52 | map[substring] = DefaultItemEvent(item, substring, config["event.$key"]!!.asList(), true) 53 | } else { 54 | map[key] = DefaultItemEvent(item, key, config["event.$key"]!!.asList()) 55 | } 56 | } 57 | return map 58 | } 59 | 60 | internal fun List.split(size: Int) = colored().flatMap { line -> 61 | if (line.length > size) { 62 | val arr = ArrayList() 63 | var s = line 64 | while (s.length > size) { 65 | val c = s.substring(0, size) 66 | val i = c.lastIndexOf("§") 67 | arr.add(c) 68 | s = if (i != -1 && i + 2 < c.length) { 69 | s.substring(i, i + 2) + s.substring(size) 70 | } else { 71 | s.substring(size) 72 | } 73 | } 74 | arr.add(s) 75 | arr 76 | } else { 77 | line.asList() 78 | } 79 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultDisplay.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.api.Display 5 | import ink.ptms.zaphkiel.api.DisplayProduct 6 | import org.bukkit.metadata.MetadataValue 7 | import org.bukkit.plugin.Plugin 8 | import taboolib.library.configuration.ConfigurationSection 9 | import java.util.concurrent.ConcurrentHashMap 10 | 11 | /** 12 | * Zaphkiel 13 | * ink.ptms.zaphkiel.impl.item.DefaultDisplay 14 | * 15 | * @author 坏黑 16 | * @since 2022/7/23 16:58 17 | */ 18 | class DefaultDisplay(override val config: ConfigurationSection) : Display() { 19 | 20 | override val id = config.name 21 | 22 | override val name = config.getString("name") 23 | 24 | override val lore = config.getStringList("lore") 25 | 26 | override val structureName = if (name != null) DefaultStructureSingle(name) else null 27 | 28 | override val structureLore = DefaultStructureList(lore) 29 | 30 | override val meta = Zaphkiel.api().getItemLoader().loadMetaFromSection(config) 31 | 32 | val metadataList = ConcurrentHashMap>() 33 | 34 | override fun build(name: Map, lore: Map>, trim: Boolean): DisplayProduct { 35 | return DisplayProduct(structureName?.build(name, trim), structureLore.build(lore.mapValues { it.value.toMutableList() }, trim)) 36 | } 37 | 38 | override fun setMetadata(key: String, value: MetadataValue) { 39 | metadataList.computeIfAbsent(key) { ConcurrentHashMap() }[value.owningPlugin?.name ?: "null"] = value 40 | } 41 | 42 | override fun getMetadata(key: String): MutableList { 43 | return metadataList[key]?.values?.toMutableList() ?: mutableListOf() 44 | } 45 | 46 | override fun hasMetadata(key: String): Boolean { 47 | return metadataList.containsKey(key) && metadataList[key]?.isNotEmpty() == true 48 | } 49 | 50 | override fun removeMetadata(key: String, plugin: Plugin) { 51 | metadataList[key]?.remove(plugin.name) 52 | } 53 | 54 | override fun equals(other: Any?): Boolean { 55 | if (this === other) return true 56 | if (other !is DefaultDisplay) return false 57 | if (id != other.id) return false 58 | return true 59 | } 60 | 61 | override fun hashCode(): Int { 62 | return id.hashCode() 63 | } 64 | 65 | override fun toString(): String { 66 | return "DefaultDisplay(config=$config, id='$id', name=$name, lore=$lore, structureName=$structureName, structureLore=$structureLore, meta=$meta)" 67 | } 68 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultGroup.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.api.Group 5 | import ink.ptms.zaphkiel.api.Item 6 | import org.bukkit.Material 7 | import org.bukkit.inventory.ItemFlag 8 | import org.bukkit.inventory.ItemStack 9 | import org.bukkit.inventory.meta.ItemMeta 10 | import org.bukkit.metadata.MetadataValue 11 | import org.bukkit.plugin.Plugin 12 | import taboolib.common.platform.function.getDataFolder 13 | import taboolib.common.util.unsafeLazy 14 | import taboolib.library.configuration.ConfigurationSection 15 | import taboolib.module.configuration.Configuration 16 | import taboolib.platform.util.modifyMeta 17 | import java.io.File 18 | import java.util.concurrent.ConcurrentHashMap 19 | 20 | /** 21 | * Zaphkiel 22 | * ink.ptms.zaphkiel.impl.item.DefaultGroup 23 | * 24 | * @author 坏黑 25 | * @since 2022/7/23 16:47 26 | */ 27 | data class DefaultGroup( 28 | override var name: String, 29 | override val file: File, 30 | override val config: ConfigurationSection, 31 | override val priority: Int = config.getInt("priority"), 32 | override val level: Int = 0, 33 | override val parent: Group? = null 34 | ) : Group() { 35 | 36 | override val path: String 37 | get() = (parent?.path ?: "") + "/" + name 38 | 39 | override val display: ItemStack 40 | get() { 41 | val items = getItems() 42 | return if (items.isNotEmpty()) { 43 | items.random().buildItemStack() 44 | } else { 45 | ItemStack(Material.CHEST_MINECART) 46 | }.modifyMeta { 47 | // 设置名称 48 | setDisplayName("§f$name") 49 | // 移除描述 50 | lore = if (items.isNotEmpty()) { 51 | listOf("", "§7${items.size} items") 52 | } else { 53 | null 54 | } 55 | // 隐藏标签 56 | addItemFlags(*ItemFlag.values()) 57 | } 58 | } 59 | 60 | val metadataList = ConcurrentHashMap>() 61 | 62 | override fun getItems(): List { 63 | return Zaphkiel.api().getItemManager().getItemMap().values.filter { it.group == this } 64 | } 65 | 66 | override fun setMetadata(key: String, value: MetadataValue) { 67 | metadataList.computeIfAbsent(key) { ConcurrentHashMap() }[value.owningPlugin?.name ?: "null"] = value 68 | } 69 | 70 | override fun getMetadata(key: String): MutableList { 71 | return metadataList[key]?.values?.toMutableList() ?: mutableListOf() 72 | } 73 | 74 | override fun hasMetadata(key: String): Boolean { 75 | return metadataList.containsKey(key) && metadataList[key]?.isNotEmpty() == true 76 | } 77 | 78 | override fun removeMetadata(key: String, plugin: Plugin) { 79 | metadataList[key]?.remove(plugin.name) 80 | } 81 | 82 | override fun equals(other: Any?): Boolean { 83 | if (this === other) return true 84 | if (other !is DefaultGroup) return false 85 | if (name != other.name) return false 86 | return true 87 | } 88 | 89 | override fun hashCode(): Int { 90 | return name.hashCode() 91 | } 92 | 93 | override fun toString(): String { 94 | return "DefaultGroup(name='$name', file=$file, config=$config, display=$display, priority=$priority)" 95 | } 96 | 97 | companion object { 98 | 99 | val NO_GROUP by unsafeLazy { DefaultGroup("#", File(getDataFolder(), "config.yml"), Configuration.empty()) } 100 | } 101 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultItem.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.api.* 5 | import ink.ptms.zaphkiel.api.event.ItemBuildEvent 6 | import ink.ptms.zaphkiel.api.event.ItemGiveEvent 7 | import ink.ptms.zaphkiel.impl.Translator 8 | import org.bukkit.entity.Player 9 | import org.bukkit.event.Cancellable 10 | import org.bukkit.event.Event 11 | import org.bukkit.event.player.PlayerEvent 12 | import org.bukkit.inventory.ItemStack 13 | import org.bukkit.metadata.MetadataValue 14 | import org.bukkit.plugin.Plugin 15 | import taboolib.common.io.digest 16 | import taboolib.common.platform.function.severe 17 | import taboolib.common.util.asList 18 | import taboolib.common.util.unsafeLazy 19 | import taboolib.library.configuration.ConfigurationSection 20 | import taboolib.module.configuration.Configuration 21 | import taboolib.module.configuration.Type 22 | import taboolib.module.configuration.util.getMap 23 | import taboolib.module.nms.ItemTag 24 | import taboolib.module.nms.ItemTagData 25 | import taboolib.platform.compat.replacePlaceholder 26 | import taboolib.platform.util.hasItem 27 | import taboolib.platform.util.isAir 28 | import taboolib.platform.util.takeItem 29 | import java.util.concurrent.CompletableFuture 30 | import java.util.concurrent.ConcurrentHashMap 31 | import java.util.function.Consumer 32 | 33 | /** 34 | * Zaphkiel 35 | * ink.ptms.zaphkiel.impl.item.DefaultItem 36 | * 37 | * @author 坏黑 38 | * @since 2022/7/23 16:51 39 | */ 40 | class DefaultItem(override val config: ConfigurationSection, override val group: Group?) : Item() { 41 | 42 | override val id = config.name 43 | 44 | override val display = config.getString("display") ?: "null" 45 | 46 | override val displayInstance = Zaphkiel.api().getItemManager().getDisplay(display) 47 | 48 | override val icon = parseIcon(config) 49 | 50 | override val iconLocked = config.contains("icon!!") 51 | 52 | override val name = parseName(config) 53 | 54 | override val nameLocked = config.contains("name!!") 55 | 56 | override val lore = parseLore(config) 57 | 58 | override val loreLocked = config.contains("lore!!") 59 | 60 | override val data = config.getConfigurationSection("data") ?: config.createSection("data") 61 | 62 | override val dataMapper = config.getMap("data-mapper").map { it.key.toString() to it.value.asList().joinToString("\n") }.toMap(HashMap()) 63 | 64 | override val model = config.getString("event.from")?.split(",")?.map { it.trim() }?.toMutableList() ?: arrayListOf() 65 | 66 | override val lockedData = getLockedData(HashMap(), data) 67 | 68 | override val eventVars = config.getConfigurationSection("event.data")?.getValues(false) ?: emptyMap() 69 | 70 | override val eventMap by unsafeLazy { 71 | val field = HashMap() 72 | if (model.isNotEmpty()) { 73 | model.forEach { 74 | val model = Zaphkiel.api().getItemManager().getModel(it) 75 | if (model != null) { 76 | field.putAll(parseEvent(this, model.config)) 77 | } else { 78 | severe("Model $it not found.") 79 | } 80 | } 81 | } else { 82 | field.putAll(parseEvent(this, config)) 83 | } 84 | field 85 | } 86 | 87 | override val meta = Zaphkiel.api().getItemLoader().loadMetaFromSection(config).toMutableList().also { 88 | it.addAll(displayInstance?.meta ?: emptyList()) 89 | } 90 | 91 | override val version = Configuration.empty(Type.YAML).run { 92 | set("value", config) 93 | if (displayInstance != null) { 94 | set("display.name", displayInstance.name) 95 | set("display.lore", displayInstance.lore) 96 | } 97 | saveToString().digest("sha-1") 98 | } 99 | 100 | val metadataList = ConcurrentHashMap>() 101 | 102 | override fun buildItemStack(player: Player?): ItemStack { 103 | return build(player).toItemStack(player) 104 | } 105 | 106 | override fun build(player: Player?): ItemStream { 107 | return build(player) {} 108 | } 109 | 110 | override fun build(player: Player?, prepareCallback: Consumer): ItemStream { 111 | val itemStream = DefaultItemStreamGenerated(icon.clone(), name.toMutableMap(), lore.toMutableMap()) 112 | val compound = itemStream.sourceCompound.computeIfAbsent("zaphkiel") { ItemTag() }.asCompound() 113 | compound[ItemKey.ID.key] = ItemTagData(id) 114 | compound[ItemKey.DATA.key] = Translator.toItemTag(ItemTag(), data) 115 | prepareCallback.accept(itemStream) 116 | return build(player, itemStream) 117 | } 118 | 119 | override fun build(player: Player?, itemStream: ItemStream): ItemStream { 120 | val pre = if (itemStream is DefaultItemStreamGenerated) { 121 | ItemBuildEvent.Pre(player, itemStream, itemStream.name, itemStream.lore) 122 | } else { 123 | ItemBuildEvent.Pre(player, itemStream, name.toMutableMap(), lore.toMutableMap()) 124 | } 125 | if (pre.call()) { 126 | // 设置数据 127 | lockedData.forEach { (k, v) -> itemStream.getZaphkielData().putDeep(k, v) } 128 | // 设置版本 129 | pre.itemStream.sourceCompound["zaphkiel"]!!.asCompound()[ItemKey.VERSION.key] = ItemTagData(version) 130 | // 替换 PlaceholderAPI 变量 131 | val placeholderReplaced = if (player != null) { 132 | val map = HashMap>() 133 | pre.lore.forEach { (key, lore) -> map[key] = lore.replacePlaceholder(player).toMutableList() } 134 | map 135 | } else null 136 | // 回调事件 137 | val post = ItemBuildEvent.Post(player, pre.itemStream, pre.name, placeholderReplaced ?: pre.lore) 138 | post.call() 139 | return post.itemStream 140 | } 141 | return itemStream 142 | } 143 | 144 | override fun isSimilar(itemStack: ItemStack): Boolean { 145 | if (itemStack.isAir()) return false 146 | return kotlin.runCatching { Zaphkiel.api().getItemHandler().getItemId(itemStack) == id }.getOrElse { false } 147 | } 148 | 149 | override fun hasItem(player: Player, amount: Int): Boolean { 150 | return player.inventory.hasItem(amount) { isSimilar(it) } 151 | } 152 | 153 | override fun takeItem(player: Player, amount: Int): Boolean { 154 | if (!hasItem(player, amount)) return false 155 | return player.inventory.takeItem(amount) { isSimilar(it) } 156 | } 157 | 158 | override fun giveItem(player: Player, amount: Int, overflow: Consumer>) { 159 | val event = ItemGiveEvent(player, build(player), amount).also { it.call() } 160 | if (!event.isCancelled) { 161 | val item = event.itemStream.rebuildToItemStack(player) 162 | item.amount = event.amount 163 | overflow.accept(player.inventory.addItem(item).values.toList()) 164 | } 165 | } 166 | 167 | override fun giveItemOrDrop(player: Player, amount: Int) { 168 | giveItem(player, amount) { it.forEach { item -> player.world.dropItem(player.location, item) } } 169 | } 170 | 171 | override fun invokeScript(key: List, event: PlayerEvent, itemStream: ItemStream, namespace: String): CompletableFuture? { 172 | val itemEvent = eventMap.entries.firstOrNull { it.key in key }?.value ?: return null 173 | if (itemEvent.isCancelled && event is Cancellable) { 174 | event.isCancelled = true 175 | } 176 | return itemEvent.invoke(event.player, event, itemStream, eventVars, namespace) 177 | } 178 | 179 | override fun invokeScript(key: List, player: Player?, event: Event, itemStream: ItemStream, namespace: String): CompletableFuture? { 180 | val itemEvent = eventMap.entries.firstOrNull { it.key in key }?.value ?: return null 181 | if (itemEvent.isCancelled && event is Cancellable) { 182 | event.isCancelled = true 183 | } 184 | return itemEvent.invoke(player, event, itemStream, eventVars, namespace) 185 | } 186 | 187 | fun getLockedData(map: MutableMap, section: ConfigurationSection, path: String = ""): MutableMap { 188 | section.getKeys(false).forEach { key -> 189 | if (key.endsWith("!!")) { 190 | map[path + key.substring(0, key.length - 2)] = Translator.toItemTag(config["data.$path$key"]) 191 | } else if (section.isConfigurationSection(key)) { 192 | getLockedData(map, section.getConfigurationSection(key)!!, "$path$key.") 193 | } 194 | } 195 | return map 196 | } 197 | 198 | override fun setMetadata(key: String, value: MetadataValue) { 199 | metadataList.computeIfAbsent(key) { ConcurrentHashMap() }[value.owningPlugin?.name ?: "null"] = value 200 | } 201 | 202 | override fun getMetadata(key: String): MutableList { 203 | return metadataList[key]?.values?.toMutableList() ?: mutableListOf() 204 | } 205 | 206 | override fun hasMetadata(key: String): Boolean { 207 | return metadataList.containsKey(key) && metadataList[key]?.isNotEmpty() == true 208 | } 209 | 210 | override fun removeMetadata(key: String, plugin: Plugin) { 211 | metadataList[key]?.remove(plugin.name) 212 | } 213 | 214 | override fun equals(other: Any?): Boolean { 215 | if (this === other) return true 216 | if (other !is DefaultItem) return false 217 | if (id != other.id) return false 218 | return true 219 | } 220 | 221 | override fun hashCode(): Int { 222 | return id.hashCode() 223 | } 224 | 225 | override fun toString(): String { 226 | return "DefaultItem(config=$config, group=$group, id='$id', display='$display', version='$version')" 227 | } 228 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultItemEvent.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.api.Item 4 | import ink.ptms.zaphkiel.api.ItemEvent 5 | import ink.ptms.zaphkiel.api.ItemStream 6 | import org.bukkit.entity.Player 7 | import org.bukkit.event.Event 8 | import taboolib.module.kether.KetherShell.eval 9 | import taboolib.module.kether.ScriptOptions 10 | import java.util.concurrent.CompletableFuture 11 | 12 | /** 13 | * Zaphkiel 14 | * ink.ptms.zaphkiel.impl.item.DefaultItemEvent 15 | * 16 | * @author 坏黑 17 | * @since 2022/7/23 17:09 18 | */ 19 | class DefaultItemEvent(item: Item, name: String, script: List, isCancelled: Boolean = false) : ItemEvent(item, name, script, isCancelled) { 20 | 21 | override fun invoke(player: Player?, event: Event, itemStream: ItemStream, data: Map, namespace: String): CompletableFuture { 22 | val future = CompletableFuture() 23 | val options = ScriptOptions.new { 24 | if (player != null) { 25 | sender(player) 26 | } 27 | namespace(listOf("zaphkiel", namespace)) 28 | vars(data) 29 | set("@ItemEvent", event) 30 | set("@ItemStream", itemStream) 31 | sandbox() 32 | detailError() 33 | } 34 | eval(script, options).thenRun { 35 | if (itemStream.signal.isNotEmpty()) { 36 | future.complete(ItemResult(itemStream.rebuildToItemStack(player))) 37 | } else { 38 | future.complete(null) 39 | } 40 | } 41 | return future 42 | } 43 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultItemStream.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.annotation.LegacyName 5 | import ink.ptms.zaphkiel.api.Item 6 | import ink.ptms.zaphkiel.api.ItemKey 7 | import ink.ptms.zaphkiel.api.ItemSignal 8 | import ink.ptms.zaphkiel.api.ItemStream 9 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 10 | import org.bukkit.entity.Player 11 | import org.bukkit.inventory.ItemStack 12 | import org.bukkit.metadata.MetadataValue 13 | import org.bukkit.plugin.Plugin 14 | import taboolib.common.util.unsafeLazy 15 | import taboolib.module.nms.* 16 | import taboolib.platform.util.isNotAir 17 | import java.util.concurrent.ConcurrentHashMap 18 | 19 | /** 20 | * Zaphkiel 21 | * ink.ptms.zaphkiel.impl.item.DefaultItemStream 22 | * 23 | * @author 坏黑 24 | * @since 2022/7/23 17:02 25 | */ 26 | open class DefaultItemStream(sourceItem: ItemStack, sourceCompound: ItemTag = sourceItem.getItemTag()) : ItemStream() { 27 | 28 | val metadataList = ConcurrentHashMap>() 29 | 30 | /** 是否锁定 */ 31 | private var isLocked = false 32 | 33 | override val sourceItem = sourceItem 34 | get() = if (isLocked) field.clone() else field 35 | 36 | override val sourceCompound = sourceCompound 37 | get() = if (isLocked) field.clone().asCompound() else field 38 | 39 | override val signal = hashSetOf() 40 | get() = if (isLocked) field.toHashSet() else field 41 | 42 | override val dropMeta by unsafeLazy { 43 | val metaItem = getZaphkielItem().meta 44 | val metaHistory = getZaphkielMetaHistory() 45 | metaHistory.filter { id -> metaItem.none { it.id == id } } 46 | } 47 | 48 | override fun isVanilla(): Boolean { 49 | return !isExtension() 50 | } 51 | 52 | override fun isExtension(): Boolean { 53 | val compound = getZaphkielCompound() ?: return false 54 | if (compound.containsKey(ItemKey.ID.key)) { 55 | return Zaphkiel.api().getItemManager().getItem(compound[ItemKey.ID.key]!!.asString()) != null 56 | } 57 | return false 58 | } 59 | 60 | override fun isOutdated(): Boolean { 61 | if (isVanilla()) { 62 | error("This item is not an extension item.") 63 | } 64 | return getZaphkielHash() != getZaphkielItem().version 65 | } 66 | 67 | override fun setDisplayName(displayName: String) { 68 | if (isLocked) { 69 | error("This item is locked.") 70 | } 71 | val display = sourceCompound.computeIfAbsent("display") { ItemTag() } as ItemTag 72 | display["Name"] = ItemTagData(displayName) 73 | } 74 | 75 | override fun setLore(lore: List) { 76 | if (isLocked) { 77 | error("This item is locked.") 78 | } 79 | val display = sourceCompound.computeIfAbsent("display") { ItemTag() } as ItemTag 80 | display["Lore"] = lore.map { ItemTagData(it) }.toCollection(ItemTagList()) 81 | } 82 | 83 | override fun rebuild(player: Player?): ItemStream { 84 | val item = getZaphkielItem() 85 | val itemStreamGenerated = DefaultItemStreamGenerated(sourceItem, item.name.toMutableMap(), item.lore.toMutableMap(), sourceCompound) 86 | // 继承 Metadata 列表 87 | itemStreamGenerated.metadataList += metadataList 88 | return item.build(player, itemStreamGenerated) 89 | } 90 | 91 | override fun rebuildToItemStack(player: Player?): ItemStack { 92 | // 若物品被损坏则跳过重构过程 93 | return if (ItemSignal.DURABILITY_DESTROYED in signal) toItemStack(player) else rebuild(player).toItemStack(player) 94 | } 95 | 96 | override fun toItemStack(player: Player?): ItemStack { 97 | if (sourceItem.isNotAir()) { 98 | val itemMeta = sourceItem.setItemTag(sourceCompound).itemMeta 99 | if (itemMeta != null) { 100 | val event = ItemReleaseEvent(sourceItem.type, sourceItem.durability.toInt(), itemMeta, this, player) 101 | event.call() 102 | sourceItem.type = event.icon 103 | sourceItem.itemMeta = event.itemMeta 104 | sourceItem.durability = event.data.toShort() 105 | } 106 | } 107 | val final = ItemReleaseEvent.Final(sourceItem.clone(), this, player) 108 | final.call() 109 | return final.itemStack 110 | } 111 | 112 | override fun getZaphkielItem(): Item { 113 | if (isVanilla()) { 114 | error("This item is not an extension item.") 115 | } 116 | return Zaphkiel.api().getItemManager().getItem(getZaphkielId())!! 117 | } 118 | 119 | @Deprecated("命名歧义", replaceWith = ReplaceWith("getZaphkielId()")) 120 | override fun getZaphkielName(): String { 121 | if (isVanilla()) { 122 | error("This item is not an extension item.") 123 | } 124 | return getZaphkielCompound()!![ItemKey.ID.key]!!.asString() 125 | } 126 | 127 | @Deprecated("命名歧义", replaceWith = ReplaceWith("getZaphkielHash()")) 128 | @LegacyName("getZaphkielHash") 129 | override fun getZaphkielVersion(): String { 130 | if (isVanilla()) { 131 | error("This item is not an extension item.") 132 | } 133 | return getZaphkielCompound()!![ItemKey.VERSION.key]!!.asString() 134 | } 135 | 136 | override fun getZaphkielData(): ItemTag { 137 | if (isVanilla()) { 138 | error("This item is not an extension item.") 139 | } 140 | return getZaphkielCompound()!![ItemKey.DATA.key]!!.asCompound() 141 | } 142 | 143 | override fun getZaphkielUniqueData(): ItemTag? { 144 | if (isVanilla()) { 145 | error("This item is not an extension item.") 146 | } 147 | return getZaphkielCompound()!![ItemKey.UNIQUE.key]?.asCompound() 148 | } 149 | 150 | override fun getZaphkielMetaHistory(): List { 151 | if (isVanilla()) { 152 | error("This item is not an extension item.") 153 | } 154 | return getZaphkielCompound()!![ItemKey.META_HISTORY.key]?.asList()?.map { it.asString() }?.toList() ?: emptyList() 155 | } 156 | 157 | override fun setZaphkielMetaHistory(meta: List) { 158 | if (isVanilla()) { 159 | error("This item is not extension item.") 160 | } 161 | if (isLocked) { 162 | error("This item is locked.") 163 | } 164 | getZaphkielCompound()!![ItemKey.META_HISTORY.key] = ItemTagList.of(*meta.map { ItemTagData(it) }.toTypedArray()) 165 | } 166 | 167 | override fun getZaphkielCompound(): ItemTag? { 168 | return sourceCompound[ItemKey.ROOT.key]?.asCompound()?.let { if (isLocked) it.clone().asCompound() else it } 169 | } 170 | 171 | override fun setMetadata(key: String, value: MetadataValue) { 172 | metadataList.computeIfAbsent(key) { ConcurrentHashMap() }[value.owningPlugin?.name ?: "null"] = value 173 | } 174 | 175 | override fun getMetadata(key: String): MutableList { 176 | return metadataList[key]?.values?.toMutableList() ?: mutableListOf() 177 | } 178 | 179 | override fun hasMetadata(key: String): Boolean { 180 | return metadataList.containsKey(key) && metadataList[key]?.isNotEmpty() == true 181 | } 182 | 183 | override fun removeMetadata(key: String, plugin: Plugin) { 184 | metadataList[key]?.remove(plugin.name) 185 | } 186 | 187 | override fun lock(value: Boolean) { 188 | isLocked = value 189 | } 190 | 191 | override fun isLocked(): Boolean { 192 | return isLocked 193 | } 194 | 195 | override fun equals(other: Any?): Boolean { 196 | if (this === other) return true 197 | if (other !is DefaultItemStream) return false 198 | if (sourceCompound != other.sourceCompound) return false 199 | return true 200 | } 201 | 202 | override fun hashCode(): Int { 203 | return sourceCompound.hashCode() 204 | } 205 | 206 | override fun toString(): String { 207 | return "DefaultItemStream(sourceItem=$sourceItem, sourceCompound=$sourceCompound, signal=$signal, dropMeta=$dropMeta)" 208 | } 209 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultItemStreamGenerated.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import org.bukkit.inventory.ItemStack 4 | import taboolib.module.nms.ItemTag 5 | import taboolib.module.nms.getItemTag 6 | 7 | /** 8 | * @author sky 9 | * @since 2019-12-26 10:59 10 | */ 11 | class DefaultItemStreamGenerated( 12 | itemStack: ItemStack, 13 | val name: MutableMap, 14 | val lore: MutableMap>, 15 | compound: ItemTag = itemStack.getItemTag(), 16 | ) : DefaultItemStream(itemStack, compound) { 17 | 18 | override fun equals(other: Any?): Boolean { 19 | if (this === other) return true 20 | if (other !is DefaultItemStreamGenerated) return false 21 | if (!super.equals(other)) return false 22 | if (name != other.name) return false 23 | if (lore != other.lore) return false 24 | return true 25 | } 26 | 27 | override fun hashCode(): Int { 28 | var result = super.hashCode() 29 | result = 31 * result + name.hashCode() 30 | result = 31 * result + lore.hashCode() 31 | return result 32 | } 33 | 34 | override fun toString(): String { 35 | return "ItemStreamBuilder(name=$name, lore=$lore)" 36 | } 37 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultSerializedItem.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import com.google.gson.JsonObject 4 | import ink.ptms.zaphkiel.api.SerializedItem 5 | 6 | /** 7 | * Zaphkiel 8 | * ink.ptms.zaphkiel.impl.item.DefaultSerializedItem 9 | * 10 | * @author 坏黑 11 | * @since 2022/7/23 17:36 12 | */ 13 | data class DefaultSerializedItem( 14 | override val id: String, 15 | override val amount: Int, 16 | override val data: JsonObject?, 17 | override val uniqueData: SerializedItem.UniqueData?, 18 | ) : SerializedItem { 19 | 20 | override fun toMap(): Map { 21 | val map = hashMapOf() 22 | map["id"] = id 23 | map["amount"] = amount 24 | if (data != null && data.size() > 0) { 25 | map["data"] = jsonObjectToMap(data) 26 | } 27 | if (uniqueData != null) { 28 | map["unique"] = uniqueData.toMap() 29 | } 30 | return map 31 | } 32 | 33 | override fun toJson(): String { 34 | return toJsonObject().toString() 35 | } 36 | 37 | override fun toJsonObject(): JsonObject { 38 | val json = JsonObject() 39 | json.addProperty("id", id) 40 | json.addProperty("amount", amount) 41 | if (data != null && data.size() > 0) { 42 | json.add("data", data) 43 | } 44 | if (uniqueData != null) { 45 | json.add("unique", uniqueData.toJsonObject()) 46 | } 47 | return json 48 | } 49 | 50 | data class UniqueData(override val player: String?, override val date: Long, override val uuid: String) : SerializedItem.UniqueData { 51 | 52 | override fun toMap(): Map { 53 | val map = hashMapOf() 54 | if (player != null) { 55 | map["player"] = player 56 | } 57 | map["date"] = date 58 | map["uuid"] = uuid 59 | return map 60 | } 61 | 62 | override fun toJson(): String { 63 | return toJsonObject().toString() 64 | } 65 | 66 | override fun toJsonObject(): JsonObject { 67 | val json = JsonObject() 68 | if (player != null) { 69 | json.addProperty("player", player) 70 | } 71 | json.addProperty("date", date) 72 | json.addProperty("uuid", uuid) 73 | return json 74 | } 75 | } 76 | 77 | companion object { 78 | 79 | fun jsonObjectToMap(json: JsonObject): Map { 80 | val map = hashMapOf() 81 | json.entrySet().forEach { (k, v) -> 82 | map[k] = when { 83 | v.isJsonPrimitive -> v.asString 84 | v.isJsonArray -> v.asJsonArray.map { it.asString } 85 | v.isJsonObject -> jsonObjectToMap(v.asJsonObject) 86 | else -> error("unsupported type: ${v::class.java}") 87 | } 88 | } 89 | return map 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultStructureList.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.api.StructureList 4 | import taboolib.common.util.VariableReader 5 | 6 | /** 7 | * Zaphkiel 8 | * ink.ptms.zaphkiel.impl.item.DefaultStructureList 9 | * 10 | * @author 坏黑 11 | * @since 2022/7/23 17:24 12 | */ 13 | class DefaultStructureList(source: List) : StructureList { 14 | 15 | val cache = source.map { VariableReader("<", ">").readToFlatten(it) }.toList() 16 | 17 | override fun build(vars: Map>, trim: Boolean): List { 18 | val newVars = vars.mapValues { it.value.toMutableList() } 19 | val out = arrayListOf() 20 | val cache = cache.toMutableList() 21 | while (cache.isNotEmpty()) { 22 | var skip = false 23 | var pass = false 24 | val builder = StringBuilder() 25 | cache[0].forEach { variable -> 26 | if (variable.isVariable) { 27 | if (variable.text.endsWith("...")) { 28 | val list = newVars[variable.text.substring(0, variable.text.length - 3)] 29 | // 对应变量不存在 30 | if (list.isNullOrEmpty()) { 31 | pass = true 32 | return@forEach 33 | } 34 | // 移除第一个添加 35 | if (list.isNotEmpty()) { 36 | builder.append(list.removeAt(0)) 37 | } 38 | // 如果还存在,则继续 39 | if (list.isNotEmpty()) { 40 | skip = true 41 | } 42 | } else { 43 | builder.append(newVars[variable.text]?.firstOrNull() ?: "") 44 | } 45 | } else { 46 | builder.append(variable.text) 47 | } 48 | } 49 | if (!skip) { 50 | cache.removeAt(0) 51 | } 52 | if (!pass) { 53 | out.add(builder.toString()) 54 | } 55 | } 56 | return out 57 | } 58 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/item/DefaultStructureSingle.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.api.StructureSingle 4 | import taboolib.common.util.VariableReader 5 | 6 | /** 7 | * Zaphkiel 8 | * ink.ptms.zaphkiel.impl.item.DefaultStructureSingle 9 | * 10 | * @author 坏黑 11 | * @since 2022/7/23 17:24 12 | */ 13 | class DefaultStructureSingle(source: String) : StructureSingle { 14 | 15 | val cache = VariableReader("<", ">").readToFlatten(source) 16 | 17 | override fun build(vars: Map, trim: Boolean): String { 18 | val value = cache.joinToString("") { if (it.isVariable) vars[it.text] ?: "" else it.text } 19 | return if (trim) value.trim() else value 20 | } 21 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaAttribute.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.attribute.AttributeModifier 5 | import org.bukkit.entity.Player 6 | import org.bukkit.inventory.EquipmentSlot 7 | import org.bukkit.inventory.meta.ItemMeta 8 | import org.bukkit.util.NumberConversions 9 | import taboolib.common5.Coerce 10 | import taboolib.library.configuration.ConfigurationSection 11 | import taboolib.module.nms.* 12 | import taboolib.type.BukkitEquipment 13 | import java.util.* 14 | 15 | @MetaKey("attribute") 16 | class MetaAttribute(root: ConfigurationSection) : Meta(root) { 17 | 18 | val attributeListLegacy = ItemTagList() 19 | val attributeList = ArrayList>() 20 | 21 | init { 22 | root.getConfigurationSection("meta.attribute")?.getKeys(false)?.forEach { hand -> 23 | root.getConfigurationSection("meta.attribute.$hand")!!.getKeys(false).forEach { name -> 24 | val attributeKey = BukkitAttribute.parse(name) 25 | if (attributeKey != null) { 26 | if (MinecraftVersion.majorLegacy >= 11600) { 27 | var equipmentSlot: EquipmentSlot? = null 28 | if (hand != "all") { 29 | equipmentSlot = BukkitEquipment.fromString(hand)?.bukkit 30 | } 31 | val amount: Double 32 | val operation: AttributeModifier.Operation 33 | val attributeValue = root.getString("meta.attribute.$hand.$name")!! 34 | if (attributeValue.endsWith("%")) { 35 | amount = Coerce.toDouble(attributeValue.substring(0, attributeValue.length - 1)) / 100.0 36 | operation = AttributeModifier.Operation.ADD_SCALAR 37 | } else { 38 | amount = Coerce.toDouble(attributeValue) 39 | operation = AttributeModifier.Operation.ADD_NUMBER 40 | } 41 | val modifier = if (equipmentSlot != null) { 42 | AttributeModifier(UUID.randomUUID(), "zaphkiel", amount, operation, equipmentSlot) 43 | } else { 44 | AttributeModifier(UUID.randomUUID(), "zaphkiel", amount, operation) 45 | } 46 | org.bukkit.attribute.Attribute.GENERIC_ATTACK_SPEED 47 | attributeList.add(attributeKey.toBukkit() to modifier) 48 | } else { 49 | try { 50 | val uuid = UUID.randomUUID() 51 | val attribute = ItemTag() 52 | val attributeValue = root.getString("meta.attribute.$hand.$name")!! 53 | if (attributeValue.endsWith("%")) { 54 | attribute["Amount"] = ItemTagData(NumberConversions.toDouble(attributeValue.substring(0, attributeValue.length - 1)) / 100.0) 55 | attribute["Operation"] = ItemTagData(1) 56 | } else { 57 | attribute["Amount"] = ItemTagData(NumberConversions.toDouble(attributeValue)) 58 | attribute["Operation"] = ItemTagData(0) 59 | } 60 | attribute["AttributeName"] = ItemTagData(attributeKey.minecraftKey) 61 | attribute["UUIDMost"] = ItemTagData(uuid.mostSignificantBits) 62 | attribute["UUIDLeast"] = ItemTagData(uuid.leastSignificantBits) 63 | attribute["Name"] = ItemTagData(attributeKey.minecraftKey) 64 | if (hand != "all") { 65 | BukkitEquipment.fromString(hand)?.run { attribute["Slot"] = ItemTagData(nms) } 66 | } 67 | attributeListLegacy.add(attribute) 68 | } catch (t: Throwable) { 69 | t.printStackTrace() 70 | } 71 | } 72 | } 73 | } 74 | } 75 | } 76 | 77 | override val id: String 78 | get() = "attribute" 79 | 80 | override fun build(player: Player?, compound: ItemTag) { 81 | if (MinecraftVersion.majorLegacy < 11600) { 82 | compound["AttributeModifiers"] = attributeListLegacy 83 | } else { 84 | compound.remove("AttributeModifiers") 85 | } 86 | } 87 | 88 | override fun build(itemMeta: ItemMeta) { 89 | if (MinecraftVersion.majorLegacy >= 11600) { 90 | val modifiers = itemMeta.attributeModifiers 91 | attributeList.forEach { 92 | // Cannot register AttributeModifier. Modifier is already applied! 93 | if (modifiers == null || modifiers.values().none { a -> a.uniqueId == it.second.uniqueId }) { 94 | itemMeta.addAttributeModifier(it.first, it.second) 95 | } 96 | } 97 | } 98 | } 99 | 100 | override fun drop(player: Player?, compound: ItemTag) { 101 | compound.remove("AttributeModifiers") 102 | } 103 | 104 | override fun toString(): String { 105 | return "MetaAttribute(attributeList=$attributeListLegacy)" 106 | } 107 | 108 | fun toArray(uuid: UUID): IntArray { 109 | return toArray(uuid.mostSignificantBits, uuid.leastSignificantBits) 110 | } 111 | 112 | fun toArray(m: Long, l: Long): IntArray { 113 | return intArrayOf((m shr 32).toInt(), m.toInt(), (l shr 32).toInt(), l.toInt()) 114 | } 115 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaCanDestroy.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.entity.Player 5 | import taboolib.common.util.asList 6 | import taboolib.library.configuration.ConfigurationSection 7 | import taboolib.module.nms.ItemTag 8 | import taboolib.module.nms.ItemTagList 9 | 10 | @MetaKey("can-destroy") 11 | class MetaCanDestroy(root: ConfigurationSection) : Meta(root) { 12 | 13 | val canDestroy = root["meta.can-destroy"]?.asList() 14 | 15 | override val id: String 16 | get() = "can-destroy" 17 | 18 | override fun build(player: Player?, compound: ItemTag) { 19 | if (canDestroy == null || compound.containsKey("CanDestroy")) { 20 | return 21 | } 22 | compound.putDeep("CanDestroy", ItemTagList.of(*canDestroy.toTypedArray())) 23 | } 24 | 25 | override fun drop(player: Player?, compound: ItemTag) { 26 | compound.remove("CanDestroy") 27 | } 28 | 29 | override fun toString(): String { 30 | return "MetaCanDestroy(canDestroy=$canDestroy)" 31 | } 32 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaCanPlaceOn.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.entity.Player 5 | import taboolib.common.util.asList 6 | import taboolib.library.configuration.ConfigurationSection 7 | import taboolib.module.nms.ItemTag 8 | import taboolib.module.nms.ItemTagList 9 | 10 | @MetaKey("can-place-on") 11 | class MetaCanPlaceOn(root: ConfigurationSection) : Meta(root) { 12 | 13 | val canPlaceOn = root["meta.can-place-on"]?.asList() 14 | 15 | override val id: String 16 | get() = "can-place-on" 17 | 18 | override fun build(player: Player?, compound: ItemTag) { 19 | if (canPlaceOn == null || compound.containsKey("CanPlaceOn")) { 20 | return 21 | } 22 | compound.putDeep("CanPlaceOn", ItemTagList.of(*canPlaceOn.toTypedArray())) 23 | } 24 | 25 | override fun drop(player: Player?, compound: ItemTag) { 26 | compound.remove("CanPlaceOn") 27 | } 28 | 29 | override fun toString(): String { 30 | return "MetaCanPlaceOn(canPlaceOn=$canPlaceOn)" 31 | } 32 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaColor.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.Color 5 | import org.bukkit.inventory.meta.ItemMeta 6 | import org.bukkit.inventory.meta.LeatherArmorMeta 7 | import org.bukkit.inventory.meta.PotionMeta 8 | import taboolib.common5.Coerce 9 | import taboolib.library.configuration.ConfigurationSection 10 | 11 | @MetaKey("color") 12 | class MetaColor(root: ConfigurationSection) : Meta(root) { 13 | 14 | val color = root.getString("meta.color")?.split("-")?.run { 15 | Color.fromRGB(Coerce.toInteger(getOrElse(0) { 0 }), Coerce.toInteger(getOrElse(1) { 0 }), Coerce.toInteger(getOrElse(2) { 0 })) 16 | } 17 | 18 | override val id: String 19 | get() = "color" 20 | 21 | override fun build(itemMeta: ItemMeta) { 22 | if (itemMeta is PotionMeta) { 23 | itemMeta.color = color ?: return 24 | } else if (itemMeta is LeatherArmorMeta) { 25 | itemMeta.setColor(color ?: return) 26 | } 27 | } 28 | 29 | override fun drop(itemMeta: ItemMeta) { 30 | if (itemMeta is PotionMeta) { 31 | itemMeta.color = null 32 | } else if (itemMeta is LeatherArmorMeta) { 33 | itemMeta.setColor(null) 34 | } 35 | } 36 | 37 | override fun toString(): String { 38 | return "MetaColor(color=$color)" 39 | } 40 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaCustomModelData.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.inventory.meta.ItemMeta 5 | import taboolib.library.configuration.ConfigurationSection 6 | 7 | @MetaKey("custom-model-data") 8 | class MetaCustomModelData(root: ConfigurationSection) : Meta(root) { 9 | 10 | val data = root.getInt("meta.custom-model-data") 11 | 12 | override val id: String 13 | get() = "custom-model-data" 14 | 15 | override fun build(itemMeta: ItemMeta) { 16 | itemMeta.setCustomModelData(data) 17 | } 18 | 19 | override fun drop(itemMeta: ItemMeta) { 20 | itemMeta.setCustomModelData(null) 21 | } 22 | 23 | override fun toString(): String { 24 | return "MetaCustomModel(data=$data)" 25 | } 26 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaData.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 4 | import ink.ptms.zaphkiel.item.meta.Meta 5 | import taboolib.library.configuration.ConfigurationSection 6 | 7 | @MetaKey("data") 8 | class MetaData(root: ConfigurationSection) : Meta(root) { 9 | 10 | val data = root.getInt("meta.data") 11 | 12 | override val id: String 13 | get() = "data" 14 | 15 | override fun build(itemReleaseEvent: ItemReleaseEvent) { 16 | itemReleaseEvent.data = data 17 | } 18 | 19 | override fun drop(itemReleaseEvent: ItemReleaseEvent) { 20 | itemReleaseEvent.data = 0 21 | } 22 | 23 | override fun toString(): String { 24 | return "MetaData(data=$data)" 25 | } 26 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaEnchantment.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.enchantments.Enchantment 5 | import org.bukkit.inventory.meta.EnchantmentStorageMeta 6 | import org.bukkit.inventory.meta.ItemMeta 7 | import org.bukkit.util.NumberConversions 8 | import taboolib.library.configuration.ConfigurationSection 9 | 10 | @MetaKey("enchantment") 11 | class MetaEnchantment(root: ConfigurationSection) : Meta(root) { 12 | 13 | val enchants = root.getConfigurationSection("meta.enchantment")?.getValues(false) 14 | ?.map { Pair(Enchantment.getByName(it.key), NumberConversions.toInt(it.value)) } 15 | ?.filter { it.first != null } 16 | ?.toMap() 17 | 18 | override val id: String 19 | get() = "enchantment" 20 | 21 | override fun build(itemMeta: ItemMeta) { 22 | if (itemMeta is EnchantmentStorageMeta) { 23 | enchants?.forEach { (enchant, level) -> itemMeta.addStoredEnchant(enchant!!, level, true) } 24 | } else { 25 | enchants?.forEach { (enchant, level) -> itemMeta.addEnchant(enchant!!, level, true) } 26 | } 27 | } 28 | 29 | override fun drop(itemMeta: ItemMeta) { 30 | if (itemMeta is EnchantmentStorageMeta) { 31 | itemMeta.storedEnchants.toMap().forEach { itemMeta.removeStoredEnchant(it.key) } 32 | } else { 33 | itemMeta.enchants.toMap().forEach { itemMeta.removeEnchant(it.key) } 34 | } 35 | } 36 | 37 | override fun toString(): String { 38 | return "MetaEnchantment(enchants=$enchants)" 39 | } 40 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaIcon.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 4 | import ink.ptms.zaphkiel.item.meta.Meta 5 | import org.bukkit.Material 6 | import taboolib.library.configuration.ConfigurationSection 7 | import taboolib.library.xseries.parseToMaterial 8 | 9 | @MetaKey("icon") 10 | class MetaIcon(root: ConfigurationSection) : Meta(root) { 11 | 12 | val icon = root.getString("meta.icon")?.run { parseToMaterial() } ?: Material.STONE 13 | 14 | override val id: String 15 | get() = "icon" 16 | 17 | override fun build(itemReleaseEvent: ItemReleaseEvent) { 18 | itemReleaseEvent.icon = icon 19 | } 20 | 21 | override fun drop(itemReleaseEvent: ItemReleaseEvent) { 22 | itemReleaseEvent.icon = itemReleaseEvent.item.icon.type 23 | } 24 | 25 | override fun toString(): String { 26 | return "MetaIcon(icon=$icon)" 27 | } 28 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaItemFlag.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.inventory.ItemFlag 5 | import org.bukkit.inventory.meta.ItemMeta 6 | import taboolib.library.configuration.ConfigurationSection 7 | 8 | @MetaKey("itemflag") 9 | class MetaItemFlag(root: ConfigurationSection) : Meta(root) { 10 | 11 | val itemflag = root.getStringList("meta.itemflag") 12 | .mapNotNull { kotlin.runCatching { ItemFlag.valueOf(it.uppercase()) }.getOrNull() } 13 | .toSet() 14 | .toTypedArray() 15 | 16 | override val id: String 17 | get() = "itemflag" 18 | 19 | override fun build(itemMeta: ItemMeta) { 20 | itemMeta.addItemFlags(*itemflag) 21 | } 22 | 23 | override fun drop(itemMeta: ItemMeta) { 24 | itemMeta.removeItemFlags(*ItemFlag.values()) 25 | } 26 | 27 | override fun toString(): String { 28 | return "MetaItemflag(itemflag=${itemflag.contentToString()})" 29 | } 30 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaKey.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | annotation class MetaKey(val value: String) -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaNative.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.entity.Player 5 | import taboolib.library.configuration.ConfigurationSection 6 | import taboolib.module.nms.ItemTag 7 | import taboolib.module.nms.ItemTagData 8 | 9 | @MetaKey("native") 10 | class MetaNative(root: ConfigurationSection) : Meta(root) { 11 | 12 | val nativeTag = ItemTag().also { nbt -> 13 | root.getConfigurationSection("meta.native")?.run { 14 | getValues(false).forEach { 15 | nbt[it.key] = ItemTagData.toNBT(it.value) 16 | } 17 | } 18 | } 19 | 20 | override val id: String 21 | get() = "native" 22 | 23 | override fun build(player: Player?, compound: ItemTag) { 24 | nativeTag.forEach { t, u -> compound[t] = u } 25 | } 26 | 27 | override fun toString(): String { 28 | return "MetaNative(nativeNBT=$nativeTag)" 29 | } 30 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaPotion.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.inventory.meta.ItemMeta 5 | import org.bukkit.inventory.meta.PotionMeta 6 | import org.bukkit.potion.PotionData 7 | import org.bukkit.potion.PotionEffect 8 | import org.bukkit.potion.PotionEffectType 9 | import org.bukkit.potion.PotionType 10 | import taboolib.common.platform.function.warning 11 | import taboolib.common5.Coerce 12 | import taboolib.library.configuration.ConfigurationSection 13 | import java.util.* 14 | 15 | @MetaKey("potion") 16 | class MetaPotion(root: ConfigurationSection) : Meta(root) { 17 | 18 | val base = root.getString("meta.potion.base") 19 | val potions = root.getConfigurationSection("meta.potion")?.getValues(false) 20 | ?.filter { PotionEffectType.getByName(it.key) != null } 21 | ?.map { 22 | PotionEffect( 23 | PotionEffectType.getByName(it.key)!!, 24 | Coerce.toInteger(it.value.toString().split("-")[0]), 25 | Coerce.toInteger(it.value.toString().split("-").getOrElse(1) { 0 }) 26 | ) 27 | }?.toList() 28 | 29 | override val id: String 30 | get() = "potion" 31 | 32 | override fun build(itemMeta: ItemMeta) { 33 | if (itemMeta is PotionMeta) { 34 | if (base != null) { 35 | try { 36 | itemMeta.basePotionData = PotionData(PotionType.valueOf(base.uppercase(Locale.getDefault()))) 37 | } catch (ignored: Throwable) { 38 | warning("Unknown base potion: $base") 39 | } 40 | } 41 | potions?.forEach { itemMeta.addCustomEffect(it, true) } 42 | } 43 | } 44 | 45 | override fun drop(itemMeta: ItemMeta) { 46 | if (itemMeta is PotionMeta) { 47 | itemMeta.basePotionData = PotionData(PotionType.WATER) 48 | itemMeta.clearCustomEffects() 49 | } 50 | } 51 | 52 | override fun toString(): String { 53 | return "MetaPotion(potions=$potions)" 54 | } 55 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaShiny.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.enchantments.Enchantment 5 | import org.bukkit.inventory.ItemFlag 6 | import org.bukkit.inventory.meta.ItemMeta 7 | import taboolib.library.configuration.ConfigurationSection 8 | 9 | /** 10 | * @author Administrator 11 | * @since 2019-12-26 17:12 12 | */ 13 | @MetaKey("shiny") 14 | class MetaShiny(root: ConfigurationSection) : Meta(root) { 15 | 16 | val shiny = root.getBoolean("meta.shiny") 17 | 18 | override val id: String 19 | get() = "shiny" 20 | 21 | override fun build(itemMeta: ItemMeta) { 22 | if (shiny) { 23 | itemMeta.addEnchant(Enchantment.ARROW_DAMAGE, 1, true) 24 | itemMeta.addItemFlags(ItemFlag.HIDE_ENCHANTS) 25 | } 26 | } 27 | 28 | override fun drop(itemMeta: ItemMeta) { 29 | itemMeta.removeEnchant(Enchantment.ARROW_DAMAGE) 30 | itemMeta.removeItemFlags(ItemFlag.HIDE_ENCHANTS) 31 | } 32 | 33 | override fun toString(): String { 34 | return "MetaShiny(shiny=$shiny)" 35 | } 36 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaSkull.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import com.mojang.authlib.GameProfile 4 | import com.mojang.authlib.properties.Property 5 | import ink.ptms.zaphkiel.item.meta.Meta 6 | import me.arcaniax.hdb.api.HeadDatabaseAPI 7 | import org.bukkit.inventory.meta.ItemMeta 8 | import org.bukkit.inventory.meta.SkullMeta 9 | import taboolib.common.platform.event.OptionalEvent 10 | import taboolib.common.platform.event.SubscribeEvent 11 | import taboolib.common.platform.function.warning 12 | import taboolib.common.reflect.Reflex.Companion.getProperty 13 | import taboolib.common.reflect.Reflex.Companion.setProperty 14 | import taboolib.library.configuration.ConfigurationSection 15 | import java.util.* 16 | 17 | /** 18 | * @author Administrator 19 | * @since 2019-12-26 17:12 20 | */ 21 | @MetaKey("skull") 22 | class MetaSkull(root: ConfigurationSection) : Meta(root) { 23 | 24 | val skullOwner = root.getString("meta.skull.owner") 25 | 26 | val skullTexture = if (root.contains("meta.skull.textures")) { 27 | SkullTexture(root.getString("meta.skull.textures.value").toString(), root.getString("meta.skull.textures.id")) 28 | } else null 29 | 30 | val skullHeadDatabase = root.getString("meta.skull.head-database") 31 | 32 | override val id: String 33 | get() = "skull" 34 | 35 | override fun build(itemMeta: ItemMeta) { 36 | if (itemMeta is SkullMeta) { 37 | if (skullOwner != null) { 38 | itemMeta.owner = skullOwner 39 | } 40 | if (skullTexture != null) { 41 | itemMeta.setProperty("profile", GameProfile(skullTexture.uuid, null).also { 42 | it.properties.put("textures", Property("textures", skullTexture.textures)) 43 | }) 44 | } 45 | if (skullHeadDatabase != null) { 46 | if (HeadDatabaseAPI.headDatabaseLoaded) { 47 | val api = HeadDatabaseAPI() 48 | val itemHead = api.getItemHead(skullHeadDatabase) 49 | if (itemHead != null) { 50 | val profile = itemHead.itemMeta!!.getProperty("profile")!! 51 | itemMeta.setProperty("profile", GameProfile(profile.id, null).also { 52 | it.properties.put("textures", profile.properties.get("textures") as Property) 53 | }) 54 | } 55 | } else { 56 | warning("HeadDatabase is not loaded") 57 | } 58 | } 59 | } 60 | } 61 | 62 | override fun drop(itemMeta: ItemMeta) { 63 | if (itemMeta is SkullMeta) { 64 | itemMeta.owner = null 65 | itemMeta.setProperty("profile", null) 66 | } 67 | } 68 | 69 | override fun toString(): String { 70 | return "MetaSkull(owner=$skullOwner, texture=$skullTexture)" 71 | } 72 | 73 | class SkullTexture(val textures: String, uuid: String?) { 74 | 75 | val uuid: UUID = if (uuid != null) UUID.fromString(uuid) else UUID.randomUUID() 76 | } 77 | 78 | internal object HeadDatabaseAPI { 79 | 80 | var headDatabaseLoaded = false 81 | private set 82 | 83 | @SubscribeEvent(bind = "me.arcaniax.hdb.api.DatabaseLoadEvent") 84 | fun e(e: OptionalEvent) { 85 | headDatabaseLoaded = true 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaSpawner.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.entity.EntityType 5 | import org.bukkit.inventory.meta.ItemMeta 6 | import org.bukkit.inventory.meta.SpawnEggMeta 7 | import taboolib.library.configuration.ConfigurationSection 8 | 9 | /** 10 | * @author Administrator 11 | * @since 2019-12-26 17:12 12 | */ 13 | @MetaKey("spawner") 14 | class MetaSpawner(root: ConfigurationSection) : Meta(root) { 15 | 16 | val type = root.getString("meta.spawner").toString() 17 | 18 | override val id: String 19 | get() = "spawner" 20 | 21 | override fun build(itemMeta: ItemMeta) { 22 | if (itemMeta is SpawnEggMeta) { 23 | itemMeta.spawnedType = kotlin.runCatching { EntityType.valueOf(type.uppercase()) }.getOrElse { EntityType.VILLAGER } 24 | } 25 | } 26 | 27 | override fun drop(itemMeta: ItemMeta) { 28 | } 29 | 30 | override fun toString(): String { 31 | return "MetaSpawnerEgg(type='$type')" 32 | } 33 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaTiphareth.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.tiphareth.TipharethAPI 4 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 5 | import ink.ptms.zaphkiel.item.meta.Meta 6 | import taboolib.library.configuration.ConfigurationSection 7 | 8 | @Suppress("SpellCheckingInspection") 9 | @MetaKey("tiphareth") 10 | class MetaTiphareth(root: ConfigurationSection) : Meta(root) { 11 | 12 | val tiphareth = root.getString("meta.tiphareth")?.run { TipharethAPI.LOADER.getByName(this)?.buildItem() } 13 | 14 | override val id: String 15 | get() = "tiphareth" 16 | 17 | override fun build(itemReleaseEvent: ItemReleaseEvent) { 18 | if (tiphareth != null) { 19 | itemReleaseEvent.icon = tiphareth.type 20 | itemReleaseEvent.itemMeta.setCustomModelData(tiphareth.itemMeta!!.customModelData) 21 | } 22 | } 23 | 24 | override fun drop(itemReleaseEvent: ItemReleaseEvent) { 25 | itemReleaseEvent.icon = itemReleaseEvent.item.icon.type 26 | itemReleaseEvent.itemMeta.setCustomModelData(null) 27 | } 28 | 29 | override fun toString(): String { 30 | return "MetaTiphareth(tiphareth=$tiphareth)" 31 | } 32 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaUnbreakable.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.inventory.meta.ItemMeta 5 | import taboolib.library.configuration.ConfigurationSection 6 | 7 | @MetaKey("unbreakable") 8 | class MetaUnbreakable(root: ConfigurationSection) : Meta(root) { 9 | 10 | val unbreakable = root.getBoolean("meta.unbreakable") 11 | 12 | override val id: String 13 | get() = "unbreakable" 14 | 15 | override fun build(itemMeta: ItemMeta) { 16 | itemMeta.isUnbreakable = unbreakable 17 | } 18 | 19 | override fun drop(itemMeta: ItemMeta) { 20 | itemMeta.isUnbreakable = false 21 | } 22 | 23 | override fun toString(): String { 24 | return "MetaUnbreakable(unbreakable=$unbreakable)" 25 | } 26 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/kotlin/ink/ptms/zaphkiel/impl/meta/MetaUnique.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.meta 2 | 3 | import ink.ptms.zaphkiel.api.ItemKey 4 | import ink.ptms.zaphkiel.item.meta.Meta 5 | import org.apache.commons.lang3.time.DateFormatUtils 6 | import org.bukkit.entity.Player 7 | import taboolib.library.configuration.ConfigurationSection 8 | import taboolib.module.nms.ItemTag 9 | import taboolib.module.nms.ItemTagData 10 | import java.util.* 11 | 12 | @MetaKey("unique") 13 | class MetaUnique(root: ConfigurationSection) : Meta(root) { 14 | 15 | val unique = root.getBoolean("meta.unique") 16 | 17 | override val id: String 18 | get() = "unique" 19 | 20 | override fun build(player: Player?, compound: ItemTag) { 21 | val base = compound["zaphkiel"]!!.asCompound() 22 | if (unique) { 23 | if (!base.containsKey(ItemKey.UNIQUE.key)) { 24 | val unique = ItemTag() 25 | if (player != null) { 26 | unique["player"] = ItemTagData(player.name) 27 | } 28 | unique["date"] = ItemTagData(System.currentTimeMillis()) 29 | unique["date-formatted"] = ItemTagData(DateFormatUtils.format(System.currentTimeMillis(), FORMAT)) 30 | unique["uuid"] = ItemTagData(UUID.randomUUID().toString()) 31 | base[ItemKey.UNIQUE.key] = unique 32 | } 33 | } else { 34 | base.remove(ItemKey.UNIQUE.key) 35 | } 36 | } 37 | 38 | override fun drop(player: Player?, compound: ItemTag) { 39 | compound.removeDeep("zaphkiel.${ItemKey.UNIQUE}") 40 | } 41 | 42 | override fun toString(): String { 43 | return "MetaUnique(unique=$unique)" 44 | } 45 | 46 | companion object { 47 | 48 | const val FORMAT = "yyyy-MM-dd HH:mm:ss" 49 | } 50 | } -------------------------------------------------------------------------------- /project/common-impl/src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Powered by TabooLib 6.0 # 4 | 5 | 6 | Database: 7 | enable: false 8 | host: localhost 9 | port: 3306 10 | user: root 11 | password: root 12 | database: minecraft 13 | prefix: zaphkiel 14 | 15 | Durability: 16 | display: '&8[ &f%symbol% &8]' 17 | display-symbol: 18 | 0: ◆ 19 | 1: ◇ -------------------------------------------------------------------------------- /project/common-impl/src/main/resources/display/def.yml: -------------------------------------------------------------------------------- 1 | default_display_1: 2 | name: '&7' 3 | lore: 4 | - '&9' 5 | - '&f' 6 | 7 | default_display_2: 8 | name: '&7' 9 | lore: 10 | - '&9' 11 | - '&f' 12 | - '' 13 | - '&a+ Damage' 14 | - '&7+ AttackSpeed &8()' -------------------------------------------------------------------------------- /project/common-impl/src/main/resources/generator/def.yml: -------------------------------------------------------------------------------- 1 | # 词条随机 2 | # 还在开发,没有实现 3 | example_gen_0: 4 | ==: text 5 | content: 6 | - id: 0 7 | value: '普通' 8 | priority: 100 9 | - id: 1 10 | value: '稀有' 11 | priority: 20 12 | - id: 2 13 | value: '史诗' 14 | priority: 5 -------------------------------------------------------------------------------- /project/common-impl/src/main/resources/item/def.yml: -------------------------------------------------------------------------------- 1 | example_sword_1: 2 | display: default_display_1 3 | icon: wooden_sword 4 | name: 5 | item_name: '&7Wooden Sword 1' 6 | lore: 7 | item_type: '&9Sword' 8 | item_description: 9 | - '&fCan be bought everywhere.' 10 | data: 11 | durability: 10 12 | meta: 13 | durability: 14 | remains: minecraft:stick 15 | attribute: 16 | mainhand: 17 | damage: +7 18 | attack_speed: +10% 19 | event: 20 | on_damage: item damage 1 21 | 22 | example_sword_2: 23 | display: default_display_2 24 | icon: iron_sword 25 | name: 26 | item_name: '&7Wooden Sword 2' 27 | lore: 28 | item_type: '&9Sword' 29 | item_description: 30 | - '&fCan be bought everywhere.' 31 | data: 32 | # 展示用数据,无实际作用 33 | damage: 10 34 | attack-speed: 0.8 35 | data-mapper: 36 | damage: it 37 | attack-speed: it 38 | attack-speed-level: |- 39 | case &attack-speed [ 40 | when < 1 -> FAST 41 | when < 2 -> NORMAL 42 | when < 3 -> SLOW 43 | else -> VERY SLOW 44 | ] -------------------------------------------------------------------------------- /project/common/build.gradle.kts: -------------------------------------------------------------------------------- 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile 2 | 3 | taboolib { subproject = true } 4 | 5 | tasks.withType(KotlinCompile::class.java) { 6 | kotlinOptions { 7 | freeCompilerArgs = listOf("-module-name", "zap_common") 8 | } 9 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/ZapAPI.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel 2 | 3 | import ink.ptms.zaphkiel.api.* 4 | 5 | /** 6 | * Zaphkiel 7 | * ink.ptms.zaphkiel.ZapAPI 8 | * 9 | * @author 坏黑 10 | * @since 2022/7/20 01:28 11 | */ 12 | interface ZapAPI { 13 | 14 | /** 15 | * 获取物品控制接口 16 | */ 17 | fun getItemHandler(): ItemHandler 18 | 19 | /** 20 | * 获取物品管理接口 21 | */ 22 | fun getItemManager(): ItemManager 23 | 24 | /** 25 | * 获取物品更新接口 26 | */ 27 | fun getItemUpdater(): ItemUpdater 28 | 29 | /** 30 | * 获取物品加载接口 31 | */ 32 | fun getItemLoader(): ItemLoader 33 | 34 | /** 35 | * 获取物品序列化接口 36 | */ 37 | fun getItemSerializer(): ItemSerializer 38 | 39 | /** 40 | * 重载物品及展示方案 41 | */ 42 | fun reload() 43 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/Zaphkiel.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel 2 | 3 | /** 4 | * Zaphkiel 5 | * ink.ptms.zaphkiel.Zaphkiel 6 | * 7 | * @author 坏黑 8 | * @since 2022/7/20 01:29 9 | */ 10 | object Zaphkiel { 11 | 12 | private var api: ZapAPI? = null 13 | 14 | /** 15 | * 获取开发者接口 16 | */ 17 | fun api(): ZapAPI { 18 | return api ?: error("ZaphkielAPI has not finished loading, or failed to load!") 19 | } 20 | 21 | /** 22 | * 注册开发者接口 23 | */ 24 | fun register(api: ZapAPI) { 25 | Zaphkiel.api = api 26 | } 27 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/annotation/Equal.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.annotation 2 | 3 | /** 4 | * 这个类可以使用 equals 进行等价比较 5 | */ 6 | @MustBeDocumented 7 | annotation class Equal -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/annotation/LegacyName.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.annotation 2 | 3 | /** 4 | * 这个字段在 1.X 版本时所对应的名字 5 | */ 6 | @MustBeDocumented 7 | annotation class LegacyName(val value: String) -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/annotation/Locked.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.annotation 2 | 3 | /** 4 | * 这个物品是被锁定的(不可修改) 5 | */ 6 | @MustBeDocumented 7 | @Target(AnnotationTarget.FIELD) 8 | annotation class Locked -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/annotation/Printable.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.annotation 2 | 3 | /** 4 | * 这个类可以使用 toString 打印所有属性 5 | */ 6 | @MustBeDocumented 7 | annotation class Printable -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/annotation/UseWarning.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.annotation 2 | 3 | @MustBeDocumented 4 | annotation class UseWarning(val value: String) -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/Display.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.Equal 4 | import ink.ptms.zaphkiel.annotation.Printable 5 | import ink.ptms.zaphkiel.item.meta.Meta 6 | import org.bukkit.metadata.Metadatable 7 | import taboolib.library.configuration.ConfigurationSection 8 | 9 | /** 10 | * Zaphkiel 11 | * ink.ptms.zaphkiel.api.Display 12 | * 13 | * @author 坏黑 14 | * @since 2022/7/20 01:32 15 | */ 16 | @Equal 17 | @Printable 18 | abstract class Display : Metadatable { 19 | 20 | /** 21 | * 配置文件节点 22 | */ 23 | abstract val config: ConfigurationSection 24 | 25 | /** 26 | * 序号 27 | */ 28 | abstract val id: String 29 | 30 | /** 31 | * 展示名称 32 | */ 33 | abstract val name: String? 34 | 35 | /** 36 | * 展示描述 37 | */ 38 | abstract val lore: List 39 | 40 | /** 41 | * 展示名称结构 42 | */ 43 | abstract val structureName: StructureSingle? 44 | 45 | /** 46 | * 结构名称描述 47 | */ 48 | abstract val structureLore: StructureList 49 | 50 | /** 51 | * 元数据 52 | */ 53 | abstract val meta: List 54 | 55 | /** 56 | * 构建展示方案 57 | */ 58 | abstract fun build(name: Map, lore: Map>, trim: Boolean = true): DisplayProduct 59 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/DisplayProduct.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | /** 4 | * Zaphkiel 5 | * ink.ptms.zaphkiel.api.DisplayProduct 6 | * 7 | * @author 坏黑 8 | * @since 2022/7/20 01:32 9 | */ 10 | data class DisplayProduct(val name: String?, val lore: List) -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/Group.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.Equal 4 | import ink.ptms.zaphkiel.annotation.Printable 5 | import org.bukkit.inventory.ItemStack 6 | import org.bukkit.metadata.Metadatable 7 | import taboolib.library.configuration.ConfigurationSection 8 | import java.io.File 9 | 10 | /** 11 | * @author sky 12 | * @since 2020-11-13 22:50 13 | */ 14 | @Equal@Printable 15 | abstract class Group : Metadatable { 16 | 17 | /** 18 | * 名称 19 | */ 20 | abstract val name: String 21 | 22 | /** 23 | * 路径 24 | */ 25 | abstract val path: String 26 | 27 | /** 28 | * 所在文件 29 | */ 30 | abstract val file: File 31 | 32 | /** 33 | * 配置文件节点 34 | */ 35 | abstract val config: ConfigurationSection 36 | 37 | /** 38 | * 展示物品 39 | */ 40 | abstract val display: ItemStack 41 | 42 | /** 43 | * 优先级(用于页面排序) 44 | */ 45 | abstract val priority: Int 46 | 47 | /** 48 | * 层级 49 | */ 50 | abstract val level: Int 51 | 52 | /** 53 | * 父组 54 | */ 55 | abstract val parent: Group? 56 | 57 | /** 58 | * 获取所有物品 59 | */ 60 | abstract fun getItems(): List 61 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/Item.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.Equal 4 | import ink.ptms.zaphkiel.annotation.LegacyName 5 | import ink.ptms.zaphkiel.annotation.Printable 6 | import ink.ptms.zaphkiel.item.meta.Meta 7 | import org.bukkit.entity.Player 8 | import org.bukkit.event.Event 9 | import org.bukkit.event.player.PlayerEvent 10 | import org.bukkit.inventory.ItemStack 11 | import org.bukkit.metadata.Metadatable 12 | import taboolib.library.configuration.ConfigurationSection 13 | import taboolib.module.nms.ItemTagData 14 | import java.util.concurrent.CompletableFuture 15 | import java.util.function.Consumer 16 | 17 | /** 18 | * Zaphkiel 19 | * ink.ptms.zaphkiel.api.Item 20 | * 21 | * @author 坏黑 22 | * @since 2022/7/20 01:32 23 | */ 24 | @Equal 25 | @Printable 26 | abstract class Item : Metadatable { 27 | 28 | /** 29 | * 配置文件节点 30 | */ 31 | abstract val config: ConfigurationSection 32 | 33 | /** 34 | * 序号 35 | */ 36 | abstract val id: String 37 | 38 | /** 39 | * 展示方案 40 | */ 41 | abstract val display: String 42 | 43 | /** 44 | * 展示方案对象 45 | */ 46 | abstract val displayInstance: Display? 47 | 48 | /** 49 | * 材质 50 | */ 51 | abstract val icon: ItemStack 52 | 53 | /** 54 | * 材质是否上锁 55 | */ 56 | abstract val iconLocked: Boolean 57 | 58 | /** 59 | * 展示名称变量 60 | */ 61 | abstract val name: MutableMap 62 | 63 | /** 64 | * 名称是否上锁 65 | */ 66 | abstract val nameLocked: Boolean 67 | 68 | /** 69 | * 展示描述变量 70 | */ 71 | abstract val lore: MutableMap> 72 | 73 | /** 74 | * 描述是否上锁 75 | */ 76 | abstract val loreLocked: Boolean 77 | 78 | /** 79 | * 物品数据 80 | */ 81 | abstract val data: ConfigurationSection 82 | 83 | /** 84 | * 物品数据映射 85 | */ 86 | abstract val dataMapper: MutableMap 87 | 88 | /** 89 | * 物品模型 90 | */ 91 | abstract val model: MutableList 92 | 93 | /** 94 | * 物品分组 95 | */ 96 | abstract val group: Group? 97 | 98 | /** 99 | * 上锁的数据 100 | */ 101 | @LegacyName("updateData") 102 | abstract val lockedData: MutableMap 103 | 104 | /** 105 | * 事件变量 106 | */ 107 | @LegacyName("eventData") 108 | abstract val eventVars: Map 109 | 110 | /** 111 | * 事件列表 112 | */ 113 | abstract val eventMap: Map 114 | 115 | /** 116 | * 元数据列表 117 | */ 118 | abstract val meta: MutableList 119 | 120 | /** 121 | * 版本签名 122 | */ 123 | @LegacyName("hash") 124 | abstract val version: String 125 | 126 | /** 127 | * 构建为 ItemStack 对象 128 | */ 129 | abstract fun buildItemStack(player: Player? = null): ItemStack 130 | 131 | /** 132 | * 构建新的物品流 133 | */ 134 | abstract fun build(player: Player?): ItemStream 135 | 136 | /** 137 | * 构建新的物品流 138 | */ 139 | abstract fun build(player: Player?, prepareCallback: Consumer): ItemStream 140 | 141 | /** 142 | * 基于已存在的 ItemSteam 构建物品流 143 | */ 144 | abstract fun build(player: Player?, itemStream: ItemStream): ItemStream 145 | 146 | /** 147 | * 是否为相同的物品(判断 ID) 148 | */ 149 | abstract fun isSimilar(itemStack: ItemStack): Boolean 150 | 151 | /** 152 | * 是否持有物品(判断 ID) 153 | */ 154 | abstract fun hasItem(player: Player, amount: Int = 1): Boolean 155 | 156 | /** 157 | * 扣除物品(判断 ID) 158 | */ 159 | abstract fun takeItem(player: Player, amount: Int = 1): Boolean 160 | 161 | /** 162 | * 添加物品(判断 ID)溢出物品将删除 163 | */ 164 | abstract fun giveItem(player: Player, amount: Int = 1, overflow: Consumer> = Consumer {}) 165 | 166 | /** 167 | * 添加物品(判断 ID)溢出物品将丢弃 168 | */ 169 | abstract fun giveItemOrDrop(player: Player, amount: Int = 1) 170 | 171 | /** 172 | * 执行脚本 173 | */ 174 | abstract fun invokeScript( 175 | key: List, 176 | event: PlayerEvent, 177 | itemStream: ItemStream, 178 | namespace: String = "zaphkiel-internal", 179 | ): CompletableFuture? 180 | 181 | /** 182 | * 基于事件执行脚本 183 | */ 184 | abstract fun invokeScript( 185 | key: List, 186 | player: Player?, 187 | event: Event, 188 | itemStream: ItemStream, 189 | namespace: String = "zaphkiel-internal", 190 | ): CompletableFuture? 191 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemEvent.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import org.bukkit.entity.Player 4 | import org.bukkit.event.Event 5 | import org.bukkit.inventory.ItemStack 6 | import java.util.concurrent.CompletableFuture 7 | 8 | /** 9 | * Zaphkiel 10 | * ink.ptms.zaphkiel.api.ItemEvent 11 | * 12 | * @author 坏黑 13 | * @since 2022/7/20 01:57 14 | */ 15 | abstract class ItemEvent(val item: Item, val name: String, val script: List, val isCancelled: Boolean) { 16 | 17 | class ItemResult(val itemStack: ItemStack) 18 | 19 | /** 20 | * 执行脚本 21 | * 若返回内容为空则代表物品没有发生变动 22 | */ 23 | abstract fun invoke( 24 | player: Player?, 25 | event: Event, 26 | itemStream: ItemStream, 27 | data: Map, 28 | namespace: String = "zaphkiel-internal", 29 | ): CompletableFuture 30 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemHandler.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.UseWarning 4 | import org.bukkit.inventory.ItemStack 5 | import taboolib.module.nms.ItemTag 6 | 7 | /** 8 | * Zaphkiel 9 | * ink.ptms.zaphkiel.api.ItemHandler 10 | * 11 | * @author 坏黑 12 | * @since 2022/7/20 02:13 13 | */ 14 | interface ItemHandler { 15 | 16 | /** 17 | * 读取 Zaphkiel 物品流 18 | */ 19 | @UseWarning("空物品将会产生异常") 20 | fun read(item: ItemStack): ItemStream 21 | 22 | /** 23 | * 获取 Zaphkiel 物品实例 24 | */ 25 | @UseWarning("空物品将会产生异常") 26 | fun getItem(item: ItemStack): Item? 27 | 28 | /** 29 | * 获取 Zaphkiel 物品名称(序号) 30 | */ 31 | @UseWarning("空物品将会产生异常") 32 | fun getItemId(item: ItemStack): String? 33 | 34 | /** 35 | * 获取 Zaphkiel 物品活跃数据 36 | */ 37 | @UseWarning("空物品将会产生异常") 38 | fun getItemData(item: ItemStack): ItemTag? 39 | 40 | /** 41 | * 获取 Zaphkiel 物品唯一数据 42 | */ 43 | @UseWarning("空物品将会产生异常") 44 | fun getItemUniqueData(item: ItemStack): ItemTag? 45 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemKey.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.LegacyName 4 | 5 | /** 6 | * @author sky 7 | * @since 2019-12-16 12:44 8 | */ 9 | enum class ItemKey(val key: String) { 10 | 11 | ID("a"), @LegacyName("HASH") VERSION("b"), DATA("c"), UNIQUE("d"), META_HISTORY("e"), ROOT("zaphkiel"); 12 | 13 | override fun toString(): String { 14 | return key 15 | } 16 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemLoader.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import taboolib.library.configuration.ConfigurationSection 5 | import java.io.File 6 | 7 | /** 8 | * Zaphkiel 9 | * ink.ptms.zaphkiel.api.ItemLoader 10 | * 11 | * @author 坏黑 12 | * @since 2022/7/20 02:32 13 | */ 14 | interface ItemLoader { 15 | 16 | /** 17 | * 从文件中加载物品 18 | */ 19 | fun loadItemFromFile(file: File): List 20 | 21 | /** 22 | * 从文件中加载模型文件 23 | */ 24 | fun loadModelFromFile(file: File): List 25 | 26 | /** 27 | * 从文件中加载展示方案 28 | */ 29 | fun loadDisplayFromFile(file: File, fromItemFile: Boolean = false): List 30 | 31 | /** 32 | * 从配置文件中读取元数据配置 33 | */ 34 | fun loadMetaFromSection(root: ConfigurationSection): List 35 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemManager.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.item.meta.Meta 4 | import org.bukkit.entity.Player 5 | import org.bukkit.inventory.ItemStack 6 | 7 | /** 8 | * Zaphkiel 9 | * ink.ptms.zaphkiel.api.ItemManager 10 | * 11 | * @author 坏黑 12 | * @since 2022/7/20 02:15 13 | */ 14 | interface ItemManager { 15 | 16 | /** 17 | * 发放物品 18 | */ 19 | fun giveItem(player: Player, item: Item, amount: Int = 1): Boolean 20 | 21 | /** 22 | * 发放物品 23 | */ 24 | fun giveItem(player: Player, name: String, amount: Int = 1): Boolean 25 | 26 | /** 27 | * 获取物品 28 | */ 29 | fun getItem(name: String): Item? 30 | 31 | /** 32 | * 获取所有物品 33 | */ 34 | fun getItemMap(): Map 35 | 36 | /** 37 | * 获取模型 38 | */ 39 | fun getModel(name: String): Model? 40 | 41 | /** 42 | * 获取所有模型 43 | */ 44 | fun getModelMap(): Map 45 | 46 | /** 47 | * 获取展示方案 48 | */ 49 | fun getDisplay(name: String): Display? 50 | 51 | /** 52 | * 获取所有展示方案 53 | */ 54 | fun getDisplayMap(): Map 55 | 56 | /** 57 | * 获取分组 58 | */ 59 | fun getGroup(name: String): Group? 60 | 61 | /** 62 | * 获取所有分组 63 | */ 64 | fun getGroupMap(): Map 65 | 66 | /** 67 | * 获取元数据 68 | */ 69 | fun getMeta(name: String): Class? 70 | 71 | /** 72 | * 获取所有元数据类 73 | */ 74 | fun getMetaMap(): Map> 75 | 76 | /** 77 | * 注册新的物品 78 | */ 79 | fun registerItem(item: Item) 80 | 81 | /** 82 | * 注销物品 83 | */ 84 | fun unregisterItem(item: Item) 85 | 86 | /** 87 | * 注册新的模型 88 | */ 89 | fun registerModel(model: Model) 90 | 91 | /** 92 | * 注销模型 93 | */ 94 | fun unregisterModel(model: Model) 95 | 96 | /** 97 | * 注册新的展示方案 98 | */ 99 | fun registerDisplay(display: Display) 100 | 101 | /** 102 | * 注销展示方案 103 | */ 104 | fun unregisterDisplay(display: Display) 105 | 106 | /** 107 | * 注册新的分组 108 | */ 109 | fun registerGroup(group: Group) 110 | 111 | /** 112 | * 注销分组 113 | */ 114 | fun unregisterGroup(group: Group) 115 | 116 | /** 117 | * 注册新的元数据类 118 | */ 119 | fun registerMeta(meta: Class) 120 | 121 | /** 122 | * 注销元数据类 123 | */ 124 | fun unregisterMeta(meta: Class) 125 | 126 | /** 127 | * 生成新的物品流 128 | */ 129 | fun generateItem(id: String, player: Player? = null): ItemStream? 130 | 131 | /** 132 | * 生成新的物品流并构建成 ItemStack 133 | */ 134 | fun generateItemStack(id: String, player: Player? = null): ItemStack? 135 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemSerializer.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import com.google.gson.JsonObject 4 | import ink.ptms.zaphkiel.annotation.UseWarning 5 | import org.bukkit.inventory.ItemStack 6 | 7 | /** 8 | * Zaphkiel 9 | * ink.ptms.zaphkiel.api.ItemSerializer 10 | * 11 | * @author 坏黑 12 | * @since 2022/7/20 02:35 13 | */ 14 | interface ItemSerializer { 15 | 16 | @UseWarning("原版物品不会产生异常,但会抹除所有数据") 17 | fun serialize(itemStack: ItemStack): SerializedItem 18 | 19 | @UseWarning("原版物品不会产生异常,但会抹除所有数据") 20 | fun serialize(itemStream: ItemStream): SerializedItem 21 | 22 | fun deserialize(json: String): ItemStream 23 | 24 | fun deserialize(json: JsonObject): ItemStream 25 | 26 | fun deserialize(item: SerializedItem): ItemStream 27 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemSignal.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.LegacyName 4 | 5 | /** 6 | * Zaphkiel 7 | * ink.ptms.zaphkiel.api.ItemSignal 8 | * 9 | * @author mac 10 | * @since 2021/11/3 12:48 上午 11 | */ 12 | enum class ItemSignal { 13 | 14 | /** 15 | * 物品是否在 checkUpdate 方法下被更新 16 | */ 17 | UPDATE_CHECKED, 18 | 19 | /** 20 | * 物品是否被 itemDamage/itemRepair 方法下更新 21 | */ 22 | @LegacyName("DURABILITY_UPDATE") 23 | DURABILITY_CHANGED, 24 | 25 | /** 26 | * 物品是否被 itemDamage/itemRepair 方法下损坏 27 | */ 28 | @LegacyName("DURABILITY_DESTROY") 29 | DURABILITY_DESTROYED 30 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemStream.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.Equal 4 | import ink.ptms.zaphkiel.annotation.Printable 5 | import ink.ptms.zaphkiel.annotation.UseWarning 6 | import org.bukkit.entity.Player 7 | import org.bukkit.inventory.ItemStack 8 | import org.bukkit.metadata.Metadatable 9 | import taboolib.module.nms.ItemTag 10 | 11 | /** 12 | * Zaphkiel 13 | * ink.ptms.zaphkiel.api.ItemStream 14 | * 15 | * @author 坏黑 16 | * @since 2022/7/20 01:30 17 | */ 18 | @Equal 19 | @Printable 20 | abstract class ItemStream : Metadatable { 21 | 22 | abstract val sourceItem: ItemStack 23 | 24 | abstract val sourceCompound: ItemTag 25 | 26 | abstract val signal: HashSet 27 | 28 | /** 29 | * 内部属性,已删除的 Meta 名称 30 | * 这组数据在物品流被创建时就已确立,无法修改。 31 | */ 32 | @UseWarning("原版物品将产生异常") 33 | abstract val dropMeta: List 34 | 35 | /** 36 | * 是否为非 Zaphkiel 物品(即原版物品) 37 | */ 38 | abstract fun isVanilla(): Boolean 39 | 40 | /** 41 | * 是否为 Zaphkiel 物品 42 | */ 43 | abstract fun isExtension(): Boolean 44 | 45 | /** 46 | * 物品是否过时(即是否需要重构) 47 | */ 48 | @UseWarning("原版物品将产生异常") 49 | abstract fun isOutdated(): Boolean 50 | 51 | /** 52 | * 设置物品的展示名(原版) 53 | */ 54 | abstract fun setDisplayName(displayName: String) 55 | 56 | /** 57 | * 设置物品的描述(原版) 58 | */ 59 | abstract fun setLore(lore: List) 60 | 61 | /** 62 | * 重构物品,并返回新的 ItemStream 实例 63 | */ 64 | @UseWarning("原版物品将产生异常") 65 | abstract fun rebuild(player: Player? = null): ItemStream 66 | 67 | /** 68 | * 重构物品实例,并保存为 ItemStack 对象 69 | */ 70 | @UseWarning("原版物品将产生异常") 71 | abstract fun rebuildToItemStack(player: Player? = null): ItemStack 72 | 73 | /** 74 | * 保存为 ItemStack 对象 75 | * 原方法名(save)存在误导,于 1.4.1 版本替换为 toItemStack。 76 | */ 77 | @UseWarning("原版物品将产生异常") 78 | abstract fun toItemStack(player: Player? = null): ItemStack 79 | 80 | /** 81 | * 获取内部物品实例 82 | */ 83 | @UseWarning("原版物品将产生异常") 84 | abstract fun getZaphkielItem(): Item 85 | 86 | /** 87 | * 获取内部物品名称 88 | */ 89 | @UseWarning("原版物品将产生异常") 90 | open fun getZaphkielId(): String { 91 | return getZaphkielName() 92 | } 93 | 94 | /** 95 | * 获取内部物品名称 96 | */ 97 | @Deprecated("命名歧义", ReplaceWith("getZaphkielId()")) 98 | @UseWarning("原版物品将产生异常") 99 | abstract fun getZaphkielName(): String 100 | 101 | /** 102 | * 获取物品版本签名 103 | */ 104 | @UseWarning("原版物品将产生异常") 105 | open fun getZaphkielHash(): String { 106 | return getZaphkielVersion() 107 | } 108 | 109 | /** 110 | * 获取物品版本签名 111 | */ 112 | @Deprecated("命名歧义", ReplaceWith("getZaphkielHash()")) 113 | @UseWarning("原版物品将产生异常") 114 | abstract fun getZaphkielVersion(): String 115 | 116 | /** 117 | * 获取物品内部数据 118 | */ 119 | @UseWarning("原版物品将产生异常") 120 | abstract fun getZaphkielData(): ItemTag 121 | 122 | /** 123 | * 获取物品唯一数据 124 | */ 125 | @UseWarning("原版物品将产生异常") 126 | abstract fun getZaphkielUniqueData(): ItemTag? 127 | 128 | /** 129 | * 获取物品元数据历史 130 | */ 131 | @UseWarning("原版物品将产生异常") 132 | abstract fun getZaphkielMetaHistory(): List 133 | 134 | /** 135 | * 设置物品元数据历史 136 | */ 137 | @UseWarning("原版物品将产生异常") 138 | abstract fun setZaphkielMetaHistory(meta: List) 139 | 140 | /** 141 | * 获取 Zaphkiel 下所有数据 142 | */ 143 | abstract fun getZaphkielCompound(): ItemTag? 144 | 145 | /** 146 | * 锁定物品 147 | * 任何对物品的修改都将产生异常(允许修改 Metadata) 148 | */ 149 | abstract fun lock(value: Boolean) 150 | 151 | /** 152 | * 获取物品锁定状态 153 | */ 154 | abstract fun isLocked(): Boolean 155 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/ItemUpdater.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.UseWarning 4 | import org.bukkit.entity.Player 5 | import org.bukkit.inventory.Inventory 6 | import org.bukkit.inventory.ItemStack 7 | 8 | /** 9 | * Zaphkiel 10 | * ink.ptms.zaphkiel.api.ItemUpdater 11 | * 12 | * @author 坏黑 13 | * @since 2022/7/20 02:14 14 | */ 15 | interface ItemUpdater { 16 | 17 | /** 18 | * 检查并更新背包中的所有物品 19 | */ 20 | fun checkUpdate(player: Player?, inventory: Inventory) 21 | 22 | /** 23 | * 检查并更新物品 24 | * 这个方法的作用是检查更新,而非完全重构 25 | */ 26 | @UseWarning("空物品将会产生异常") 27 | fun checkUpdate(player: Player?, item: ItemStack): ItemStream 28 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/JsonContainer.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import com.google.gson.JsonObject 4 | 5 | /** 6 | * Zaphkiel 7 | * ink.ptms.zaphkiel.api.JsonContainer 8 | * 9 | * @author 坏黑 10 | * @since 2022/7/20 02:40 11 | */ 12 | interface JsonContainer { 13 | 14 | /** 15 | * 转换为 Map 对象 16 | */ 17 | fun toMap(): Map 18 | 19 | /** 20 | * 转换为 Json 字符串 21 | */ 22 | fun toJson(): String 23 | 24 | /** 25 | * 转换为 JsonObject 对象 26 | */ 27 | fun toJsonObject(): JsonObject 28 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/Model.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import taboolib.library.configuration.ConfigurationSection 4 | 5 | /** 6 | * @author sky 7 | * @since 2019-12-25 8:07 8 | */ 9 | data class Model(val id: String, val config: ConfigurationSection) -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/SerializedItem.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import com.google.gson.JsonObject 4 | import ink.ptms.zaphkiel.annotation.Equal 5 | import ink.ptms.zaphkiel.annotation.Printable 6 | 7 | /** 8 | * Zaphkiel 9 | * ink.ptms.zaphkiel.api.SerializedItem 10 | * 11 | * @author 坏黑 12 | * @since 2022/7/20 02:35 13 | */ 14 | @Equal 15 | @Printable 16 | interface SerializedItem : JsonContainer { 17 | 18 | /** 19 | * 关键字段「物品序号」原版物品将会标记为「minecraft:*」 20 | */ 21 | val id: String 22 | 23 | /** 24 | * 关键字段「物品数量」 25 | */ 26 | val amount: Int 27 | 28 | /** 29 | * 关键字段「物品数据」 30 | */ 31 | val data: JsonObject? 32 | 33 | /** 34 | * 关键字段「物品签名」 35 | */ 36 | val uniqueData: UniqueData? 37 | 38 | /** 39 | * 物品签名 40 | */ 41 | @Equal 42 | @Printable 43 | interface UniqueData : JsonContainer { 44 | 45 | /** 46 | * 关键字段「玩家名称」 47 | */ 48 | val player: String? 49 | 50 | /** 51 | * 关键字段「构建时间」 52 | */ 53 | val date: Long 54 | 55 | /** 56 | * 关键字段「唯一序号」 57 | */ 58 | val uuid: String 59 | } 60 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/StructureList.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.Equal 4 | import ink.ptms.zaphkiel.annotation.Printable 5 | 6 | /** 7 | * @author sky 8 | * @since 2019-12-15 14:55 9 | */ 10 | @Equal 11 | @Printable 12 | interface StructureList { 13 | 14 | fun build(vars: Map>, trim: Boolean): List 15 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/StructureSingle.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api 2 | 3 | import ink.ptms.zaphkiel.annotation.Equal 4 | import ink.ptms.zaphkiel.annotation.Printable 5 | 6 | /** 7 | * @author sky 8 | * @since 2019-12-15 14:55 9 | */ 10 | @Equal 11 | @Printable 12 | interface StructureSingle { 13 | 14 | fun build(vars: Map, trim: Boolean): String 15 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/event/Alias.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api.event 2 | 3 | /** 4 | * 物品构建之前(可被取消) 5 | * 所有数据均可修改。 6 | * 7 | * 该事件在物品发送到玩家背包时通常会触发两次: 8 | * - 第一次是在产生 ItemStack 时进行初次构建 9 | * - 第二次是在 ItemGiveEvent 事件后重构 10 | */ 11 | typealias ZapItemBuildEvent = ItemBuildEvent.Pre 12 | 13 | /** 14 | * 物品构建之后(不可取消) 15 | * 16 | * 可以修改: 17 | * - itemStream 18 | * 不可修改: 19 | * - name 20 | * - lore 21 | * 22 | * 在 [ZapItemBuildEvent] 后触发。 23 | */ 24 | typealias ZapItemPostBuildEvent = ItemBuildEvent.Post 25 | 26 | /** 27 | * 物品检查更新前(可被取消) 28 | * 29 | * 不可修改: 30 | * - itemStream 31 | */ 32 | typealias ZapItemCheckUpdateEvent = ItemBuildEvent.CheckUpdate 33 | 34 | /** 35 | * 物品正在从 ItemStream 转变到 ItemStack 时(不可取消) 36 | * 37 | * 可以修改: 38 | * - icon 39 | * - data 40 | * - itemMeta 41 | * 不可修改: 42 | * - itemStream 43 | */ 44 | typealias ZapItemGenerateEvent = ItemReleaseEvent 45 | 46 | /** 47 | * 物品已从 ItemStream 转变到 ItemStack(不可取消) 48 | * 49 | * 可以修改: 50 | * - itemStack 51 | * 不可修改: 52 | * - itemStream 53 | */ 54 | typealias ZapItemPostGenerateEvent = ItemReleaseEvent.Final 55 | 56 | /** 57 | * 物品选择展示方案时(不可取消) 58 | * 59 | * 可以修改: 60 | * - display 61 | * 不可修改: 62 | * - itemStream 63 | */ 64 | typealias ZapDisplaySelectEvent = ItemReleaseEvent.SelectDisplay 65 | 66 | /** 67 | * 物品描述生成时(不可取消) 68 | * 69 | * 可以修改: 70 | * - name 71 | * - lore 72 | * 不可修改: 73 | * - itemStream 74 | */ 75 | typealias ZapDisplayGenerateEvent = ItemReleaseEvent.Display -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/event/Editable.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api.event 2 | 3 | /** 4 | * Zaphkiel 5 | * ink.ptms.zaphkiel.api.event.Editable 6 | * 7 | * @author 坏黑 8 | * @since 2023/3/20 13:55 9 | */ 10 | interface Editable { 11 | 12 | fun addName(key: String, value: Any) 13 | 14 | fun addLore(key: String, value: Any) 15 | 16 | fun addLore(key: String, value: List) 17 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/event/ItemBuildEvent.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api.event 2 | 3 | import ink.ptms.zaphkiel.annotation.Locked 4 | import ink.ptms.zaphkiel.api.ItemStream 5 | import org.bukkit.entity.Player 6 | import taboolib.platform.type.BukkitProxyEvent 7 | 8 | /** 9 | * @author sky 10 | * @since 2019-12-15 16:44 11 | */ 12 | class ItemBuildEvent { 13 | 14 | /** 15 | * 构建之前 16 | * 可被取消 17 | * 18 | * 该事件在物品发送到玩家背包时通常会触发两次: 19 | * - 第一次是在产生 ItemStack 时进行初次构建 20 | * - 第二次是在 ItemGiveEvent 事件后重构 21 | */ 22 | class Pre( 23 | val player: Player?, 24 | val itemStream: ItemStream, 25 | val name: MutableMap, 26 | val lore: MutableMap> 27 | ) : BukkitProxyEvent(), Editable { 28 | 29 | val item = itemStream.getZaphkielItem() 30 | 31 | override fun addName(key: String, value: Any) { 32 | name[key] = value.toString() 33 | } 34 | 35 | override fun addLore(key: String, value: Any) { 36 | val list = lore.computeIfAbsent(key) { arrayListOf() } 37 | when (value) { 38 | is List<*> -> list.addAll(value.map { it.toString() }) 39 | else -> list.add(value.toString()) 40 | } 41 | } 42 | 43 | override fun addLore(key: String, value: List) { 44 | value.forEach { addLore(key, it) } 45 | } 46 | } 47 | 48 | /** 49 | * 构建之后 50 | * 不可取消 51 | * 名称、描述、数据已就绪 52 | */ 53 | class Post(val player: Player?, val itemStream: ItemStream, val name: Map, val lore: Map>) : BukkitProxyEvent() { 54 | 55 | override val allowCancelled: Boolean 56 | get() = false 57 | 58 | val item = itemStream.getZaphkielItem() 59 | } 60 | 61 | /** 62 | * 检查更新 63 | * 可被取消 64 | * 递交至构建事件之前 65 | */ 66 | class CheckUpdate(val player: Player?, @Locked val itemStream: ItemStream, isOutdated: Boolean) : BukkitProxyEvent() { 67 | 68 | val item = itemStream.getZaphkielItem() 69 | 70 | init { 71 | isCancelled = !isOutdated 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/event/ItemEvent.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api.event 2 | 3 | import ink.ptms.zaphkiel.api.ItemStream 4 | import org.bukkit.entity.Player 5 | import org.bukkit.event.block.Action 6 | import org.bukkit.event.inventory.ClickType 7 | import org.bukkit.event.inventory.InventoryClickEvent 8 | import org.bukkit.event.player.* 9 | import org.bukkit.inventory.EquipmentSlot 10 | import org.bukkit.inventory.ItemStack 11 | import taboolib.platform.type.BukkitProxyEvent 12 | 13 | /** 14 | * @author sky 15 | * @since 2020-04-20 12:37 16 | */ 17 | class ItemEvent { 18 | 19 | class InventoryClick(val itemStreamCurrent: ItemStream?, val itemStreamButton: ItemStream?, val bukkitEvent: InventoryClickEvent) : BukkitProxyEvent() { 20 | 21 | override val allowCancelled: Boolean 22 | get() = false 23 | 24 | /** 25 | * 保存点击位置的物品 26 | */ 27 | var saveCurrent = false 28 | 29 | /** 30 | * 保存按键位置的物品 31 | */ 32 | var saveButton = false 33 | 34 | var cursor: ItemStack? 35 | get() = bukkitEvent.cursor 36 | set(value) { 37 | bukkitEvent.whoClicked.setItemOnCursor(value) 38 | } 39 | 40 | var currentItem: ItemStack? 41 | get() = bukkitEvent.currentItem 42 | set(value) { 43 | bukkitEvent.currentItem = value 44 | } 45 | 46 | val whoClicked = bukkitEvent.whoClicked 47 | 48 | val slotType = bukkitEvent.slotType 49 | 50 | val clickedInventory = bukkitEvent.clickedInventory 51 | 52 | val slot = bukkitEvent.slot 53 | 54 | val rawSlot = bukkitEvent.rawSlot 55 | 56 | val hotbarButton = bukkitEvent.hotbarButton 57 | 58 | val action = bukkitEvent.action 59 | 60 | val click = bukkitEvent.click 61 | 62 | val isRightClick = bukkitEvent.click == ClickType.RIGHT 63 | 64 | val isLeftClick = bukkitEvent.click == ClickType.LEFT 65 | 66 | val isShiftClick = bukkitEvent.click == ClickType.SHIFT_LEFT || bukkitEvent.click == ClickType.SHIFT_RIGHT 67 | } 68 | 69 | class InteractEntity(val itemStream: ItemStream, val bukkitEvent: PlayerInteractEntityEvent) : BukkitProxyEvent() { 70 | 71 | /** 72 | * 保存交互物品 73 | */ 74 | var save = false 75 | 76 | val player = bukkitEvent.player 77 | 78 | val isRightClicked = bukkitEvent.rightClicked 79 | 80 | val hand = bukkitEvent.hand 81 | 82 | fun isMainhand() = bukkitEvent.hand == EquipmentSlot.HAND 83 | 84 | fun isOffhand() = bukkitEvent.hand == EquipmentSlot.OFF_HAND 85 | } 86 | 87 | class Interact(val itemStream: ItemStream, val bukkitEvent: PlayerInteractEvent) : BukkitProxyEvent() { 88 | 89 | /** 90 | * 保存交互物品 91 | */ 92 | var save = false 93 | 94 | val player = bukkitEvent.player 95 | 96 | val action = bukkitEvent.action 97 | 98 | val item = bukkitEvent.item 99 | 100 | val material = bukkitEvent.material 101 | 102 | val isBlockInHand = bukkitEvent.isBlockInHand 103 | 104 | val clickedBlock = bukkitEvent.clickedBlock 105 | 106 | val blockFace = bukkitEvent.blockFace 107 | 108 | val hand = bukkitEvent.hand 109 | 110 | fun hasBlock() = bukkitEvent.hasBlock() 111 | 112 | fun hasItem() = bukkitEvent.hasItem() 113 | 114 | fun isRightClick() = bukkitEvent.action == Action.RIGHT_CLICK_AIR || bukkitEvent.action == Action.RIGHT_CLICK_BLOCK 115 | 116 | fun isRightClickAir() = bukkitEvent.action == Action.RIGHT_CLICK_AIR 117 | 118 | fun isRightClickBlock() = bukkitEvent.action == Action.RIGHT_CLICK_BLOCK 119 | 120 | fun isLeftClick() = bukkitEvent.action == Action.LEFT_CLICK_AIR || bukkitEvent.action == Action.LEFT_CLICK_BLOCK 121 | 122 | fun isLeftClickAir() = bukkitEvent.action == Action.LEFT_CLICK_AIR 123 | 124 | fun isLeftClickBlock() = bukkitEvent.action == Action.LEFT_CLICK_BLOCK 125 | 126 | fun isPhysical() = bukkitEvent.action == Action.PHYSICAL 127 | 128 | fun isMainhand() = bukkitEvent.hand == EquipmentSlot.HAND 129 | 130 | fun isOffhand() = bukkitEvent.hand == EquipmentSlot.OFF_HAND 131 | 132 | } 133 | 134 | class Consume(val itemStream: ItemStream, val bukkitEvent: PlayerItemConsumeEvent) : BukkitProxyEvent() { 135 | 136 | override val allowCancelled: Boolean 137 | get() = false 138 | 139 | var item: ItemStack? 140 | get() = bukkitEvent.item 141 | set(value) { 142 | bukkitEvent.setItem(value) 143 | } 144 | 145 | val player = bukkitEvent.player 146 | } 147 | 148 | class Pick(val itemStream: ItemStream, val bukkitEvent: PlayerPickupItemEvent) : BukkitProxyEvent() { 149 | 150 | override val allowCancelled: Boolean 151 | get() = false 152 | 153 | /** 154 | * 保存交互物品 155 | */ 156 | var save = false 157 | set(_) { 158 | field = false 159 | error("PlayerPickupItemEvent#save is not supported, item modification is not safe in this event.") 160 | } 161 | 162 | val item = bukkitEvent.item 163 | 164 | val remaining = bukkitEvent.remaining 165 | 166 | val player = bukkitEvent.player 167 | } 168 | 169 | class Drop(val itemStream: ItemStream, val bukkitEvent: PlayerDropItemEvent) : BukkitProxyEvent() { 170 | 171 | override val allowCancelled: Boolean 172 | get() = false 173 | 174 | /** 175 | * 保存交互物品 176 | */ 177 | var save = false 178 | 179 | val itemDrop = bukkitEvent.itemDrop 180 | 181 | val player = bukkitEvent.player 182 | } 183 | 184 | class Select(val itemStream: ItemStream, val player: Player) : BukkitProxyEvent() { 185 | 186 | override val allowCancelled: Boolean 187 | get() = false 188 | 189 | /** 190 | * 保存交互物品 191 | */ 192 | var save = false 193 | } 194 | 195 | class AsyncTick(val itemStream: ItemStream, val player: Player) : BukkitProxyEvent() { 196 | 197 | override val allowCancelled: Boolean 198 | get() = false 199 | 200 | /** 201 | * 保存交互物品 202 | */ 203 | var save = false 204 | } 205 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/event/ItemGiveEvent.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api.event 2 | 3 | import ink.ptms.zaphkiel.api.ItemStream 4 | import org.bukkit.entity.Player 5 | import taboolib.platform.type.BukkitProxyEvent 6 | 7 | /** 8 | * Zaphkiel 9 | * ink.ptms.zaphkiel.api.event.ItemGiveEvent 10 | * 11 | * @author 坏黑 12 | * @since 2022/9/6 13:53 13 | */ 14 | class ItemGiveEvent(val player: Player, var itemStream: ItemStream, var amount: Int) : BukkitProxyEvent() -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/event/ItemReleaseEvent.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api.event 2 | 3 | import ink.ptms.zaphkiel.annotation.Locked 4 | import ink.ptms.zaphkiel.api.ItemStream 5 | import org.bukkit.Material 6 | import org.bukkit.entity.Player 7 | import org.bukkit.inventory.ItemStack 8 | import org.bukkit.inventory.meta.ItemMeta 9 | import taboolib.platform.type.BukkitProxyEvent 10 | 11 | /** 12 | * 当物品释放时 13 | * 可以在该事件下修改即将写入物品栈的 icon、data、itemMeta 信息 14 | * 15 | * @author sky 16 | * @since 2019-12-25 11:38 17 | */ 18 | class ItemReleaseEvent( 19 | var icon: Material, 20 | var data: Int, 21 | var itemMeta: ItemMeta, 22 | @Locked 23 | val itemStream: ItemStream, 24 | val player: Player? = null 25 | ) : BukkitProxyEvent() { 26 | 27 | override val allowCancelled: Boolean 28 | get() = false 29 | 30 | val item = itemStream.getZaphkielItem() 31 | 32 | /** 33 | * 当物品释放时 34 | * 可以在该事件下修改最终物品栈 35 | */ 36 | class Final( 37 | var itemStack: ItemStack, 38 | @Locked 39 | val itemStream: ItemStream, 40 | val player: Player? = null 41 | ): BukkitProxyEvent() { 42 | 43 | override val allowCancelled: Boolean 44 | get() = false 45 | 46 | val item = itemStream.getZaphkielItem() 47 | } 48 | 49 | /** 50 | * 当物品释放时 51 | * 可以在该事件下修改名称与描述变量 52 | */ 53 | class Display( 54 | @Locked 55 | val itemStream: ItemStream, 56 | val name: MutableMap, 57 | val lore: MutableMap>, 58 | val player: Player? = null, 59 | ) : BukkitProxyEvent(), Editable { 60 | 61 | val item = itemStream.getZaphkielItem() 62 | 63 | override val allowCancelled: Boolean 64 | get() = false 65 | 66 | override fun addName(key: String, value: Any) { 67 | name[key] = value.toString() 68 | } 69 | 70 | override fun addLore(key: String, value: Any) { 71 | val list = lore.computeIfAbsent(key) { arrayListOf() } 72 | when (value) { 73 | is List<*> -> list.addAll(value.map { it.toString() }) 74 | else -> list.add(value.toString()) 75 | } 76 | } 77 | 78 | override fun addLore(key: String, value: List) { 79 | value.forEach { addLore(key, it) } 80 | } 81 | } 82 | 83 | /** 84 | * 当物品释放时选择展示方案时 85 | * 可以在该事件下修改即将使用的展示方案 86 | */ 87 | class SelectDisplay( 88 | @Locked 89 | val itemStream: ItemStream, 90 | var display: ink.ptms.zaphkiel.api.Display, 91 | val player: Player? = null 92 | ): BukkitProxyEvent() { 93 | 94 | val item = itemStream.getZaphkielItem() 95 | 96 | override val allowCancelled: Boolean 97 | get() = false 98 | } 99 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/api/event/PluginReloadEvent.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.api.event 2 | 3 | import taboolib.platform.type.BukkitProxyEvent 4 | 5 | /** 6 | * @author sky 7 | * @since 2019-12-25 22:00 8 | */ 9 | class PluginReloadEvent { 10 | 11 | class Item : BukkitProxyEvent() { 12 | 13 | override val allowCancelled: Boolean 14 | get() = false 15 | } 16 | 17 | class Display : BukkitProxyEvent() { 18 | 19 | override val allowCancelled: Boolean 20 | get() = false 21 | } 22 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/impl/item/Extensions.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.impl.item 2 | 3 | import ink.ptms.zaphkiel.Zaphkiel 4 | import ink.ptms.zaphkiel.api.ItemStream 5 | import org.bukkit.inventory.ItemStack 6 | import taboolib.platform.util.isAir 7 | 8 | fun ItemStack?.toExtensionStreamOrNull(): ItemStream? { 9 | return toItemStreamOrNull()?.takeIf { it.isExtension() } 10 | } 11 | 12 | fun ItemStack?.toItemStreamOrNull(): ItemStream? { 13 | return if (isAir) null else this!!.toItemStream() 14 | } 15 | 16 | fun ItemStack.toItemStream(): ItemStream { 17 | return Zaphkiel.api().getItemHandler().read(this) 18 | } -------------------------------------------------------------------------------- /project/common/src/main/kotlin/ink/ptms/zaphkiel/item/meta/Meta.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel.item.meta 2 | 3 | import ink.ptms.zaphkiel.api.event.ItemBuildEvent 4 | import ink.ptms.zaphkiel.api.event.ItemReleaseEvent 5 | import org.bukkit.entity.Player 6 | import org.bukkit.inventory.meta.ItemMeta 7 | import taboolib.library.configuration.ConfigurationSection 8 | import taboolib.module.nms.ItemTag 9 | 10 | abstract class Meta(val root: ConfigurationSection) { 11 | 12 | /** 13 | * 元数据序号 14 | */ 15 | abstract val id: String 16 | 17 | /** 18 | * 元数据是否上锁 19 | */ 20 | var locked = false 21 | 22 | /** 23 | * 在 [ItemReleaseEvent] 事件中构建元数据 24 | */ 25 | open fun build(itemReleaseEvent: ItemReleaseEvent) { 26 | } 27 | 28 | /** 29 | * 在 [ItemBuildEvent.Post] 事件构建物品后设置元数据 30 | */ 31 | open fun build(player: Player?, compound: ItemTag) { 32 | } 33 | 34 | /** 35 | * 在 [ItemReleaseEvent] 事件中构建元数据 36 | */ 37 | open fun build(itemMeta: ItemMeta) { 38 | } 39 | 40 | /** 41 | * 在 [ItemReleaseEvent] 事件中删除元数据 42 | */ 43 | open fun drop(itemReleaseEvent: ItemReleaseEvent) { 44 | } 45 | 46 | /** 47 | * 在 [ItemBuildEvent.Post] 事件构建物品后删除元数据 48 | */ 49 | open fun drop(player: Player?, compound: ItemTag) { 50 | } 51 | 52 | /** 53 | * 在 [ItemReleaseEvent] 事件中删除元数据 54 | */ 55 | open fun drop(itemMeta: ItemMeta) { 56 | } 57 | } -------------------------------------------------------------------------------- /project/module-bukkit/build.gradle.kts: -------------------------------------------------------------------------------- 1 | taboolib { subproject = true } 2 | 3 | dependencies { 4 | api(project(":project:common")) 5 | api(project(":project:common-impl")) 6 | compileOnly("ink.ptms:nms-all:1.0.0") 7 | compileOnly("ink.ptms.core:v11802:11802-minimize:mapped") 8 | compileOnly("ink.ptms.core:v11802:11802-minimize:universal") 9 | } -------------------------------------------------------------------------------- /project/module-bukkit/src/main/kotlin/ink/ptms/zaphkiel/ZaphkielCommand.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel 2 | 3 | import ink.ptms.zaphkiel.impl.feature.openGroupMenu 4 | import ink.ptms.zaphkiel.impl.item.toItemStream 5 | import org.bukkit.Bukkit 6 | import org.bukkit.Sound 7 | import org.bukkit.command.CommandSender 8 | import org.bukkit.entity.Player 9 | import taboolib.common.io.zip 10 | import taboolib.common.platform.command.* 11 | import taboolib.expansion.createHelper 12 | import taboolib.module.chat.colored 13 | import taboolib.platform.util.isAir 14 | 15 | /** 16 | * @author sky 17 | * @since 2019-12-15 22:39 18 | */ 19 | @CommandHeader(name = "Zaphkiel", aliases = ["zl", "item"], permission = "*") 20 | object ZaphkielCommand { 21 | 22 | @CommandBody 23 | val main = mainCommand { 24 | createHelper() 25 | } 26 | 27 | @CommandBody 28 | val list = subCommand { 29 | dynamic("group") { 30 | suggest { Zaphkiel.api().getItemManager().getGroupMap().keys.toList() } 31 | execute { sender, _, argument -> 32 | sender.openGroupMenu(Zaphkiel.api().getItemManager().getGroup(argument)!!) 33 | } 34 | } 35 | execute { sender, _, _ -> sender.openGroupMenu() } 36 | } 37 | 38 | @CommandBody 39 | val give = subCommand { 40 | dynamic(comment = "item") { 41 | suggestion { _, _ -> 42 | Zaphkiel.api().getItemManager().getItemMap().keys.toList() 43 | } 44 | execute { sender, _, argument -> 45 | Zaphkiel.api().getItemManager().giveItem(sender, argument) 46 | } 47 | dynamic(optional = true, comment = "player") { 48 | suggestion { _, _ -> 49 | Bukkit.getOnlinePlayers().map { it.name } 50 | } 51 | execute { _, context, argument -> 52 | val player = Bukkit.getPlayerExact(argument)!! 53 | Zaphkiel.api().getItemManager().giveItem(player, context["item"]) 54 | } 55 | dynamic(optional = true, comment = "amount") { 56 | execute { _, context, argument -> 57 | val player = Bukkit.getPlayerExact(context["player"])!! 58 | val amount = argument.toIntOrNull() ?: 1 59 | Zaphkiel.api().getItemManager().giveItem(player, context["item"], amount) 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | @CommandBody 67 | val serialize = subCommand { 68 | execute { sender, _, _ -> 69 | try { 70 | val serializedItem = Zaphkiel.api().getItemSerializer().serialize(sender.inventory.itemInMainHand) 71 | val json = serializedItem.toJson().replace('§', '&') 72 | val zipped = json.toByteArray().zip() 73 | notify(sender, "序列化: &f$json") 74 | notify( 75 | sender, 76 | "明文: &f${json.length} &7字符, &f${json.toByteArray().size} &7字节 &a-> &7压缩后: &f${zipped.size} &7字节" 77 | ) 78 | } catch (ex: Throwable) { 79 | notify(sender, "无效的物品: $ex") 80 | } 81 | } 82 | } 83 | 84 | @CommandBody 85 | val rebuild = subCommand { 86 | execute { sender, _, _ -> 87 | val itemInMainHand = sender.inventory.itemInMainHand 88 | if (itemInMainHand.isAir()) { 89 | notify(sender, "请手持物品.") 90 | return@execute 91 | } 92 | val itemStream = itemInMainHand.toItemStream() 93 | if (itemStream.isExtension()) { 94 | sender.inventory.setItemInMainHand(itemStream.rebuildToItemStack(sender)) 95 | notify(sender, "成功.") 96 | } else { 97 | notify(sender, "不是 Zaphkiel 物品.") 98 | } 99 | } 100 | } 101 | 102 | @CommandBody 103 | val reload = subCommand { 104 | execute { sender, _, _ -> 105 | Zaphkiel.api().reload() 106 | notify(sender, "成功.") 107 | } 108 | } 109 | 110 | fun notify(sender: CommandSender, value: String) { 111 | sender.sendMessage("§c[Zaphkiel] §7${value.colored()}") 112 | if (sender is Player) { 113 | sender.playSound(sender.location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 1f, 2f) 114 | } 115 | } 116 | } -------------------------------------------------------------------------------- /project/module-legacy-api/build.gradle.kts: -------------------------------------------------------------------------------- 1 | taboolib { subproject = true } 2 | 3 | dependencies { 4 | api(project(":project:common")) 5 | compileOnly("ink.ptms:nms-all:1.0.0") 6 | compileOnly("ink.ptms.core:v11802:11802-minimize:mapped") 7 | compileOnly("ink.ptms.core:v11802:11802-minimize:universal") 8 | } -------------------------------------------------------------------------------- /project/module-legacy-api/src/main/kotlin/ink/ptms/zaphkiel/ZaphkielAPI.kt: -------------------------------------------------------------------------------- 1 | package ink.ptms.zaphkiel 2 | 3 | import com.google.gson.JsonObject 4 | import ink.ptms.zaphkiel.api.* 5 | import ink.ptms.zaphkiel.item.meta.Meta 6 | import org.bukkit.entity.Player 7 | import org.bukkit.inventory.Inventory 8 | import org.bukkit.inventory.ItemStack 9 | import taboolib.common.platform.function.getDataFolder 10 | import taboolib.library.configuration.ConfigurationSection 11 | import taboolib.module.nms.ItemTag 12 | import java.io.File 13 | 14 | /** 15 | * @author sky 16 | * @since 2019-12-15 20:14 17 | */ 18 | @Deprecated("Use ink.ptms.zaphkiel.Zaphkiel#api()") 19 | object ZaphkielAPI { 20 | 21 | val loaded: ArrayList 22 | get() = arrayListOf() 23 | 24 | val folderItem: File 25 | get() = File(getDataFolder(), "item") 26 | 27 | val folderDisplay: File 28 | get() = File(getDataFolder(), "display") 29 | 30 | val registeredItem: HashMap 31 | get() = Zaphkiel.api().getItemManager().getItemMap() as HashMap 32 | 33 | val registeredModel: HashMap 34 | get() = Zaphkiel.api().getItemManager().getModelMap() as HashMap 35 | 36 | val registeredDisplay: HashMap 37 | get() = Zaphkiel.api().getItemManager().getDisplayMap() as HashMap 38 | 39 | val registeredGroup: HashMap 40 | get() = Zaphkiel.api().getItemManager().getGroupMap() as HashMap 41 | 42 | val registeredMeta: Map> 43 | get() = Zaphkiel.api().getItemManager().getMetaMap() 44 | 45 | fun read(item: ItemStack): ItemStream { 46 | return Zaphkiel.api().getItemHandler().read(item) 47 | } 48 | 49 | fun getItem(id: String, player: Player? = null): ItemStream? { 50 | return Zaphkiel.api().getItemManager().generateItem(id, player) 51 | } 52 | 53 | fun getItemStack(id: String, player: Player? = null): ItemStack? { 54 | return Zaphkiel.api().getItemManager().generateItemStack(id, player) 55 | } 56 | 57 | fun getName(item: ItemStack): String? { 58 | return Zaphkiel.api().getItemHandler().getItemId(item) 59 | } 60 | 61 | fun getData(item: ItemStack): ItemTag? { 62 | return Zaphkiel.api().getItemHandler().getItemData(item) 63 | } 64 | 65 | fun getUnique(item: ItemStack): ItemTag? { 66 | return Zaphkiel.api().getItemHandler().getItemUniqueData(item) 67 | } 68 | 69 | fun getItem(item: ItemStack): Item? { 70 | return Zaphkiel.api().getItemHandler().getItem(item) 71 | } 72 | 73 | fun checkUpdate(player: Player?, inventory: Inventory) { 74 | Zaphkiel.api().getItemUpdater().checkUpdate(player, inventory) 75 | } 76 | 77 | fun checkUpdate(player: Player?, item: ItemStack): ItemStream { 78 | return Zaphkiel.api().getItemUpdater().checkUpdate(player, item) 79 | } 80 | 81 | fun reloadItem() { 82 | Zaphkiel.api().reload() 83 | } 84 | 85 | fun loadItemFromFile(file: File) { 86 | Zaphkiel.api().getItemLoader().loadItemFromFile(file).forEach { 87 | Zaphkiel.api().getItemManager().registerItem(it) 88 | } 89 | } 90 | 91 | fun loadModelFromFile(file: File) { 92 | Zaphkiel.api().getItemLoader().loadModelFromFile(file).forEach { 93 | Zaphkiel.api().getItemManager().registerModel(it) 94 | } 95 | } 96 | 97 | fun reloadDisplay() { 98 | Zaphkiel.api().reload() 99 | } 100 | 101 | fun loadDisplayFromFile(file: File, fromItemFile: Boolean = false) { 102 | Zaphkiel.api().getItemLoader().loadDisplayFromFile(file, fromItemFile).forEach { 103 | Zaphkiel.api().getItemManager().registerDisplay(it) 104 | } 105 | } 106 | 107 | fun readMeta(root: ConfigurationSection): MutableList { 108 | return Zaphkiel.api().getItemLoader().loadMetaFromSection(root).toMutableList() 109 | } 110 | 111 | fun serialize(itemStack: ItemStack): JsonObject { 112 | return Zaphkiel.api().getItemSerializer().serialize(itemStack).toJsonObject() 113 | } 114 | 115 | fun serialize(itemStream: ItemStream): JsonObject { 116 | return Zaphkiel.api().getItemSerializer().serialize(itemStream).toJsonObject() 117 | } 118 | 119 | fun deserialize(json: String): ItemStream { 120 | return Zaphkiel.api().getItemSerializer().deserialize(json) 121 | } 122 | 123 | fun deserialize(json: JsonObject): ItemStream { 124 | return Zaphkiel.api().getItemSerializer().deserialize(json) 125 | } 126 | } -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | rootProject.name = "Zaphkiel" 2 | 3 | include("plugin") 4 | include("project:common") 5 | include("project:common-impl") 6 | include("project:module-bukkit") 7 | include("project:module-legacy-api") --------------------------------------------------------------------------------