初始提交

This commit is contained in:
小白
2022-09-08 23:39:46 +08:00
commit dae9931df4
31 changed files with 1421 additions and 0 deletions
@@ -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()
}
}
@@ -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()
}
}
@@ -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
}
}
}
@@ -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
}
}
}
@@ -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<CommandSender> { _, _ ->
ShopManager.shops.map { it.getName() }
}
execute<Player> { sender, _, argument ->
val shop = ShopManager.shops.first { it.getName() == argument }
shop.open(sender)
}
dynamic("玩家", permission = "admin") {
suggestion<CommandSender> { _, _ ->
onlinePlayers.map { it.name }
}
execute<CommandSender> { _, context, argument ->
val player = Bukkit.getPlayerExact(argument)!!
val shop = ShopManager.shops.first { it.getName() == context.argument(-1) }
shop.open(player)
}
}
}
}
}
@@ -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)
}
@@ -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<String>
val name: String
val vanilla: Boolean
val commands: List<String>
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))
}
}
}
}
@@ -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<String>, override val name: String,
override val key: Char, override val vanilla: Boolean, override val commands: List<String>
) : 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<String>()
for (line in this) {
newLore.add(PlaceholderAPI.setPlaceholders(player, line))
}
this.clear()
this.addAll(newLore)
}
}
}
@@ -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<String>,
override val vanilla: Boolean,
override val commands: List<String>
) : 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)
}
}
}
}
@@ -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<String>()
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)
}
}
}
@@ -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<String>,
override val vanilla: Boolean,
override val commands: List<String>
) : 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)
}
}
}
@@ -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)
}
@@ -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<Item>()
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<Basic>(getTitle()) {
rows(slots.size)
slots = ArrayList<List<Char>>().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")
}
}
}
@@ -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<Shop>()
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} 个商店配置")
}
}
@@ -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
}
@@ -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)
}
}
View File
+6
View File
@@ -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] 你没有足够的钱"
+70
View File
@@ -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% 物品'
+68
View File
@@ -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}'
+131
View File
@@ -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}'