More code

This commit is contained in:
Auxilor
2024-06-28 23:23:48 +01:00
parent 9fc01c7fef
commit 3b647ba084
11 changed files with 289 additions and 61 deletions

View File

@@ -3,18 +3,26 @@ 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.CommandInscribe
import com.willfp.ecoscrolls.config.TargetsYml
import com.willfp.ecoscrolls.display.ScrollDisplay
import com.willfp.ecoscrolls.gui.updateInscribeMenu
import com.willfp.ecoscrolls.scrolls.ScrollLevel
import com.willfp.ecoscrolls.target.ScrollFinder
import com.willfp.ecoscrolls.target.Targets
import com.willfp.ecoscrolls.util.DiscoverRecipeListener
import com.willfp.libreforge.SimpleProvidedHolder
import com.willfp.libreforge.NamedValue
import com.willfp.libreforge.loader.LibreforgePlugin
import com.willfp.libreforge.loader.configs.ConfigCategory
import com.willfp.libreforge.registerGenericHolderProvider
import com.willfp.libreforge.registerHolderPlaceholderProvider
import com.willfp.libreforge.registerHolderProvider
import org.bukkit.event.Listener
import org.checkerframework.checker.units.qual.m
import java.util.regex.Pattern
internal lateinit var plugin: EcoScrollsPlugin
private set
@@ -22,8 +30,39 @@ internal lateinit var plugin: EcoScrollsPlugin
class EcoScrollsPlugin : LibreforgePlugin() {
val targetsYml = TargetsYml(this)
init {
plugin = this
}
override fun handleEnable() {
registerHolderProvider(ScrollFinder.toHolderProvider())
registerHolderPlaceholderProvider<ScrollLevel> { it, _ ->
listOf(
NamedValue("level", it.level),
)
}
PlaceholderManager.registerPlaceholder(
object : DynamicPlaceholder(plugin, Pattern.compile("scroll_([a-z]+)_([a-zA-Z0-9_]+)")) {
override fun getValue(args: String, context: PlaceholderContext): String? {
val matcher = pattern.matcher(args)
if (!matcher.matches()) {
return null
}
// Get the scroll and identifier from the matched groups
val scroll = matcher.group(1)
val identifier = matcher.group(2)
// Return empty instead of null for optional placeholders, like hot potato books
val scrollInstance = Scrolls[scroll] ?: return ""
return scrollInstance.getPlaceholder(identifier, context) ?: ""
}
}
)
}
override fun handleReload() {
@@ -49,4 +88,8 @@ class EcoScrollsPlugin : LibreforgePlugin() {
DiscoverRecipeListener(this)
)
}
override fun createDisplayModule(): DisplayModule {
return ScrollDisplay(this)
}
}

View File

@@ -3,6 +3,8 @@ package com.willfp.ecoscrolls.commands
import com.willfp.eco.core.EcoPlugin
import com.willfp.eco.core.command.impl.Subcommand
import com.willfp.eco.core.drops.DropQueue
import com.willfp.eco.core.items.Items.toSNBT
import com.willfp.eco.core.items.toSNBT
import com.willfp.ecoscrolls.scrolls.Scrolls
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
@@ -50,7 +52,7 @@ class CommandGive(
val scroll = Scrolls[args[1]]
if (scroll == null) {
sender.sendMessage(plugin.langYml.getMessage("invalid-stone"))
sender.sendMessage(plugin.langYml.getMessage("invalid-scroll"))
return
}

View File

@@ -0,0 +1,24 @@
package com.willfp.ecoscrolls.display
import com.willfp.eco.core.display.DisplayModule
import com.willfp.eco.core.display.DisplayPriority
import com.willfp.eco.core.fast.fast
import com.willfp.ecoscrolls.EcoScrollsPlugin
import com.willfp.ecoscrolls.scrolls.scroll
import com.willfp.ecoscrolls.scrolls.scrolls
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
class ScrollDisplay(
plugin: EcoScrollsPlugin
): DisplayModule(plugin, DisplayPriority.HIGHEST) {
override fun display(itemStack: ItemStack, player: Player?, vararg args: Any) {
val fis = itemStack.fast()
fis.scroll?.displayScroll(fis, player)
for (scroll in fis.scrolls) {
fis.lore = fis.lore + scroll.scroll.getLore(itemStack, player)
}
}
}

View File

@@ -1,6 +1,7 @@
package com.willfp.ecoscrolls.gui
import com.willfp.eco.core.drops.DropQueue
import com.willfp.eco.core.fast.fast
import com.willfp.eco.core.gui.GUIComponent
import com.willfp.eco.core.gui.captiveSlot
import com.willfp.eco.core.gui.menu
@@ -9,6 +10,7 @@ import com.willfp.eco.core.gui.menu.events.CaptiveItemChangeEvent
import com.willfp.eco.core.gui.onEvent
import com.willfp.eco.core.gui.onLeftClick
import com.willfp.eco.core.gui.slot
import com.willfp.eco.core.gui.slot.ConfigSlot
import com.willfp.eco.core.gui.slot.CustomSlot
import com.willfp.eco.core.gui.slot.FillerMask
import com.willfp.eco.core.gui.slot.MaskItems
@@ -45,10 +47,13 @@ private val Menu.status by menuStateVar(InscriptionStatus.EMPTY)
private val Menu.scroll by menuStateVar<Optional<Scroll>>()
private val capturedItem = CaptiveItem()
private val capturedScrollItem = CaptiveItem()
private lateinit var capturedItem: CaptiveItem
private lateinit var capturedScrollItem: CaptiveItem
internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
capturedItem = CaptiveItem()
capturedScrollItem = CaptiveItem()
val violationContext = ViolationContext(plugin, "Inscription Table")
val openEffects = Effects.compile(
@@ -62,6 +67,20 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
)
inscriptionTable = menu(plugin.configYml.getInt("gui.rows")) {
allowChangingHeldItem()
title = plugin.configYml.getFormattedString("gui.title")
val indicatorPattern = plugin.configYml.getStrings("gui.indicator.pattern")
for (i in 1..indicatorPattern.size) {
val row = indicatorPattern[i - 1]
for (j in 1..9) {
if (row[j - 1] != '0') {
setSlot(i, j, IndicatorSlot(plugin))
}
}
}
setMask(
FillerMask(
MaskItems.fromItemNames(
@@ -98,6 +117,7 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
)
onEvent<CaptiveItemChangeEvent> { player, menu, _ ->
menu.scroll[player] = Optional.empty()
val item = capturedItem[player]
val scrollItem = capturedScrollItem[player]
@@ -107,12 +127,11 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
val scroll = scrollItem.scroll
if (scroll == null) {
menu.status[player] = InscriptionStatus.DENY
} else if (scroll.canInscribe(item)) {
menu.scroll[player] = Optional.of(scroll)
menu.status[player] = InscriptionStatus.ALLOW
} else {
menu.status[player] = if (scroll.canInscribe(item)) {
InscriptionStatus.ALLOW
} else {
InscriptionStatus.DENY
}
menu.status[player] = InscriptionStatus.DENY
}
}
}
@@ -132,13 +151,41 @@ internal fun updateInscribeMenu(plugin: EcoScrollsPlugin) {
.forceTelekinesis()
.push()
}
for (config in plugin.configYml.getSubsections("gui.custom-slots")) {
setSlot(
config.getInt("row"),
config.getInt("column"),
ConfigSlot(config)
)
}
}
}
private class IndicatorSlot(plugin: EcoScrollsPlugin) : CustomSlot() {
private val allowed = Items.lookup(plugin.configYml.getString("gui.indicator.allow-item")).item
private val denied = Items.lookup(plugin.configYml.getString("gui.indicator.deny-item")).item
init {
create()
}
private fun create() {
init(slot { player, menu ->
val status = menu.status[player]
when (status) {
InscriptionStatus.ALLOW -> allowed
else -> denied
}
})
}
}
private class CloseSlot(private val plugin: EcoScrollsPlugin) : CustomSlot() {
private val item = Items.lookup(plugin.configYml.getString("gui.close.item")).modify {
setDisplayName(plugin.langYml.getFormattedString("gui.close.name"))
addLoreLines(plugin.langYml.getFormattedStrings("gui.close.lore"))
setDisplayName(plugin.configYml.getFormattedString("gui.close.name"))
addLoreLines(plugin.configYml.getFormattedStrings("gui.close.lore"))
}
init {
@@ -201,16 +248,16 @@ private abstract class MenuSlot(
}
private fun getItem(player: Player, menu: Menu): ItemStack {
val name = plugin.langYml.getString("gui.${status.name.lowercase()}.name")
val name = plugin.configYml.getString("gui.${status.name.lowercase()}.name")
.injectPlaceholders(player, menu)
val lore = plugin.langYml.getStrings("gui.${status.name.lowercase()}.lore")
val lore = plugin.configYml.getStrings("gui.${status.name.lowercase()}.lore")
.map { it.injectPlaceholders(player, menu) }
return item.modify {
setDisplayName(name)
addLoreLines(lore)
}
return item.fast().apply {
this.displayName = name
this.lore = lore
}.unwrap()
}
private fun String.injectPlaceholders(player: Player, menu: Menu): String {
@@ -250,10 +297,18 @@ private class AllowSlot(plugin: EcoScrollsPlugin, violationContext: ViolationCon
val inscribed = scroll.inscribe(item, player)
if (inscribed) {
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
menu.callEvent(player, CaptiveItemChangeEvent(0, 0, null, null))
}
}

View File

@@ -50,6 +50,7 @@ var FastItemStack.scrolls: Set<ScrollLevel>
set(value) {
this.persistentDataContainer.scrolls = value
}
var PersistentDataContainer.scrolls: Set<ScrollLevel>
get() {
if (!this.has(SCROLLS_KEY, PersistentDataType.TAG_CONTAINER_ARRAY)) {
@@ -75,18 +76,18 @@ var PersistentDataContainer.scrolls: Set<ScrollLevel>
return
}
val tag = mutableListOf<PersistentDataContainer>()
val tags = mutableListOf<PersistentDataContainer>()
for (scroll in scrolls) {
for (scroll in value) {
val scrollTag = newPersistentDataContainer()
scrollTag.set(SCROLL_ID_KEY, PersistentDataType.STRING, scroll.scroll.id)
scrollTag.set(SCROLL_LEVEL_KEY, PersistentDataType.INTEGER, scroll.level)
tag += scrollTag
tags += scrollTag
}
this.set(SCROLLS_KEY, PersistentDataType.TAG_CONTAINER_ARRAY, tag.toTypedArray())
this.set(SCROLLS_KEY, PersistentDataType.TAG_CONTAINER_ARRAY, tags.toTypedArray())
}
fun ItemStack.getScrollLevel(scroll: Scroll): ScrollLevel? {

View File

@@ -1,10 +1,23 @@
package com.willfp.ecoscrolls.scrolls
import com.willfp.eco.core.config.interfaces.Config
import com.willfp.eco.core.display.Display
import com.willfp.eco.core.fast.FastItemStack
import com.willfp.eco.core.fast.fast
import com.willfp.eco.core.integrations.placeholder.PlaceholderManager
import com.willfp.eco.core.items.Items
import com.willfp.eco.core.placeholder.InjectablePlaceholder
import com.willfp.eco.core.placeholder.PlaceholderInjectable
import com.willfp.eco.core.placeholder.context.PlaceholderContext
import com.willfp.eco.core.placeholder.context.placeholderContext
import com.willfp.eco.core.placeholder.templates.DynamicInjectablePlaceholder
import com.willfp.eco.core.placeholder.templates.DynamicPlaceholder
import com.willfp.eco.core.price.ConfiguredPrice
import com.willfp.eco.core.recipe.Recipes
import com.willfp.eco.core.registry.KRegistrable
import com.willfp.eco.util.evaluateExpression
import com.willfp.eco.util.evaluateExpressionOrNull
import com.willfp.eco.util.formatEco
import com.willfp.ecoscrolls.EcoScrollsPlugin
import com.willfp.ecoscrolls.plugin
import com.willfp.ecoscrolls.target.Targets
@@ -16,6 +29,8 @@ import com.willfp.libreforge.triggers.TriggerData
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack
import java.util.Objects
import java.util.regex.Pattern
import kotlin.math.exp
class Scroll(
plugin: EcoScrollsPlugin,
@@ -40,8 +55,16 @@ class Scroll(
val maxLevel = config.getInt("max-level")
private val _item = Items.lookup(config.getString("item.item")).item.apply {
this.scroll = this@Scroll
private val itemName = config.getString("item.name")
private val itemLore = config.getStrings("item.lore")
private val _item = run {
val base = Items.lookup(config.getString("item.item")).item
val fis = base.fast()
fis.scroll = this
fis.displayName = itemName.formatEco()
fis.lore = itemLore.formatEco().map { Display.PREFIX + it } + fis.lore
fis.unwrap()
}
val item: ItemStack
@@ -57,6 +80,8 @@ class Scroll(
val targets = config.getStrings("targets")
.mapNotNull { Targets[it] }
private val conflicts = config.getStrings("conflicts")
val inscriptionConditions = Conditions.compile(
config.getSubsections("inscription.conditions"),
context.with("inscription conditions")
@@ -71,6 +96,30 @@ class Scroll(
config.getSubsection("inscription.price"),
)
private val lore = config.getStrings("lore")
private val levelPlaceholder = object : DynamicInjectablePlaceholder(Pattern.compile("level")) {
override fun getValue(p0: String, p1: PlaceholderContext): String? {
return p1.itemStack?.getScrollLevel(this@Scroll)?.level?.toString()
}
}
private val levelInjectable = object : PlaceholderInjectable {
override fun getPlaceholderInjections(): List<InjectablePlaceholder> {
return listOf(
levelPlaceholder
)
}
override fun addInjectablePlaceholder(p0: MutableIterable<InjectablePlaceholder>) {
//
}
override fun clearInjectedPlaceholders() {
//
}
}
fun getLevel(level: Int): ScrollLevel {
return levels.getOrPut(level) {
createLevel(level)
@@ -82,7 +131,11 @@ class Scroll(
}
fun canInscribe(itemStack: ItemStack): Boolean {
if (!targets.none { it.matches(itemStack) }) {
if (targets.none { it.matches(itemStack) }) {
return false
}
if (itemStack.scrolls.any { it.scroll.conflictsWith(this) }) {
return false
}
@@ -121,7 +174,8 @@ class Scroll(
inscriptionEffects.trigger(
TriggerData(
player = player
player = player,
item = itemStack
).dispatch(player.toDispatcher())
)
@@ -136,6 +190,36 @@ class Scroll(
itemStack.scrolls = itemStack.scrolls.filter { it.scroll != this }.toSet() + level
}
fun getLore(itemStack: ItemStack, player: Player?): List<String> {
return lore.formatEco(
placeholderContext(
player = player,
item = itemStack,
injectable = levelInjectable
)
).map { Display.PREFIX + it }
}
fun displayScroll(fis: FastItemStack, player: Player?) {
fis.displayName = itemName.formatEco(player = player)
fis.lore = itemLore.formatEco(placeholderContext(player = player))
.map { Display.PREFIX + it } + fis.lore
}
fun getPlaceholder(identifier: String, context: PlaceholderContext): String? {
if ((levelPlaceholder.getValue(levelPlaceholder.pattern.pattern(), context)?.toIntOrNull() ?: 0) < 1) {
return null
}
val expression = config.getString("placeholders.$identifier")
return expression.formatEco(context.withInjectableContext(levelInjectable))
}
fun conflictsWith(other: Scroll): Boolean {
return this.conflicts.contains(other.id) ||
other.conflicts.contains(this.id)
}
override fun equals(other: Any?): Boolean {
if (other !is Scroll) {
return false

View File

@@ -23,7 +23,7 @@ class ScrollLevel(
}
override fun toString(): String {
return id.toString()
return "ScrollLevel(scroll=$scroll, level=$level)"
}
override fun hashCode(): Int {

View File

@@ -10,6 +10,8 @@ discover-recipes: true
gui:
rows: 6
title: "Inscription Table"
mask:
# The way the mask works is by having a list of materials
# And then a pattern to use those materials.
@@ -25,41 +27,41 @@ gui:
- black_stained_glass_pane
- magenta_stained_glass_pane
pattern:
- "011111110"
- "012202210"
- "012111210"
- "010111010"
- "011111110"
- "011101110"
- "111111111"
- "100010001"
- "111000111"
- "211101112"
- "221111122"
- "222101222"
show-allowed:
allow-material: lime_stained_glass_pane
deny-material: red_stained_glass_pane
indicator:
allow-item: lime_stained_glass_pane
deny-item: red_stained_glass_pane
# 1 is a show-allowed slot,
# 0 is not.
pattern:
- "100000001"
- "100000001"
- "100000001"
- "100000001"
- "100000001"
- "100000001"
- "000000000"
- "001101100"
- "000111000"
- "000000000"
- "000000000"
- "000000000"
inscribe-slot:
row: 2
row: 4
column: 5
scroll-slot:
row: 4
column: 7
row: 2
column: 8
item-slot:
row: 4
column: 3
row: 2
column: 2
close:
material: barrier
item: barrier
name: "&cClose"
lore: []
location:
@@ -67,7 +69,7 @@ gui:
column: 5
allow:
material: feather unbreaking:1 hide_enchants
item: feather unbreaking:1 hide_enchants
name: "&aInscribe Item"
lore:
- "&7Inscribe %scroll% &7onto"
@@ -80,13 +82,13 @@ gui:
- "&eClick to inscribe!"
deny:
material: barrier
item: barrier
name: "&cCannot Inscribe"
lore:
- "&7You cannot inscribe this item with this!"
empty:
material: feather unbreaking:1 hide_enchants
item: feather unbreaking:1 hide_enchants
name: "&aInscribe Item"
lore:
- "&7Place an item on the left and"
@@ -104,3 +106,6 @@ gui:
# Effects to run when trying to inscribe an item without meeting the conditions
deny-effects: [ ]
# Custom GUI slots; see here for a how-to: https://plugins.auxilor.io/all-plugins/custom-gui-slots
custom-slots: [ ]

View File

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

View File

@@ -1,8 +1,13 @@
messages:
prefix: "&#2d2d2d&lEcoScrolls&r &8» &r"
prefix: "&#2F0743&lEcoScrolls&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!"
all: "All"
needs-player: "&cYou must specify a player!"
needs-scroll: "&cYou must specify a scroll!"
invalid-player: "&cYou must specify a player!"
invalid-scroll: "&cYou must specify a scroll!"
give-success: "Gave %scroll%&r to %recipient%&r!"

View File

@@ -23,7 +23,6 @@ item:
# Options for inscribing items with the scroll
inscription:
# The conditions required to inscribe the item
# not-met-lines will show on the inscription table if the conditions are not met
# not-met-effects will run if someone tries to inscribe the item without meeting the conditions
conditions: [ ]
@@ -41,18 +40,28 @@ inscription:
targets:
- sword
# The conflicts that the scroll has with other scrolls
conflicts: [ ]
# The lore added to items when inscribed with the scroll
lore:
- ""
- "&7This item has been inscribed with"
- "&6Example Scroll"
# Item placeholders, can be used in other plugins.
# The placeholder is %ecoscrolls_scroll_<scroll>_<placeholder>%
placeholders:
bonus: "%level% * 2"
# Read https://plugins.auxilor.io/effects/configuring-an-effect
# The effects for the scroll
effects:
- id: give_money
- id: send_message
args:
amount: "0.25 * %victim_level%"
message: "&6You have used the Example Scroll!"
triggers:
- kill
filters:
not_entities:
- player
- alt_click
# Read https://plugins.auxilor.io/effects/configuring-a-condition
# The conditions for the scroll to work