mirror of
https://github.com/devproje/px32-bot.git
synced 2024-11-26 10:43:05 +00:00
feat: add async task container
This commit is contained in:
parent
867a7c4ff7
commit
74fb7c7e04
14 changed files with 206 additions and 131 deletions
|
@ -3,11 +3,13 @@ package net.projecttl.p.x32.api
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
||||||
import net.projecttl.p.x32.api.model.PluginConfig
|
import net.projecttl.p.x32.api.model.PluginConfig
|
||||||
|
import net.projecttl.p.x32.api.util.AsyncTaskContainer
|
||||||
import org.slf4j.Logger
|
import org.slf4j.Logger
|
||||||
import org.slf4j.LoggerFactory
|
import org.slf4j.LoggerFactory
|
||||||
|
|
||||||
abstract class Plugin {
|
abstract class Plugin {
|
||||||
private val handlerContainer = mutableListOf<ListenerAdapter>()
|
private val handlerContainer = mutableListOf<ListenerAdapter>()
|
||||||
|
val taskContainer = AsyncTaskContainer()
|
||||||
|
|
||||||
val config = this.javaClass.getResourceAsStream("/plugin.json")!!.let {
|
val config = this.javaClass.getResourceAsStream("/plugin.json")!!.let {
|
||||||
val raw = it.bufferedReader().readText()
|
val raw = it.bufferedReader().readText()
|
||||||
|
|
|
@ -3,7 +3,6 @@ package net.projecttl.p.x32.api.command
|
||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
|
||||||
import net.dv8tion.jda.api.JDA
|
import net.dv8tion.jda.api.JDA
|
||||||
import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent
|
import net.dv8tion.jda.api.events.interaction.command.MessageContextInteractionEvent
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent
|
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent
|
||||||
|
@ -11,8 +10,8 @@ import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEven
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
||||||
import net.dv8tion.jda.api.interactions.commands.build.Commands
|
import net.dv8tion.jda.api.interactions.commands.build.Commands
|
||||||
|
|
||||||
fun commandHandler(block: (CommandHandler) -> Unit): CommandHandler {
|
fun commandHandler(guildId: Long = 0L, block: (CommandHandler) -> Unit): CommandHandler {
|
||||||
val handler = CommandHandler()
|
val handler = CommandHandler(guildId)
|
||||||
block.invoke(handler)
|
block.invoke(handler)
|
||||||
|
|
||||||
return handler
|
return handler
|
||||||
|
@ -25,15 +24,14 @@ class CommandHandler(val guildId: Long = 0L) : ListenerAdapter() {
|
||||||
override fun onSlashCommandInteraction(ev: SlashCommandInteractionEvent) {
|
override fun onSlashCommandInteraction(ev: SlashCommandInteractionEvent) {
|
||||||
val name = ev.interaction.name
|
val name = ev.interaction.name
|
||||||
|
|
||||||
commands.forEach { command ->
|
commands.singleOrNull { it.data.name == name }?.also { command ->
|
||||||
if (command.data.name == name) {
|
if (command is GlobalCommand) {
|
||||||
if (command is GlobalCommand) {
|
GlobalScope.launch {
|
||||||
GlobalScope.launch {
|
command.execute(ev)
|
||||||
command.execute(ev)
|
println("${ev.user.id} is use command for: ${ev.interaction.name}")
|
||||||
}
|
|
||||||
|
|
||||||
return@forEach
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -41,15 +39,14 @@ class CommandHandler(val guildId: Long = 0L) : ListenerAdapter() {
|
||||||
override fun onUserContextInteraction(ev: UserContextInteractionEvent) {
|
override fun onUserContextInteraction(ev: UserContextInteractionEvent) {
|
||||||
val name = ev.interaction.name
|
val name = ev.interaction.name
|
||||||
|
|
||||||
commands.forEach { command ->
|
commands.singleOrNull { it.data.name == name }?.also { command ->
|
||||||
if (command.data.name == name) {
|
if (command is UserContext) {
|
||||||
if (command is UserContext) {
|
GlobalScope.launch {
|
||||||
GlobalScope.launch {
|
command.execute(ev)
|
||||||
command.execute(ev)
|
println("${ev.user.id} is use user context for: ${ev.interaction.name}")
|
||||||
}
|
|
||||||
|
|
||||||
return@forEach
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -57,15 +54,14 @@ class CommandHandler(val guildId: Long = 0L) : ListenerAdapter() {
|
||||||
override fun onMessageContextInteraction(ev: MessageContextInteractionEvent) {
|
override fun onMessageContextInteraction(ev: MessageContextInteractionEvent) {
|
||||||
val name = ev.interaction.name
|
val name = ev.interaction.name
|
||||||
|
|
||||||
commands.forEach { command ->
|
commands.singleOrNull { it.data.name == name }?.also { command ->
|
||||||
if (command.data.name == name) {
|
if (command is MessageContext) {
|
||||||
if (command is MessageContext) {
|
GlobalScope.launch {
|
||||||
GlobalScope.launch {
|
command.execute(ev)
|
||||||
command.execute(ev)
|
println("${ev.user.id} is use message context for: ${ev.interaction.name}")
|
||||||
}
|
|
||||||
|
|
||||||
return@forEach
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,16 +38,24 @@ class AsyncTask(val loop: Boolean = true, val block: suspend () -> Unit) {
|
||||||
* This feature is Experimental
|
* This feature is Experimental
|
||||||
*/
|
*/
|
||||||
class AsyncTaskContainer {
|
class AsyncTaskContainer {
|
||||||
private val tasks = mutableMapOf<Long, AsyncTask>()
|
val tasks = mutableMapOf<Long, AsyncTask>()
|
||||||
private var tid = 0L
|
private var tid = 0L
|
||||||
|
|
||||||
fun getTask(tid: Long): AsyncTask? {
|
fun getTask(tid: Long): AsyncTask? {
|
||||||
return tasks[tid]
|
return tasks[tid]
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTask(task: AsyncTask) {
|
suspend fun createTask(task: AsyncTask) {
|
||||||
tasks[tid] = task
|
tasks[tid] = task
|
||||||
println("created task with id: $tid")
|
println("created task with id: $tid")
|
||||||
|
try {
|
||||||
|
task.run()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
tasks.remove(tid)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
tid++
|
tid++
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package net.projecttl.p.x32.api.util
|
||||||
|
|
||||||
import net.dv8tion.jda.api.EmbedBuilder
|
import net.dv8tion.jda.api.EmbedBuilder
|
||||||
import net.dv8tion.jda.api.entities.User
|
import net.dv8tion.jda.api.entities.User
|
||||||
import java.time.LocalDate
|
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import net.dv8tion.jda.api.interactions.commands.build.CommandData
|
||||||
import net.dv8tion.jda.internal.interactions.CommandDataImpl
|
import net.dv8tion.jda.internal.interactions.CommandDataImpl
|
||||||
import net.projecttl.p.x32.api.command.GlobalCommand
|
import net.projecttl.p.x32.api.command.GlobalCommand
|
||||||
import net.projecttl.p.x32.config.DefaultConfig
|
import net.projecttl.p.x32.config.DefaultConfig
|
||||||
import net.projecttl.p.x32.kernel.PluginLoader
|
import net.projecttl.p.x32.kernel.CoreKernel.PluginLoader
|
||||||
import java.lang.management.ManagementFactory
|
import java.lang.management.ManagementFactory
|
||||||
|
|
||||||
object Info : GlobalCommand {
|
object Info : GlobalCommand {
|
||||||
|
|
|
@ -8,7 +8,7 @@ import net.dv8tion.jda.internal.interactions.CommandDataImpl
|
||||||
import net.projecttl.p.x32.api.command.GlobalCommand
|
import net.projecttl.p.x32.api.command.GlobalCommand
|
||||||
import net.projecttl.p.x32.api.util.colour
|
import net.projecttl.p.x32.api.util.colour
|
||||||
import net.projecttl.p.x32.api.util.footer
|
import net.projecttl.p.x32.api.util.footer
|
||||||
import net.projecttl.p.x32.kernel.PluginLoader
|
import net.projecttl.p.x32.kernel.CoreKernel.PluginLoader
|
||||||
|
|
||||||
object PluginCommand : GlobalCommand {
|
object PluginCommand : GlobalCommand {
|
||||||
override val data = CommandData.fromData(CommandDataImpl("plugin", "봇에 불러온 플러그인을 확인 합니다").toData())
|
override val data = CommandData.fromData(CommandDataImpl("plugin", "봇에 불러온 플러그인을 확인 합니다").toData())
|
||||||
|
|
|
@ -1,14 +1,22 @@
|
||||||
package net.projecttl.p.x32.kernel
|
package net.projecttl.p.x32.kernel
|
||||||
|
|
||||||
import kotlinx.coroutines.sync.Mutex
|
import kotlinx.coroutines.sync.Mutex
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import net.dv8tion.jda.api.JDA
|
import net.dv8tion.jda.api.JDA
|
||||||
import net.dv8tion.jda.api.JDABuilder
|
import net.dv8tion.jda.api.JDABuilder
|
||||||
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
import net.dv8tion.jda.api.hooks.ListenerAdapter
|
||||||
import net.dv8tion.jda.api.requests.GatewayIntent
|
import net.dv8tion.jda.api.requests.GatewayIntent
|
||||||
|
import net.projecttl.p.x32.api.Plugin
|
||||||
import net.projecttl.p.x32.api.command.CommandHandler
|
import net.projecttl.p.x32.api.command.CommandHandler
|
||||||
|
import net.projecttl.p.x32.api.model.PluginConfig
|
||||||
|
import net.projecttl.p.x32.api.util.AsyncTaskContainer
|
||||||
import net.projecttl.p.x32.config.Config
|
import net.projecttl.p.x32.config.Config
|
||||||
import net.projecttl.p.x32.func.BundleModule
|
import net.projecttl.p.x32.func.BundleModule
|
||||||
import net.projecttl.p.x32.logger
|
import net.projecttl.p.x32.logger
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.util.jar.JarFile
|
||||||
|
|
||||||
class CoreKernel(token: String) {
|
class CoreKernel(token: String) {
|
||||||
private val builder = JDABuilder.createDefault(token, listOf(
|
private val builder = JDABuilder.createDefault(token, listOf(
|
||||||
|
@ -116,4 +124,88 @@ class CoreKernel(token: String) {
|
||||||
|
|
||||||
memLock.unlock()
|
memLock.unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object PluginLoader {
|
||||||
|
private val plugins = mutableMapOf<PluginConfig, Plugin>()
|
||||||
|
private val parentDir = File("./plugins").apply {
|
||||||
|
if (!exists()) {
|
||||||
|
mkdirs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPlugins(): Map<PluginConfig, Plugin> {
|
||||||
|
return plugins.toMap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun putModule(config: PluginConfig, plugin: Plugin) {
|
||||||
|
try {
|
||||||
|
logger.info("Load module ${config.name} v${config.version}")
|
||||||
|
plugin.onLoad()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
plugin.destroy()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins[config] = plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
fun load() {
|
||||||
|
parentDir.listFiles()?.forEach { file ->
|
||||||
|
loadPlugin(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info("Loaded ${plugins.size} plugins")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun destroy() {
|
||||||
|
plugins.forEach { (config, plugin) ->
|
||||||
|
logger.info("disable ${config.name} plugin...")
|
||||||
|
|
||||||
|
try {
|
||||||
|
plugin.destroy()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
logger.error("failed to destroy ${config.name} plugin")
|
||||||
|
ex.printStackTrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun loadPlugin(file: File) {
|
||||||
|
if (file.name == "px32-bot-module") {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file.name.endsWith(".jar")) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val jar = JarFile(file)
|
||||||
|
val cnf = jar.entries().toList().singleOrNull { jarEntry -> jarEntry.name == "plugin.json" }
|
||||||
|
if (cnf == null)
|
||||||
|
return logger.error("${file.name} is not a plugin. aborted")
|
||||||
|
|
||||||
|
val stream = jar.getInputStream(cnf)
|
||||||
|
val raw = stream.use {
|
||||||
|
return@use it.readBytes().toString(Charset.forName("UTF-8"))
|
||||||
|
}
|
||||||
|
|
||||||
|
val config = Json.decodeFromString<PluginConfig>(raw)
|
||||||
|
val cl = URLClassLoader(arrayOf(file.toPath().toUri().toURL()))
|
||||||
|
val obj = cl.loadClass(config.main).getDeclaredConstructor().newInstance()
|
||||||
|
|
||||||
|
if (obj !is Plugin)
|
||||||
|
return logger.error("${config.name} is not valid main class. aborted")
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.info("Load plugin ${config.name} v${config.version}")
|
||||||
|
obj.onLoad()
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
ex.printStackTrace()
|
||||||
|
return logger.error("Failed to load plugin ${config.name}")
|
||||||
|
}
|
||||||
|
|
||||||
|
plugins[config] = obj
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
package net.projecttl.p.x32.kernel
|
|
||||||
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
import net.projecttl.p.x32.api.Plugin
|
|
||||||
import net.projecttl.p.x32.api.model.PluginConfig
|
|
||||||
import net.projecttl.p.x32.logger
|
|
||||||
import java.io.File
|
|
||||||
import java.net.URLClassLoader
|
|
||||||
import java.nio.charset.Charset
|
|
||||||
import java.util.jar.JarFile
|
|
||||||
|
|
||||||
object PluginLoader {
|
|
||||||
private val plugins = mutableMapOf<PluginConfig, Plugin>()
|
|
||||||
private val parentDir = File("./plugins").apply {
|
|
||||||
if (!exists()) {
|
|
||||||
mkdirs()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getPlugins(): Map<PluginConfig, Plugin> {
|
|
||||||
return plugins.toMap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun putModule(config: PluginConfig, plugin: Plugin) {
|
|
||||||
try {
|
|
||||||
logger.info("Load module ${config.name} v${config.version}")
|
|
||||||
plugin.onLoad()
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
ex.printStackTrace()
|
|
||||||
plugin.destroy()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins[config] = plugin
|
|
||||||
}
|
|
||||||
|
|
||||||
fun load() {
|
|
||||||
parentDir.listFiles()?.forEach { file ->
|
|
||||||
loadPlugin(file)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.info("Loaded ${plugins.size} plugins")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun destroy() {
|
|
||||||
plugins.forEach { (config, plugin) ->
|
|
||||||
logger.info("disable ${config.name} plugin...")
|
|
||||||
|
|
||||||
try {
|
|
||||||
plugin.destroy()
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
logger.error("failed to destroy ${config.name} plugin")
|
|
||||||
ex.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadPlugin(file: File) {
|
|
||||||
if (file.name == "px32-bot-module") {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!file.name.endsWith(".jar")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val jar = JarFile(file)
|
|
||||||
val cnf = jar.entries().toList().singleOrNull { jarEntry -> jarEntry.name == "plugin.json" }
|
|
||||||
if (cnf == null)
|
|
||||||
return logger.error("${file.name} is not a plugin. aborted")
|
|
||||||
|
|
||||||
val stream = jar.getInputStream(cnf)
|
|
||||||
val raw = stream.use {
|
|
||||||
return@use it.readBytes().toString(Charset.forName("UTF-8"))
|
|
||||||
}
|
|
||||||
|
|
||||||
val config = Json.decodeFromString<PluginConfig>(raw)
|
|
||||||
val cl = URLClassLoader(arrayOf(file.toPath().toUri().toURL()))
|
|
||||||
val obj = cl.loadClass(config.main).getDeclaredConstructor().newInstance()
|
|
||||||
|
|
||||||
if (obj !is Plugin)
|
|
||||||
return logger.error("${config.name} is not valid main class. aborted")
|
|
||||||
|
|
||||||
try {
|
|
||||||
logger.info("Load plugin ${config.name} v${config.version}")
|
|
||||||
obj.onLoad()
|
|
||||||
} catch (ex: Exception) {
|
|
||||||
ex.printStackTrace()
|
|
||||||
return logger.error("Failed to load plugin ${config.name}")
|
|
||||||
}
|
|
||||||
|
|
||||||
plugins[config] = obj
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +0,0 @@
|
||||||
package net.projecttl.p.x32.kernel
|
|
||||||
|
|
||||||
object TaskManager {
|
|
||||||
}
|
|
|
@ -1,8 +1,11 @@
|
||||||
token=<discord_bot_token>
|
token=<discord_bot_token>
|
||||||
owner=
|
owner=
|
||||||
|
|
||||||
|
# Px32's Default module activation
|
||||||
|
# setting value is 1 or 0
|
||||||
bundle_func=1
|
bundle_func=1
|
||||||
|
|
||||||
|
# Database connection settings
|
||||||
db_driver=org.sqlite.JDBC
|
db_driver=org.sqlite.JDBC
|
||||||
db_url=jdbc:sqlite:data.db
|
db_url=jdbc:sqlite:data.db
|
||||||
db_username=
|
db_username=
|
||||||
|
|
|
@ -17,6 +17,8 @@ class BundleModule : Plugin() {
|
||||||
addHandler(Ready)
|
addHandler(Ready)
|
||||||
addHandler(commandHandler { handler ->
|
addHandler(commandHandler { handler ->
|
||||||
handler.addCommand(Avatar)
|
handler.addCommand(Avatar)
|
||||||
|
handler.addCommand(Bmi)
|
||||||
|
handler.addCommand(Dice)
|
||||||
handler.addCommand(MsgLength)
|
handler.addCommand(MsgLength)
|
||||||
handler.addCommand(MsgPurge)
|
handler.addCommand(MsgPurge)
|
||||||
handler.addCommand(Ping)
|
handler.addCommand(Ping)
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
package net.projecttl.p.x32.func.command
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.EmbedBuilder
|
||||||
|
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent
|
||||||
|
import net.dv8tion.jda.api.interactions.commands.OptionType
|
||||||
|
import net.dv8tion.jda.api.interactions.commands.build.CommandData
|
||||||
|
import net.dv8tion.jda.internal.interactions.CommandDataImpl
|
||||||
|
import net.projecttl.p.x32.api.command.GlobalCommand
|
||||||
|
import net.projecttl.p.x32.api.util.colour
|
||||||
|
import net.projecttl.p.x32.api.util.footer
|
||||||
|
import java.math.RoundingMode
|
||||||
|
import java.text.DecimalFormat
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
object Bmi : GlobalCommand {
|
||||||
|
override val data = CommandData.fromData(CommandDataImpl("bmi", "키와 몸무게 기반으로 bmi지수를 계산할 수 있어요").apply {
|
||||||
|
addOption(OptionType.NUMBER, "height", "신장 길이를 적어 주세요 (cm)", true)
|
||||||
|
addOption(OptionType.NUMBER, "weight", "몸무게를 적어 주세요 (kg)", true)
|
||||||
|
}.toData())
|
||||||
|
|
||||||
|
override suspend fun execute(ev: SlashCommandInteractionEvent) {
|
||||||
|
val height = ev.getOption("height")!!.asDouble
|
||||||
|
val weight = ev.getOption("weight")!!.asDouble
|
||||||
|
|
||||||
|
if (height <= 0.0 || weight <= 0.0) {
|
||||||
|
ev.reply(":warning: 키 또는 몸무게가 0 또는 음수일 수 없어요").setEphemeral(true).queue()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val bmi = weight / (height / 100).pow(2)
|
||||||
|
fun result(bmi: Double): String {
|
||||||
|
return when {
|
||||||
|
bmi < 18.5 -> "**저체중**"
|
||||||
|
bmi in 18.5..24.9 -> "**정상 체중**"
|
||||||
|
bmi in 25.0.. 29.9 -> "**과체중**"
|
||||||
|
else -> "**비만**"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val df = DecimalFormat("#.##")
|
||||||
|
df.roundingMode = RoundingMode.HALF_UP
|
||||||
|
|
||||||
|
ev.replyEmbeds(EmbedBuilder().apply {
|
||||||
|
setTitle(":pencil: BMI 지수가 나왔어요")
|
||||||
|
setDescription("${result(bmi)} 이에요")
|
||||||
|
addField(":straight_ruler: **신장 길이**", "`${height}cm`", true)
|
||||||
|
addField(":scales: **몸무게**", "`${weight}kg`", true)
|
||||||
|
addField(":chart_with_downwards_trend: **BMI 지수**", "`${df.format(bmi)}` ", true)
|
||||||
|
|
||||||
|
colour()
|
||||||
|
footer(ev.user)
|
||||||
|
}.build()).queue()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package net.projecttl.p.x32.func.command
|
||||||
|
|
||||||
|
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent
|
||||||
|
import net.dv8tion.jda.api.interactions.commands.build.CommandData
|
||||||
|
import net.dv8tion.jda.internal.interactions.CommandDataImpl
|
||||||
|
import net.projecttl.p.x32.api.command.GlobalCommand
|
||||||
|
import kotlin.random.Random
|
||||||
|
import kotlin.random.nextInt
|
||||||
|
|
||||||
|
object Dice : GlobalCommand {
|
||||||
|
override val data = CommandData.fromData(CommandDataImpl("dice", "랜덤으로 주사위를 굴립니다").toData())
|
||||||
|
|
||||||
|
override suspend fun execute(ev: SlashCommandInteractionEvent) {
|
||||||
|
val rand = Random.nextInt(1..6)
|
||||||
|
ev.reply(":game_die: **${rand}**").queue()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
package net.projecttl.p.x32.func.command
|
package net.projecttl.p.x32.func.command
|
||||||
|
|
||||||
import net.projecttl.p.x32.func.Conf
|
|
||||||
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent
|
import net.dv8tion.jda.api.events.interaction.command.SlashCommandInteractionEvent
|
||||||
import net.dv8tion.jda.api.interactions.commands.OptionType
|
import net.dv8tion.jda.api.interactions.commands.OptionType
|
||||||
import net.dv8tion.jda.api.interactions.commands.build.CommandData
|
import net.dv8tion.jda.api.interactions.commands.build.CommandData
|
||||||
import net.dv8tion.jda.internal.interactions.CommandDataImpl
|
import net.dv8tion.jda.internal.interactions.CommandDataImpl
|
||||||
import net.projecttl.p.x32.api.command.GlobalCommand
|
import net.projecttl.p.x32.api.command.GlobalCommand
|
||||||
|
import net.projecttl.p.x32.func.Conf
|
||||||
|
|
||||||
object MsgPurge : GlobalCommand {
|
object MsgPurge : GlobalCommand {
|
||||||
override val data = CommandData.fromData(
|
override val data = CommandData.fromData(
|
||||||
|
|
Loading…
Reference in a new issue