Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class PlayerPacketHandler(private val player: ServerPlayer, private val handler:
val item = PylonItem.fromStack(bukkitStack) ?: return stack
val prototype = item.schema.getItemStack()
prototype.copyDataFrom(bukkitStack) { it != DataComponentTypes.ITEM_NAME && it != DataComponentTypes.LORE }
prototype.amount = bukkitStack.amount
val translatedPrototype = prototype.clone()
try {
handler.handleItem(translatedPrototype)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ open class PylonBlock internal constructor(val block: Block) {

val key = schema.key

val nameTranslationKey = schema.nameTranslationKey
val loreTranslationKey = schema.loreTranslationKey
val defaultWailaTranslationKey = schema.defaultWailaTranslationKey

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,20 @@ class PylonBlockSchema(

val addon = getAddon(key)

val nameTranslationKey: TranslatableComponent
val loreTranslationKey: TranslatableComponent
val defaultWailaTranslationKey: TranslatableComponent

init {
val prefix = "pylon.${key.namespace}.item.${key.key}"
nameTranslationKey = Component.translatable("$prefix.name")
loreTranslationKey = Component.translatable("$prefix.lore")
val default = "$prefix.waila"
defaultWailaTranslationKey = Component.translatable(
if (addon.translator.languages.any { addon.translator.canTranslate(default, it) }) default else "$prefix.name"
)
defaultWailaTranslationKey = if (addon.translator.languages.any { addon.translator.canTranslate(default, it) }) {
Component.translatable(default)
} else {
nameTranslationKey
}
}

private val createConstructor: MethodHandle = blockClass.findConstructorMatching(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import net.kyori.adventure.text.Component
import org.bukkit.event.Event
import org.bukkit.event.EventHandler
import org.bukkit.event.Listener
import org.bukkit.event.inventory.InventoryOpenEvent
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.inventory.ItemStack
Expand Down Expand Up @@ -46,7 +45,7 @@ interface PylonGuiBlock : PylonBreakHandler, PylonInteractBlock, PylonNoVanillaC
* The title of the GUI
*/
val guiTitle: Component
get() = (this as PylonBlock).defaultWailaTranslationKey
get() = (this as PylonBlock).nameTranslationKey

/**
* The GUI associated with this block.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import net.kyori.adventure.key.Key
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.TextReplacementConfig
import net.kyori.adventure.text.TranslatableComponent
import net.kyori.adventure.text.TranslationArgument
import net.kyori.adventure.text.TranslationArgumentLike
import net.kyori.adventure.text.VirtualComponent
import net.kyori.adventure.text.format.NamedTextColor
import net.kyori.adventure.text.format.Style
Expand Down Expand Up @@ -225,7 +227,11 @@ class PylonTranslator private constructor(private val addon: PylonAddon) : Trans
editData(DataComponentTypes.LORE) { lore ->
val newLore = lore.lines().flatMap { line ->
if (!isPylon(line)) return@flatMap listOf(line)
val translated = GlobalTranslator.render(line.withArguments(arguments), locale)
val concatenatedArguments: MutableList<TranslationArgumentLike> = arguments.toMutableList()
if (line is TranslatableComponent) {
concatenatedArguments.addAll(line.arguments())
}
val translated = GlobalTranslator.render(line.withArguments(concatenatedArguments), locale)
if (translated.plainText.isBlank()) return@flatMap emptyList()
val encoded = LineWrapEncoder.encode(translated)
val wrapped = encoded.copy(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.meta.ItemMeta
import org.bukkit.persistence.PersistentDataContainer
import org.jetbrains.annotations.ApiStatus
import xyz.xenondevs.invui.item.Item
import xyz.xenondevs.invui.item.ItemProvider
import java.util.function.Consumer
import kotlin.collections.forEach
Expand Down Expand Up @@ -69,6 +70,8 @@ open class ItemStackBuilder internal constructor(val stack: ItemStack) : ItemPro
stack.setData(type)
}

fun <T : Any> get(type: DataComponentType.Valued<T>) = stack.getData(type)

/**
* @see ItemStack.unsetData
*/
Expand Down Expand Up @@ -134,6 +137,10 @@ open class ItemStackBuilder internal constructor(val stack: ItemStack) : ItemPro

fun lore(vararg lore: String) = lore(*lore.map(::fromMiniMessage).toTypedArray())

fun clearLore() = apply {
stack.setData(DataComponentTypes.LORE, ItemLore.lore())
}

fun hideFromTooltip(componentType: DataComponentType) = apply {
val tooltipDisplay = stack.getData(DataComponentTypes.TOOLTIP_DISPLAY)
val hidden = tooltipDisplay?.hiddenComponents()?.toMutableSet() ?: mutableSetOf()
Expand Down Expand Up @@ -317,6 +324,10 @@ open class ItemStackBuilder internal constructor(val stack: ItemStack) : ItemPro
fun useCooldown(cooldownTicks: Int, cooldownGroup: Key?)
= set(DataComponentTypes.USE_COOLDOWN, UseCooldown.useCooldown(cooldownTicks / 20.0f).cooldownGroup(cooldownGroup))

public override fun clone(): ItemStackBuilder {
return of(stack.clone())
}

fun build(): ItemStack = stack.clone()

/**
Expand Down Expand Up @@ -364,6 +375,11 @@ open class ItemStackBuilder internal constructor(val stack: ItemStack) : ItemPro
return of(ItemStack(material))
}

@JvmStatic
fun of(item: Item): ItemStackBuilder {
return of(ItemStack(item.itemProvider.get()))
}

/**
* Creates a new [ItemStack] for a GUI item, sets its pdc key and adds
* a custom model data string for resource packs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,24 @@ object GuiItems {
.set(DataComponentTypes.TOOLTIP_DISPLAY, TooltipDisplay.tooltipDisplay().hideTooltip(true))
)

/**
* A lime glass pane named 'Input'
*/
@JvmStatic
fun input(): Item = SimpleItem(
ItemStackBuilder.gui(Material.LIME_STAINED_GLASS_PANE, pylonKey("input"))
.name(Component.translatable("pylon.pyloncore.gui.input"))
)

/**
* An orange glass pane named 'Output'
*/
@JvmStatic
fun output(): Item = SimpleItem(
ItemStackBuilder.gui(Material.ORANGE_STAINED_GLASS_PANE, pylonKey("output"))
.name(Component.translatable("pylon.pyloncore.gui.output"))
)

/**
* Item that automatically cycles through durability to represent processing time.
* Intended for use in recipe displays.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,52 +6,130 @@ import io.github.pylonmc.pylon.core.util.gui.unit.UnitFormat
import io.papermc.paper.datacomponent.DataComponentTypes
import io.papermc.paper.datacomponent.item.TooltipDisplay
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.TextColor
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.inventory.ClickType
import org.bukkit.event.inventory.InventoryClickEvent
import xyz.xenondevs.invui.item.ItemProvider
import xyz.xenondevs.invui.item.impl.AbstractItem
import java.time.Duration
import kotlin.math.min

/**
* An item that counts down (by default) from a maximum durability, symbolising progress.
* An item that counts down (or up if [countDown] is true) from a maximum durability, symbolising progress.
*
* For example, this might be used in a custom furnace to show how much burn time is left on
* the current fuel. In this case, you'd want override [totalTime] and set it to the the total
* the current fuel. In this case, you'd want override [setTotalTimeTicks] and set it to the the total
* burn time of the fuel (eg: 80 seconds for coal), and then gradually increase [progress] as the
* remaining burn time decreased.
*
* @param material The material to use for the item
* @param inverse If true, the progress bar will be inverted, meaning that 0.0 is full and 1.0 is empty.
* Using any `set` methods on here will automatically update the item in any windows that contain it.
*
* @param builder The item stack builder to use for the item
* @param countDown If true, the progress bar will be inverted, meaning that 0.0 is full and 1.0 is empty.
*/
abstract class ProgressItem @JvmOverloads constructor(
private val material: Material,
private val inverse: Boolean = false
open class ProgressItem @JvmOverloads constructor(
builder: ItemStackBuilder,
private val countDown: Boolean = true
) : AbstractItem() {

@JvmOverloads constructor(material: Material, inverse: Boolean = true) : this(ItemStackBuilder.of(material), inverse)

/**
* The item to be displayed
*/
var itemStackBuilder: ItemStackBuilder = builder
set(value) {
field = value
notifyWindows()
}

/**
* The total time of whatever process this item is representing
*/
var totalTime: Duration? = null
set(value) {
field = value
notifyWindows()
if (field == null) {
progress = 0.0
}
}

/**
* How far through the [totalTime] we are
*/
var progress: Double = 0.0
set(value) {
field = value.coerceIn(0.0, 1.0)
notifyWindows()
}

open val totalTime: Duration? = null
/**
* Sets how far through the [totalTime] we are
*/
fun setRemainingTime(time: Duration) {
check(totalTime != null) { "Remaining time can only be set if total time is not null" }
progress = 1.0 - time.toNanos().toDouble() / totalTime!!.toNanos().toDouble()
}

/**
* Sets how far through the [totalTime] we are
*/
fun setRemainingTimeSeconds(seconds: Int) {
setRemainingTime(Duration.ofSeconds(seconds.toLong()))
}

/**
* Sets how far through the [totalTime] we are
*/
fun setRemainingTimeTicks(ticks: Int) {
setRemainingTime(Duration.ofMillis((ticks * 1000.0 / 20.0).toLong()))
}

fun setTotalTimeSeconds(seconds: Int?) {
totalTime = seconds?.let { Duration.ofSeconds(it.toLong()) }
}

fun setTotalTimeTicks(ticks: Int?) {
totalTime = ticks?.let { Duration.ofMillis((it * 1000.0 / 20.0).toLong()) }
}

@Suppress("UnstableApiUsage")
override fun getItemProvider(): ItemProvider {
var progressValue = progress
if (!inverse) {
if (!countDown) {
progressValue = 1 - progressValue
}
val builder = ItemStackBuilder.of(material)
.set(DataComponentTypes.MAX_STACK_SIZE, 1)

val builder = itemStackBuilder
.clone()
.set(DataComponentTypes.MAX_DAMAGE, MAX_DURABILITY)
.set(DataComponentTypes.DAMAGE, (progressValue * MAX_DURABILITY).toInt())
.set(
DataComponentTypes.TOOLTIP_DISPLAY, TooltipDisplay.tooltipDisplay()
.addHiddenComponents(DataComponentTypes.DAMAGE, DataComponentTypes.MAX_DAMAGE)
)

if (totalTime != null) {
// +1 so the durability bar is always visible
builder.set(DataComponentTypes.DAMAGE, min(MAX_DURABILITY, (progressValue * MAX_DURABILITY + 1).toInt()))
}

// Hide damage and max damage text
val tooltipDisplay = builder.get(DataComponentTypes.TOOLTIP_DISPLAY)
val newTooltipDisplay = TooltipDisplay.tooltipDisplay()
if (tooltipDisplay != null) {
// clone existing tooltip because modifying it does not work for some godforesaken reason
newTooltipDisplay.hideTooltip(tooltipDisplay.hideTooltip())
for (tooltip in tooltipDisplay.hiddenComponents()) {
newTooltipDisplay.addHiddenComponents(tooltip)
}
}
newTooltipDisplay.addHiddenComponents(DataComponentTypes.DAMAGE, DataComponentTypes.MAX_DAMAGE)
builder.set(
DataComponentTypes.TOOLTIP_DISPLAY,
newTooltipDisplay
)

// Set time in lore
totalTime?.let {
val remaining = it - it * progress
builder.lore(
Expand All @@ -61,22 +139,15 @@ abstract class ProgressItem @JvmOverloads constructor(
)
)
}
completeItem(builder)

return builder
}

/**
* This is used to modify the item being displayed.
*
* @param builder The item builder representing the progress item
*/
protected abstract fun completeItem(builder: ItemStackBuilder)

override fun handleClick(clickType: ClickType, player: Player, event: InventoryClickEvent) {}

companion object {
private const val MAX_DURABILITY = 1000
}
}

private operator fun Duration.times(value: Double): Duration = Duration.ofMillis((toMillis() * value).toLong())
private operator fun Duration.times(value: Double): Duration = Duration.ofMillis((toMillis() * value).toLong())
4 changes: 3 additions & 1 deletion pylon-core/src/main/resources/lang/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ gui:
next: "Next page (%current%/%total%)"
previous: "Previous page (%current%/%total%)"

time_left: "Time left: %time%"
time_left: "<arrow> Time left: <#d6d1b3>%time%"
input: "Input"
output: "Output"

guide:
title: "Pylon Guide"
Expand Down