Initial commit

This commit is contained in:
Auxilor
2022-03-16 16:51:53 +00:00
commit a4e755b9e4
41 changed files with 2568 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
package com.willfp.ecocrates
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.ecocrates.commands.CommandEcoCrates
import com.willfp.ecocrates.crate.placed.CrateDisplay
import com.willfp.ecocrates.crate.placed.PlacedCrates
import com.willfp.ecocrates.util.PlacedCrateListener
import org.bukkit.event.Listener
class EcoCratesPlugin : EcoPlugin(0, 0, "&#6dd5ed") {
init {
instance = this
}
override fun handleDisable() {
PlacedCrates.removeAll()
}
override fun handleReload() {
CrateDisplay(this).start()
}
override fun loadPluginCommands(): List<PluginCommand> {
return listOf(
CommandEcoCrates(this)
)
}
override fun loadListeners(): List<Listener> {
return listOf(
PlacedCrateListener(this)
)
}
companion object {
/**
* Instance of the plugin.
*/
lateinit var instance: EcoCratesPlugin
private set
}
}

View File

@@ -0,0 +1,25 @@
package com.willfp.ecocrates.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.PluginCommand
import org.bukkit.command.CommandSender
class CommandEcoCrates(plugin: EcoPlugin) : PluginCommand(
plugin,
"ecocrates",
"ecocrates.command.ecocrates",
true
) {
init {
this.addSubcommand(CommandReload(plugin))
.addSubcommand(CommandOpen(plugin))
.addSubcommand(CommandPreview(plugin))
.addSubcommand(CommandGive(plugin))
.addSubcommand(CommandKeys(plugin))
.addSubcommand(CommandSet(plugin))
}
override fun onExecute(sender: CommandSender, args: List<String>) {
sender.sendMessage(plugin.langYml.getMessage("invalid-command"))
}
}

View File

@@ -0,0 +1,94 @@
package com.willfp.ecocrates.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.savedDisplayName
import com.willfp.ecocrates.crate.Crates
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.util.StringUtil
class CommandGive(plugin: EcoPlugin) : Subcommand(
plugin,
"give",
"ecocrates.command.give",
false
) {
override fun onExecute(sender: CommandSender, args: List<String>) {
if (args.isEmpty()) {
sender.sendMessage(plugin.langYml.getMessage("must-specify-player"))
return
}
@Suppress("DEPRECATION")
val player = Bukkit.getOfflinePlayer(args[0])
if (!player.hasPlayedBefore()) {
sender.sendMessage(plugin.langYml.getMessage("invalid-player"))
return
}
if (args.size < 2) {
sender.sendMessage("must-specify-crate")
return
}
val crate = Crates.getByID(args[1])
if (crate == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-crate"))
return
}
val amount = args.getOrNull(2)?.toIntOrNull() ?: 1
crate.giveKeys(player, amount)
sender.sendMessage(
plugin.langYml.getMessage("gave-keys")
.replace("%amount%", amount.toString())
.replace("%crate%", crate.name)
.replace("%user%", player.savedDisplayName)
)
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Crates.values().map { it.id }
}
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Bukkit.getOnlinePlayers().map { it.name },
completions
)
return completions
}
if (args.size == 2) {
StringUtil.copyPartialMatches(
args[1],
Crates.values().map { it.id },
completions
)
return completions
}
if (args.size == 3) {
StringUtil.copyPartialMatches(
args[2],
listOf("1", "2", "3", "4", "5", "10"),
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -0,0 +1,19 @@
package com.willfp.ecocrates.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecocrates.crate.KeyGUI
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
class CommandKeys(plugin: EcoPlugin) : Subcommand(
plugin,
"keys",
"ecocrates.command.keys",
true
) {
override fun onExecute(player: CommandSender, args: List<String>) {
player as Player
KeyGUI.open(player)
}
}

View File

@@ -0,0 +1,42 @@
package com.willfp.ecocrates.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecocrates.crate.Crates
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandOpen(plugin: EcoPlugin) : Subcommand(
plugin,
"open",
"ecocrates.command.open",
true
) {
override fun onExecute(player: CommandSender, args: List<String>) {
player as Player
val crate = Crates.getByID(args[0]) ?: return
crate.openWithKey(player)
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Crates.values().map { it.id }
}
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Crates.values().map { it.id },
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -0,0 +1,41 @@
package com.willfp.ecocrates.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecocrates.crate.Crates
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandPreview(plugin: EcoPlugin) : Subcommand(
plugin,
"preview",
"ecocrates.command.preview",
true
) {
override fun onExecute(player: CommandSender, args: List<String>) {
player as Player
val crate = Crates.getByID(args[0]) ?: return
crate.previewForPlayer(player)
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Crates.values().map { it.id }
}
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Crates.values().map { it.id },
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.ecocrates.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.util.NumberUtils
import com.willfp.eco.util.StringUtils
import org.bukkit.command.CommandSender
class CommandReload(plugin: EcoPlugin) : Subcommand(
plugin,
"reload",
"ecocrates.command.reload",
false
) {
override fun onExecute(sender: CommandSender, args: List<String>) {
sender.sendMessage(
plugin.langYml.getMessage("reloaded", StringUtils.FormatOption.WITHOUT_PLACEHOLDERS)
.replace("%time%", NumberUtils.format(plugin.reloadWithTime().toDouble()))
)
}
}

View File

@@ -0,0 +1,63 @@
package com.willfp.ecocrates.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.ecocrates.crate.Crates
import com.willfp.ecocrates.crate.placed.PlacedCrates
import org.bukkit.command.CommandSender
import org.bukkit.entity.Player
import org.bukkit.util.StringUtil
class CommandSet(plugin: EcoPlugin) : Subcommand(
plugin,
"set",
"ecocrates.command.set",
true
) {
override fun onExecute(player: CommandSender, args: List<String>) {
player as Player
if (args.isEmpty()) {
player.sendMessage(plugin.langYml.getMessage("must-specify-crate"))
return
}
val crate = Crates.getByID(args[0])
if (crate == null) {
player.sendMessage(plugin.langYml.getMessage("invalid-crate"))
return
}
val block = player.getTargetBlockExact(10)
if (block == null) {
player.sendMessage(plugin.langYml.getMessage("must-target-block"))
return
}
PlacedCrates.setAsCrate(block.location, crate)
player.sendMessage(plugin.langYml.getMessage("set-block-as-crate"))
}
override fun tabComplete(sender: CommandSender, args: List<String>): List<String> {
val completions = mutableListOf<String>()
if (args.isEmpty()) {
return Crates.values().map { it.id }
}
if (args.size == 1) {
StringUtil.copyPartialMatches(
args[0],
Crates.values().map { it.id },
completions
)
return completions
}
return emptyList()
}
}

View File

@@ -0,0 +1,168 @@
package com.willfp.ecocrates.crate
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.data.keys.PersistentDataKey
import com.willfp.eco.core.data.keys.PersistentDataKeyType
import com.willfp.eco.core.data.profile
import com.willfp.eco.core.gui.menu
import com.willfp.eco.core.gui.menu.MenuBuilder
import com.willfp.eco.core.gui.slot
import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.MaskItems
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.placeholder.PlayerPlaceholder
import com.willfp.eco.util.formatEco
import com.willfp.ecocrates.reward.Reward
import com.willfp.ecocrates.util.ConfiguredSound
import com.willfp.ecocrates.util.PlayableSound
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
class Crate(
private val config: Config,
private val plugin: EcoPlugin
) {
val id = config.getString("id")
val name = config.getFormattedString("name")
val keysKey = PersistentDataKey(
plugin.namespacedKeyFactory.create("${id}_keys"),
PersistentDataKeyType.INT,
0
).player()
val hologramLines = config.getFormattedStrings("placed.hologram")
val hologramHeight = config.getDouble("placed.hologram-height")
private val rewards = config.getSubsections("rewards").map { Reward(it) }
private val previewGUI = menu(config.getInt("gui.rows")) {
setMask(
FillerMask(
MaskItems.fromItemNames(config.getStrings("gui.mask.items")),
*config.getStrings("gui.mask.pattern").toTypedArray()
)
)
setTitle(config.getFormattedString("gui.title"))
for (reward in rewards) {
setSlot(
reward.displayRow,
reward.displayColumn,
slot(reward.display) {
}
)
}
}
private val onFinishSound = PlayableSound(
config.getSubsections("onFinish.sounds")
.map { ConfiguredSound.fromConfig(it) }
)
init {
PlayerPlaceholder(
plugin,
"${id}_keys",
) { getKeys(it).toString() }.register()
}
private fun getRandomReward(displayWeight: Boolean = false): Reward {
var weight = 100.0
val selection = rewards.toList().shuffled()
lateinit var current: Reward
for (i in 0..Int.MAX_VALUE) {
current = selection[i % selection.size]
weight -= if (displayWeight) current.displayWeight else current.weight
if (weight <= 0) {
break
}
}
return current
}
private fun makeRoll(player: Player): Roll {
val display = mutableListOf<Reward>()
// Add three to the scroll times so that it lines up
for (i in 0..(SCROLL_TIMES + 3)) {
display.add(getRandomReward(displayWeight = true)) // Fill roll with display weight items
}
// The last item should use the actual weights.
return Roll(display, getRandomReward(), this, this.plugin, player)
}
internal fun addToKeyGUI(builder: MenuBuilder) {
builder.setSlot(
config.getInt("keygui.row"),
config.getInt("keygui.column"),
slot(
ItemStackBuilder(Items.lookup(config.getString("keygui.item"))).build()
) {
onLeftClick { event, _, _ ->
val player = event.whoClicked as Player
openWithKey(player)
}
onRightClick { event, _, _ ->
event.whoClicked.closeInventory()
config.getFormattedStrings("keygui.rightClickMessage")
.forEach { event.whoClicked.sendMessage(it) }
}
setUpdater { player, _, previous ->
previous.apply {
itemMeta = itemMeta?.apply {
lore = config.getStrings("keygui.lore")
.map { it.replace("%keys%", getKeys(player).toString()) }
.map { it.formatEco(player) }
}
}
previous
}
}
)
}
fun openWithKey(player: Player) {
val keys = player.profile.read(keysKey)
if (keys == 0) {
player.sendMessage(plugin.langYml.getMessage("not-enough-keys").replace("%crate%", this.name))
return
}
player.profile.write(keysKey, keys - 1)
open(player)
}
fun open(player: Player) {
makeRoll(player).roll()
}
fun previewForPlayer(player: Player) {
previewGUI.open(player)
}
fun handleFinish(player: Player, roll: Roll) {
roll.reward.giveTo(player)
onFinishSound.play(player.location)
}
fun giveKeys(player: OfflinePlayer, amount: Int) {
player.profile.write(keysKey, player.profile.read(keysKey) + amount)
}
fun getKeys(player: OfflinePlayer): Int {
return player.profile.read(keysKey)
}
}

View File

@@ -0,0 +1,46 @@
package com.willfp.ecocrates.crate
import com.google.common.collect.HashBiMap
import com.google.common.collect.ImmutableList
import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.ecocrates.EcoCratesPlugin
import com.willfp.ecocrates.crate.placed.PlacedCrates
@Suppress("UNUSED")
object Crates {
private val BY_ID = HashBiMap.create<String, Crate>()
/**
* Get crate matching id.
*
* @param id The id to query.
* @return The matching crate, or null if not found.
*/
@JvmStatic
fun getByID(id: String): Crate? {
return BY_ID[id]
}
/**
* List of all registered crates.
*
* @return The crates.
*/
@JvmStatic
fun values(): List<Crate> {
return ImmutableList.copyOf(BY_ID.values)
}
@JvmStatic
@ConfigUpdater
fun update(plugin: EcoCratesPlugin) {
BY_ID.clear()
for (config in plugin.configYml.getSubsections("crates")) {
val crate = Crate(config, plugin)
BY_ID[crate.id] = crate
}
PlacedCrates.load()
}
}

View File

@@ -0,0 +1,36 @@
package com.willfp.ecocrates.crate
import com.willfp.eco.core.config.updating.ConfigUpdater
import com.willfp.eco.core.gui.menu
import com.willfp.eco.core.gui.menu.Menu
import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.MaskItems
import com.willfp.ecocrates.EcoCratesPlugin
import org.bukkit.entity.Player
object KeyGUI {
private lateinit var menu: Menu
@JvmStatic
@ConfigUpdater
fun update(plugin: EcoCratesPlugin) {
menu = menu(plugin.configYml.getInt("keygui.rows")) {
setMask(
FillerMask(
MaskItems.fromItemNames(plugin.configYml.getStrings("keygui.mask.items")),
*plugin.configYml.getStrings("keygui.mask.pattern").toTypedArray()
)
)
setTitle(plugin.configYml.getFormattedString("keygui.title"))
for (crate in Crates.values()) {
crate.addToKeyGUI(this)
}
}
}
fun open(player: Player) {
menu.open(player)
}
}

View File

@@ -0,0 +1,112 @@
package com.willfp.ecocrates.crate
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.gui.menu
import com.willfp.eco.core.gui.slot
import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.MaskItems
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.ecocrates.reward.Reward
import com.willfp.ecocrates.util.ExactTestableItem
import org.bukkit.Material
import org.bukkit.Sound
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
const val SCROLL_TIMES = 35
private val delays = listOf(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 4, 5, 6, 10, 12, 25)
class Roll(
private val rollItems: List<Reward>,
val reward: Reward,
private val crate: Crate,
private val plugin: EcoPlugin,
private val player: Player
) {
private val display = rollItems.toMutableList().apply {
add(reward) // Add the item that the player will win
addAll(rollItems.shuffled()) // Add extra items for filler
}
private var scroll = 0
private var tick = 0
private val runnable = plugin.runnableFactory.create {
val currentDelay = delays[scroll]
if (tick % currentDelay == 0) {
tick = 0
scroll++
gui.refresh(player)
player.playSound(
player.location,
Sound.BLOCK_STONE_BUTTON_CLICK_ON,
1.0f,
1.0f
)
if (scroll >= SCROLL_TIMES) {
it.cancel()
plugin.scheduler.runLater(60) { player.closeInventory() }
}
}
tick++
}
private val gui = menu(3) {
setMask(
FillerMask(
MaskItems(
ExactTestableItem(
ItemStackBuilder(Material.BLACK_STAINED_GLASS_PANE)
.setDisplayName("")
.build()
),
ExactTestableItem(
ItemStackBuilder(Material.GREEN_STAINED_GLASS_PANE)
.setDisplayName("")
.build()
)
),
"111121111",
"000000000",
"111121111"
)
)
setTitle(crate.name)
for (i in 1..9) {
setSlot(
2,
i,
slot(
ItemStack(Material.AIR)
) {
setUpdater { _, _, _ ->
display[(9 - i) + scroll].display
}
}
)
}
onClose { event, _ ->
handleFinish(event.player as Player)
}
}
fun roll() {
gui.open(player)
// Run the scroll animation
runnable.runTaskTimer(1, 1)
}
private fun handleFinish(player: Player) {
runnable.cancel()
crate.handleFinish(player, this)
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.ecocrates.crate.placed
import com.willfp.eco.core.EcoPlugin
class CrateDisplay(
private val plugin: EcoPlugin
) {
private var tick = 0
fun start() {
plugin.scheduler.runTimer(1, 1) { tick() }
}
private fun tick() {
for (crate in PlacedCrates.values()) {
crate.tick(tick)
}
tick++
}
}

View File

@@ -0,0 +1,34 @@
package com.willfp.ecocrates.crate.placed
import com.willfp.eco.core.integrations.hologram.HologramManager
import com.willfp.ecocrates.crate.Crate
import org.bukkit.Location
class PlacedCrate(
val crate: Crate,
blockLocation: Location
) {
// Center the location, they're mutable because bukkit is bad at designing APIs.
private val location = blockLocation.clone().apply {
x += 0.5
y += 0.5
z += 0.5
}
private val hologram = HologramManager.createHologram(location.clone().apply {
y += crate.hologramHeight
}, crate.hologramLines)
internal fun tick(tick: Int) {
tick.toLong() // Just shut up, compiler
tickHolograms()
}
internal fun onRemove() {
hologram.remove()
}
private fun tickHolograms() {
//hologram.setContents(crate.hologramLines)
}
}

View File

@@ -0,0 +1,85 @@
package com.willfp.ecocrates.crate.placed
import com.willfp.eco.core.config.ConfigType
import com.willfp.eco.core.config.StaticBaseConfig
import com.willfp.ecocrates.EcoCratesPlugin
import com.willfp.ecocrates.crate.Crate
import com.willfp.ecocrates.crate.Crates
import org.bukkit.Bukkit
import org.bukkit.Location
private val plugin = EcoCratesPlugin.instance
private object YamlStorage : StaticBaseConfig(
"placedcrates",
plugin,
ConfigType.YAML
)
private fun Location.toShortString(): String {
return "$blockX,$blockY,$blockZ@${world!!.name.lowercase()}"
}
private fun locationFromShortString(string: String): Location? {
val split = string.split("@")
if (split.size != 2) {
return null
}
val coords = split[0].split(",")
if (coords.size != 3) {
return null
}
val world = Bukkit.getWorld(split[1]) ?: return null
val x = coords[0].toIntOrNull() ?: return null
val y = coords[1].toIntOrNull() ?: return null
val z = coords[2].toIntOrNull() ?: return null
return Location(world, x.toDouble(), y.toDouble(), z.toDouble())
}
object PlacedCrates {
private val loaded = mutableMapOf<Location, PlacedCrate>()
fun getCrateAt(location: Location): Crate? {
return loaded[location]?.crate
}
fun setAsCrate(location: Location, crate: Crate) {
loaded[location] = PlacedCrate(crate, location)
YamlStorage.set("crates.${location.toShortString()}", crate.id)
YamlStorage.save()
}
fun removeCrate(location: Location) {
loaded[location]?.onRemove()
loaded.remove(location)
YamlStorage.set("crates.${location.toShortString()}", null)
YamlStorage.save()
}
internal fun load() {
removeAll()
for (shortString in YamlStorage.getSubsection("crates").getKeys(false)) {
val location = locationFromShortString(shortString) ?: continue
val id = YamlStorage.getString("crates.$shortString")
val crate = Crates.getByID(id) ?: continue
loaded[location] = PlacedCrate(crate, location)
}
}
internal fun removeAll() {
for (crate in loaded.values) {
crate.onRemove()
}
loaded.clear()
}
fun values(): List<PlacedCrate> {
return loaded.values.toList()
}
}

View File

@@ -0,0 +1,47 @@
package com.willfp.ecocrates.reward
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.drops.DropQueue
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.items.builder.ItemStackBuilder
import com.willfp.eco.core.recipe.parts.EmptyTestableItem
import org.bukkit.Bukkit
import org.bukkit.entity.Player
class Reward(
private val config: Config
) {
val commands = config.getStrings("commands")
val items = config.getStrings("items").map { Items.lookup(it) }.filterNot { it is EmptyTestableItem }
val display = ItemStackBuilder(Items.lookup(config.getString("display.item")))
.addLoreLines(config.getStrings("display.lore"))
.build()
val messages = config.getFormattedStrings("messages")
val weight = config.getDouble("weight")
val displayWeight = config.getDouble("displayWeight")
val displayRow = config.getInt("gui.row")
val displayColumn = config.getInt("gui.column")
fun giveTo(player: Player) {
for (command in commands) {
Bukkit.dispatchCommand(
Bukkit.getConsoleSender(),
command.replace("%player%", player.name)
)
}
DropQueue(player)
.addItems(items.map { it.item })
.forceTelekinesis()
.push()
messages.forEach { player.sendMessage(it) }
}
}

View File

@@ -0,0 +1,35 @@
package com.willfp.ecocrates.util;
import com.willfp.eco.core.config.interfaces.Config
import org.bukkit.Location
import org.bukkit.Sound
data class ConfiguredSound(
private val sound: Sound,
private val pitch: Double,
private val volume: Double
) {
fun play(location: Location) {
location.world?.playSound(location, sound, volume.toFloat(), pitch.toFloat())
}
companion object {
fun fromConfig(config: Config): ConfiguredSound {
return ConfiguredSound(
Sound.valueOf(config.getString("sound").uppercase()),
config.getDouble("pitch"),
config.getDouble("volume")
)
}
}
}
data class PlayableSound(
val sounds: Iterable<ConfiguredSound>
) {
fun play(location: Location) {
for (sound in sounds) {
sound.play(location)
}
}
}

View File

@@ -0,0 +1,14 @@
package com.willfp.ecocrates.util
import com.willfp.eco.core.items.TestableItem
import org.bukkit.inventory.ItemStack
class ExactTestableItem(
private var itemStack: ItemStack
) : TestableItem {
override fun matches(itemStack: ItemStack?): Boolean {
return itemStack == this.itemStack
}
override fun getItem(): ItemStack = itemStack.clone()
}

View File

@@ -0,0 +1,65 @@
package com.willfp.ecocrates.util
import com.willfp.eco.core.EcoPlugin
import com.willfp.ecocrates.crate.placed.PlacedCrates
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.player.PlayerInteractEvent
import java.util.*
class PlacedCrateListener(
private val plugin: EcoPlugin
) : Listener {
// Janky fix to interact events firing twice
private val preventDoubles = mutableSetOf<UUID>()
@EventHandler
fun handleClick(event: PlayerInteractEvent) {
val player = event.player
val block = event.clickedBlock ?: return
if (player.isSneaking) {
return
}
if (preventDoubles.contains(player.uniqueId)) {
return
}
val crate = PlacedCrates.getCrateAt(block.location) ?: return
when (event.action) {
Action.LEFT_CLICK_BLOCK -> crate.previewForPlayer(player)
Action.RIGHT_CLICK_BLOCK -> crate.openWithKey(player)
else -> return
}
preventDoubles.add(player.uniqueId)
plugin.scheduler.run { preventDoubles.remove(player.uniqueId) }
event.isCancelled = true
}
@EventHandler
fun handleBreak(event: BlockBreakEvent) {
val player = event.player
if (!player.hasPermission("ecocrates.break")) {
return
}
val block = event.block
if (!player.isSneaking) {
return
}
PlacedCrates.getCrateAt(block.location) ?: return
PlacedCrates.removeCrate(block.location)
player.sendMessage(plugin.langYml.getMessage("removed-crate"))
event.isCancelled = true
}
}

View File

@@ -0,0 +1,92 @@
#
# EcoCrates
# by Auxilor
#
keygui:
rows: 3
mask:
items:
- black_stained_glass_pane
pattern:
- "111111111"
- "110101011"
- "111111111"
title: "Your Keys"
crates:
- id: demo
name: "Demo Crate"
gui:
title: Demo Crate
rows: 6
mask:
items:
- black_stained_glass_pane
pattern:
- "111111111"
- "100000001"
- "100000001"
- "100000001"
- "100000001"
- "111111111"
keygui:
item: tripwire_hook unbreaking:1 hide_enchants name:"Demo Crate"
lore:
- "&famogus? sus? impostor?"
- "&fYou have %keys% keys"
row: 2
column: 3
rightClickMessage:
- "Buy a Demo Crate key here! get lured into the trap of gambling addiction"
onFinish:
sounds:
- sound: entity_firework_rocket_launch
volume: 100
pitch: 1
placed:
hologram-height: 1.5
hologram:
- "Amogus? Sus!"
- "&b&lLeft Click to Preview"
- '&a&lRight click to Open'
rewards:
- commands: [ ]
items:
- diamond
messages:
- 'amogus?'
weight: 10
displayWeight: 25
display:
item: diamond
lore: []
gui:
row: 2
column: 2
- commands: [ ]
items:
- emerald
display:
item: emerald
lore: []
messages:
- 'amogus?!!'
weight: 10
displayWeight: 50
gui:
row: 2
column: 3
- commands: [ ]
items:
- bedrock
display:
item: bedrock
lore: []
messages:
- 'amogus?!!'
weight: 10000000
displayWeight: 0
gui:
row: 2
column: 4

View File

@@ -0,0 +1,15 @@
messages:
prefix: "&#6dd5ed&lEcoCrates&r &8» &r"
no-permission: "&cYou don't have permission to do this!"
not-player: "&cThis command must be run by a player"
invalid-command: "&cUnknown subcommand!"
reloaded: "Reloaded! Took %time%ms"
not-enough-keys: "&cYou don't have enough keys to open %crate%&c!"
must-specify-crate: "&cYou must specify a valid crate!"
invalid-crate: "&cUnknown crate!"
must-specify-player: "&cYou must specify a player!"
invalid-player: "&cUnknown player!"
gave-keys: "Gave %amount%&f %crate%&f key(s) to %user%&f!"
must-target-block: "&cYou must be looking at a block!"
set-block-as-crate: "Set block to be a crate!"
removed-crate: "Removed crate!"

View File

@@ -0,0 +1 @@
# This file is for internal storage only.

View File

@@ -0,0 +1,56 @@
name: EcoCrates
version: ${projectVersion}
main: com.willfp.ecocrates.EcoCratesPlugin
api-version: 1.17
authors: [ Auxilor ]
website: willfp.com
load: STARTUP
depend:
- eco
- ProtocolLib
commands:
ecocrates:
aliases:
- crates
description: Base plugin command
permission: ecocrates.command.ecocrates
permissions:
ecocrates.*:
description: All ecocrates permissions
default: op
children:
ecocrates.command.reload: true
ecocrates.command.ecocrates: true
ecocrates.command.give: true
ecocrates.command.open: true
ecocrates.command.preview: true
ecocrates.command.keys: true
ecocrates.command.set: true
ecocrates.break: true
ecocrates.command.ecocrates:
description: Allows the use of /ecocrates (base command)
default: true
ecocrates.command.reload:
description: Allows reloading the config
default: op
ecocrates.command.give:
description: Allows giving players keys
default: op
ecocrates.command.open:
description: Allows opening crates with /ecocrates open
default: true
ecocrates.command.preview:
description: Allows previewing crates with /ecocrates preview
default: true
ecocrates.command.keys:
description: Allows viewing owned keys with /ecocrates keys
default: true
ecocrates.command.set:
description: Allows marking a block as a crate
default: op
ecocrates.break:
description: Allows breaking crate blocks
default: op