Implemented remaining features

This commit is contained in:
Auxilor
2024-07-05 14:17:36 +01:00
parent 3b647ba084
commit 2f9516a599
17 changed files with 421 additions and 32 deletions

View File

@@ -1,27 +1,38 @@
package com.willfp.ecoscrolls package com.willfp.ecoscrolls
import com.willfp.ecoscrolls.scrolls.Scrolls
import com.willfp.ecoscrolls.commands.CommandEcoScrolls
import com.willfp.eco.core.command.impl.PluginCommand import com.willfp.eco.core.command.impl.PluginCommand
import com.willfp.eco.core.display.DisplayModule import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.placeholder.context.PlaceholderContext import com.willfp.eco.core.placeholder.context.PlaceholderContext
import com.willfp.eco.core.placeholder.templates.DynamicPlaceholder import com.willfp.eco.core.placeholder.templates.DynamicPlaceholder
import com.willfp.ecoscrolls.commands.CommandEcoScrolls
import com.willfp.ecoscrolls.commands.CommandInscribe import com.willfp.ecoscrolls.commands.CommandInscribe
import com.willfp.ecoscrolls.config.TargetsYml import com.willfp.ecoscrolls.config.TargetsYml
import com.willfp.ecoscrolls.display.ScrollDisplay import com.willfp.ecoscrolls.display.ScrollDisplay
import com.willfp.ecoscrolls.gui.updateInscribeMenu import com.willfp.ecoscrolls.gui.updateInscribeMenu
import com.willfp.ecoscrolls.libreforge.ConditionHasScroll
import com.willfp.ecoscrolls.libreforge.EffectInscribeItem
import com.willfp.ecoscrolls.libreforge.FilterScroll
import com.willfp.ecoscrolls.libreforge.TriggerInscribe
import com.willfp.ecoscrolls.libreforge.TriggerTryInscribe
import com.willfp.ecoscrolls.scrolls.InscriptionHandler
import com.willfp.ecoscrolls.scrolls.ScrollLevel import com.willfp.ecoscrolls.scrolls.ScrollLevel
import com.willfp.ecoscrolls.scrolls.Scrolls
import com.willfp.ecoscrolls.target.ScrollFinder import com.willfp.ecoscrolls.target.ScrollFinder
import com.willfp.ecoscrolls.target.Targets import com.willfp.ecoscrolls.target.Targets
import com.willfp.ecoscrolls.util.AntiPlaceListener
import com.willfp.ecoscrolls.util.DiscoverRecipeListener import com.willfp.ecoscrolls.util.DiscoverRecipeListener
import com.willfp.ecoscrolls.util.DragAndDropListener
import com.willfp.libreforge.NamedValue import com.willfp.libreforge.NamedValue
import com.willfp.libreforge.conditions.Conditions
import com.willfp.libreforge.effects.Effects
import com.willfp.libreforge.filters.Filters
import com.willfp.libreforge.loader.LibreforgePlugin import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory import com.willfp.libreforge.loader.configs.ConfigCategory
import com.willfp.libreforge.registerHolderPlaceholderProvider import com.willfp.libreforge.registerHolderPlaceholderProvider
import com.willfp.libreforge.registerHolderProvider import com.willfp.libreforge.registerHolderProvider
import com.willfp.libreforge.triggers.Triggers
import org.bukkit.event.Listener import org.bukkit.event.Listener
import org.checkerframework.checker.units.qual.m
import java.util.regex.Pattern import java.util.regex.Pattern
internal lateinit var plugin: EcoScrollsPlugin internal lateinit var plugin: EcoScrollsPlugin
@@ -30,11 +41,19 @@ internal lateinit var plugin: EcoScrollsPlugin
class EcoScrollsPlugin : LibreforgePlugin() { class EcoScrollsPlugin : LibreforgePlugin() {
val targetsYml = TargetsYml(this) val targetsYml = TargetsYml(this)
val inscriptionHandler = InscriptionHandler(this)
init { init {
plugin = this plugin = this
} }
override fun handleEnable() { override fun handleEnable() {
Conditions.register(ConditionHasScroll)
Effects.register(EffectInscribeItem)
Filters.register(FilterScroll)
Triggers.register(TriggerInscribe)
Triggers.register(TriggerTryInscribe)
registerHolderProvider(ScrollFinder.toHolderProvider()) registerHolderProvider(ScrollFinder.toHolderProvider())
registerHolderPlaceholderProvider<ScrollLevel> { it, _ -> registerHolderPlaceholderProvider<ScrollLevel> { it, _ ->
@@ -68,6 +87,7 @@ class EcoScrollsPlugin : LibreforgePlugin() {
override fun handleReload() { override fun handleReload() {
updateInscribeMenu(this) updateInscribeMenu(this)
Targets.update(this) Targets.update(this)
inscriptionHandler.reload()
} }
override fun loadConfigCategories(): List<ConfigCategory> { override fun loadConfigCategories(): List<ConfigCategory> {
@@ -85,7 +105,9 @@ class EcoScrollsPlugin : LibreforgePlugin() {
override fun loadListeners(): List<Listener> { override fun loadListeners(): List<Listener> {
return listOf( return listOf(
DiscoverRecipeListener(this) DiscoverRecipeListener(this),
DragAndDropListener(this),
AntiPlaceListener
) )
} }

View File

@@ -93,7 +93,7 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
addComponent( addComponent(
plugin.configYml.getInt("gui.inscribe-slot.row"), plugin.configYml.getInt("gui.inscribe-slot.row"),
plugin.configYml.getInt("gui.inscribe-slot.column"), plugin.configYml.getInt("gui.inscribe-slot.column"),
Inscriber(plugin, violationContext), Inscriber(plugin),
) )
addComponent( addComponent(
@@ -125,7 +125,7 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
menu.status[player] = InscriptionStatus.EMPTY menu.status[player] = InscriptionStatus.EMPTY
} else { } else {
val scroll = scrollItem.scroll val scroll = scrollItem.scroll
if (scroll == null) { if (scroll == null || !scroll.isInscriptionTableEnabled) {
menu.status[player] = InscriptionStatus.DENY menu.status[player] = InscriptionStatus.DENY
} else if (scroll.canInscribe(item)) { } else if (scroll.canInscribe(item)) {
menu.scroll[player] = Optional.of(scroll) menu.scroll[player] = Optional.of(scroll)
@@ -203,10 +203,9 @@ private class CloseSlot(private val plugin: EcoScrollsPlugin) : CustomSlot() {
private class Inscriber( private class Inscriber(
plugin: EcoScrollsPlugin, plugin: EcoScrollsPlugin
violationContext: ViolationContext
) : GUIComponent { ) : GUIComponent {
private val allowSlot = AllowSlot(plugin, violationContext) private val allowSlot = AllowSlot(plugin)
private val denySlot = DenySlot(plugin) private val denySlot = DenySlot(plugin)
private val emptySlot = EmptySlot(plugin) private val emptySlot = EmptySlot(plugin)
@@ -279,32 +278,18 @@ private abstract class MenuSlot(
} }
} }
private class AllowSlot(plugin: EcoScrollsPlugin, violationContext: ViolationContext) : MenuSlot(plugin, InscriptionStatus.ALLOW) { private class AllowSlot(plugin: EcoScrollsPlugin) : MenuSlot(plugin, InscriptionStatus.ALLOW) {
private val applyEffects = Effects.compile(
plugin.configYml.getSubsections("gui.apply-effects"),
violationContext.with("Apply Effects")
)
private val denyEffects = Effects.compile(
plugin.configYml.getSubsections("gui.deny-effects"),
violationContext.with("Deny Effects")
)
override fun onClick(player: Player, event: InventoryClickEvent, slot: Slot, menu: Menu) { override fun onClick(player: Player, event: InventoryClickEvent, slot: Slot, menu: Menu) {
val scroll = menu.scroll[player]?.getOrNull() ?: return val scroll = menu.scroll[player]?.getOrNull() ?: return
val item = capturedItem[player] ?: return val item = capturedItem[player] ?: return
val inscribed = scroll.inscribe(item, player) val didInscribe = plugin.inscriptionHandler.tryInscribe(item, scroll, player)
if (inscribed) { if (didInscribe) {
val scrollItem = capturedScrollItem[player] val scrollItem = capturedScrollItem[player]
?: throw IllegalStateException("Scroll item is null") ?: throw IllegalStateException("Scroll item is null")
scrollItem.amount -= 1 scrollItem.amount -= 1
applyEffects.trigger(TriggerData(player = player).dispatch(player.toDispatcher()))
} else {
denyEffects.trigger(TriggerData(player = player).dispatch(player.toDispatcher()))
} }
// Cheat to update the menu // Cheat to update the menu

View File

@@ -0,0 +1,31 @@
package com.willfp.ecoscrolls.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoscrolls.scrolls.ScrollLevel
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.arguments
import com.willfp.libreforge.conditions.Condition
import com.willfp.libreforge.getHoldersOfType
object ConditionHasScroll : Condition<NoCompileData>("has_scroll") {
override val arguments = arguments {
require("scroll", "You must specify the scroll!")
}
override fun isMet(
dispatcher: Dispatcher<*>,
config: Config,
holder: ProvidedHolder,
compileData: NoCompileData
): Boolean {
val scroll = config.getString("scroll")
val level = config.getIntOrNull("level") ?: 1
return dispatcher.getHoldersOfType<ScrollLevel>()
.any {
it.scroll.id == scroll && it.level >= level
}
}
}

View File

@@ -0,0 +1,35 @@
package com.willfp.ecoscrolls.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoscrolls.scrolls.Scroll
import com.willfp.ecoscrolls.scrolls.ScrollLevel
import com.willfp.ecoscrolls.scrolls.Scrolls
import com.willfp.libreforge.Dispatcher
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.ProvidedHolder
import com.willfp.libreforge.arguments
import com.willfp.libreforge.conditions.Condition
import com.willfp.libreforge.effects.Effect
import com.willfp.libreforge.getHoldersOfType
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
object EffectInscribeItem : Effect<NoCompileData>("inscribe_item") {
override val parameters = setOf(
TriggerParameter.ITEM
)
override val arguments = arguments {
require("scroll", "You must specify the scroll!")
}
override fun onTrigger(config: Config, data: TriggerData, compileData: NoCompileData): Boolean {
val item = data.item ?: return false
val scroll = Scrolls[config.getString("scroll")] ?: return false
scroll.inscribe(item)
return true
}
}

View File

@@ -0,0 +1,21 @@
package com.willfp.ecoscrolls.libreforge
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.ecoscrolls.scrolls.event.ScrollEvent
import com.willfp.libreforge.NoCompileData
import com.willfp.libreforge.filters.Filter
import com.willfp.libreforge.triggers.TriggerData
object FilterScroll : Filter<NoCompileData, Collection<String>>("scroll") {
override fun getValue(config: Config, data: TriggerData?, key: String): Collection<String> {
return config.getStrings(key)
}
override fun isMet(data: TriggerData, value: Collection<String>, compileData: NoCompileData): Boolean {
val event = data.event as? ScrollEvent ?: return true
return value.any { id ->
id.equals(event.scroll.id, ignoreCase = true)
}
}
}

View File

@@ -0,0 +1,28 @@
package com.willfp.ecoscrolls.libreforge
import com.willfp.ecoscrolls.scrolls.event.ScrollInscribeEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.event.EventHandler
object TriggerInscribe : Trigger("inscribe") {
override val parameters = setOf(
TriggerParameter.ITEM,
TriggerParameter.PLAYER,
TriggerParameter.EVENT
)
@EventHandler
fun handle(event: ScrollInscribeEvent) {
this.dispatch(
event.player.toDispatcher(),
TriggerData(
player = event.player,
item = event.itemStack,
event = event
)
)
}
}

View File

@@ -0,0 +1,28 @@
package com.willfp.ecoscrolls.libreforge
import com.willfp.ecoscrolls.scrolls.event.ScrollTryInscribeEvent
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.Trigger
import com.willfp.libreforge.triggers.TriggerData
import com.willfp.libreforge.triggers.TriggerParameter
import org.bukkit.event.EventHandler
object TriggerTryInscribe : Trigger("try_inscribe") {
override val parameters = setOf(
TriggerParameter.ITEM,
TriggerParameter.PLAYER,
TriggerParameter.EVENT
)
@EventHandler
fun handle(event: ScrollTryInscribeEvent) {
this.dispatch(
event.player.toDispatcher(),
TriggerData(
player = event.player,
item = event.itemStack,
event = event
)
)
}
}

View File

@@ -0,0 +1,82 @@
package com.willfp.ecoscrolls.scrolls
import com.willfp.ecoscrolls.EcoScrollsPlugin
import com.willfp.ecoscrolls.scrolls.event.ScrollInscribeEvent
import com.willfp.ecoscrolls.scrolls.event.ScrollTryInscribeEvent
import com.willfp.libreforge.NamedValue
import com.willfp.libreforge.ViolationContext
import com.willfp.libreforge.effects.EffectList
import com.willfp.libreforge.effects.Effects
import com.willfp.libreforge.toDispatcher
import com.willfp.libreforge.triggers.TriggerData
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
class InscriptionHandler(private val plugin: EcoScrollsPlugin) {
private val context = ViolationContext(plugin, "Inscriptions")
private lateinit var applyEffects: EffectList
private lateinit var denyEffects: EffectList
val scrollLimit = plugin.configYml.getInt("inscription.scroll-limit")
.let { if (it <= 0) Int.MAX_VALUE else it }
init {
reload()
}
internal fun reload() {
applyEffects = Effects.compile(
plugin.configYml.getSubsections("inscription.apply-effects"),
context.with("Apply Effects")
)
denyEffects = Effects.compile(
plugin.configYml.getSubsections("inscription.deny-effects"),
context.with("Deny Effects")
)
}
private fun inscriptionTrigger(item: ItemStack, scroll: Scroll, player: Player) =
TriggerData(
player = player,
item = item,
text = scroll.name
).dispatch(player.toDispatcher())
.apply {
addPlaceholder(
NamedValue(
"scroll",
scroll.name
)
)
addPlaceholder(
NamedValue(
"scroll_id",
scroll.id
)
)
}
fun tryInscribe(item: ItemStack, scroll: Scroll, player: Player): Boolean {
val tryEvent = ScrollTryInscribeEvent(player, scroll, item)
plugin.server.pluginManager.callEvent(tryEvent)
if (tryEvent.isCancelled) {
return false
}
val didInscribe = scroll.inscribe(item, player)
if (didInscribe) {
applyEffects.trigger(inscriptionTrigger(item, scroll, player))
val event = ScrollInscribeEvent(player, scroll, item)
plugin.server.pluginManager.callEvent(event)
} else {
denyEffects.trigger(inscriptionTrigger(item, scroll, player))
}
return didInscribe
}
}

View File

@@ -96,6 +96,10 @@ class Scroll(
config.getSubsection("inscription.price"), config.getSubsection("inscription.price"),
) )
val isDragAndDropEnabled = config.getBool("inscription.drag-and-drop")
val isInscriptionTableEnabled = config.getBool("inscription.inscription-table")
private val lore = config.getStrings("lore") private val lore = config.getStrings("lore")
private val levelPlaceholder = object : DynamicInjectablePlaceholder(Pattern.compile("level")) { private val levelPlaceholder = object : DynamicInjectablePlaceholder(Pattern.compile("level")) {
@@ -135,7 +139,13 @@ class Scroll(
return false return false
} }
if (itemStack.scrolls.any { it.scroll.conflictsWith(this) }) { val currentScrolls = itemStack.scrolls
if (currentScrolls.size >= plugin.inscriptionHandler.scrollLimit) {
return false
}
if (currentScrolls.any { it.scroll.conflictsWith(this) }) {
return false return false
} }
@@ -155,7 +165,8 @@ class Scroll(
if (!inscriptionConditions.areMetAndTrigger( if (!inscriptionConditions.areMetAndTrigger(
TriggerData( TriggerData(
player = player player = player,
item = itemStack
).dispatch(player.toDispatcher()) ).dispatch(player.toDispatcher())
) )
) { ) {

View File

@@ -0,0 +1,7 @@
package com.willfp.ecoscrolls.scrolls.event
import com.willfp.ecoscrolls.scrolls.Scroll
interface ScrollEvent {
val scroll: Scroll
}

View File

@@ -0,0 +1,26 @@
package com.willfp.ecoscrolls.scrolls.event
import com.willfp.ecoscrolls.scrolls.Scroll
import org.bukkit.entity.Player
import org.bukkit.event.HandlerList
import org.bukkit.event.player.PlayerEvent
import org.bukkit.inventory.ItemStack
class ScrollInscribeEvent(
player: Player,
override val scroll: Scroll,
val itemStack: ItemStack
): PlayerEvent(player), ScrollEvent {
override fun getHandlers(): HandlerList {
return handlerList
}
companion object {
private val handlerList = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList {
return handlerList
}
}
}

View File

@@ -0,0 +1,35 @@
package com.willfp.ecoscrolls.scrolls.event
import com.willfp.ecoscrolls.scrolls.Scroll
import org.bukkit.entity.Player
import org.bukkit.event.Cancellable
import org.bukkit.event.HandlerList
import org.bukkit.event.player.PlayerEvent
import org.bukkit.inventory.ItemStack
class ScrollTryInscribeEvent(
player: Player,
override val scroll: Scroll,
val itemStack: ItemStack,
): PlayerEvent(player), Cancellable, ScrollEvent {
private var cancelled = false
override fun isCancelled() = cancelled
override fun setCancelled(cancel: Boolean) {
cancelled = cancel
}
override fun getHandlers(): HandlerList {
return handlerList
}
companion object {
private val handlerList = HandlerList()
@JvmStatic
fun getHandlerList(): HandlerList {
return handlerList
}
}
}

View File

@@ -0,0 +1,15 @@
package com.willfp.ecoscrolls.util
import com.willfp.ecoscrolls.scrolls.scroll
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockPlaceEvent
object AntiPlaceListener: Listener {
@EventHandler
fun handle(event: BlockPlaceEvent) {
if (event.itemInHand.scroll != null) {
event.isCancelled = true
}
}
}

View File

@@ -0,0 +1,45 @@
package com.willfp.ecoscrolls.util
import com.willfp.eco.core.items.isEcoEmpty
import com.willfp.ecoscrolls.EcoScrollsPlugin
import com.willfp.ecoscrolls.scrolls.scroll
import org.bukkit.GameMode
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.inventory.InventoryClickEvent
class DragAndDropListener(private val plugin: EcoScrollsPlugin) : Listener {
@EventHandler
fun onDrag(event: InventoryClickEvent) {
val player = event.whoClicked as? Player ?: return
if (player.gameMode == GameMode.CREATIVE) {
return
}
val current = event.currentItem ?: return
val cursor = event.cursor ?: return
if (current.isEcoEmpty) {
return
}
val scroll = cursor.scroll ?: return
if (!scroll.isDragAndDropEnabled) {
return
}
if (!scroll.canInscribe(current)) {
return
}
val didInscribe = plugin.inscriptionHandler.tryInscribe(current, scroll, player)
if (didInscribe) {
cursor.amount -= 1
event.isCancelled = true
}
}
}

View File

@@ -101,11 +101,23 @@ gui:
# Effects to run when the GUI is closed # Effects to run when the GUI is closed
close-effects: [ ] close-effects: [ ]
# Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots
custom-slots: [ ]
# Options for inscribing items
inscription:
# Effects to run when an item is inscribed # Effects to run when an item is inscribed
# The text placeholder is the name of the scroll, read here:
# https://plugins.auxilor.io/effects/configuring-an-effect#placeholders
# You can also use %scroll% and %scroll_id% as placeholders.
apply-effects: [ ] apply-effects: [ ]
# Effects to run when trying to inscribe an item without meeting the conditions # Effects to run when trying to inscribe an item without meeting the conditions
# The text placeholder is the name of the scroll, read here:
# https://plugins.auxilor.io/effects/configuring-an-effect#placeholders
# You can also use %scroll% and %scroll_id% as placeholders.
deny-effects: [ ] deny-effects: [ ]
# Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots # The maximum amount of scrolls that can be applied to an item
custom-slots: [ ] # Set to -1 for unlimited
scroll-limit: -1

View File

@@ -4,5 +4,5 @@ environment:
options: options:
resource-id: 2873 resource-id: 2873
bstats-id: 16436 bstats-id: 22538
color: "&#1e3c72" color: "&#1e3c72"

View File

@@ -36,6 +36,12 @@ inscription:
type: coins type: coins
display: "&e%value% coins" display: "&e%value% coins"
# If the scroll can be applied to items via drag-and-drop
drag-and-drop: true
# If the scroll can be applied to items via the inscription table
inscription-table: true
# The items that the scroll can be applied to, see targets.yml # The items that the scroll can be applied to, see targets.yml
targets: targets:
- sword - sword
@@ -55,7 +61,7 @@ placeholders:
bonus: "%level% * 2" bonus: "%level% * 2"
# Read https://plugins.auxilor.io/effects/configuring-an-effect # Read https://plugins.auxilor.io/effects/configuring-an-effect
# The effects for the scroll # The effects for the scroll to give
effects: effects:
- id: send_message - id: send_message
args: args: