Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: begin work on chatTranslations #56

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions chatty-paper/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ dependencies {

// Shaded
implementation(libs.imageloader)
implementation(libs.deepl)

}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.mineinabyss.chatty

import com.charleskorn.kaml.YamlComment
import com.mineinabyss.chatty.components.ChannelType
import com.mineinabyss.chatty.helpers.TranslationLanguage
import com.mineinabyss.idofront.textcomponents.miniMsg
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
Expand All @@ -18,6 +20,7 @@ data class ChattyChannel(
val proxy: Boolean = false,
val discordsrv: Boolean = true,
val messageDeletion: MessageDeletion = MessageDeletion(),
val translation: Translation = Translation(),
val isDefaultChannel: Boolean = false,
val isStaffChannel: Boolean = false,
val format: String = "",
Expand All @@ -26,6 +29,25 @@ data class ChattyChannel(
val channelAliases: List<String> = listOf(),
) {

@Serializable
data class Translation(
@YamlComment("Which type of translation should be done for the target language.",
"FORCE - Forces all messages to be translated to the target language",
"SKIP_SAME_LANGUAGE - Avoids translating a message if the senders language is same as ones own",
"ALL_SAME_LANGUAGE - Translates all messages to the receivers language",
"NONE - Disables translation"
)
val type: TargetLanguageType = TargetLanguageType.NONE,
@YamlComment("The default language for this channel to translate to.")
val targetLanguage: TranslationLanguage = TranslationLanguage.English_US,
//@YamlComment("Whether there should be a rate limitation per player for this channel.")
//val rateLimitPerPlayer: Boolean = true,
) {
enum class TargetLanguageType {
FORCE, SKIP_SAME_LANGUAGE, ALL_SAME_LANGUAGE, NONE
}
}

@Serializable
data class MessageDeletion(
val enabled: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.mineinabyss.chatty

import com.charleskorn.kaml.YamlComment
import com.deepl.api.Language
import com.deepl.api.LanguageCode
import com.mineinabyss.chatty.components.ChannelType
import com.mineinabyss.chatty.helpers.TranslationLanguage
import com.mineinabyss.idofront.serialization.DurationSerializer
import com.mineinabyss.idofront.textcomponents.miniMsg
import kotlinx.serialization.*
Expand All @@ -10,6 +13,7 @@ import kotlin.time.Duration.Companion.minutes

@Serializable
data class ChattyConfig(
val translation: Translation = Translation(),
val playerHeadFont: String = "minecraft:chatty_heads",
val nicknames: Nickname = Nickname(),
val chat: Chat = Chat(),
Expand All @@ -23,6 +27,16 @@ data class ChattyConfig(
val channels: MutableMap<String, ChattyChannel> = mutableMapOf("global" to ChattyChannel(ChannelType.GLOBAL, messageDeletion = ChattyChannel.MessageDeletion(true))),
) {

@Serializable
data class Translation(
@YamlComment("The character to append on translated messages")
val translationMark: String = "𝒯",
@YamlComment("The default language for this server to translate to if a channel has unspecified targetLanguage.")
val defaultLanguage: TranslationLanguage = TranslationLanguage.English_US,
@YamlComment("The authKey for your DeepL Account. Can be found here: https://www.deepl.com/your-account/summary")
internal val authKey: String? = null,
)

@Serializable
data class Chat(
val disableChatSigning: Boolean = true,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
package com.mineinabyss.chatty

import com.deepl.api.Translator
import com.mineinabyss.chatty.helpers.DiscordEmoteFixer
import com.mineinabyss.chatty.queries.SpyingPlayersQuery
import com.mineinabyss.geary.systems.query.CachedQuery
import com.mineinabyss.idofront.di.DI
import com.mineinabyss.idofront.messaging.ComponentLogger

const val chattyProxyChannel = "chatty:proxy"
const val discordSrvChannel = "chatty:discordsrv"
val chatty by DI.observe<ChattyContext>()
interface ChattyContext {
val plugin: ChattyPlugin
val config: ChattyConfig
val logger: ComponentLogger
val translator: Translator
val messages: ChattyMessages
val emotefixer: DiscordEmoteFixer
val isPlaceholderApiLoaded: Boolean
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.mineinabyss.chatty

import com.mineinabyss.chatty.commands.ChattyBrigadierCommands
import com.deepl.api.Translator
import com.mineinabyss.chatty.components.ChannelData
import com.mineinabyss.chatty.components.ChattyNickname
import com.mineinabyss.chatty.helpers.DiscordEmoteFixer
import com.mineinabyss.chatty.helpers.translatorStatus
import com.mineinabyss.chatty.listeners.ChatListener
import com.mineinabyss.chatty.listeners.ChattyProxyListener
import com.mineinabyss.chatty.listeners.DiscordListener
Expand All @@ -16,6 +18,8 @@ import com.mineinabyss.geary.modules.geary
import com.mineinabyss.geary.systems.builders.cache
import com.mineinabyss.idofront.config.config
import com.mineinabyss.idofront.di.DI
import com.mineinabyss.idofront.messaging.ComponentLogger
import com.mineinabyss.idofront.messaging.observeLogger
import com.mineinabyss.idofront.plugin.Plugins
import com.mineinabyss.idofront.plugin.listeners
import github.scarsz.discordsrv.DiscordSRV
Expand Down Expand Up @@ -53,10 +57,13 @@ class ChattyPlugin : JavaPlugin() {
}

fun createChattyContext() {
translatorStatus = true
DI.remove<ChattyContext>()
val chattyContext = object : ChattyContext {
override val plugin: ChattyPlugin = this@ChattyPlugin
override val config: ChattyConfig by config("config", dataFolder.toPath(), ChattyConfig())
override val logger: ComponentLogger by plugin.observeLogger()
override val translator: Translator = Translator(config.translation.authKey.takeUnless { it.isNullOrEmpty() } ?: "x")
override val messages: ChattyMessages by config("messages", dataFolder.toPath(), ChattyMessages())
override val emotefixer: DiscordEmoteFixer by config("emotefixer", dataFolder.toPath(), DiscordEmoteFixer())
override val isPlaceholderApiLoaded: Boolean get() = Plugins.isEnabled("PlaceholderAPI")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.mineinabyss.chatty.components

import com.deepl.api.Language
import com.deepl.api.LanguageCode
import com.mineinabyss.chatty.chatty
import com.mineinabyss.chatty.helpers.TranslationLanguage
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
@SerialName("chatty:translation")
data class ChattyTranslation(val language: TranslationLanguage = chatty.config.translation.defaultLanguage, val translateSameLanguage: Boolean = false)
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
@file:Suppress("ReplaceSizeZeroCheckWithIsEmpty")

package com.mineinabyss.chatty.extensions

interface BaseMutableMap<K, V> : BaseMap<K, V>, MutableMap<K, V> {
override fun putAll(from: Map<out K, V>) {
for ((k, v) in from) put(k, v)
}
}

interface BaseMap<K, V> : Map<K, V> {
override fun isEmpty(): Boolean = size == 0
override fun containsKey(key: K): Boolean = keys.contains(key)
override fun containsValue(value: V): Boolean = values.contains(value)
}

interface BaseMutableList<T> : BaseList<T>, MutableList<T> {
override fun iterator(): MutableIterator<T> = listIterator(0)
override fun listIterator(): MutableListIterator<T> = listIterator(0)
override fun listIterator(index: Int): MutableListIterator<T> = BaseMutableListIterator(this, index)
override fun subList(fromIndex: Int, toIndex: Int): MutableList<T> = BaseSubMutableList(this, fromIndex, toIndex)

override fun add(element: T): Boolean {
add(size, element)
return true
}

override fun addAll(elements: Collection<T>): Boolean = addAll(size, elements)

override fun clear() {
while (isNotEmpty()) removeAt(size - 1)
}

override fun remove(element: T): Boolean {
val index = indexOf(element)
val found = index >= 0
if (found) removeAt(index)
return found
}

override fun retainAll(elements: Collection<T>): Boolean {
val set = elements.toSet()
return retainAll { it in set }
}

override fun removeAll(elements: Collection<T>): Boolean {
val set = elements.toSet()
return removeAll { it in set }
}
}

interface BaseList<T> : List<T> {
override fun containsAll(elements: Collection<T>): Boolean {
val elementsSet = elements.toSet()
for (n in 0 until size) if (this[n] in elementsSet) return true
return false
}
override fun contains(element: T): Boolean = indexOf(element) >= 0
override fun isEmpty(): Boolean = size == 0
override fun iterator(): Iterator<T> = listIterator(0)
override fun listIterator(): ListIterator<T> = listIterator(0)
override fun listIterator(index: Int): ListIterator<T> = BaseListIterator(this, index)
override fun subList(fromIndex: Int, toIndex: Int): List<T> = BaseSubList(this, fromIndex, toIndex)
override fun lastIndexOf(element: T): Int {
for (n in size - 1 downTo 0) if (this[n] == element) return n
return -1
}
override fun indexOf(element: T): Int {
for (n in 0 until size) if (this[n] == element) return n
return -1
}
}

open class BaseSubList<T>(val list: List<T>, start: Int, end: Int) : BaseList<T> {
var start: Int = start ; protected set
var end: Int = end ; protected set
override val size: Int get() = end - start
fun checkIndex(index: Int): Int {
if (index < 0 || index >= size) throw IndexOutOfBoundsException()
return start + index
}

override fun get(index: Int): T = list[checkIndex(index)]
}

open class BaseSubMutableList<T>(val mlist: MutableList<T>, start: Int, end: Int) : BaseSubList<T>(mlist, start, end),
BaseMutableList<T> {
override fun add(index: Int, element: T) {
mlist.add(checkIndex(index), element)
end++
}

override fun addAll(index: Int, elements: Collection<T>): Boolean {
val before = mlist.size
val out = mlist.addAll(checkIndex(index), elements)
end += mlist.size - before
return out
}

override fun removeAt(index: Int): T {
end--
return mlist.removeAt(checkIndex(index))
}

override fun set(index: Int, element: T): T = mlist.set(checkIndex(index), element)
}

open class BaseListIterator<T>(val list: List<T>, var index: Int) : ListIterator<T> {
override fun hasNext(): Boolean = index < list.size
override fun hasPrevious(): Boolean = (index > 0)
override fun next(): T = list[index++]
override fun nextIndex(): Int = index
override fun previous(): T = list[--index]
override fun previousIndex(): Int = index - 1
}

open class BaseMutableListIterator<T>(val mlist: MutableList<T>, index: Int) : BaseListIterator<T>(mlist, index), MutableListIterator<T> {
override fun add(element: T) = mlist.add(index, element)
override fun remove() { mlist.removeAt(index) }
override fun set(element: T) { mlist[index] = element }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.mineinabyss.chatty.extensions

open class CacheMap<K, V>(
val maxSize: Int = 16,
) : BaseCacheMap<K, V>() {
override fun mustFree(key: K, value: V): Boolean = size > maxSize
}

open class BaseCacheMap<K, V>() : BaseMutableMap<K, V> {
val map: LinkedHashMap<K, V> = LinkedHashMap()

protected open fun mustFree(key: K, value: V): Boolean = false
protected open fun keyToRemove(key: K, value: V): K = map.keys.first()
protected open fun freed(key: K, value: V) {
}

override val size: Int get() = map.size

override fun remove(key: K): V? {
val value = map.remove(key)
if (value != null) freed(key, value)
return value
}

override fun putAll(from: Map<out K, V>) { for ((k, v) in from) put(k, v) }
override fun put(key: K, value: V): V? {
val oldValue = map[key]
if (oldValue != value) {
remove(key) // refresh if exists
map[key] = value
putNew(key, value)
}
//while (isNotEmpty() && mustFree(key, value) && !map.containsKey(key)) {
while (isNotEmpty() && mustFree(key, value)) {
val keyToRemove = keyToRemove(key, value)
remove(keyToRemove)
}
return oldValue
}

protected open fun putNew(key: K, value: V) {
}

override fun clear() {
val keys = map.keys.toList()
for (key in keys) remove(key)
}

override val entries: MutableSet<MutableMap.MutableEntry<K, V>> get() = map.entries
override val keys: MutableSet<K> get() = map.keys
override val values: MutableCollection<V> get() = map.values

override fun get(key: K): V? = map.get(key)

override fun toString(): String = map.toString()

override fun equals(other: Any?): Boolean = (other is BaseCacheMap<*, *>) && (this.map == other.map)
override fun hashCode(): Int = this.map.hashCode()
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ object ChattyPermissions {
const val BYPASS_TAG_PERM = "chatty.tags.bypass"
const val BYPASS_CHAT_FILTERS_PERM = "chatty.chat.filters.bypass"
const val MODERATION_PERM = "chatty.moderation"
const val BYPASS_TRANSLATION = "chatty.translation.bypass"
val chatFormattingPerms = mapOf(
Permission("chatty.tags.color") to StandardTags.color(),
Permission("chatty.tags.rainbow") to StandardTags.rainbow(),
Expand Down
Loading
Loading