commit dae9931df4ecdecc1b4f8ac1b860c1efc04e2ff4 Author: 小白 <67080574+xbaimiao@users.noreply.github.com> Date: Thu Sep 8 23:39:46 2022 +0800 初始提交 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f8baeaf --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.gradle +.idea +build +bin \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1625c17 --- /dev/null +++ b/LICENSE @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0f859cf --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Building + +* [Gradle](https://gradle.org/) - Dependency Management + +The GradleWrapper in included in this project. + +**Windows:** + +``` +gradlew.bat clean build +``` + +**macOS/Linux:** + +``` +./gradlew clean build +``` + +Build artifacts should be found in `./build/libs` folder. \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..2925247 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,80 @@ +plugins { + `java-library` + `maven-publish` + id("io.izzel.taboolib") version "1.42" + id("org.jetbrains.kotlin.jvm") version "1.5.10" +} + +taboolib { + description { + dependencies { + name("PlaceholderAPI").optional(true) + name("Vault").optional(true) + } + } + install("common") + install("common-5") + install("module-chat") + install("module-configuration") + install("module-database") + install("module-lang") + install("module-ui") + install("module-nms-util") + install("module-nms") + install("platform-bukkit") + install("expansion-command-helper") + classifier = null + version = "6.0.9-84" +} + +repositories { + mavenCentral() + maven("https://repo.xbaimiao.com/nexus/content/repositories/releases/") +} + +dependencies { + compileOnly("ink.ptms:nms-all:1.0.0") + compileOnly("public:papi:1.0.0") + compileOnly("public:vault:1.0.0") + compileOnly("ink.ptms.core:v11902:11902-minimize:mapped") + compileOnly("ink.ptms.core:v11902:11902-minimize:universal") + compileOnly(kotlin("stdlib")) + compileOnly(fileTree("libs")) +} + +tasks.withType { + options.encoding = "UTF-8" +} + +tasks.withType { + kotlinOptions { + jvmTarget = "1.8" + freeCompilerArgs = listOf("-Xjvm-default=all") + } +} + +configure { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +publishing { + repositories { + maven { + url = uri("https://repo.tabooproject.org/repository/releases") + credentials { + username = project.findProperty("taboolibUsername").toString() + password = project.findProperty("taboolibPassword").toString() + } + authentication { + create("basic") + } + } + } + publications { + create("library") { + from(components["java"]) + groupId = project.group.toString() + } + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..c172c1d --- /dev/null +++ b/gradle.properties @@ -0,0 +1,2 @@ +group=com.github.xbaimiao.shoppro +version=1.0.0 \ No newline at end of file diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..94336fc Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..fe753c9 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists \ No newline at end of file diff --git a/gradlew b/gradlew new file mode 100644 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..4d301ca --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1 @@ +rootProject.name="ShopPro" \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/ShopPro.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/ShopPro.kt new file mode 100644 index 0000000..b87707b --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/ShopPro.kt @@ -0,0 +1,26 @@ +package com.github.xbaimiao.shoppro + +import com.github.xbaimiao.shoppro.core.database.Database +import com.github.xbaimiao.shoppro.core.shop.ShopManager +import taboolib.common.platform.Plugin +import taboolib.module.configuration.Config +import taboolib.module.configuration.Configuration + +object ShopPro : Plugin() { + + @Config(value = "config.yml") + lateinit var config: Configuration + private set + + lateinit var database: Database + + override fun onEnable() { + ShopManager.load() + } + + fun reload() { + ShopManager.shops.clear() + ShopManager.load() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/Util.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/Util.kt new file mode 100644 index 0000000..2e26eb7 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/Util.kt @@ -0,0 +1,13 @@ +package com.github.xbaimiao.shoppro + +import java.text.DecimalFormat + + +object Util { + + fun Double.format(): Double { + val df = DecimalFormat("#0.00") + return df.format(this).toDouble() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/api/ShopProBuyEvent.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/api/ShopProBuyEvent.kt new file mode 100644 index 0000000..924a411 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/api/ShopProBuyEvent.kt @@ -0,0 +1,27 @@ +package com.github.xbaimiao.shoppro.api + +import com.github.xbaimiao.shoppro.core.item.ShopItem +import org.bukkit.entity.Player +import org.bukkit.event.Event +import org.bukkit.event.HandlerList + +class ShopProBuyEvent( + val item: ShopItem, + val amount: Int, + val player: Player +) : Event() { + + override fun getHandlers(): HandlerList { + return handlerList + } + + companion object { + private val handlerList = HandlerList() + + @JvmStatic + fun getHandlerList(): HandlerList { + return handlerList + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/api/ShopProSellEvent.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/api/ShopProSellEvent.kt new file mode 100644 index 0000000..4b9f351 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/api/ShopProSellEvent.kt @@ -0,0 +1,29 @@ +package com.github.xbaimiao.shoppro.api + +import com.github.xbaimiao.shoppro.core.item.ShopItem +import org.bukkit.entity.Player +import org.bukkit.event.Event +import org.bukkit.event.HandlerList +import org.bukkit.event.inventory.ClickType +import org.bukkit.inventory.Inventory + +class ShopProSellEvent( + val item: ShopItem, + val amount: Int, + val player: Player +) : Event() { + + override fun getHandlers(): HandlerList { + return handlerList + } + + companion object { + private val handlerList = HandlerList() + + @JvmStatic + fun getHandlerList(): HandlerList? { + return handlerList + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/Commands.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/Commands.kt new file mode 100644 index 0000000..9e2c50e --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/Commands.kt @@ -0,0 +1,42 @@ +package com.github.xbaimiao.shoppro.core + +import com.github.xbaimiao.shoppro.core.shop.ShopManager +import org.bukkit.Bukkit +import org.bukkit.command.CommandSender +import org.bukkit.entity.Player +import taboolib.common.platform.command.* +import taboolib.expansion.createHelper +import taboolib.platform.util.onlinePlayers + +@CommandHeader("shoppro", aliases = ["sp"], permissionDefault = PermissionDefault.TRUE) +object Commands { + + @CommandBody + val main = mainCommand { + createHelper() + } + + @CommandBody + val open = subCommand { + dynamic("name") { + suggestion { _, _ -> + ShopManager.shops.map { it.getName() } + } + execute { sender, _, argument -> + val shop = ShopManager.shops.first { it.getName() == argument } + shop.open(sender) + } + dynamic("玩家", permission = "admin") { + suggestion { _, _ -> + onlinePlayers.map { it.name } + } + execute { _, context, argument -> + val player = Bukkit.getPlayerExact(argument)!! + val shop = ShopManager.shops.first { it.getName() == context.argument(-1) } + shop.open(player) + } + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/database/Database.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/database/Database.kt new file mode 100644 index 0000000..eb3fe3a --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/database/Database.kt @@ -0,0 +1,28 @@ +package com.github.xbaimiao.shoppro.core.database + +import com.github.xbaimiao.shoppro.core.item.Item +import org.bukkit.entity.Player + +interface Database { + + /** + * 获取该物品该玩家今日已购买多少次了 + */ + fun getPlayerLimit(player: Player, item: Item): Long + + /** + * 设置该物品该玩家今日已购买多少次了 + */ + fun setPlayerLimit(player: Player, item: Item, amount: Long) + + /** + * 获取该物品今日已购买多少次了 + */ + fun getServerLimit(item: Item) + + /** + * 设置该物品今日已购买多少次了 + */ + fun setServerLimit(item: Item, amount: Long) + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/Item.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/Item.kt new file mode 100644 index 0000000..5f3329a --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/Item.kt @@ -0,0 +1,50 @@ +package com.github.xbaimiao.shoppro.core.item + +import com.github.xbaimiao.shoppro.core.shop.ShopManager +import com.github.xbaimiao.shoppro.core.vault.Vault +import com.github.xbaimiao.shoppro.core.vault.VaultImpl +import org.bukkit.Bukkit +import org.bukkit.Material +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import org.bukkit.permissions.Permission +import taboolib.module.chat.colored + +interface Item { + + val key: Char + val material: Material + val lore: List + val name: String + val vanilla: Boolean + val commands: List + + val vault: Vault + get() = VaultImpl + + fun isCommodity(): Boolean + fun buildItem(): ItemStack + fun update(player: Player, itemStack: ItemStack) + + fun exeCommands(player: Player) { + commands.map { it.replace("%player%", player.name) }.forEach { command -> + if (command.startsWith("[tell] ")) { + player.sendMessage(command.substring(7).colored()) + } else if (command.startsWith("[console] ")) { + Bukkit.dispatchCommand(Bukkit.getConsoleSender(), command.substring(10)) + } else if (command.startsWith("[player] ")) { + Bukkit.dispatchCommand(player, command.substring(9)) + } else if (command.startsWith("[open] ")) { + val shop = ShopManager.shops.firstOrNull { it.getName() == command.substring(7) } + shop?.open(player) + } else if (command.startsWith("[op] ")) { + Bukkit.dispatchCommand(object : Player by player { + override fun isOp() = true + override fun hasPermission(p0: Permission) = true + override fun hasPermission(p0: String) = true + }, command.substring(5)) + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ItemImpl.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ItemImpl.kt new file mode 100644 index 0000000..acd21cc --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ItemImpl.kt @@ -0,0 +1,36 @@ +package com.github.xbaimiao.shoppro.core.item + +import me.clip.placeholderapi.PlaceholderAPI +import org.bukkit.Material +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import taboolib.platform.util.modifyLore + +open class ItemImpl( + override val material: Material, override val lore: List, override val name: String, + override val key: Char, override val vanilla: Boolean, override val commands: List +) : Item { + + override fun isCommodity(): Boolean { + return false + } + + override fun buildItem(): ItemStack { + return taboolib.platform.util.buildItem(material) { + this.name = this@ItemImpl.name + this.lore.addAll(this@ItemImpl.lore) + } + } + + override fun update(player: Player, itemStack: ItemStack) { + itemStack.modifyLore { + val newLore = ArrayList() + for (line in this) { + newLore.add(PlaceholderAPI.setPlaceholders(player, line)) + } + this.clear() + this.addAll(newLore) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ItemsAdderShopItem.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ItemsAdderShopItem.kt new file mode 100644 index 0000000..d355ec7 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ItemsAdderShopItem.kt @@ -0,0 +1,59 @@ +package com.github.xbaimiao.shoppro.core.item + +import org.bukkit.Material +import org.bukkit.inventory.ItemStack +import taboolib.library.xseries.XMaterial +import taboolib.module.nms.getItemTag + +class ItemsAdderShopItem( + override val key: Char, + override val price: Double, + iaMaterial: String, + override val limitServer: Long, + override val limitPlayer: Long, + override val name: String, + override val lore: List, + override val vanilla: Boolean, + override val commands: List +) : ShopItem() { + + override val material: Material + + private val custom: Int + + private var customPotionColor: Int? = null + + init { + iaMaterial.split(":").let { strings -> + material = XMaterial.matchXMaterial(strings[1]).get().parseMaterial()!! + custom = strings[2].toInt() + strings.getOrNull(3)?.let { customPotionColor = it.toInt() } + } + } + + override fun equal(itemStack: ItemStack): Boolean { + return itemStack.type == material && itemStack.itemMeta?.customModelData == custom + } + + override fun vanillaItem(): ItemStack { + return taboolib.platform.util.buildItem(material) { + this.customModelData = custom + } + } + + override fun buildItem(): ItemStack { + return taboolib.platform.util.buildItem(material) { + this.name = this@ItemsAdderShopItem.name + this.lore.addAll(this@ItemsAdderShopItem.lore) + this.customModelData = custom + }.also { item -> + customPotionColor?.let { + val tag = item.getItemTag() + tag.putDeep("meta.CustomPotionColor.data", it) + tag.putDeep("meta.CustomPotionColor.type", "INT") + tag.saveTo(item) + } + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ShopItem.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ShopItem.kt new file mode 100644 index 0000000..38bde82 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/ShopItem.kt @@ -0,0 +1,49 @@ +package com.github.xbaimiao.shoppro.core.item + +import me.clip.placeholderapi.PlaceholderAPI +import org.bukkit.entity.Player +import org.bukkit.inventory.ItemStack +import taboolib.platform.util.modifyLore + +abstract class ShopItem : Item { + + abstract val price: Double + abstract val limitServer: Long + abstract val limitPlayer: Long + + override fun isCommodity(): Boolean { + return true + } + + abstract fun vanillaItem(): ItemStack + + abstract fun equal(itemStack: ItemStack): Boolean + + fun isLimit(): Boolean { + return limitPlayer != 0L && limitServer != 0L + } + + override fun update(player: Player, itemStack: ItemStack) { + val playerLimit = "1" + val serverLimit = "1" + val priceAll = "1" + itemStack.modifyLore { + val newLore = ArrayList() + for (line in this) { + val newLine = line.replace("\${name}", name) + .replace("\${price}", price.toString()) + .replace("\${money}", vault.getMoney(player).toString()) + .replace("\${price64}", (price * 64).toString()) + .replace("\${limit}", limitPlayer.toString()) + .replace("\${priceAll}", priceAll) + .replace("\${allLimit}", limitServer.toString()) + .replace("\${limit-player}", playerLimit) + .replace("\${limit-server}", serverLimit) + newLore.add(PlaceholderAPI.setPlaceholders(player, newLine)) + } + this.clear() + this.addAll(newLore) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/VanillaShopItem.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/VanillaShopItem.kt new file mode 100644 index 0000000..3d23e69 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/item/VanillaShopItem.kt @@ -0,0 +1,33 @@ +package com.github.xbaimiao.shoppro.core.item + +import org.bukkit.Material +import org.bukkit.inventory.ItemStack + +class VanillaShopItem( + override val key: Char, + override val material: Material, + override val price: Double, + override val limitServer: Long, + override val limitPlayer: Long, + override val name: String, + override val lore: List, + override val vanilla: Boolean, + override val commands: List +) : ShopItem() { + + override fun vanillaItem(): ItemStack { + return taboolib.platform.util.buildItem(material) + } + + override fun equal(itemStack: ItemStack): Boolean { + return itemStack.itemMeta?.hasLore() == false && itemStack.type == material + } + + override fun buildItem(): ItemStack { + return taboolib.platform.util.buildItem(material) { + this.name = this@VanillaShopItem.name + this.lore.addAll(this@VanillaShopItem.lore) + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/Shop.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/Shop.kt new file mode 100644 index 0000000..4ac9f73 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/Shop.kt @@ -0,0 +1,26 @@ +package com.github.xbaimiao.shoppro.core.shop + +import org.bukkit.entity.Player + +abstract class Shop { + + enum class ShopType(val string: String) { + BUY("buy"), SELL("sell"); + + companion object { + fun formString(string: String): ShopType { + return ShopType.values().first { it.string == string } + } + } + + } + + abstract fun getTitle(): String + + abstract fun getType(): ShopType + + abstract fun getName(): String + + abstract fun open(player: Player) + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/ShopImpl.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/ShopImpl.kt new file mode 100644 index 0000000..9f76b46 --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/ShopImpl.kt @@ -0,0 +1,167 @@ +package com.github.xbaimiao.shoppro.core.shop + +import com.github.xbaimiao.shoppro.api.ShopProBuyEvent +import com.github.xbaimiao.shoppro.api.ShopProSellEvent +import com.github.xbaimiao.shoppro.core.item.* +import org.bukkit.Bukkit +import org.bukkit.configuration.Configuration +import org.bukkit.entity.Player +import taboolib.library.xseries.parseToMaterial +import taboolib.module.chat.colored +import taboolib.module.ui.ClickType +import taboolib.module.ui.openMenu +import taboolib.module.ui.type.Basic +import taboolib.platform.util.giveItem +import taboolib.platform.util.hasItem +import taboolib.platform.util.sendLang +import taboolib.platform.util.takeItem + +class ShopImpl(private val configuration: Configuration) : Shop() { + + private val slots = configuration.getStringList("slots").map { it.toCharArray().toList() } + + private val items = ArrayList() + + init { + val section = configuration.getConfigurationSection("items")!! + for (key in section.getKeys(false)) { + if (section.getBoolean("$key.is-commodity", true)) { + val materialString = section.getString("$key.material")!! + if (materialString.startsWith("IA")) { + items.add( + ItemsAdderShopItem( + key[0], + section.getDouble("$key.price"), + materialString, + section.getLong("$key.limit"), + section.getLong("$key.limit-player"), + section.getString("$key.name")!!.colored(), + section.getStringList("$key.lore").colored(), + section.getBoolean("$key.vanilla", true), + section.getStringList("$key.commands") + ) + ) + } else { + items.add( + VanillaShopItem( + key[0], + section.getString("$key.material")!!.parseToMaterial(), + section.getDouble("$key.price"), + section.getLong("$key.limit"), + section.getLong("$key.limit-player"), + section.getString("$key.name")!!.colored(), + section.getStringList("$key.lore").colored(), + section.getBoolean("$key.vanilla", true), + section.getStringList("$key.commands") + ) + ) + } + } else { + items.add( + ItemImpl( + section.getString("$key.material")!!.parseToMaterial(), + section.getStringList("$key.lore").colored(), + section.getString("$key.name")!!.colored(), + key[0], + section.getBoolean("$key.vanilla", true), + section.getStringList("$key.commands") + ) + ) + } + } + } + + override fun getTitle(): String { + return configuration.getString("title")!!.colored() + } + + override fun getType(): ShopType { + return ShopType.formString(configuration.getString("type")!!) + } + + override fun getName(): String { + return configuration.getString("name")!!.colored() + } + + override fun open(player: Player) { + player.openMenu(getTitle()) { + rows(slots.size) + slots = ArrayList>().also { it.addAll(this@ShopImpl.slots) } + onClick { + it.isCancelled = true + } + for (item in this@ShopImpl.items) { + val itemStack = item.buildItem() + item.update(player, itemStack) + set(item.key, itemStack) + if (item is ShopItem) { + if (getType() == ShopType.BUY) { + onClick(item.key) { event -> + if (event.clickType != ClickType.CLICK) { + return@onClick + } + val amount = when (event.clickEvent().click) { + org.bukkit.event.inventory.ClickType.LEFT -> 1 + org.bukkit.event.inventory.ClickType.RIGHT -> 64 + else -> 1 + } + buy(amount, item, player) + event.currentItem?.let { item.update(player, it) } + } + } + if (getType() == ShopType.SELL) { + onClick(item.key) { event -> + if (event.clickType != ClickType.CLICK) { + return@onClick + } + val amount = when (event.clickEvent().click) { + org.bukkit.event.inventory.ClickType.LEFT -> 1 + org.bukkit.event.inventory.ClickType.RIGHT -> 64 + else -> 1 + } + sell(amount, item, player) + event.currentItem?.let { item.update(player, it) } + } + } + } else { + onClick(item.key) { + item.exeCommands(player) + } + } + } + } + } + + private fun buy(amount: Int, item: ShopItem, player: Player) { + if (item.isLimit()){ + // TODO + } + if (item.vault.takeMoney(player, item.price * amount)) { + if (item.vanilla) { + val vanilla = item.vanillaItem() + vanilla.amount = amount + player.giveItem(vanilla) + } + Bukkit.getPluginManager().callEvent(ShopProBuyEvent(item, amount, player)) + item.exeCommands(player) + player.sendLang("buy-item", amount, item.name, item.price * amount) + } else { + player.sendLang("not-money") + } + } + + private fun sell(amount: Int, item: ShopItem, player: Player) { + if (item.isLimit()){ + // TODO + } + if (player.inventory.hasItem(amount) { item.equal(it) }) { + player.inventory.takeItem(amount) { item.equal(it) } + item.vault.giveMoney(player, item.price * amount) + Bukkit.getPluginManager().callEvent(ShopProSellEvent(item, amount, player)) + player.sendLang("sell-item", amount, item.name, item.price * amount) + } else { + player.sendLang("not-item") + } + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/ShopManager.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/ShopManager.kt new file mode 100644 index 0000000..722515b --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/shop/ShopManager.kt @@ -0,0 +1,28 @@ +package com.github.xbaimiao.shoppro.core.shop + +import org.bukkit.configuration.file.YamlConfiguration +import taboolib.common.platform.function.info +import taboolib.platform.BukkitPlugin +import java.io.File + +object ShopManager { + + val shops = ArrayList() + + fun load() { + val fileDirectory = File(BukkitPlugin.getInstance().dataFolder, "shops") + + var files = fileDirectory.listFiles() + if (files == null || files.isEmpty()) { + BukkitPlugin.getInstance().saveResource("shops${File.separator}limit-buy.yml", false) + BukkitPlugin.getInstance().saveResource("shops${File.separator}limit-sell.yml", false) + BukkitPlugin.getInstance().saveResource("shops${File.separator}sell.yml", false) + files = fileDirectory.listFiles() + } + files?.forEach { file -> + shops.add(ShopImpl(YamlConfiguration.loadConfiguration(file))) + } + info("加载了 ${shops.size} 个商店配置") + } + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/vault/Vault.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/vault/Vault.kt new file mode 100644 index 0000000..47e753a --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/vault/Vault.kt @@ -0,0 +1,15 @@ +package com.github.xbaimiao.shoppro.core.vault + +import org.bukkit.entity.Player + +interface Vault { + + fun hasMoney(player: Player, double: Double): Boolean + + fun giveMoney(player: Player, double: Double) + + fun takeMoney(player: Player, double: Double): Boolean + + fun getMoney(player: Player): Double + +} \ No newline at end of file diff --git a/src/main/kotlin/com/github/xbaimiao/shoppro/core/vault/VaultImpl.kt b/src/main/kotlin/com/github/xbaimiao/shoppro/core/vault/VaultImpl.kt new file mode 100644 index 0000000..4969ede --- /dev/null +++ b/src/main/kotlin/com/github/xbaimiao/shoppro/core/vault/VaultImpl.kt @@ -0,0 +1,30 @@ +package com.github.xbaimiao.shoppro.core.vault + +import com.github.xbaimiao.shoppro.Util.format +import org.bukkit.entity.Player +import taboolib.platform.compat.VaultService + +object VaultImpl : Vault { + + override fun hasMoney(player: Player, double: Double): Boolean { + return getMoney(player) >= double.format() + } + + override fun giveMoney(player: Player, double: Double) { + VaultService.economy!!.depositPlayer(player, double.format()) + } + + override fun takeMoney(player: Player, double: Double): Boolean { + if (!hasMoney(player, double.format())) { + return false + } + VaultService.economy!!.withdrawPlayer(player, double.format()) + return true + } + + override fun getMoney(player: Player): Double { + return VaultService.economy!!.getBalance(player) + } + + +} \ No newline at end of file diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml new file mode 100644 index 0000000..e69de29 diff --git a/src/main/resources/lang/zh_CN.yml b/src/main/resources/lang/zh_CN.yml new file mode 100644 index 0000000..bbc01dc --- /dev/null +++ b/src/main/resources/lang/zh_CN.yml @@ -0,0 +1,6 @@ +shop-not-found: "&7[&e&l!&7] 你需要打开什么商店呢" +not-item: "&7[&e&l!&7] 你没有足够的可以出售的物品" +sell-item: "&7[&e&l!&7] 你出售了§6 {0}个 §7{1}§7获得了§6 {2}" +sell-limit: "&7[&e&l!&7] 此物品已达到今日收购限制" +buy-item: "&7[&e&l!&7] 你购买了§6 {0}个 §7{1} §7花费了§6 {2}" +not-money: "&7[&e&l!&7] 你没有足够的钱" diff --git a/src/main/resources/shops/limit-buy.yml b/src/main/resources/shops/limit-buy.yml new file mode 100644 index 0000000..d641eed --- /dev/null +++ b/src/main/resources/shops/limit-buy.yml @@ -0,0 +1,70 @@ +# 商店类型 +# buy 为购买商店 +# sell 为收购商店 +type: buy +name: "默认出售商店" +title: "系统出售商店" +# 物品摆放顺序 +slots: + - 'NNNNNNNNN' + - 'NAB N' + - 'NNNNNNNNN' +items: + N: + material: GLASS_PANE + name: ' ' + lore: + - ' ' + # 是否为商品 + is-commodity: false + # 普通物品收购示例 + A: + material: STONE + name: '石头' + # 每日限购买 + limit: 5000 + # 每个玩家限购买 + limit-player: 500 + # 物品金额 + price: 2 + lore: + - '&e| &7这里可以购买&6 ${name}' + - '&e| &7购买单价 &6${price}' + - '&e| &7你的余额 &6${money}' + - '' + - '&e|&6 左击 &7购买 &6单个' + - '&e|&6 右击 &7购买 &6一组 &7需要 &6${price64}' + - '' + - '&e| &7限买公示:' + - '&e| &7每人限制购买: ${limit}' + - '&e| &7全服限制购买: ${allLimit}' + - '&e| &7您已购买: ${limit-player}' + - '&e| &7全服剩余: ${limit-server}' + # itemsadder 物品购买示例 + # 需要使用IA:前缀 中间为物品材质 后面为物品customData + B: + material: 'IA:PAPER:10001' + name: 'IA物品名' + # 每日限购买 + limit: 5000 + # 每个玩家限购买 + limit-player: 500 + # 物品金额 + price: 2 + lore: + - '&e| &7这里可以购买&6 ${name}' + - '&e| &7购买单价 &6${price}' + - '&e| &7你的余额 &6${money}' + - '' + - '&e|&6 左击 &7购买 &6单个' + - '&e|&6 右击 &7购买 &6一组 &7需要 &6${price64}' + - '' + - '&e| &7限买公示:' + - '&e| &7每人限制购买: ${limit}' + - '&e| &7全服限制购买: ${allLimit}' + - '&e| &7您已购买: ${limit-player}' + - '&e| &7全服剩余: ${limit-server}' + # 关闭此选项 可只执行命令 不给原版物品 + vanilla: false + commands: + - '[console] ia give %player% 物品' \ No newline at end of file diff --git a/src/main/resources/shops/limit-sell.yml b/src/main/resources/shops/limit-sell.yml new file mode 100644 index 0000000..18a72cb --- /dev/null +++ b/src/main/resources/shops/limit-sell.yml @@ -0,0 +1,68 @@ +# 商店类型 +# buy 为出售商店 +# sell 为收购商店 +type: sell +name: "默认收购商店" +title: "系统收购商店" +# 物品摆放顺序 +slots: + - 'NNNNNNNNN' + - 'NAB N' + - 'NNNNNNNNN' +items: + N: + material: GLASS_PANE + name: ' ' + lore: + - ' ' + # 是否为商品 + is-commodity: false + # 普通物品收购示例 + A: + material: STONE + name: '石头' + # 每日限出售 + limit: 5000 + # 每个玩家限出售 + limit-player: 500 + # 物品金额 + price: 1 + lore: + - '&e| &7这里可以出售你背包里面的&6 ${name}' + - '&e| &7收购单价 &6${price}' + - '&e| &7你的余额 &6${money}' + - '' + - '&e|&6 左击 &7出售 &6单个' + - '&e|&6 右击 &7出售 &6一组 &7获得 &6${price64}' + - '&e|&6 Shift + 右击 &7出售 &6背包所有 &7获得${priceAll}' + - '' + - '&e| &7限售公示:' + - '&e| &7每人限制出售: ${limit}' + - '&e| &7全服限制出售: ${allLimit}' + - '&e| &7您已出售: ${limit-player}' + - '&e| &7全服剩余: ${limit-server}' + # itemsadder 物品收购示例 + # 需要使用IA:前缀 中间为物品材质 后面为物品customData,如果是药水需要在添加一个 CustomPotionColor + B: + material: 'IA:PAPER:10001' + name: 'IA物品名' + # 每日限出售 + limit: 5000 + # 每个玩家限出售 + limit-player: 500 + # 物品金额 + price: 1 + lore: + - '&e| &7这里可以出售你背包里面的&6 ${name}' + - '&e| &7收购单价 &6${price}' + - '&e| &7你的余额 &6${money}' + - '' + - '&e|&6 左击 &7出售 &6单个' + - '&e|&6 右击 &7出售 &6一组 &7获得 &6${price64}' + - '&e|&6 Shift + 右击 &7出售 &6背包所有 &7获得${priceAll}' + - '' + - '&e| &7限售公示:' + - '&e| &7每人限制出售: ${limit}' + - '&e| &7全服限制出售: ${allLimit}' + - '&e| &7您已出售: ${limit-player}' + - '&e| &7全服剩余: ${limit-server}' diff --git a/src/main/resources/shops/sell.yml b/src/main/resources/shops/sell.yml new file mode 100644 index 0000000..d3f8386 --- /dev/null +++ b/src/main/resources/shops/sell.yml @@ -0,0 +1,131 @@ +type: sell +name: "自带收购商店" +title: "系统收购商店" + +slots: + - 'NNNNNNNNN' + - 'NQWERTYUN' + - 'NIOP N' + - 'NNNNNNNNX' + +items: + N: + material: GLASS_PANE + name: ' ' + lore: + - ' ' + is-commodity: false + X: + material: ARROW + name: '&f下一页' + lore: + - '&f点击前往下一页' + is-commodity: false + commands: + - '[open] 默认收购商店' + Q: + material: COAL + name: '&f&l煤炭' + price: 0.5 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + # 关闭此选项 可只执行命令 不给原版物品 + vanilla: false + commands: + - '[console] give %player% COAL' + W: + material: IRON_INGOT + name: '&f&l铁锭' + price: 10 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + E: + material: GOLD_INGOT + name: '&f&l金锭' + price: 13 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + R: + material: COPPER_INGOT + name: '&f&l铜锭' + price: 12 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + T: + material: DIAMOND + name: '&f&l钻石' + price: 20 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + Y: + material: BREAD + name: '&f&l面包' + price: 3 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + U: + material: CAKE + name: '&f&l蛋糕' + price: 30 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + I: + material: PUMPKIN_PIE + name: '&f&l南瓜派' + price: 4 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + O: + material: MUSHROOM_STEW + name: '&f&l蘑菇煲' + price: 2 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}' + + # itemsadder 物品 + P: + material: 'IA:PAPER:10007' + name: 'itemsadder' + price: 20 + lore: + - '&a&l左键 &f&l出售单个' + - '&a&l右键 &f&l出售一组' + - '&a&lShift + 右键 &f&l出售背包所有可出售物品' + - '' + - '&a&l收购价格 &c&l${price}'