mirror of
https://gitlab.bixilon.de/bixilon/minosoft.git
synced 2025-09-16 10:55:01 -04:00
rewrite legacy chat component reading, tests
This commit is contained in:
parent
01777d6daa
commit
9c833c0599
@ -17,18 +17,11 @@ import de.bixilon.kutil.cast.CastUtil.nullCast
|
||||
import de.bixilon.kutil.json.JsonUtil.toJsonList
|
||||
import de.bixilon.kutil.json.JsonUtil.toJsonObject
|
||||
import de.bixilon.kutil.primitive.BooleanUtil.toBoolean
|
||||
import de.bixilon.kutil.url.URLUtil.toURL
|
||||
import de.bixilon.minosoft.data.language.translate.Translator
|
||||
import de.bixilon.minosoft.data.text.events.click.ClickEvent
|
||||
import de.bixilon.minosoft.data.text.events.click.ClickEvents
|
||||
import de.bixilon.minosoft.data.text.events.click.OpenURLClickEvent
|
||||
import de.bixilon.minosoft.data.text.events.hover.HoverEvents
|
||||
import de.bixilon.minosoft.data.text.formatting.ChatCode.Companion.toColor
|
||||
import de.bixilon.minosoft.data.text.formatting.ChatFormattingCode
|
||||
import de.bixilon.minosoft.data.text.formatting.ChatFormattingCodes
|
||||
import de.bixilon.minosoft.data.text.formatting.PostChatFormattingCodes
|
||||
import de.bixilon.minosoft.data.text.formatting.PreChatFormattingCodes
|
||||
import de.bixilon.minosoft.data.text.formatting.color.ChatColors
|
||||
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.KUtil.format
|
||||
@ -36,113 +29,20 @@ import de.bixilon.minosoft.util.KUtil.toResourceLocation
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.get
|
||||
import javafx.collections.ObservableList
|
||||
import javafx.scene.Node
|
||||
import java.text.CharacterIterator
|
||||
import java.text.StringCharacterIterator
|
||||
|
||||
class BaseComponent : ChatComponent {
|
||||
val parts: MutableList<ChatComponent> = mutableListOf()
|
||||
|
||||
constructor(parts: MutableList<ChatComponent>) {
|
||||
this.parts += parts
|
||||
}
|
||||
|
||||
constructor(vararg parts: Any?) {
|
||||
for (part in parts) {
|
||||
this.parts += part.format()
|
||||
}
|
||||
}
|
||||
|
||||
constructor(parent: TextComponent? = null, legacy: String = "", restrictedMode: Boolean = false) {
|
||||
val currentText = StringBuilder()
|
||||
var currentColor = parent?.color
|
||||
var currentFormatting: MutableSet<ChatFormattingCode> = parent?.formatting?.toMutableSet() ?: mutableSetOf()
|
||||
|
||||
val iterator = StringCharacterIterator(legacy)
|
||||
|
||||
var char = iterator.first()
|
||||
|
||||
|
||||
fun push() {
|
||||
if (currentText.isEmpty()) {
|
||||
return
|
||||
}
|
||||
val spaceSplit = currentText.split(' ')
|
||||
var currentMessage = ""
|
||||
|
||||
fun push(clickEvent: ClickEvent?) {
|
||||
if (currentMessage.isEmpty()) {
|
||||
return
|
||||
}
|
||||
parts += TextComponent(message = currentMessage, color = currentColor, formatting = currentFormatting.toMutableSet(), clickEvent = clickEvent)
|
||||
currentMessage = ""
|
||||
}
|
||||
|
||||
for ((index, split) in spaceSplit.withIndex()) {
|
||||
var clickEvent: ClickEvent? = null
|
||||
if (split.isNotBlank()) {
|
||||
for (protocol in URLProtocols.VALUES) {
|
||||
if (!split.startsWith(protocol.prefix)) {
|
||||
continue
|
||||
}
|
||||
if (protocol.restricted && restrictedMode) {
|
||||
break
|
||||
}
|
||||
clickEvent = OpenURLClickEvent(split.toURL())
|
||||
break
|
||||
}
|
||||
}
|
||||
if (split.isNotEmpty()) {
|
||||
if (clickEvent != null) {
|
||||
// push previous
|
||||
push(null)
|
||||
|
||||
currentMessage = split
|
||||
push(clickEvent)
|
||||
} else {
|
||||
currentMessage += split
|
||||
}
|
||||
}
|
||||
|
||||
if (index != spaceSplit.size - 1) {
|
||||
currentMessage += " "
|
||||
}
|
||||
}
|
||||
push(null)
|
||||
currentFormatting = mutableSetOf()
|
||||
currentColor = null
|
||||
currentText.clear()
|
||||
}
|
||||
|
||||
while (char != CharacterIterator.DONE) {
|
||||
if (char != ProtocolDefinition.TEXT_COMPONENT_FORMATTING_PREFIX) {
|
||||
currentText.append(char)
|
||||
char = iterator.next()
|
||||
continue
|
||||
}
|
||||
|
||||
val formattingChar = iterator.next()
|
||||
|
||||
ChatColors.VALUES.getOrNull(Character.digit(formattingChar, 16))?.let {
|
||||
push()
|
||||
currentColor = it.nullCast<RGBColor>()
|
||||
} ?: ChatFormattingCodes.getChatFormattingCodeByChar(formattingChar)?.let {
|
||||
push()
|
||||
|
||||
if (it == PostChatFormattingCodes.RESET) {
|
||||
push()
|
||||
} else {
|
||||
currentFormatting.add(it)
|
||||
}
|
||||
} ?: let {
|
||||
// ignore and ignore next char
|
||||
char = iterator.next()
|
||||
}
|
||||
// check because of above
|
||||
if (char == CharacterIterator.DONE) {
|
||||
break
|
||||
}
|
||||
char = iterator.next()
|
||||
}
|
||||
|
||||
push()
|
||||
}
|
||||
|
||||
constructor(translator: Translator? = null, parent: TextComponent? = null, json: Map<String, Any>, restrictedMode: Boolean = false) {
|
||||
var currentParent: TextComponent? = null
|
||||
var currentText = ""
|
||||
@ -150,7 +50,7 @@ class BaseComponent : ChatComponent {
|
||||
fun parseExtra() {
|
||||
json["extra"].toJsonList()?.let {
|
||||
for (data in it) {
|
||||
parts += ChatComponent.of(data, translator, currentParent, restrictedMode)
|
||||
this += ChatComponent.of(data, translator, currentParent, restrictedMode)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -186,7 +86,7 @@ class BaseComponent : ChatComponent {
|
||||
hoverEvent = hoverEvent,
|
||||
)
|
||||
if (currentText.isNotEmpty()) {
|
||||
parts += textComponent
|
||||
this += textComponent
|
||||
}
|
||||
currentParent = textComponent
|
||||
|
||||
@ -199,7 +99,7 @@ class BaseComponent : ChatComponent {
|
||||
with.add(part ?: continue)
|
||||
}
|
||||
}
|
||||
parts += translator?.translate(it.toResourceLocation(), currentParent, restrictedMode, *with.toTypedArray()) ?: ChatComponent.of(json["with"], translator, currentParent, restrictedMode)
|
||||
this += translator?.translate(it.toResourceLocation(), currentParent, restrictedMode, *with.toTypedArray()) ?: ChatComponent.of(json["with"], translator, currentParent, restrictedMode)
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,8 +195,15 @@ class BaseComponent : ChatComponent {
|
||||
return legacyText
|
||||
}
|
||||
|
||||
operator fun plusAssign(component: ChatComponent) {
|
||||
if (component.length == 0) {
|
||||
return
|
||||
}
|
||||
parts += component
|
||||
}
|
||||
|
||||
operator fun plusAssign(text: Any?) {
|
||||
parts += text.format()
|
||||
this += text.format()
|
||||
}
|
||||
|
||||
private fun <T> MutableSet<T>.addOrRemove(value: T, addOrRemove: Boolean?) {
|
||||
|
@ -133,7 +133,7 @@ interface ChatComponent {
|
||||
}
|
||||
}
|
||||
|
||||
return BaseComponent(parent, string, restrictedMode)
|
||||
return LegacyComponentReader.parse(parent, string, restrictedMode)
|
||||
}
|
||||
|
||||
fun String.chat(): ChatComponent {
|
||||
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This software is not affiliated with Mojang AB, the original developer of Minecraft.
|
||||
*/
|
||||
|
||||
package de.bixilon.minosoft.data.text
|
||||
|
||||
import de.bixilon.kutil.url.URLUtil.toURL
|
||||
import de.bixilon.minosoft.data.text.events.click.ClickEvent
|
||||
import de.bixilon.minosoft.data.text.events.click.OpenFileClickEvent
|
||||
import de.bixilon.minosoft.data.text.events.click.OpenURLClickEvent
|
||||
import de.bixilon.minosoft.data.text.formatting.ChatFormattingCode
|
||||
import de.bixilon.minosoft.data.text.formatting.ChatFormattingCodes
|
||||
import de.bixilon.minosoft.data.text.formatting.PostChatFormattingCodes
|
||||
import de.bixilon.minosoft.data.text.formatting.color.ChatColors
|
||||
import de.bixilon.minosoft.data.text.formatting.color.RGBColor
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import java.io.File
|
||||
import java.text.CharacterIterator
|
||||
import java.text.StringCharacterIterator
|
||||
|
||||
private typealias PartList = MutableList<ChatComponent>
|
||||
|
||||
object LegacyComponentReader {
|
||||
|
||||
|
||||
private fun PartList.push(sequence: SequenceBuilder, restricted: Boolean) {
|
||||
if (sequence.text.isEmpty()) return
|
||||
|
||||
val split = sequence.text.split(' ')
|
||||
|
||||
val text = StringBuilder()
|
||||
|
||||
for ((index, part) in split.withIndex()) {
|
||||
val event = getClickEvent(part, restricted)
|
||||
if (event == null) {
|
||||
text.append(part)
|
||||
|
||||
if (index < split.size - 1) {
|
||||
text.append(" ") // space was lost in the split process
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (text.isNotEmpty()) {
|
||||
// an url follows, push the previous part
|
||||
this += TextComponent(text, sequence.color, sequence.formatting.toMutableSet())
|
||||
text.clear()
|
||||
}
|
||||
|
||||
this += TextComponent(part, sequence.color, sequence.formatting.toMutableSet(), event)
|
||||
}
|
||||
if (text.isNotEmpty()) {
|
||||
// data that was not pushed yet
|
||||
this += TextComponent(text, sequence.color, sequence.formatting.toMutableSet())
|
||||
}
|
||||
|
||||
sequence.reset() // clear it up again for next usage
|
||||
}
|
||||
|
||||
private fun getClickEvent(link: String, restricted: Boolean): ClickEvent? {
|
||||
for (protocol in URLProtocols.VALUES) {
|
||||
if (!link.startsWith(protocol.prefix)) {
|
||||
continue
|
||||
}
|
||||
if (protocol.restricted && restricted) {
|
||||
break
|
||||
}
|
||||
return if (protocol == URLProtocols.FILE) OpenFileClickEvent(File(link.removePrefix(protocol.prefix))) else OpenURLClickEvent(link.toURL())
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
|
||||
fun parse(parent: TextComponent? = null, legacy: String = "", restricted: Boolean = false): ChatComponent {
|
||||
val parts: PartList = mutableListOf()
|
||||
|
||||
val sequence = SequenceBuilder(color = parent?.color, formatting = parent?.formatting?.toMutableSet() ?: mutableSetOf())
|
||||
|
||||
val iterator = StringCharacterIterator(legacy)
|
||||
|
||||
var char: Char
|
||||
while (true) {
|
||||
char = iterator.getAndNext()
|
||||
if (char == CharacterIterator.DONE) break
|
||||
|
||||
if (char != ProtocolDefinition.TEXT_COMPONENT_FORMATTING_PREFIX) {
|
||||
sequence.text.append(char)
|
||||
continue
|
||||
}
|
||||
|
||||
val formattingChar = iterator.getAndNext()
|
||||
|
||||
val color = ChatColors.VALUES.getOrNull(Character.digit(formattingChar, 16))
|
||||
if (color != null) {
|
||||
parts.push(sequence, restricted) // try push previous, because this is a color change
|
||||
sequence.color = color
|
||||
continue
|
||||
}
|
||||
val formatting = ChatFormattingCodes.getChatFormattingCodeByChar(formattingChar)
|
||||
if (formatting != null) {
|
||||
parts.push(sequence, restricted) // try push previous, because this is a formatting change
|
||||
|
||||
if (formatting != PostChatFormattingCodes.RESET) {
|
||||
// a reset means resetting, this is done by the previous push
|
||||
sequence.formatting += formatting
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// ignore the next char, it is not valid formatting and should be hidden
|
||||
}
|
||||
|
||||
parts.push(sequence, restricted)
|
||||
|
||||
return when {
|
||||
parts.isEmpty() -> EmptyComponent
|
||||
parts.size == 1 -> parts.first()
|
||||
else -> BaseComponent(parts)
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringCharacterIterator.getAndNext(): Char {
|
||||
val char = current()
|
||||
next()
|
||||
return char
|
||||
}
|
||||
|
||||
private data class SequenceBuilder(
|
||||
var text: StringBuilder = StringBuilder(),
|
||||
var color: RGBColor? = null,
|
||||
var formatting: MutableSet<ChatFormattingCode> = mutableSetOf(),
|
||||
) {
|
||||
|
||||
fun reset() {
|
||||
text.clear()
|
||||
color = null
|
||||
formatting.clear()
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -36,6 +36,15 @@ class CopyToClipboardClickEvent(
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return text.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is CopyToClipboardClickEvent) return false
|
||||
return other.text == text
|
||||
}
|
||||
|
||||
companion object : ClickEventFactory<CopyToClipboardClickEvent> {
|
||||
override val name = "copy_to_clipboard"
|
||||
|
||||
|
@ -48,6 +48,15 @@ class OpenFileClickEvent(
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return file.path.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is OpenFileClickEvent) return false
|
||||
return other.file.path == file.path
|
||||
}
|
||||
|
||||
companion object : ClickEventFactory<OpenFileClickEvent> {
|
||||
override val name: String = "open_file"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -46,6 +46,15 @@ class OpenURLClickEvent(
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return url.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is OpenURLClickEvent) return false
|
||||
return other.url == url
|
||||
}
|
||||
|
||||
companion object : ClickEventFactory<OpenURLClickEvent> {
|
||||
override val name: String = "open_url"
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -37,6 +37,15 @@ class SendMessageClickEvent(
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return message.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is SendMessageClickEvent) return false
|
||||
return other.message == message
|
||||
}
|
||||
|
||||
companion object : ClickEventFactory<SendMessageClickEvent>, MultiNameFactory<SendMessageClickEvent> {
|
||||
override val name: String = "send_message"
|
||||
override val aliases: Set<String> = setOf("run_command")
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -20,6 +20,15 @@ class SuggestChatClickEvent(
|
||||
val message: String,
|
||||
) : ClickEvent {
|
||||
|
||||
override fun hashCode(): Int {
|
||||
return message.hashCode()
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is SuggestChatClickEvent) return false
|
||||
return other.message == message
|
||||
}
|
||||
|
||||
companion object : ClickEventFactory<SuggestChatClickEvent>, MultiNameFactory<SuggestChatClickEvent> {
|
||||
override val name: String = "suggest_chat"
|
||||
override val aliases: Set<String> = setOf("suggest_command")
|
||||
|
@ -28,6 +28,7 @@ import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.json.Jackson
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTTagTypes
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
|
||||
open class InByteBuffer : de.bixilon.kutil.buffer.bytes.`in`.InByteBuffer {
|
||||
@ -44,14 +45,11 @@ open class InByteBuffer : de.bixilon.kutil.buffer.bytes.`in`.InByteBuffer {
|
||||
return readByte() / 32.0
|
||||
}
|
||||
|
||||
// TODO kutil 1.19.2
|
||||
/*
|
||||
override fun readString(length: Int = readVarInt()): String {
|
||||
override fun readString(length: Int): String {
|
||||
val string = String(readByteArray(length), StandardCharsets.UTF_8)
|
||||
check(string.length <= ProtocolDefinition.STRING_MAX_LENGTH) { "String max string length exceeded ${string.length} > ${ProtocolDefinition.STRING_MAX_LENGTH}" }
|
||||
return string
|
||||
}
|
||||
*/
|
||||
|
||||
fun readJson(): Map<String, Any> {
|
||||
return Jackson.MAPPER.readValue(readString(), Jackson.JSON_MAP_TYPE)
|
||||
|
@ -18,6 +18,8 @@ import de.bixilon.kotlinglm.vec3.Vec3i
|
||||
import de.bixilon.minosoft.data.registries.identified.Namespaces
|
||||
import de.bixilon.minosoft.data.registries.identified.ResourceLocation
|
||||
import de.bixilon.minosoft.data.text.ChatComponent
|
||||
import de.bixilon.minosoft.protocol.ProtocolUtil.encodeNetwork
|
||||
import de.bixilon.minosoft.protocol.protocol.ProtocolDefinition
|
||||
import de.bixilon.minosoft.util.json.Jackson
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTTagTypes
|
||||
import de.bixilon.minosoft.util.nbt.tag.NBTUtil.nbtType
|
||||
@ -36,8 +38,6 @@ open class OutByteBuffer : de.bixilon.kutil.buffer.bytes.out.OutByteBuffer {
|
||||
}
|
||||
|
||||
|
||||
// TODO kutil 1.19.2
|
||||
/*
|
||||
override fun writeString(string: String) {
|
||||
check(string.length <= ProtocolDefinition.STRING_MAX_LENGTH) { "String max string length exceeded ${string.length} > ${ProtocolDefinition.STRING_MAX_LENGTH}" }
|
||||
val bytes = string.encodeNetwork()
|
||||
@ -45,8 +45,6 @@ open class OutByteBuffer : de.bixilon.kutil.buffer.bytes.out.OutByteBuffer {
|
||||
writeBareByteArray(bytes)
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
protected fun writeNBTTagType(type: NBTTagTypes) {
|
||||
writeByte(type.ordinal)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
* Minosoft
|
||||
* Copyright (C) 2020-2022 Moritz Zwerger
|
||||
* Copyright (C) 2020-2023 Moritz Zwerger
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
@ -13,7 +13,10 @@
|
||||
|
||||
package de.bixilon.minosoft.data.text
|
||||
|
||||
import de.bixilon.kutil.url.URLUtil.toURL
|
||||
import de.bixilon.minosoft.data.text.ChatComponent.Companion.chat
|
||||
import de.bixilon.minosoft.data.text.events.click.OpenFileClickEvent
|
||||
import de.bixilon.minosoft.data.text.events.click.OpenURLClickEvent
|
||||
import de.bixilon.minosoft.data.text.formatting.color.ChatColors
|
||||
import de.bixilon.minosoft.data.text.formatting.color.RGBColor.Companion.asColor
|
||||
import org.junit.jupiter.api.Test
|
||||
@ -30,28 +33,28 @@ internal class ChatComponentTest {
|
||||
|
||||
@Test
|
||||
fun testSimpleText() {
|
||||
val expected = BaseComponent(parts = arrayOf(TextComponent("Test")))
|
||||
val expected = TextComponent("Test")
|
||||
val actual = "Test".chat()
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimpleColor() {
|
||||
val expected = BaseComponent(parts = arrayOf(TextComponent("Test").color(ChatColors.RED)))
|
||||
val expected = TextComponent("Test").color(ChatColors.RED)
|
||||
val actual = "§cTest".chat()
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSimpleColoredFormatting() {
|
||||
val expected = BaseComponent(parts = arrayOf(TextComponent("Test").color(ChatColors.RED).strikethrough()))
|
||||
val expected = TextComponent("Test").color(ChatColors.RED).strikethrough()
|
||||
val actual = "§c§mTest".chat()
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testSwappedSimpleColoredFormatting() {
|
||||
val expected = BaseComponent(parts = arrayOf(TextComponent("Test").color(ChatColors.RED).strikethrough()))
|
||||
val expected = TextComponent("Test").color(ChatColors.RED).strikethrough()
|
||||
val actual = "§m§cTest".chat()
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
@ -66,6 +69,47 @@ internal class ChatComponentTest {
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun url1() {
|
||||
val expected = BaseComponent(
|
||||
TextComponent("Test").color(ChatColors.RED),
|
||||
TextComponent("https://bixilon.de").color(ChatColors.GREEN).clickEvent(OpenURLClickEvent("https://bixilon.de".toURL())),
|
||||
)
|
||||
val actual = "§cTest§ahttps://bixilon.de".chat()
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun url2() {
|
||||
val expected = BaseComponent(
|
||||
TextComponent("Test ").color(ChatColors.RED),
|
||||
TextComponent("file:/home/moritz").color(ChatColors.GREEN).clickEvent(OpenFileClickEvent("/home/moritz")),
|
||||
)
|
||||
val actual = ChatComponent.of("§cTest §afile:/home/moritz")
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun url3() {
|
||||
val expected = BaseComponent(
|
||||
TextComponent("Hi, please take care of: "),
|
||||
TextComponent("https://bixilon.de/technoblade").clickEvent(OpenURLClickEvent("https://bixilon.de/technoblade".toURL())),
|
||||
)
|
||||
val actual = ChatComponent.of("Hi, please take care of: https://bixilon.de/technoblade")
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun restrictedMode() {
|
||||
val expected = BaseComponent(
|
||||
TextComponent("Test ").color(ChatColors.RED),
|
||||
TextComponent("file:/home/moritz").color(ChatColors.GREEN),
|
||||
)
|
||||
val actual = ChatComponent.of("§cTest §afile:/home/moritz", restrictedMode = true)
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun test2FormattedTexts() {
|
||||
val expected = BaseComponent(
|
||||
@ -137,11 +181,7 @@ internal class ChatComponentTest {
|
||||
|
||||
@Test
|
||||
fun testInvalidJson() {
|
||||
val expected = BaseComponent(
|
||||
parts = arrayOf(
|
||||
TextComponent("""{text":"Test"}"""),
|
||||
)
|
||||
)
|
||||
val expected = TextComponent("""{text":"Test"}""")
|
||||
val actual = """{text":"Test"}""".chat()
|
||||
assertEquals(expected, actual)
|
||||
}
|
||||
@ -169,4 +209,24 @@ internal class ChatComponentTest {
|
||||
val text = ChatComponent.of("dummy§anext")
|
||||
assertEquals(text.getJson(), listOf(mapOf("text" to "dummy"), mapOf("text" to "next", "color" to "green")))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun hypixelMotd() {
|
||||
val string = " §aHypixel Network §c[1.8-1.19]\n §c§lLUNAR MAPS §7§l§ §6§lCOSMETICS §7| §d§lSKYBLOCK 0.17.3"
|
||||
val component = ChatComponent.of(string)
|
||||
|
||||
val expected = BaseComponent(
|
||||
" ",
|
||||
TextComponent("Hypixel Network ").color(ChatColors.GREEN),
|
||||
TextComponent("[1.8-1.19]\n ").color(ChatColors.RED),
|
||||
TextComponent("LUNAR MAPS ").color(ChatColors.RED).bold(),
|
||||
TextComponent("COSMETICS ").color(ChatColors.GOLD).bold(),
|
||||
TextComponent("| ").color(ChatColors.GRAY),
|
||||
TextComponent("SKYBLOCK 0.17.3").color(ChatColors.LIGHT_PURPLE).bold(),
|
||||
)
|
||||
|
||||
|
||||
assertEquals(" Hypixel Network [1.8-1.19]\n LUNAR MAPS COSMETICS | SKYBLOCK 0.17.3", component.message)
|
||||
assertEquals(expected, component)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user