diff --git a/.gitignore b/.gitignore
index a09754c..8d4941c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,5 +8,5 @@ gradle-app.setting
.gradletasknamecache
# IntelliJ IDEA
-/.idea/
+/.idea/*
!/.idea/codeStyles
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 0000000..03529d1
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..79ee123
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/configurationExtension.kt b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/configurationExtension.kt
new file mode 100644
index 0000000..b5f0cf9
--- /dev/null
+++ b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/configurationExtension.kt
@@ -0,0 +1,29 @@
+package me.patrykanuszczyk.textcomponentserialization
+
+import net.md_5.bungee.api.chat.TextComponent
+import org.bukkit.configuration.ConfigurationSection
+import org.bukkit.inventory.ItemStack
+
+fun ConfigurationSection.getTextComponent(path: String): TextComponent? {
+ return deserializeTextComponent(this.get(path))
+}
+
+fun ConfigurationSection.setTextComponent(path: String, value: TextComponent?) {
+ this.set(path, value.serialize())
+}
+
+fun ConfigurationSection.getTextComponentList(path: String): List {
+ return this.getList(path).map { deserializeTextComponent(it) }
+}
+
+fun ConfigurationSection.setTextComponentList(path: String, value: List) {
+ this.set(path, value.map { it.serialize() })
+}
+
+fun ConfigurationSection.getBook(path: String): ItemStack? {
+ return deserializeBook(this.get(path))
+}
+
+fun ConfigurationSection.setBook(path: String, value: ItemStack?) {
+ this.set(path, serializeBook(value))
+}
\ No newline at end of file
diff --git a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/deserialize.kt b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/deserialize.kt
index f9b1ca0..a8d7c45 100644
--- a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/deserialize.kt
+++ b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/deserialize.kt
@@ -4,8 +4,15 @@ import net.md_5.bungee.api.ChatColor
import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.HoverEvent
import net.md_5.bungee.api.chat.TextComponent
+import org.bukkit.Material
import org.bukkit.configuration.ConfigurationSection
+import org.bukkit.inventory.ItemStack
+import org.bukkit.inventory.meta.BookMeta
+/**
+ * Deserializes a text component.
+ * @since 1.0
+ */
fun deserializeTextComponent(obj: Any?): TextComponent? {
val map = when (obj) {
null -> return null
@@ -20,16 +27,17 @@ fun deserializeTextComponent(obj: Any?): TextComponent? {
component.text = map["text"] as String? ?: ""
- component.extra = (map["extra"] as List<*>)
- .map {
- deserializeTextComponent(
- it ?: throw NullPointerException("Extra object is null!")
- )
- }
+ if (map["extra"] != null)
+ component.extra = (map["extra"] as List<*>)
+ .map {
+ deserializeTextComponent(
+ it ?: throw NullPointerException("Extra object is null!")
+ )
+ }
val color = deserializeChatColor(map["color"])
-
component.color = color
+
component.setBold(map["bold"] as Boolean?)
component.setItalic(map["italic"] as Boolean?)
component.setUnderlined(map["underlined"] as Boolean?)
@@ -46,8 +54,12 @@ fun deserializeTextComponent(obj: Any?): TextComponent? {
return component
}
+/**
+ * Deserializes a chat color.
+ * @since 1.0
+ */
fun deserializeChatColor(obj: Any?): ChatColor? {
- if(obj == null) return null
+ if (obj == null) return null
require(obj is String) { "Color has to be a string!" }
val canonicalName = obj
@@ -57,33 +69,93 @@ fun deserializeChatColor(obj: Any?): ChatColor? {
return ChatColor.valueOf(canonicalName)
}
+/**
+ * Deserializes a click event.
+ * @since 1.0
+ */
fun deserializeClickEvent(obj: Any?): ClickEvent? {
- if (obj == null) return null
- require(obj is ConfigurationSection) { "Click event has to be a configuration section or null!" }
+ val map = when(obj) {
+ null -> return null
+ is ConfigurationSection -> obj.getValues(false)
+ is Map<*,*> -> obj
+ else -> throw IllegalArgumentException("Couldn't deserialize click event from ${obj::class.qualifiedName}!")
+ }.toMapOf()
- val actionString = obj.getString("action")
+ val actionString = map["action"] ?: throw NullPointerException("No action specified for click event!")
val actionCanonicalName = actionString
.replace(' ', '_')
.toUpperCase()
val action = ClickEvent.Action.valueOf(actionCanonicalName)
- val value = obj.getString("value")
+ val value = map["value"]
return ClickEvent(action, value)
}
+/**
+ * Deserializes a hover event.
+ * @since 1.0
+ */
fun deserializeHoverEvent(obj: Any?): HoverEvent? {
- if(obj == null) return null
- require(obj is ConfigurationSection) { "Hover event has to be a configuration section or null!" }
+ val map = when(obj) {
+ null -> return null
+ is ConfigurationSection -> obj.getValues(true)
+ is Map<*,*> -> obj
+ else -> throw IllegalArgumentException("Couldn't deserialize click event from ${obj::class.qualifiedName}!")
+ }.toMapOf()
- val actionString = obj.getString("action")
+ val actionString = map["action"] as String
val actionCanonicalName = actionString
.replace(' ', '_')
.toUpperCase()
val action = HoverEvent.Action.valueOf(actionCanonicalName)
val value =
- deserializeTextComponent(obj.get("value"))
+ deserializeTextComponent(map["value"])
return HoverEvent(action, arrayOf(value))
+}
+
+/**
+ * Deserializes a book.
+ * @since 1.0
+ */
+fun deserializeBook(obj: Any?): ItemStack? {
+ val map = when (obj) {
+ null -> return null
+ is ConfigurationSection -> obj.getValues(true)
+ is Map<*, *> -> obj.toMapOf()
+ else -> throw IllegalArgumentException("Couldn't deserialize text component from ${obj::class.qualifiedName}!")
+ }
+
+ val stack = ItemStack(Material.WRITTEN_BOOK)
+
+ val meta = stack.itemMeta as BookMeta
+
+ meta.title = map["title"] as String?
+ meta.author = map["author"] as String?
+ meta.generation = deserializeBookGeneration(map["generation"])
+
+ meta.spigot().pages = (map["pages"] as List<*>).map {
+ arrayOf(deserializeTextComponent(it))
+ }
+
+ stack.itemMeta = meta
+
+ return stack
+}
+
+/**
+ * Deserializes book generation.
+ * @since 1.0
+ */
+fun deserializeBookGeneration(obj: Any?): BookMeta.Generation? {
+ if (obj == null) return null
+ require(obj is String) { "Book generation has to be a string!" }
+
+ val canonicalName = obj
+ .replace(' ', '_')
+ .toUpperCase()
+
+ return BookMeta.Generation.valueOf(canonicalName)
}
\ No newline at end of file
diff --git a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/format.kt b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/format.kt
new file mode 100644
index 0000000..0a50b4b
--- /dev/null
+++ b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/format.kt
@@ -0,0 +1,55 @@
+package me.patrykanuszczyk.textcomponentserialization
+
+import net.md_5.bungee.api.chat.ClickEvent
+import net.md_5.bungee.api.chat.HoverEvent
+import net.md_5.bungee.api.chat.TextComponent
+import org.bukkit.ChatColor
+import org.bukkit.inventory.ItemStack
+import org.bukkit.inventory.meta.BookMeta
+
+fun formatString(string: String, placeholders: Map? = null): String {
+ var stringFormatted = string
+ placeholders?.forEach { (key, value) ->
+ stringFormatted = stringFormatted.replace("{$key}", value, true)
+ }
+ return ChatColor.translateAlternateColorCodes('&', stringFormatted)
+}
+
+fun TextComponent.format(placeholders: Map? = null): TextComponent {
+ val newComponent = TextComponent(this)
+ if (text != null) newComponent.text = formatString(text, placeholders)
+ //extra?.forEach { newComponent.addExtra((it as TextComponent).format(placeholders)) }
+ if(extra != null)
+ newComponent.extra = extra.map { (it as TextComponent).format(placeholders) }
+ if (insertion != null) newComponent.insertion = formatString(insertion, placeholders)
+ if (clickEvent != null)
+ newComponent.clickEvent = ClickEvent(clickEvent.action, formatString(clickEvent.value, placeholders))
+ if (hoverEvent != null)
+ newComponent.hoverEvent = HoverEvent(hoverEvent.action, hoverEvent.value.map {
+ (it as TextComponent).format(placeholders)
+ }.toTypedArray())
+ return newComponent
+}
+
+fun formatBook(book: ItemStack?, placeholders: Map? = null): ItemStack? {
+ if (book == null) return null
+
+ val oldMeta = book.itemMeta as BookMeta
+
+ val newBook = ItemStack(book)
+
+ val meta = newBook.itemMeta as BookMeta
+ meta.title = formatString(oldMeta.title, placeholders)
+ meta.author = formatString(oldMeta.author, placeholders)
+ meta.generation = oldMeta.generation
+
+ meta.spigot().addPage(*oldMeta.spigot().pages.map { page ->
+ page.map {
+ (it as TextComponent).format(placeholders)
+ }.toTypedArray()
+ }.toTypedArray())
+
+ newBook.itemMeta = meta
+
+ return newBook
+}
\ No newline at end of file
diff --git a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/isEmpty.kt b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/isEmpty.kt
new file mode 100644
index 0000000..d664614
--- /dev/null
+++ b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/isEmpty.kt
@@ -0,0 +1,12 @@
+package me.patrykanuszczyk.textcomponentserialization
+
+import net.md_5.bungee.api.chat.TextComponent
+
+val TextComponent.isEmpty: Boolean
+ get() {
+ if(!text.isNullOrEmpty()) return false
+
+ return extra.all { it is TextComponent && it.isEmpty }
+ }
+
+val TextComponent.isNotEmpty: Boolean get() = !isEmpty
\ No newline at end of file
diff --git a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/mapConvert.kt b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/mapConvert.kt
index 20a716b..c9f8019 100644
--- a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/mapConvert.kt
+++ b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/mapConvert.kt
@@ -1,7 +1,6 @@
package me.patrykanuszczyk.textcomponentserialization
-@JvmSynthetic
-internal inline fun Map<*, *>.toMapOf(): MutableMap {
+inline fun Map<*, *>.toMapOf(): MutableMap {
val map = mutableMapOf()
for ((key, value) in this) {
diff --git a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/serialize.kt b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/serialize.kt
index a804f24..a00b257 100644
--- a/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/serialize.kt
+++ b/src/main/kotlin/me/patrykanuszczyk/textcomponentserialization/serialize.kt
@@ -4,42 +4,49 @@ import net.md_5.bungee.api.ChatColor
import net.md_5.bungee.api.chat.ClickEvent
import net.md_5.bungee.api.chat.HoverEvent
import net.md_5.bungee.api.chat.TextComponent
-
+import org.bukkit.Material
+import org.bukkit.inventory.ItemStack
+import org.bukkit.inventory.meta.BookMeta
+
+/**
+ * Serializes a text component.
+ * @since 1.0
+ */
@JvmName("serializeTextComponent")
fun TextComponent?.serialize(): Any? {
- if(this == null) return null
+ if (this == null) return null
val map = mutableMapOf()
if (!text.isNullOrEmpty())
- map += "text" to text
+ map["text"] = text
if (!extra.isNullOrEmpty())
- map += "extra" to extra.map { (it as TextComponent).serialize() }
+ map["extra"] = extra.map { (it as TextComponent).serialize() }
if (colorRaw != null)
- map += "color" to serializeChatColor(colorRaw)!!
+ map["color"] = serializeChatColor(colorRaw)!!
if (isBoldRaw != null)
- map += "bold" to isBoldRaw
+ map["bold"] = isBoldRaw
if (isItalicRaw != null)
- map += "italic" to isItalicRaw
+ map["italic"] = isItalicRaw
if (isUnderlinedRaw != null)
- map += "underlined" to isUnderlinedRaw
+ map["underlined"] = isUnderlinedRaw
if (isStrikethroughRaw != null)
- map += "strikethrough" to isStrikethroughRaw
+ map["strikethrough"] = isStrikethroughRaw
if (isObfuscatedRaw != null)
- map += "obfuscated" to isObfuscatedRaw
+ map["obfuscated"] = isObfuscatedRaw
if (insertion != null)
- map += "insertion" to insertion
+ map["insertion"] = insertion
if (clickEvent != null) {
- map += "clickEvent" to serializeClickEvent(
+ map["clickEvent"] = serializeClickEvent(
clickEvent
)!!
}
if (hoverEvent != null) {
- map += "hoverEvent" to serializeHoverEvent(
+ map["hoverEvent"] = serializeHoverEvent(
hoverEvent
)!!
}
@@ -49,23 +56,31 @@ fun TextComponent?.serialize(): Any? {
"text" -> return map.getValue("text")
"extra" -> return map.getValue("extra")
}
- } else if(map.keys.isEmpty()) {
+ } else if (map.keys.isEmpty()) {
return ""
}
return map
}
+/**
+ * Serializes a chat color.
+ * @since 1.0
+ */
fun serializeChatColor(color: ChatColor?): Any? {
- if(color == null) return null
+ if (color == null) return null
return color.name
.replace('_', ' ')
.toLowerCase()
}
+/**
+ * Serializes a click event.
+ * @since 1.0
+ */
fun serializeClickEvent(event: ClickEvent?): Any? {
- if(event == null) return null
+ if (event == null) return null
val action = event.action.name
.replace('_', ' ')
@@ -79,8 +94,12 @@ fun serializeClickEvent(event: ClickEvent?): Any? {
)
}
+/**
+ * Serializes a hover event.
+ * @since 1.0
+ */
fun serializeHoverEvent(event: HoverEvent?): Any? {
- if(event == null) return null
+ if (event == null) return null
val action = event.action.name
.replace('_', ' ')
@@ -88,7 +107,7 @@ fun serializeHoverEvent(event: HoverEvent?): Any? {
val values = event.value
- val component = (if(values.size == 1)
+ val component = (if (values.size == 1)
values[0]
else
TextComponent(*values)) as TextComponent
@@ -99,4 +118,45 @@ fun serializeHoverEvent(event: HoverEvent?): Any? {
"action" to action,
"value" to value
)
+}
+
+/**
+ * Serializes a book item stack.
+ * @since 1.0
+ */
+fun serializeBook(stack: ItemStack?): Any? {
+ if (stack == null) return null
+ require(stack.type == Material.WRITTEN_BOOK) { "Book has to be of type WRITTEN_BOOK." }
+
+ val bookMeta = stack.itemMeta as BookMeta
+ val map = mutableMapOf()
+
+ map["title"] = bookMeta.title
+ map["author"] = bookMeta.author
+ map["generation"] = serializeBookGeneration(bookMeta.generation)!!
+
+ map["pages"] = bookMeta.spigot().pages
+ .map {
+ if (it.size == 1)
+ it[0] as TextComponent
+ else
+ TextComponent(*it)
+ }
+ .map {
+ it.serialize()
+ }
+
+ return map
+}
+
+/**
+ * Serializes book generation.
+ * @since 1.0
+ */
+fun serializeBookGeneration(generation: BookMeta.Generation?): Any? {
+ if (generation == null) return null
+
+ return generation.name
+ .replace('_', ' ')
+ .toLowerCase()
}
\ No newline at end of file