数据库添加缓存 优化性能
This commit is contained in:
@@ -6,9 +6,14 @@ import com.github.xbaimiao.shoppro.core.database.SQLiteDatabase
|
||||
import com.github.xbaimiao.shoppro.core.item.ItemLoaderManager
|
||||
import com.github.xbaimiao.shoppro.core.shop.ShopManager
|
||||
import com.github.xbaimiao.shoppro.core.vault.DiyCurrency
|
||||
import com.github.xbaimiao.shoppro.core.vault.VaultImpl
|
||||
import com.xbaimiao.ktor.KtorPluginsBukkit
|
||||
import com.xbaimiao.ktor.KtorStat
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.event.player.PlayerJoinEvent
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import taboolib.common.platform.Plugin
|
||||
import taboolib.common.platform.event.SubscribeEvent
|
||||
import taboolib.common.platform.function.info
|
||||
import taboolib.module.configuration.Config
|
||||
import taboolib.module.configuration.Configuration
|
||||
@@ -33,7 +38,13 @@ object ShopPro : Plugin(), KtorStat {
|
||||
}
|
||||
ShopManager.load()
|
||||
DiyCurrency.load()
|
||||
VaultImpl.startTask()
|
||||
|
||||
database = if (config.getBoolean("mysql.enable")) MysqlDatabase(config) else SQLiteDatabase()
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach {
|
||||
database.loadPlayerData(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun reload() {
|
||||
@@ -41,7 +52,31 @@ object ShopPro : Plugin(), KtorStat {
|
||||
ShopManager.shops.clear()
|
||||
ShopManager.load()
|
||||
DiyCurrency.load()
|
||||
|
||||
Bukkit.getOnlinePlayers().forEach {
|
||||
database.releasePlayerData(it)
|
||||
}
|
||||
|
||||
database = if (config.getBoolean("mysql.enable")) MysqlDatabase(config) else SQLiteDatabase()
|
||||
Bukkit.getOnlinePlayers().forEach {
|
||||
database.loadPlayerData(it)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
override fun onDisable() {
|
||||
VaultImpl.flush()
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun join(event: PlayerJoinEvent) {
|
||||
val player = event.player
|
||||
database.loadPlayerData(player)
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
fun quit(event: PlayerQuitEvent) {
|
||||
val player = event.player
|
||||
database.releasePlayerData(player)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,4 +29,8 @@ interface Database {
|
||||
|
||||
fun reset()
|
||||
|
||||
}
|
||||
fun loadPlayerData(player: Player)
|
||||
|
||||
fun releasePlayerData(player: Player)
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.github.xbaimiao.shoppro.core.database
|
||||
import com.github.xbaimiao.shoppro.core.item.Item
|
||||
import com.github.xbaimiao.shoppro.core.item.impl.ItemsAdderShopItem
|
||||
import org.bukkit.entity.Player
|
||||
import taboolib.common.platform.function.submitAsync
|
||||
import taboolib.module.database.Host
|
||||
import taboolib.module.database.Table
|
||||
import javax.sql.DataSource
|
||||
@@ -25,6 +26,8 @@ abstract class SqlDatabase : Database {
|
||||
// ServerTable 无 User
|
||||
val playerLine = "user"
|
||||
|
||||
private val playerAlreadyDataCache = HashMap<String, HashMap<String, LimitData>>()
|
||||
|
||||
override fun reset() {
|
||||
serverTable.workspace(dataSource) {
|
||||
executeUpdate("DELETE FROM $serverTableName;").run()
|
||||
@@ -50,8 +53,20 @@ abstract class SqlDatabase : Database {
|
||||
} ?: LimitData.ofNull()
|
||||
}
|
||||
|
||||
private fun Item.toCacheKey(): String {
|
||||
val item = this
|
||||
return "${item.key}-${item.material}-${if (item is ItemsAdderShopItem) item.custom else 0}"
|
||||
}
|
||||
|
||||
override fun getPlayerAlreadyData(player: Player, item: Item): LimitData {
|
||||
return playerTable.workspace(dataSource) {
|
||||
val cache = playerAlreadyDataCache[player.name] ?: error("玩家 ${player.name} 数据缓存未加载")
|
||||
|
||||
val cacheKey = item.toCacheKey()
|
||||
if (cache.containsKey(cacheKey)) {
|
||||
return cache[cacheKey]!!
|
||||
}
|
||||
|
||||
val databaseLimitData = playerTable.workspace(dataSource) {
|
||||
select {
|
||||
where {
|
||||
playerLine eq player.uniqueId.toString()
|
||||
@@ -65,6 +80,57 @@ abstract class SqlDatabase : Database {
|
||||
}.firstOrNull {
|
||||
LimitData.formString(this.getString(dataLine))
|
||||
} ?: LimitData.ofNull()
|
||||
|
||||
cache[cacheKey] = databaseLimitData
|
||||
return databaseLimitData
|
||||
}
|
||||
|
||||
override fun setPlayerAlreadyData(player: Player, item: Item, amount: LimitData) {
|
||||
val cache = playerAlreadyDataCache[player.name] ?: error("玩家 ${player.name} 数据缓存未加载")
|
||||
val cacheKey = item.toCacheKey()
|
||||
cache[cacheKey] = amount
|
||||
|
||||
submitAsync {
|
||||
if (playerTable.workspace(dataSource) {
|
||||
select {
|
||||
where {
|
||||
playerLine eq player.uniqueId.toString()
|
||||
itemKeyLine eq item.key.toString()
|
||||
itemMaterialLine eq item.material.toString()
|
||||
if (item is ItemsAdderShopItem) {
|
||||
itemCustomLine eq item.custom
|
||||
}
|
||||
}
|
||||
}
|
||||
}.find()) {
|
||||
playerTable.workspace(dataSource) {
|
||||
update {
|
||||
where {
|
||||
playerLine eq player.uniqueId.toString()
|
||||
itemKeyLine eq item.key.toString()
|
||||
itemMaterialLine eq item.material.toString()
|
||||
if (item is ItemsAdderShopItem) {
|
||||
itemCustomLine eq item.custom
|
||||
}
|
||||
}
|
||||
set(dataLine, amount.toString())
|
||||
}
|
||||
}.run()
|
||||
} else {
|
||||
val custom = if (item is ItemsAdderShopItem) item.custom else 0
|
||||
playerTable.workspace(dataSource) {
|
||||
insert {
|
||||
value(
|
||||
item.key.toString(),
|
||||
item.material.toString(),
|
||||
custom,
|
||||
amount.toString(),
|
||||
player.uniqueId.toString()
|
||||
)
|
||||
}
|
||||
}.run()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun addAmount(item: Item, player: Player, amount: LimitData) {
|
||||
@@ -106,46 +172,12 @@ abstract class SqlDatabase : Database {
|
||||
}
|
||||
}
|
||||
|
||||
override fun setPlayerAlreadyData(player: Player, item: Item, amount: LimitData) {
|
||||
if (playerTable.workspace(dataSource) {
|
||||
select {
|
||||
where {
|
||||
playerLine eq player.uniqueId.toString()
|
||||
itemKeyLine eq item.key.toString()
|
||||
itemMaterialLine eq item.material.toString()
|
||||
if (item is ItemsAdderShopItem) {
|
||||
itemCustomLine eq item.custom
|
||||
}
|
||||
}
|
||||
}
|
||||
}.find()) {
|
||||
playerTable.workspace(dataSource) {
|
||||
update {
|
||||
where {
|
||||
playerLine eq player.uniqueId.toString()
|
||||
itemKeyLine eq item.key.toString()
|
||||
itemMaterialLine eq item.material.toString()
|
||||
if (item is ItemsAdderShopItem) {
|
||||
itemCustomLine eq item.custom
|
||||
}
|
||||
}
|
||||
set(dataLine, amount.toString())
|
||||
}
|
||||
}.run()
|
||||
} else {
|
||||
val custom = if (item is ItemsAdderShopItem) item.custom else 0
|
||||
playerTable.workspace(dataSource) {
|
||||
insert {
|
||||
value(
|
||||
item.key.toString(),
|
||||
item.material.toString(),
|
||||
custom,
|
||||
amount.toString(),
|
||||
player.uniqueId.toString()
|
||||
)
|
||||
}
|
||||
}.run()
|
||||
}
|
||||
override fun loadPlayerData(player: Player) {
|
||||
playerAlreadyDataCache[player.name] = HashMap()
|
||||
}
|
||||
|
||||
}
|
||||
override fun releasePlayerData(player: Player) {
|
||||
playerAlreadyDataCache.remove(player.name)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ interface KetherCondition {
|
||||
if (conditionIcon == null || conditionName == null) {
|
||||
return ItemStack(Material.AIR)
|
||||
}
|
||||
return taboolib.platform.util.buildItem(conditionIcon!!) {
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(conditionIcon!!) {
|
||||
name = conditionName!!.colored().replacePapi(player)
|
||||
conditionLore.forEach {
|
||||
lore += it.colored().replacePapi(player)
|
||||
@@ -37,4 +37,4 @@ interface KetherCondition {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,9 +9,7 @@ import org.bukkit.configuration.ConfigurationSection
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import taboolib.library.xseries.XMaterial
|
||||
import taboolib.library.xseries.XSkull
|
||||
import taboolib.library.xseries.parseToMaterial
|
||||
import taboolib.platform.util.ItemBuilder
|
||||
import java.util.*
|
||||
|
||||
class HeadShopItem(
|
||||
@@ -29,8 +27,8 @@ class HeadShopItem(
|
||||
}
|
||||
|
||||
override fun vanillaItem(player: Player): ItemStack {
|
||||
return taboolib.platform.util.buildItem(material) {
|
||||
skullTexture = XSkull.SkullTexture(head, UUID.randomUUID())
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(material) {
|
||||
skullTexture = com.github.xbaimiao.shoppro.util.ItemBuilder.SkullTexture(head, UUID.randomUUID())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,10 +37,10 @@ class HeadShopItem(
|
||||
}
|
||||
|
||||
override fun buildItem(player: Player): ItemStack {
|
||||
return taboolib.platform.util.buildItem(material) {
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(material) {
|
||||
this.name = this@HeadShopItem.name
|
||||
this.lore.addAll(this@HeadShopItem.lore)
|
||||
skullTexture = XSkull.SkullTexture(head, UUID.randomUUID())
|
||||
skullTexture = com.github.xbaimiao.shoppro.util.ItemBuilder.SkullTexture(head, UUID.randomUUID())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import org.bukkit.configuration.ConfigurationSection
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import taboolib.library.xseries.XMaterial
|
||||
import taboolib.library.xseries.XSkull
|
||||
import taboolib.module.chat.colored
|
||||
import taboolib.platform.util.modifyLore
|
||||
import java.util.*
|
||||
@@ -49,12 +48,12 @@ class ItemImpl(
|
||||
}
|
||||
|
||||
override fun buildItem(player: Player): ItemStack {
|
||||
return taboolib.platform.util.buildItem(material) {
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(material) {
|
||||
this.name = this@ItemImpl.name
|
||||
this.lore.addAll(this@ItemImpl.lore)
|
||||
custom?.let { customModelData = it }
|
||||
head?.let {
|
||||
skullTexture = XSkull.SkullTexture(it, UUID.randomUUID())
|
||||
skullTexture = com.github.xbaimiao.shoppro.util.ItemBuilder.SkullTexture(it, UUID.randomUUID())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class ItemsAdderShopItem(
|
||||
itemSetting: ItemSetting
|
||||
) : ShopItem(itemSetting) {
|
||||
|
||||
final override val material: Material
|
||||
override val material: Material
|
||||
|
||||
val custom: Int
|
||||
|
||||
@@ -34,13 +34,13 @@ class ItemsAdderShopItem(
|
||||
}
|
||||
|
||||
override fun vanillaItem(player: Player): ItemStack {
|
||||
return taboolib.platform.util.buildItem(material) {
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(material) {
|
||||
this.customModelData = custom
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildItem(player: Player): ItemStack {
|
||||
return taboolib.platform.util.buildItem(material) {
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(material) {
|
||||
this.name = this@ItemsAdderShopItem.name
|
||||
this.lore.addAll(this@ItemsAdderShopItem.lore)
|
||||
this.customModelData = custom
|
||||
@@ -67,4 +67,4 @@ class ItemsAdderShopItem(
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package com.github.xbaimiao.shoppro.core.item.impl
|
||||
import com.github.xbaimiao.shoppro.core.item.Item
|
||||
import com.github.xbaimiao.shoppro.core.item.ItemLoader
|
||||
import com.github.xbaimiao.shoppro.core.shop.Shop
|
||||
import ink.ptms.zaphkiel.Zaphkiel
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.configuration.ConfigurationSection
|
||||
@@ -19,14 +18,14 @@ import pers.neige.neigeitems.manager.ItemManager
|
||||
class NeigeItem(
|
||||
private val neigeItem: ItemGenerator,
|
||||
itemSetting: ItemSetting,
|
||||
private val neigeId :String
|
||||
private val neigeId: String
|
||||
) : VanillaShopItem(itemSetting) {
|
||||
|
||||
override val material: Material
|
||||
get() = neigeItem.staticItemStack.type
|
||||
|
||||
override fun vanillaItem(player: Player): ItemStack {
|
||||
return ItemManager.getItemStack(neigeId,player)!!
|
||||
return ItemManager.getItemStack(neigeId, player)!!
|
||||
}
|
||||
|
||||
override fun equal(itemStack: ItemStack): Boolean {
|
||||
@@ -42,8 +41,8 @@ class NeigeItem(
|
||||
error("NeigeItems Plugin not found")
|
||||
}
|
||||
val neigeId = section.getString("material")!!.substring(prefix.length + 1)
|
||||
val item = ItemManager.getItem(neigeId)?: error("NeigeItems $neigeId not found")
|
||||
return NeigeItem(item, section.toItemSetting(char, shop),neigeId)
|
||||
val item = ItemManager.getItem(neigeId) ?: error("NeigeItems $neigeId not found")
|
||||
return NeigeItem(item, section.toItemSetting(char, shop), neigeId)
|
||||
}
|
||||
|
||||
override fun parseToMaterial(section: ConfigurationSection): Material {
|
||||
@@ -52,4 +51,4 @@ class NeigeItem(
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ import taboolib.platform.util.hasLore
|
||||
open class VanillaShopItem(itemSetting: ItemSetting) : ShopItem(itemSetting) {
|
||||
|
||||
override fun vanillaItem(player: Player): ItemStack {
|
||||
return taboolib.platform.util.buildItem(material)
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(material)
|
||||
}
|
||||
|
||||
override fun equal(itemStack: ItemStack): Boolean {
|
||||
@@ -20,7 +20,7 @@ open class VanillaShopItem(itemSetting: ItemSetting) : ShopItem(itemSetting) {
|
||||
}
|
||||
|
||||
override fun buildItem(player: Player): ItemStack {
|
||||
return taboolib.platform.util.buildItem(material) {
|
||||
return com.github.xbaimiao.shoppro.util.buildItem(material) {
|
||||
this.name = this@VanillaShopItem.name
|
||||
this.lore.addAll(this@VanillaShopItem.lore)
|
||||
}
|
||||
@@ -35,4 +35,4 @@ open class VanillaShopItem(itemSetting: ItemSetting) : ShopItem(itemSetting) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import taboolib.module.chat.colored
|
||||
import taboolib.module.ui.ClickType
|
||||
import taboolib.module.ui.openMenu
|
||||
import taboolib.module.ui.type.Basic
|
||||
import taboolib.module.ui.type.Chest
|
||||
import taboolib.platform.util.giveItem
|
||||
import taboolib.platform.util.hasItem
|
||||
import taboolib.platform.util.sendLang
|
||||
|
||||
@@ -2,16 +2,59 @@ package com.github.xbaimiao.shoppro.core.vault
|
||||
|
||||
import com.github.xbaimiao.shoppro.util.Util.format
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.player.PlayerQuitEvent
|
||||
import taboolib.common.platform.event.EventPriority
|
||||
import taboolib.common.platform.event.SubscribeEvent
|
||||
import taboolib.common.platform.function.submit
|
||||
import taboolib.platform.compat.VaultService
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
|
||||
object VaultImpl : Currency {
|
||||
|
||||
private val queue = ConcurrentLinkedQueue<ValueQueue>()
|
||||
|
||||
private data class ValueQueue(val player: Player, val money: Double)
|
||||
|
||||
fun startTask() {
|
||||
submit(period = 20) {
|
||||
flush()
|
||||
}
|
||||
}
|
||||
|
||||
@SubscribeEvent(priority = EventPriority.LOWEST)
|
||||
fun quit(event: PlayerQuitEvent) {
|
||||
val iterator = queue.iterator()
|
||||
var amount = 0.0
|
||||
while (iterator.hasNext()) {
|
||||
val queue = iterator.next()
|
||||
if (queue.player.uniqueId == event.player.uniqueId) {
|
||||
amount += queue.money
|
||||
iterator.remove()
|
||||
}
|
||||
}
|
||||
if (amount > 0) {
|
||||
realGiveMoney(event.player, amount)
|
||||
}
|
||||
}
|
||||
|
||||
fun flush() {
|
||||
queue.groupBy { it.player }.forEach { (player, valueQueues) ->
|
||||
val amount = valueQueues.sumOf { it.money }
|
||||
realGiveMoney(player, amount)
|
||||
}
|
||||
queue.clear()
|
||||
}
|
||||
|
||||
private fun realGiveMoney(player: Player, double: Double) {
|
||||
VaultService.economy!!.depositPlayer(player, double.format())
|
||||
}
|
||||
|
||||
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())
|
||||
queue.offer(ValueQueue(player, double))
|
||||
}
|
||||
|
||||
override fun takeMoney(player: Player, double: Double): Boolean {
|
||||
@@ -26,5 +69,4 @@ object VaultImpl : Currency {
|
||||
return VaultService.economy!!.getBalance(player).format()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,363 @@
|
||||
package com.github.xbaimiao.shoppro.util
|
||||
|
||||
import com.mojang.authlib.GameProfile
|
||||
import com.mojang.authlib.properties.Property
|
||||
import org.bukkit.ChatColor
|
||||
import org.bukkit.Color
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.block.banner.Pattern
|
||||
import org.bukkit.enchantments.Enchantment
|
||||
import org.bukkit.entity.EntityType
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.meta.*
|
||||
import org.bukkit.potion.PotionData
|
||||
import org.bukkit.potion.PotionEffect
|
||||
import taboolib.library.reflex.Reflex.Companion.getProperty
|
||||
import taboolib.library.reflex.Reflex.Companion.invokeMethod
|
||||
import taboolib.library.reflex.Reflex.Companion.setProperty
|
||||
import taboolib.library.xseries.XMaterial
|
||||
import taboolib.module.chat.colored
|
||||
import taboolib.platform.util.isAir
|
||||
import java.util.*
|
||||
|
||||
|
||||
/**
|
||||
* 通过现有物品构建新的物品
|
||||
*
|
||||
* @param itemStack 原始物品
|
||||
* @param builder 构建器
|
||||
* @return 新的物品
|
||||
* @throws IllegalArgumentException 如果物品为空气
|
||||
*/
|
||||
fun buildItem(itemStack: ItemStack, builder: ItemBuilder.() -> Unit = {}): ItemStack {
|
||||
if (itemStack.isAir()) {
|
||||
error("air")
|
||||
}
|
||||
return ItemBuilder(itemStack).also(builder).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 [Material] 材质构建新的物品
|
||||
*
|
||||
* @param material 材质
|
||||
* @param builder 构建器
|
||||
* @return 新的物品
|
||||
* @throws IllegalArgumentException 如果材质为空气
|
||||
*/
|
||||
fun buildItem(material: Material, builder: ItemBuilder.() -> Unit = {}): ItemStack {
|
||||
// 在低版本, 并没有 Material.isAir() 方法
|
||||
if (material == Material.AIR) {
|
||||
error("air")
|
||||
}
|
||||
return ItemBuilder(material).also(builder).build()
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 [XMaterial] 材质构建新的物品
|
||||
*
|
||||
* @param material 材质
|
||||
* @param builder 构建器
|
||||
* @return 新的物品
|
||||
* @throws IllegalArgumentException 如果材质为空气
|
||||
*/
|
||||
fun buildItem(material: XMaterial, builder: ItemBuilder.() -> Unit = {}): ItemStack {
|
||||
// 在低版本, 并没有 Material.isAir() 方法
|
||||
if (material == XMaterial.AIR) {
|
||||
error("air")
|
||||
}
|
||||
return ItemBuilder(material.parseMaterial() ?: error("material.parseMaterial() is null")).also(builder).build()
|
||||
}
|
||||
|
||||
open class ItemBuilder {
|
||||
|
||||
class SkullTexture(val textures: String, val uuid: UUID? = UUID.randomUUID())
|
||||
|
||||
/**
|
||||
* 物品材质
|
||||
*/
|
||||
var material: Material
|
||||
|
||||
/**
|
||||
* 数量
|
||||
*/
|
||||
var amount = 1
|
||||
|
||||
/**
|
||||
* 附加值(损伤值)
|
||||
*/
|
||||
var damage = 0
|
||||
|
||||
/**
|
||||
* 展示名称
|
||||
*/
|
||||
var name: String? = null
|
||||
|
||||
/**
|
||||
* 描述
|
||||
*/
|
||||
val lore = ArrayList<String>()
|
||||
|
||||
/**
|
||||
* 标签
|
||||
*/
|
||||
val flags = ArrayList<ItemFlag>()
|
||||
|
||||
/**
|
||||
* 附魔
|
||||
*/
|
||||
val enchants = HashMap<Enchantment, Int>()
|
||||
|
||||
/**
|
||||
* 旗帜花纹
|
||||
*/
|
||||
val patterns = ArrayList<Pattern>()
|
||||
|
||||
/**
|
||||
* 颜色
|
||||
*/
|
||||
var color: Color? = null
|
||||
|
||||
/**
|
||||
* 药水效果
|
||||
*/
|
||||
val potions = ArrayList<PotionEffect>()
|
||||
|
||||
/**
|
||||
* 基础药水效果
|
||||
*/
|
||||
var potionData: PotionData? = null
|
||||
|
||||
/**
|
||||
* 生物类型
|
||||
*/
|
||||
var spawnType: EntityType? = null
|
||||
|
||||
/**
|
||||
* 头颅信息
|
||||
*/
|
||||
var skullOwner: String? = null
|
||||
|
||||
/**
|
||||
* 头颅材质信息
|
||||
*/
|
||||
var skullTexture: SkullTexture? = null
|
||||
|
||||
/**
|
||||
* 无法破坏
|
||||
*/
|
||||
var isUnbreakable = false
|
||||
|
||||
/**
|
||||
* CustomModelData
|
||||
*/
|
||||
var customModelData = -1
|
||||
|
||||
/**
|
||||
* 原始数据
|
||||
* 尝试修复自定义 nbt 失效的问题
|
||||
*/
|
||||
var originMeta: ItemMeta? = null
|
||||
|
||||
/**
|
||||
* 当构建完成时,做出最后修改
|
||||
*/
|
||||
var finishing: (ItemStack) -> Unit = {}
|
||||
|
||||
|
||||
/**
|
||||
* 使其发光
|
||||
*/
|
||||
fun shiny() {
|
||||
flags += ItemFlag.HIDE_ENCHANTS
|
||||
enchants[Enchantment.LURE] = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏所有附加信息(赋予所有 ItemFlag)
|
||||
*/
|
||||
fun hideAll() {
|
||||
flags.addAll(ItemFlag.values())
|
||||
}
|
||||
|
||||
open fun getSkinValue(skull: ItemMeta): SkullTexture? {
|
||||
var profile: GameProfile? = null
|
||||
try {
|
||||
profile = skull.getProperty("profile")
|
||||
} catch (ignored: Exception) {
|
||||
}
|
||||
if (profile != null && !profile.properties["textures"].isEmpty()) {
|
||||
for (property in profile.properties["textures"]) {
|
||||
if (property.value.isNotEmpty()) {
|
||||
return SkullTexture(property.value, profile.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 上色
|
||||
*/
|
||||
fun colored() {
|
||||
if (name != null) {
|
||||
name = try {
|
||||
name!!.colored()
|
||||
} catch (ex: NoClassDefFoundError) {
|
||||
ChatColor.translateAlternateColorCodes('&', name!!)
|
||||
}
|
||||
}
|
||||
if (lore.isNotEmpty()) {
|
||||
val newLore = try {
|
||||
lore.colored()
|
||||
} catch (ex: NoClassDefFoundError) {
|
||||
lore.map { ChatColor.translateAlternateColorCodes('&', it) }
|
||||
}
|
||||
lore.clear()
|
||||
lore += newLore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建物品
|
||||
*/
|
||||
open fun build(): ItemStack {
|
||||
val itemStack = ItemStack(material)
|
||||
itemStack.amount = amount
|
||||
if (damage != 0) {
|
||||
itemStack.durability = damage.toShort()
|
||||
}
|
||||
val itemMeta = originMeta ?: itemStack.itemMeta ?: return itemStack
|
||||
itemMeta.setDisplayName(name)
|
||||
itemMeta.lore = lore
|
||||
kotlin.runCatching {
|
||||
itemMeta.addItemFlags(*flags.map { org.bukkit.inventory.ItemFlag.valueOf(it.name) }.toTypedArray())
|
||||
}
|
||||
if (itemMeta is EnchantmentStorageMeta) {
|
||||
enchants.forEach { (e, lvl) -> itemMeta.addStoredEnchant(e, lvl, true) }
|
||||
} else {
|
||||
enchants.forEach { (e, lvl) -> itemMeta.addEnchant(e, lvl, true) }
|
||||
}
|
||||
when (itemMeta) {
|
||||
is LeatherArmorMeta -> {
|
||||
itemMeta.setColor(color)
|
||||
}
|
||||
|
||||
is PotionMeta -> {
|
||||
itemMeta.color = color
|
||||
potions.forEach { itemMeta.addCustomEffect(it, true) }
|
||||
if (potionData != null) {
|
||||
itemMeta.basePotionData = potionData!!
|
||||
}
|
||||
}
|
||||
|
||||
is SkullMeta -> {
|
||||
if (skullOwner != null) {
|
||||
itemMeta.owner = skullOwner
|
||||
}
|
||||
if (skullTexture != null) {
|
||||
itemMeta.setProperty("profile", GameProfile(skullTexture!!.uuid, null).also {
|
||||
it.properties.put("textures", Property("textures", skullTexture!!.textures))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
itemMeta.isUnbreakable = isUnbreakable
|
||||
} catch (ex: NoSuchMethodError) {
|
||||
try {
|
||||
itemMeta.invokeMethod<Any>("spigot")!!.invokeMethod<Any>("setUnbreakable", isUnbreakable)
|
||||
} catch (ignored: NoSuchMethodException) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (spawnType != null && itemMeta is SpawnEggMeta) {
|
||||
itemMeta.spawnedType = spawnType
|
||||
}
|
||||
} catch (ignored: NoClassDefFoundError) {
|
||||
}
|
||||
try {
|
||||
if (patterns.isNotEmpty() && itemMeta is BannerMeta) {
|
||||
patterns.forEach { itemMeta.addPattern(it) }
|
||||
}
|
||||
} catch (ignored: NoClassDefFoundError) {
|
||||
}
|
||||
try {
|
||||
if (customModelData != -1) {
|
||||
itemMeta.invokeMethod<Void>("setCustomModelData", customModelData)
|
||||
}
|
||||
} catch (ignored: NoSuchMethodException) {
|
||||
}
|
||||
itemStack.itemMeta = itemMeta
|
||||
finishing(itemStack)
|
||||
return itemStack
|
||||
}
|
||||
|
||||
constructor(material: Material) {
|
||||
this.material = material
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过现有物品构建新的物品
|
||||
* 读取基本信息
|
||||
*/
|
||||
constructor(item: ItemStack) {
|
||||
material = item.type
|
||||
amount = item.amount
|
||||
damage = item.durability.toInt()
|
||||
// 如果物品没有 ItemMeta 则不进行后续操作
|
||||
val itemMeta = item.itemMeta ?: return
|
||||
originMeta = itemMeta
|
||||
name = itemMeta.displayName
|
||||
lore += itemMeta.lore ?: emptyList()
|
||||
flags += kotlin.runCatching { itemMeta.itemFlags.map { ItemFlag.valueOf(it.name) } }.getOrElse { emptyList() }
|
||||
enchants += if (itemMeta is EnchantmentStorageMeta) {
|
||||
itemMeta.storedEnchants
|
||||
} else {
|
||||
itemMeta.enchants
|
||||
}
|
||||
when (itemMeta) {
|
||||
is LeatherArmorMeta -> {
|
||||
color = itemMeta.color
|
||||
}
|
||||
|
||||
is PotionMeta -> {
|
||||
color = itemMeta.color
|
||||
potions += itemMeta.customEffects
|
||||
potionData = itemMeta.basePotionData
|
||||
}
|
||||
|
||||
is SkullMeta -> {
|
||||
if (itemMeta.owner != null) {
|
||||
skullOwner = itemMeta.owner
|
||||
}
|
||||
skullTexture = getSkinValue(itemMeta)
|
||||
}
|
||||
}
|
||||
try {
|
||||
customModelData = itemMeta.getProperty<Int>("customModelData") ?: -1
|
||||
} catch (ignored: NoSuchFieldException) {
|
||||
}
|
||||
try {
|
||||
isUnbreakable = itemMeta.isUnbreakable
|
||||
} catch (ex: NoSuchMethodError) {
|
||||
try {
|
||||
isUnbreakable = itemMeta.invokeMethod<Any>("spigot")!!.invokeMethod<Boolean>("isUnbreakable") ?: false
|
||||
} catch (ignored: NoSuchMethodException) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
if (itemMeta is SpawnEggMeta && itemMeta.spawnedType != null) {
|
||||
spawnType = itemMeta.spawnedType
|
||||
}
|
||||
} catch (ignored: NoClassDefFoundError) {
|
||||
} catch (ignored: UnsupportedOperationException) {
|
||||
|
||||
}
|
||||
try {
|
||||
if (itemMeta is BannerMeta && itemMeta.patterns.isNotEmpty()) {
|
||||
patterns += itemMeta.patterns
|
||||
}
|
||||
} catch (ignored: NoClassDefFoundError) {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.github.xbaimiao.shoppro.util;
|
||||
|
||||
public enum ItemFlag {
|
||||
HIDE_ENCHANTS,
|
||||
HIDE_ATTRIBUTES,
|
||||
HIDE_UNBREAKABLE,
|
||||
HIDE_DESTROYS,
|
||||
HIDE_PLACED_ON,
|
||||
HIDE_POTION_EFFECTS,
|
||||
HIDE_DYE
|
||||
}
|
||||
Reference in New Issue
Block a user