Add messages.yml and functionality to purchase GUI

The plugin now has a functioning messages.yml that has the options to
set messages (improving customisability), as well as the shop now has a
working buy menu where u can see the price changes and what not.
Supports prices and rounding to 2 decimal places.
master
ALI Hamza 2020-03-11 18:11:27 +07:00
parent 34008d5d6b
commit 1e4f3dab01
No known key found for this signature in database
GPG Key ID: BCA8A46C87798C4C
6 changed files with 252 additions and 28 deletions

@ -1,24 +1,52 @@
package pw.hamzantal.shopreborn package pw.hamzantal.shopreborn
import hazae41.minecraft.kutils.bukkit.msg import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.entity.Player import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType.*
import org.bukkit.event.inventory.InventoryClickEvent import org.bukkit.event.inventory.InventoryClickEvent
import org.bukkit.event.inventory.InventoryCloseEvent
import org.bukkit.inventory.Inventory
import org.bukkit.inventory.ItemStack
import kotlin.math.max
import kotlin.math.min
enum class PurchaseType { BUY, SELL }
class PurchaseEvent(
val inv: Inventory,
val item: ItemStack,
val shop: ShopConfig,
val p: Player,
val block: ShopConfig.Item,
val type: PurchaseType
)
val purchases = mutableListOf<PurchaseEvent>()
fun closeListener(e: InventoryCloseEvent) {
val purchase = purchases.firstOrNull { it.inv == e.inventory } ?: return
purchases -= purchase
}
fun baseListener(e: InventoryClickEvent) { fun baseListener(e: InventoryClickEvent) {
if (e.inventory == Configurations.main.inventory) { if (e.inventory == GlobalConfig.main.inventory) {
mainClick(e) mainClick(e)
return return
} }
val shop = Configurations.shops.firstOrNull { it.inventories.contains(e.inventory)} ?: return val purchase = purchases.firstOrNull { it.inv == e.inventory }
shopClick(e, shop) if (purchase != null) clickInventory(e, purchase)
val shop = GlobalConfig.shops.firstOrNull { it.inventories.contains(e.inventory) } ?: return
shopClick(e, shop)
} }
fun mainClick(e: InventoryClickEvent) { fun mainClick(e: InventoryClickEvent) {
e.isCancelled = true e.isCancelled = true
if (e.rawSlot > e.inventory.size) return if (e.rawSlot > e.inventory.size) return
val main = Configurations.main val main = GlobalConfig.main
val p = e.whoClicked as Player val p = e.whoClicked as Player
val block = main.blocks.firstOrNull { it.slot == e.slot } ?: return val block = main.blocks.firstOrNull { it.slot == e.slot } ?: return
@ -31,7 +59,7 @@ fun shopClick(e: InventoryClickEvent, shop: ShopConfig) {
e.isCancelled = true e.isCancelled = true
if (e.rawSlot > e.inventory.size) return if (e.rawSlot > e.inventory.size) return
val main = Configurations.main val main = GlobalConfig.main
val p = e.whoClicked as Player val p = e.whoClicked as Player
//Check Menu Buttons //Check Menu Buttons
@ -47,7 +75,7 @@ fun shopClick(e: InventoryClickEvent, shop: ShopConfig) {
return return
} }
if(e.currentItem == main.buttons.previous) { if (e.currentItem == main.buttons.previous) {
val current = shop.inventories.indexOf(e.inventory) val current = shop.inventories.indexOf(e.inventory)
if (current == 0) return if (current == 0) return
p.openInventory(shop.inventories[current - 1]) p.openInventory(shop.inventories[current - 1])
@ -55,13 +83,91 @@ fun shopClick(e: InventoryClickEvent, shop: ShopConfig) {
//Buy / Sell Item //Buy / Sell Item
val block = shop.blocks.firstOrNull { it.item == e.currentItem } ?: return val block = shop.blocks.firstOrNull { it.item == e.currentItem } ?: return
if (block is ShopConfig.Command) {
TODO()
}
when(block) { when (e.click) {
is ShopConfig.Item -> { LEFT -> buy(e, p, shop, block as ShopConfig.Item)
p.msg("Buying ${block.item.type.name} for ${block.buy}") RIGHT -> TODO()
MIDDLE -> TODO()
else -> return
}
}
fun clickInventory(e: InventoryClickEvent, pe: PurchaseEvent) {
e.isCancelled = true
val block = pe.block
val origin = block.item
val singleCost =
if (pe.type == PurchaseType.BUY) pe.block.buy / origin.amount
else pe.block.sell / origin.amount
val lore =
if (pe.type == PurchaseType.BUY) GlobalConfig.messages.buyLore
else GlobalConfig.messages.sellLore
when (e.currentItem) {
PurchaseItems.set1 -> {
pe.item.amount = 1
pe.item.setLore(lore.mixPlaceholder(price = singleCost))
}
PurchaseItems.sub10 -> {
val now = max(1, pe.item.amount - 10)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
} }
is ShopConfig.Command -> { PurchaseItems.sub1 -> {
p.msg("Buying ${block.item.type.name} producing ${block.commands.joinToString(",")}") val now = max(1, pe.item.amount - 1)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
} }
PurchaseItems.add1 -> {
val now = min(64, pe.item.amount + 1)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
}
PurchaseItems.add10 -> {
val now = min(64, pe.item.amount + 10)
pe.item.amount = now
pe.item.setLore(lore.mixPlaceholder(price = singleCost * now))
}
PurchaseItems.set64 -> {
pe.item.amount = 64
pe.item.setLore(lore.mixPlaceholder(price = singleCost * 64))
}
}
pe.inv.setItem(22, pe.item)
}
val base = Array<ItemStack?>(54) { null }.apply {
set(18, PurchaseItems.set1)
set(19, PurchaseItems.sub10)
set(20, PurchaseItems.sub1)
set(24, PurchaseItems.add1)
set(25, PurchaseItems.add10)
set(26, PurchaseItems.set64)
}
fun Material.prettyName() = name.split("_").joinToString(" ") { it.toLowerCase().capitalize() }
fun buy(e: InventoryClickEvent, p: Player, shop: ShopConfig, block: ShopConfig.Item) {
val item = e.currentItem.clone()
if (block.buy == -1.0) return
val name = if (item.itemMeta.hasDisplayName()) item.itemMeta.displayName else item.type.prettyName()
val inv = Bukkit.createInventory(null, 54, "&2Buying $name".c).apply {
contents = base.clone()
val buyLore = GlobalConfig.messages.buyLore.mixPlaceholder(price = block.buy)
setItem(22, e.currentItem.setLore(buyLore))
setItem(39, PurchaseItems.buyConfirm)
setItem(41, PurchaseItems.cancel)
} }
p.openInventory(inv)
purchases.add(PurchaseEvent(inv, item, shop, p, block, PurchaseType.BUY))
} }

@ -12,9 +12,10 @@ import java.io.File
import kotlin.math.ceil import kotlin.math.ceil
import kotlin.math.max import kotlin.math.max
object Configurations { object GlobalConfig {
var dataFolder = File("") var dataFolder = File("")
lateinit var main: MainConfig lateinit var main: MainConfig
lateinit var messages: Messages
val shops = mutableListOf<ShopConfig>() val shops = mutableListOf<ShopConfig>()
} }
@ -59,10 +60,10 @@ class MainConfig(file: File) : ConfigFile(file) {
} }
fun addShops() { fun addShops() {
Configurations.shops.addAll(shops!!.keys.map { GlobalConfig.shops.addAll(shops!!.keys.map {
ShopConfig( ShopConfig(
it, it,
Configurations.dataFolder[shops!!.getString(it)] GlobalConfig.dataFolder[shops!!.getString(it)]
) )
}) })
} }
@ -70,7 +71,7 @@ class MainConfig(file: File) : ConfigFile(file) {
class ShopConfig(val name: String, file: File) : ConfigFile(file) { class ShopConfig(val name: String, file: File) : ConfigFile(file) {
open class Block(val item: ItemStack) open class Block(val item: ItemStack)
class Item(item: ItemStack, val buy: Int, val sell: Int) : Block(item) class Item(item: ItemStack, val buy: Double, val sell: Double) : Block(item)
class Command(item: ItemStack, val asPlayer: Boolean, val commands: List<String>) : Block(item) class Command(item: ItemStack, val asPlayer: Boolean, val commands: List<String>) : Block(item)
init { init {
@ -104,8 +105,8 @@ class ShopConfig(val name: String, file: File) : ConfigFile(file) {
?.map<ConfigurationSection, Block> { ?.map<ConfigurationSection, Block> {
val type = it.getString("type") val type = it.getString("type")
val buy = it.getInt("buyPrice", -1) val buy = it.getDouble("buyPrice", -1.0)
val sell = it.getInt("sellPrice", -1) val sell = it.getDouble("sellPrice", -.01)
val item = it.getConfigurationSection("item").asItem(buy, sell) val item = it.getConfigurationSection("item").asItem(buy, sell)
when (type) { when (type) {
@ -128,6 +129,7 @@ class ShopConfig(val name: String, file: File) : ConfigFile(file) {
val inventories = mutableListOf<Inventory>() val inventories = mutableListOf<Inventory>()
val inventory: Inventory val inventory: Inventory
init { init {
inventory = makeInventory(size, title, menuRow, blocks, 1) inventory = makeInventory(size, title, menuRow, blocks, 1)
inventories += inventory inventories += inventory
@ -140,7 +142,7 @@ class ShopConfig(val name: String, file: File) : ConfigFile(file) {
fun makeInventory(size: Int, title: String, menuRow: Int = -1, items: List<ShopConfig.Block>, page: Int): Inventory { fun makeInventory(size: Int, title: String, menuRow: Int = -1, items: List<ShopConfig.Block>, page: Int): Inventory {
return Bukkit.createInventory(null, size, title.c).apply { return Bukkit.createInventory(null, size, title.c).apply {
if (menuRow > 0) { if (menuRow > 0) {
val buttons = Configurations.main.buttons val buttons = GlobalConfig.main.buttons
for (i in menuRow until menuRow + 9) { for (i in menuRow until menuRow + 9) {
setItem(i, buttons.pane) setItem(i, buttons.pane)
} }
@ -157,15 +159,17 @@ fun makeInventory(size: Int, title: String, menuRow: Int = -1, items: List<ShopC
} }
} }
fun ConfigurationSection.asItem(buy: Int = -1, sell: Int = -1): ItemStack { fun ConfigurationSection.asItem(buy: Double = -1.0, sell: Double = -1.0): ItemStack {
val material = Material.valueOf(getString("material").toUpperCase()) val material = Material.valueOf(getString("material").toUpperCase())
val item = ItemStack(material, getInt("quantity", 1), getInt("damage", 0).toShort()) val item = ItemStack(material, getInt("quantity", 1), getInt("damage", 0).toShort())
item.itemMeta = item.itemMeta.apply { item.itemMeta = item.itemMeta.apply {
displayName = getString("name", "").c displayName = getString("name", "").c
val configLore = getStringList("lore").map { it.c }.toMutableList() val configLore = getStringList("lore").map { it.c }.toMutableList()
if (buy > 0) configLore += "&fPurchase for $$buy".c val messages = GlobalConfig.messages
if (sell > 0) configLore += "&fSell for $$sell".c
if (buy > 0) configLore += messages.buyLore.mixPlaceholder(price = buy)
if (sell > 0) configLore += messages.sellLore.mixPlaceholder(price = sell)
lore = configLore lore = configLore
} }

@ -0,0 +1,44 @@
package pw.hamzantal.shopreborn
import hazae41.minecraft.kutils.bukkit.ConfigFile
import java.io.File
class Messages(file: File, pl: ShopReborn) : ConfigFile(file) {
val currency by string("currency", "$")
val buyLore by string("buyLore")
val sellLore by string("stringLore")
val itemLore by string("itemLore")
val set1 by string("set1")
val sub10 by string("sub10")
val sub1 by string("sub1")
val add1 by string("add1")
val add10 by string("add10")
val set64 by string("set64")
val sellConfirm by string("sell.confirm")
val sellAll by string("sell.sellAll")
val sellAllLore by string("sell.sellAllLore")
val buyConfirm by string("buy.confirm")
val cancel by string("cancel")
init {
if (!file.exists()) {
val messages = pl.getResource("messages.yml").bufferedReader().readLines().joinToString("\n")
file.createNewFile()
file.writeText(messages)
}
}
}
fun String.mixPlaceholder(amount: Int = 0, price: Double = 0.0): String =
replace("%AMOUNT%", amount.toString())
.replace(
"%PRICE%",
String.format("%s%.2f", GlobalConfig.messages.currency, price)
)
.c

@ -0,0 +1,47 @@
package pw.hamzantal.shopreborn
import org.bukkit.Material
import org.bukkit.inventory.ItemStack
object PurchaseItems {
fun paneStack(damage: Int, name: String): ItemStack {
return ItemStack(Material.STAINED_GLASS_PANE, 1, damage.toShort()).apply {
itemMeta = itemMeta.apply {
displayName = name.c
}
}
}
fun blockStack(damage: Int, name: String): ItemStack {
return ItemStack(Material.STAINED_GLASS, 1, damage.toShort()).apply {
itemMeta = itemMeta.apply {
displayName = name.c
}
}
}
val msgs = GlobalConfig.messages
val set1 = paneStack(14, msgs.set1)
val sub10 = paneStack(14, msgs.sub10)
val sub1 = paneStack(14, msgs.sub1)
val add1 = paneStack(5, msgs.add1)
val add10 = paneStack(5, msgs.add10)
val set64 = paneStack(5, msgs.set64)
val sellConfirm = blockStack(5, msgs.sellConfirm)
val sellAll = blockStack(5, msgs.sellAll)
val buyConfirm = blockStack(5, msgs.buyConfirm)
val cancel = blockStack(14, msgs.cancel)
}
fun ItemStack.setLore(s: String): ItemStack {
return apply {
itemMeta = itemMeta.apply {
lore = listOf(s.c)
}
}
}

@ -1,7 +1,6 @@
package pw.hamzantal.shopreborn package pw.hamzantal.shopreborn
import hazae41.minecraft.kutils.bukkit.command import hazae41.minecraft.kutils.bukkit.command
import hazae41.minecraft.kutils.bukkit.info
import hazae41.minecraft.kutils.bukkit.listen import hazae41.minecraft.kutils.bukkit.listen
import hazae41.minecraft.kutils.get import hazae41.minecraft.kutils.get
import org.bukkit.entity.Player import org.bukkit.entity.Player
@ -12,21 +11,23 @@ class ShopReborn : JavaPlugin() {
override fun onEnable() { override fun onEnable() {
saveDefaultConfig() saveDefaultConfig()
Configurations.dataFolder = dataFolder GlobalConfig.dataFolder = dataFolder
Configurations.main = GlobalConfig.messages = Messages(dataFolder["messages.yml"], this)
GlobalConfig.main =
MainConfig(dataFolder["config.yml"]) MainConfig(dataFolder["config.yml"])
Configurations.main.addShops() GlobalConfig.main.addShops()
listen(callback = ::baseListener) listen(callback = ::baseListener)
listen(callback = ::closeListener)
command("shop") { sender, args -> command("shop") { sender, args ->
if (sender !is Player) return@command if (sender !is Player) return@command
if (args.isEmpty()) { if (args.isEmpty()) {
sender.openInventory(Configurations.main.inventory) sender.openInventory(GlobalConfig.main.inventory)
return@command return@command
} }
val shop = Configurations.shops.firstOrNull { it.name == args.component1() } ?: return@command val shop = GlobalConfig.shops.firstOrNull { it.name == args.component1() } ?: return@command
sender.openInventory(shop.inventory) sender.openInventory(shop.inventory)
} }
} }

@ -0,0 +1,22 @@
currency: "$"
buyLore: "&6Buy price: &c%PRICE%"
sellLore: "&6Sell price: &c%PRICE%"
itemLore: "&6Left click to buy, Right click to sell"
set1: "&c&lSet to 1"
sub10: "&c&lRemove 10"
sub1: "&c&lRemove 1"
add1: "&a&lAdd 1"
add10: "&a&lAdd 10"
set64: "&a&lSet 64"
# Confirm for selling/buying (after selecting the item)
sell:
confirm: "&a&lConfirm"
sellAll: "&a&lSell all"
sellAllLore: "&7Sell all for &a%PRICE%"
buy:
confirm: "&a&lConfirm"
cancel: "&c&lCancel"