mirror of
https://github.com/GayPizzaSpecifications/foundation.git
synced 2025-08-02 21:20:55 +00:00
Add basic channel and chat bridge.
This commit is contained in:
parent
be7df6dcc6
commit
69380906e6
@ -3,6 +3,7 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
|||||||
plugins {
|
plugins {
|
||||||
java
|
java
|
||||||
id("org.jetbrains.kotlin.jvm") version "1.6.10" apply false
|
id("org.jetbrains.kotlin.jvm") version "1.6.10" apply false
|
||||||
|
id("org.jetbrains.kotlin.plugin.serialization") version "1.6.10" apply false
|
||||||
id("com.github.johnrengelman.shadow") version "7.1.1" apply false
|
id("com.github.johnrengelman.shadow") version "7.1.1" apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ allprojects {
|
|||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
plugins.apply("org.jetbrains.kotlin.jvm")
|
plugins.apply("org.jetbrains.kotlin.jvm")
|
||||||
|
plugins.apply("org.jetbrains.kotlin.plugin.serialization")
|
||||||
plugins.apply("com.github.johnrengelman.shadow")
|
plugins.apply("com.github.johnrengelman.shadow")
|
||||||
|
|
||||||
group = "io.gorence"
|
group = "io.gorence"
|
||||||
@ -35,6 +37,9 @@ subprojects {
|
|||||||
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
implementation(platform("org.jetbrains.kotlin:kotlin-bom"))
|
||||||
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
|
||||||
|
|
||||||
|
// Serialization
|
||||||
|
implementation("com.charleskorn.kaml:kaml:0.38.0")
|
||||||
|
|
||||||
// Paper API
|
// Paper API
|
||||||
compileOnly("io.papermc.paper:paper-api:1.18.1-R0.1-SNAPSHOT")
|
compileOnly("io.papermc.paper:paper-api:1.18.1-R0.1-SNAPSHOT")
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation("net.dv8tion:JDA:5.0.0-alpha.2")
|
implementation("net.dv8tion:JDA:5.0.0-alpha.2") {
|
||||||
|
exclude(module = "opus-java")
|
||||||
|
}
|
||||||
|
|
||||||
compileOnly(project(":foundation-core"))
|
compileOnly(project(":foundation-core"))
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,68 @@
|
|||||||
package cloud.kubelet.foundation.bifrost
|
package cloud.kubelet.foundation.bifrost
|
||||||
|
|
||||||
|
import cloud.kubelet.foundation.bifrost.model.BifrostConfig
|
||||||
import cloud.kubelet.foundation.core.FoundationCorePlugin
|
import cloud.kubelet.foundation.core.FoundationCorePlugin
|
||||||
|
import cloud.kubelet.foundation.core.Util
|
||||||
|
import com.charleskorn.kaml.Yaml
|
||||||
|
import io.papermc.paper.event.player.AsyncChatEvent
|
||||||
|
import net.dv8tion.jda.api.JDA
|
||||||
|
import net.dv8tion.jda.api.JDABuilder
|
||||||
|
import net.dv8tion.jda.api.events.GenericEvent
|
||||||
|
import net.dv8tion.jda.api.events.message.MessageReceivedEvent
|
||||||
|
import net.dv8tion.jda.api.hooks.EventListener
|
||||||
|
import net.kyori.adventure.text.Component
|
||||||
|
import net.kyori.adventure.text.TextComponent
|
||||||
|
import org.bukkit.event.EventHandler
|
||||||
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
|
import kotlin.io.path.inputStream
|
||||||
|
|
||||||
|
class FoundationBifrostPlugin : JavaPlugin(), EventListener, Listener {
|
||||||
|
private lateinit var config: BifrostConfig
|
||||||
|
private lateinit var jda: JDA
|
||||||
|
|
||||||
class FoundationBifrostPlugin : JavaPlugin() {
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
slF4JLogger.info("Enabling!")
|
|
||||||
|
|
||||||
val foundation = server.pluginManager.getPlugin("Foundation") as FoundationCorePlugin
|
val foundation = server.pluginManager.getPlugin("Foundation") as FoundationCorePlugin
|
||||||
slF4JLogger.info("Plugin data path: ${foundation.pluginDataPath}")
|
slF4JLogger.info("Plugin data path: ${foundation.pluginDataPath}")
|
||||||
|
|
||||||
|
val configPath = Util.copyDefaultConfig(slF4JLogger, foundation.pluginDataPath, "bifrost.yaml")
|
||||||
|
config = Yaml.default.decodeFromStream(BifrostConfig.serializer(), configPath.inputStream())
|
||||||
|
|
||||||
|
server.pluginManager.registerEvents(this, this)
|
||||||
|
|
||||||
|
jda = JDABuilder
|
||||||
|
.createDefault(config.authentication.token)
|
||||||
|
.addEventListeners(this)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onEvent(e: GenericEvent) {
|
||||||
|
when (e) {
|
||||||
|
is MessageReceivedEvent -> {
|
||||||
|
// Prevent this bot from receiving its own messages and creating a feedback loop.
|
||||||
|
if (e.author.id == jda.selfUser.id) return
|
||||||
|
|
||||||
|
slF4JLogger.debug(
|
||||||
|
"${e.guild.name} - ${e.channel.name} - ${e.author.name}: ${e.message.contentDisplay}"
|
||||||
|
)
|
||||||
|
server.sendMessage(Component.text("${e.author.name} - ${e.message.contentDisplay}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
private fun onPlayerChat(e: AsyncChatEvent) {
|
||||||
|
val channel = jda.getTextChannelById(config.channel.id)
|
||||||
|
if (channel == null) {
|
||||||
|
slF4JLogger.error("Failed to retrieve channel ${config.channel.id}")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val message = e.message()
|
||||||
|
if (message is TextComponent) {
|
||||||
|
channel.sendMessage("${e.player.name}: ${message.content()}").queue()
|
||||||
|
} else {
|
||||||
|
slF4JLogger.error("Not sure what to do here, message != TextComponent: ${message.javaClass}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
package cloud.kubelet.foundation.bifrost.model
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BifrostConfig(
|
||||||
|
val authentication: BifrostAuthentication,
|
||||||
|
val channel: BifrostChannel,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BifrostAuthentication(
|
||||||
|
val token: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class BifrostChannel(
|
||||||
|
val id: String,
|
||||||
|
)
|
@ -1,10 +1,8 @@
|
|||||||
package cloud.kubelet.foundation.core
|
package cloud.kubelet.foundation.core
|
||||||
|
|
||||||
import cloud.kubelet.foundation.core.command.BackupCommand
|
import cloud.kubelet.foundation.core.command.BackupCommand
|
||||||
import io.papermc.paper.event.player.ChatEvent
|
|
||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
import org.bukkit.command.CommandExecutor
|
import org.bukkit.command.CommandExecutor
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.Listener
|
import org.bukkit.event.Listener
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
import org.bukkit.plugin.java.JavaPlugin
|
||||||
import java.nio.file.Path
|
import java.nio.file.Path
|
||||||
@ -23,7 +21,9 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
|||||||
}
|
}
|
||||||
return _pluginDataPath
|
return _pluginDataPath
|
||||||
}
|
}
|
||||||
private set(value) { _pluginDataPath = value }
|
private set(value) {
|
||||||
|
_pluginDataPath = value
|
||||||
|
}
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
pluginDataPath = dataFolder.toPath()
|
pluginDataPath = dataFolder.toPath()
|
||||||
@ -41,7 +41,7 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
|||||||
|
|
||||||
val log = slF4JLogger
|
val log = slF4JLogger
|
||||||
log.info("Features:")
|
log.info("Features:")
|
||||||
Util.printFeatureStatus(log, "Backup: ", BACKUP_ENABLED)
|
Util.printFeatureStatus(log, "Backup", BACKUP_ENABLED)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerCommandExecutor(name: String, executor: CommandExecutor) {
|
private fun registerCommandExecutor(name: String, executor: CommandExecutor) {
|
||||||
@ -49,8 +49,11 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
|||||||
command.setExecutor(executor)
|
command.setExecutor(executor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
// TODO: Disabling chat reformatting until I do something with it and figure out how to make it
|
||||||
|
// be less disruptive.
|
||||||
|
/*@EventHandler
|
||||||
private fun onChatMessage(e: ChatEvent) {
|
private fun onChatMessage(e: ChatEvent) {
|
||||||
|
return
|
||||||
e.isCancelled = true
|
e.isCancelled = true
|
||||||
val name = e.player.displayName()
|
val name = e.player.displayName()
|
||||||
val component = Component.empty()
|
val component = Component.empty()
|
||||||
@ -60,7 +63,7 @@ class FoundationCorePlugin : JavaPlugin(), Listener {
|
|||||||
.append(Component.text(' '))
|
.append(Component.text(' '))
|
||||||
.append(e.message())
|
.append(e.message())
|
||||||
server.sendMessage(component)
|
server.sendMessage(component)
|
||||||
}
|
}*/
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val BACKUPS_DIRECTORY = "backups"
|
private const val BACKUPS_DIRECTORY = "backups"
|
||||||
|
@ -3,5 +3,5 @@ package cloud.kubelet.foundation.core
|
|||||||
import net.kyori.adventure.text.format.TextColor
|
import net.kyori.adventure.text.format.TextColor
|
||||||
|
|
||||||
object TextColors {
|
object TextColors {
|
||||||
val AMARANTH_PINK = TextColor.fromHexString("#F7A8B8")
|
val AMARANTH_PINK = TextColor.fromHexString("#F7A8B8")!!
|
||||||
}
|
}
|
@ -3,6 +3,7 @@ package cloud.kubelet.foundation.core
|
|||||||
import net.kyori.adventure.text.Component
|
import net.kyori.adventure.text.Component
|
||||||
import net.kyori.adventure.text.format.TextColor
|
import net.kyori.adventure.text.format.TextColor
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
|
import java.nio.file.Path
|
||||||
|
|
||||||
object Util {
|
object Util {
|
||||||
private val leftBracket: Component = Component.text('[')
|
private val leftBracket: Component = Component.text('[')
|
||||||
@ -14,15 +15,50 @@ object Util {
|
|||||||
logger.info("{}: {}", feature, if (state) "Enabled" else "Disabled")
|
logger.info("{}: {}", feature, if (state) "Enabled" else "Disabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatSystemMessage(message: String?): Component {
|
fun formatSystemMessage(message: String): Component {
|
||||||
return formatSystemMessage(TextColors.AMARANTH_PINK, message)
|
return formatSystemMessage(TextColors.AMARANTH_PINK, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun formatSystemMessage(prefixColor: TextColor?, message: String?): Component {
|
fun formatSystemMessage(prefixColor: TextColor, message: String): Component {
|
||||||
return leftBracket
|
return leftBracket
|
||||||
.append(foundationName.color(prefixColor))
|
.append(foundationName.color(prefixColor))
|
||||||
.append(rightBracket)
|
.append(rightBracket)
|
||||||
.append(whitespace)
|
.append(whitespace)
|
||||||
.append(Component.text(message!!))
|
.append(Component.text(message))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the default configuration from the resource [resourceName] into the directory [targetPath].
|
||||||
|
* @param targetPath The output directory as a path, it must exist before calling this.
|
||||||
|
* @param resourceName Path to resource, it should be in the root of the `resources` directory,
|
||||||
|
* without the leading slash.
|
||||||
|
*/
|
||||||
|
fun copyDefaultConfig(log: Logger, targetPath: Path, resourceName: String): Path {
|
||||||
|
if (resourceName.startsWith("/")) {
|
||||||
|
throw IllegalArgumentException("resourceName starts with slash")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!targetPath.toFile().exists()) {
|
||||||
|
throw Exception("Configuration output path does not exist!")
|
||||||
|
}
|
||||||
|
val outPath = targetPath.resolve(resourceName)
|
||||||
|
val outFile = outPath.toFile()
|
||||||
|
if (outFile.exists()) {
|
||||||
|
log.debug("Configuration file already exists.")
|
||||||
|
return outPath
|
||||||
|
}
|
||||||
|
|
||||||
|
val resourceStream = javaClass.getResourceAsStream("/$resourceName")
|
||||||
|
?: throw Exception("Configuration resource does not exist!")
|
||||||
|
val outputStream = outFile.outputStream()
|
||||||
|
|
||||||
|
resourceStream.use {
|
||||||
|
outputStream.use {
|
||||||
|
log.info("Copied default configuration to $outPath")
|
||||||
|
resourceStream.copyTo(outputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outPath
|
||||||
}
|
}
|
||||||
}
|
}
|
10
foundation-core/src/main/resources/bifrost.yaml
Normal file
10
foundation-core/src/main/resources/bifrost.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Authentication configuration for the bridge.
|
||||||
|
authentication:
|
||||||
|
# Token from the Discord Bot developer's page.
|
||||||
|
token: abc123
|
||||||
|
|
||||||
|
# Channel configuration for the bridge.
|
||||||
|
channel:
|
||||||
|
# Channel ID, can be copied by turning on Developer Mode in User Settings -> Advanced. The ID can
|
||||||
|
# then be copied by right-clicking the channel and selecting "Copy ID".
|
||||||
|
id: 123456789
|
Loading…
Reference in New Issue
Block a user