mirror of
				https://github.com/GayPizzaSpecifications/foundation.git
				synced 2025-11-04 11:39:39 +00:00 
			
		
		
		
	Add basic channel and chat bridge.
This commit is contained in:
		@ -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
 | 
				
			||||||
		Reference in New Issue
	
	Block a user