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

View File

@@ -93,7 +93,7 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
addComponent(
plugin.configYml.getInt("gui.inscribe-slot.row"),
plugin.configYml.getInt("gui.inscribe-slot.column"),
Inscriber(plugin, violationContext),
Inscriber(plugin),
)
addComponent(
@@ -125,7 +125,7 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
menu.status[player] = InscriptionStatus.EMPTY
} else {
val scroll = scrollItem.scroll
if (scroll == null) {
if (scroll == null || !scroll.isInscriptionTableEnabled) {
menu.status[player] = InscriptionStatus.DENY
} else if (scroll.canInscribe(item)) {
menu.scroll[player] = Optional.of(scroll)
@@ -203,10 +203,9 @@ private class CloseSlot(private val plugin: EcoScrollsPlugin) : CustomSlot() {
private class Inscriber(
plugin: EcoScrollsPlugin,
violationContext: ViolationContext
plugin: EcoScrollsPlugin
) : GUIComponent {
private val allowSlot = AllowSlot(plugin, violationContext)
private val allowSlot = AllowSlot(plugin)
private val denySlot = DenySlot(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 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")
)
private class AllowSlot(plugin: EcoScrollsPlugin) : MenuSlot(plugin, InscriptionStatus.ALLOW) {
override fun onClick(player: Player, event: InventoryClickEvent, slot: Slot, menu: Menu) {
val scroll = menu.scroll[player]?.getOrNull() ?: 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]
?: throw IllegalStateException("Scroll item is null")
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

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"),
)
val isDragAndDropEnabled = config.getBool("inscription.drag-and-drop")
val isInscriptionTableEnabled = config.getBool("inscription.inscription-table")
private val lore = config.getStrings("lore")
private val levelPlaceholder = object : DynamicInjectablePlaceholder(Pattern.compile("level")) {
@@ -135,7 +139,13 @@ class Scroll(
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
}
@@ -155,7 +165,8 @@ class Scroll(
if (!inscriptionConditions.areMetAndTrigger(
TriggerData(
player = player
player = player,
item = itemStack
).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
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
# 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: [ ]
# 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: [ ]
# Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots
custom-slots: [ ]
# The maximum amount of scrolls that can be applied to an item
# Set to -1 for unlimited
scroll-limit: -1

View File

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

View File

@@ -36,6 +36,12 @@ inscription:
type: 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
targets:
- sword
@@ -55,7 +61,7 @@ placeholders:
bonus: "%level% * 2"
# Read https://plugins.auxilor.io/effects/configuring-an-effect
# The effects for the scroll
# The effects for the scroll to give
effects:
- id: send_message
args: