From d95d4237d1ba835f44d31eaa1d40d957cfa47c4d Mon Sep 17 00:00:00 2001 From: Lukas Planz Date: Sat, 7 Oct 2023 13:39:27 +0200 Subject: [PATCH] Add custom player heads to the GUI --- CHANGELOG.md | 7 +++ .../md5lukas/waypoints/util/SpigotHelper.kt | 16 ++++++ .../inventory/InventoryConfiguration.kt | 39 ++++++++++----- .../waypoints/lang/ItemTranslation.kt | 49 ++++++++++--------- .../waypoints/pointers/WaypointTrackable.kt | 4 +- .../md5lukas/waypoints/util/APIExtensions.kt | 14 ++---- waypoints/src/main/resources/config.yml | 20 ++++---- waypoints/src/main/resources/lang/en.yml | 2 - 8 files changed, 92 insertions(+), 59 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c310c3..62984d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## [Unreleased] +### Added +- The GUI supports the usage of custom player heads + +### Changed +- Partial update of chinese translations by [SnowCutieOwO](https://github.com/SnowCutieOwO) +- The default config has been updated to replace some items with custom player heads + ## 4.2.0 ### Added diff --git a/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt b/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt index 75342fa..9c6e820 100644 --- a/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt +++ b/utils/src/main/kotlin/de/md5lukas/waypoints/util/SpigotHelper.kt @@ -1,8 +1,13 @@ package de.md5lukas.waypoints.util +import de.md5lukas.commons.paper.editMeta +import java.net.URL +import java.util.* import org.bukkit.Location +import org.bukkit.Material import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack +import org.bukkit.inventory.meta.SkullMeta import org.bukkit.plugin.Plugin fun parseLocationString(player: Player, input: String): Location? { @@ -36,3 +41,14 @@ fun minecraftVersionAtLeast(plugin: Plugin, minor: Int, patch: Int = 0): Boolean } return parsedVersion[1] >= minor && parsedVersion[2] >= patch } + +fun createCustomPlayerHead(plugin: Plugin, textureId: String): ItemStack { + val profile = plugin.server.createProfile(UUID.randomUUID()) + + profile.setTextures( + profile.textures.also { it.skin = URL("https://textures.minecraft.net/texture/$textureId") }) + + val stack = ItemStack(Material.PLAYER_HEAD) + stack.editMeta { playerProfile = profile } + return stack +} diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/inventory/InventoryConfiguration.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/inventory/InventoryConfiguration.kt index 65b3e44..a448703 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/inventory/InventoryConfiguration.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/config/inventory/InventoryConfiguration.kt @@ -4,8 +4,11 @@ import de.md5lukas.commons.paper.getStringNotNull import de.md5lukas.konfig.Configurable import de.md5lukas.konfig.ExportConfigurationSection import de.md5lukas.konfig.SkipConfig +import de.md5lukas.waypoints.util.createCustomPlayerHead import org.bukkit.Material import org.bukkit.configuration.ConfigurationSection +import org.bukkit.inventory.ItemStack +import org.bukkit.plugin.Plugin @Configurable class InventoryConfiguration { @@ -16,25 +19,37 @@ class InventoryConfiguration { private var rootConfig: ConfigurationSection set(value) { _rootConfig = value - materialCache.clear() + itemCache.clear() } get() = _rootConfig!! - private val materialCache = HashMap() + private val itemCache = HashMap() - fun getMaterial(path: String): Material { - val cached = materialCache[path] + private val headPrefix = Material.PLAYER_HEAD.name + ":" + + fun createNewStack(plugin: Plugin, path: String): ItemStack { + val cached = itemCache[path] if (cached != null) { - return cached + return cached.clone() } val materialString = rootConfig.getStringNotNull(path) - val material = - Material.matchMaterial(materialString) - ?: throw IllegalArgumentException("The material $materialString at $path is not valid") - - materialCache[path] = material - - return material + val stack = + if (materialString.startsWith(headPrefix)) { + try { + createCustomPlayerHead(plugin, materialString.substring(headPrefix.length)) + } catch (t: Throwable) { + throw IllegalArgumentException("Invalid player head format at $path", t) + } + } else { + ItemStack( + Material.matchMaterial(materialString) + ?: throw IllegalArgumentException( + "The material $materialString at $path is not valid")) + } + + itemCache[path] = stack + + return stack.clone() } } diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/lang/ItemTranslation.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/lang/ItemTranslation.kt index 1d68221..20eec20 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/lang/ItemTranslation.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/lang/ItemTranslation.kt @@ -28,34 +28,37 @@ class ItemTranslation( private val rawDescription: String get() = translationLoader[descriptionKey] - val material: Material + val rawStack: ItemStack get() = - fixedMaterial - ?: translationLoader.plugin.waypointsConfig.inventory.getMaterial( - key + if (appendItemSuffix) ".item" else "") + fixedMaterial?.let(::ItemStack) + ?: translationLoader.plugin.waypointsConfig.inventory.createNewStack( + translationLoader.plugin, + key + if (appendItemSuffix) ".item" else "", + ) val item: ItemStack get() = getItem() - fun getItem(vararg resolvers: TagResolver): ItemStack = - ItemStack(material).also { - it.itemMeta = - it.itemMeta!!.also { itemMeta -> - itemMeta.displayName( - translationLoader.itemMiniMessage.deserialize(rawDisplayName, *resolvers)) - var discard = true // Remove leading blank lines - itemMeta.lore( - rawDescription.lineSequence().mapNotNullTo(mutableListOf()) { line -> - if (line.isNotBlank()) { - discard = false - } - if (discard) { - null - } else { - translationLoader.itemMiniMessage.deserialize(line, *resolvers) - } - }) - } + fun getItem(vararg resolvers: TagResolver): ItemStack = getItem(null, *resolvers) + + fun getItem(materialOverride: Material?, vararg resolvers: TagResolver): ItemStack = + (materialOverride?.let(::ItemStack) ?: rawStack).also { + it.editMeta { itemMeta -> + itemMeta.displayName( + translationLoader.itemMiniMessage.deserialize(rawDisplayName, *resolvers)) + var discard = true // Remove leading blank lines + itemMeta.lore( + rawDescription.lineSequence().mapNotNullTo(mutableListOf()) { line -> + if (line.isNotBlank()) { + discard = false + } + if (discard) { + null + } else { + translationLoader.itemMiniMessage.deserialize(line, *resolvers) + } + }) + } } override fun reset() {} diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/WaypointTrackable.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/WaypointTrackable.kt index fcd45bc..0224e81 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/WaypointTrackable.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/pointers/WaypointTrackable.kt @@ -4,7 +4,6 @@ import de.md5lukas.waypoints.WaypointsPlugin import de.md5lukas.waypoints.api.Waypoint import org.bukkit.Location import org.bukkit.entity.Player -import org.bukkit.inventory.ItemStack class WaypointTrackable(private val plugin: WaypointsPlugin, val waypoint: Waypoint) : StaticTrackable { @@ -28,8 +27,7 @@ class WaypointTrackable(private val plugin: WaypointsPlugin, val waypoint: Waypo .withReplacements(*waypoint.getResolvers(player, translatedTarget)) } - override val hologramItem = - ItemStack(waypoint.material ?: plugin.apiExtensions.run { waypoint.getIconMaterial() }) + override val hologramItem = plugin.apiExtensions.run { waypoint.getIconStack() } override fun equals(other: Any?): Boolean { return waypoint == (other as? WaypointTrackable)?.waypoint diff --git a/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/APIExtensions.kt b/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/APIExtensions.kt index 493a8c7..434076c 100644 --- a/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/APIExtensions.kt +++ b/waypoints/src/main/kotlin/de/md5lukas/waypoints/util/APIExtensions.kt @@ -15,7 +15,6 @@ import de.md5lukas.waypoints.gui.SharedDisplayable import de.md5lukas.waypoints.lang.InventoryTranslation import net.kyori.adventure.text.Component import org.bukkit.Location -import org.bukkit.Material import org.bukkit.entity.Player import org.bukkit.inventory.ItemStack @@ -42,7 +41,7 @@ class APIExtensions(private val plugin: WaypointsPlugin) { Type.PRIVATE -> translations.WAYPOINT_ICON_PRIVATE Type.PUBLIC -> translations.WAYPOINT_ICON_PUBLIC Type.PERMISSION -> translations.WAYPOINT_ICON_PERMISSION - }.getItem(*getResolvers(player)) + }.getItem(material, *getResolvers(player)) when (type) { Type.DEATH -> null @@ -51,8 +50,6 @@ class APIExtensions(private val plugin: WaypointsPlugin) { Type.PERMISSION -> translations.WAYPOINT_ICON_PERMISSION_CUSTOM_DESCRIPTION }?.let { stack.applyDescription(it, description) } - material?.also { stack.type = it } - return stack } @@ -77,14 +74,14 @@ class APIExtensions(private val plugin: WaypointsPlugin) { }, ) - fun Waypoint.getIconMaterial(): Material = - material + fun Waypoint.getIconStack(): ItemStack = + material?.let(::ItemStack) ?: when (type) { Type.DEATH -> translations.WAYPOINT_ICON_DEATH Type.PRIVATE -> translations.WAYPOINT_ICON_PRIVATE Type.PUBLIC -> translations.WAYPOINT_ICON_PUBLIC Type.PERMISSION -> translations.WAYPOINT_ICON_PERMISSION - }.material + }.rawStack fun Waypoint.getHologramTranslations() = when (type) { @@ -142,6 +139,7 @@ class APIExtensions(private val plugin: WaypointsPlugin) { Type.PERMISSION -> translations.FOLDER_ICON_PERMISSION else -> throw IllegalStateException("An folder with the type $type should not exist") }.getItem( + material, "name" placeholder name, "description" placeholder (description ?: ""), "created_at" placeholder createdAt, @@ -156,8 +154,6 @@ class APIExtensions(private val plugin: WaypointsPlugin) { Type.PERMISSION -> translations.FOLDER_ICON_PERMISSION_CUSTOM_DESCRIPTION }?.let { stack.applyDescription(it, description) } - material?.also { stack.type = it } - return stack } diff --git a/waypoints/src/main/resources/config.yml b/waypoints/src/main/resources/config.yml index 08f0870..84fbe22 100644 --- a/waypoints/src/main/resources/config.yml +++ b/waypoints/src/main/resources/config.yml @@ -425,8 +425,8 @@ sounds: inventory: general: - previous: ARROW - next: ARROW + previous: "PLAYER_HEAD:bd69e06e5dadfd84e5f3d1c21063f2553b2fa945ee1d4d7152fdc5425bc12a9" + next: "PLAYER_HEAD:19bf3292e126a105b54eba713aa1b152d541a1d8938829c56364d178ed22bf" back: BARRIER background: @@ -437,7 +437,7 @@ inventory: overview: cycleSort: HOPPER - settings: CRAFTING_TABLE + settings: "PLAYER_HEAD:e4d49bae95c790c3b1ff5b2f01052a714d6185481d5b1c85930b3f99d2321674" deselect: MILK_BUCKET setWaypoint: TORCH createFolder: WRITABLE_BOOK @@ -471,7 +471,7 @@ inventory: deselect: MILK_BUCKET delete: item: LAVA_BUCKET - question: OAK_SIGN + question: "PLAYER_HEAD:badc048a7ce78f7dad72a07da27d85c0916881e5522eeed1e3daf217a38c1a" confirm: LAVA_BUCKET cancel: WATER_BUCKET rename: NAME_TAG @@ -486,12 +486,12 @@ inventory: make: public: item: ENCHANTED_BOOK - question: OAK_SIGN + question: "PLAYER_HEAD:badc048a7ce78f7dad72a07da27d85c0916881e5522eeed1e3daf217a38c1a" confirm: ENCHANTED_BOOK cancel: BARRIER permission: item: ENCHANTED_BOOK - question: OAK_SIGN + question: "PLAYER_HEAD:badc048a7ce78f7dad72a07da27d85c0916881e5522eeed1e3daf217a38c1a" confirm: ENCHANTED_BOOK cancel: BARRIER changeMapIcon: FILLED_MAP @@ -505,7 +505,7 @@ inventory: delete: item: LAVA_BUCKET - question: OAK_SIGN + question: "PLAYER_HEAD:badc048a7ce78f7dad72a07da27d85c0916881e5522eeed1e3daf217a38c1a" confirm: LAVA_BUCKET cancel: WATER_BUCKET rename: NAME_TAG @@ -515,14 +515,14 @@ inventory: noFolder: MINECART selectBeaconColor: - moveLeft: ARROW - moveRight: ARROW + moveLeft: "PLAYER_HEAD:8652e2b936ca8026bd28651d7c9f2819d2e923697734d18dfdb13550f8fdad5f" + moveRight: "PLAYER_HEAD:2a3b8f681daad8bf436cae8da3fe8131f62a162ab81af639c3e0644aa6abac2f" confirm: background: GRAY_STAINED_GLASS_PANE playerList: - refresh: FISHING_ROD + refresh: "PLAYER_HEAD:e887cc388c8dcfcf1ba8aa5c3c102dce9cf7b1b63e786b34d4f1c3796d3e9d61" tracking: background: GRAY_STAINED_GLASS_PANE diff --git a/waypoints/src/main/resources/lang/en.yml b/waypoints/src/main/resources/lang/en.yml index b40478a..883ecbf 100644 --- a/waypoints/src/main/resources/lang/en.yml +++ b/waypoints/src/main/resources/lang/en.yml @@ -1,5 +1,3 @@ - - prefix: "Waypoints > " scriptPrefix: "WaypointsScript > "