diff --git a/.dockerfile b/.dockerfile deleted file mode 100644 index a0edd36..0000000 --- a/.dockerfile +++ /dev/null @@ -1,45 +0,0 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -.fleet/ -.kotlin/ - -.env -!.env.example - -### IntelliJ IDEA ### -.idea/ -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Mac OS ### -.DS_Store diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 3afbdd6..0000000 --- a/Dockerfile +++ /dev/null @@ -1,17 +0,0 @@ -FROM amazoncorretto:21-alpine3.20 - -ARG BOT_TOKEN -ENV BOT_TOKEN=${BOT_TOKEN} - -WORKDIR /opt/bot/build - -COPY . . -RUN chmod a+x ./gradlew -RUN ./gradlew shadowJar -RUN cp ./build/libs/px32-bot.jar ../ - -WORKDIR /opt/bot -RUN rm -rf ./build -RUN export BOT_TOKEN=${BOT_TOKEN} - -ENTRYPOINT ["java", "-Xmx4096M", "-jar", "/opt/bot/px32-bot.jar"] diff --git a/build.gradle.kts b/build.gradle.kts index fa28a2f..3b861ba 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,6 +1,7 @@ plugins { id("java") kotlin("jvm") version "2.0.20" + id("com.gradleup.shadow") version "8.3.0" } group = property("group")!! @@ -10,42 +11,37 @@ val ktor_version: String by project val log4j_version: String by project val exposed_version: String by project -allprojects { - apply(plugin = "java") - apply(plugin = "org.jetbrains.kotlin.jvm") - - java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) - } - - sourceCompatibility = JavaVersion.VERSION_21 - targetCompatibility = JavaVersion.VERSION_21 +java { + toolchain { + languageVersion.set(JavaLanguageVersion.of(21)) } - repositories { - mavenCentral() - } + sourceCompatibility = JavaVersion.VERSION_21 + targetCompatibility = JavaVersion.VERSION_21 } -subprojects { - dependencies { - implementation(kotlin("stdlib")) - implementation(kotlin("reflect")) - implementation("net.dv8tion:JDA:5.1.0") - implementation("io.ktor:ktor-client-cio:$ktor_version") - implementation("io.ktor:ktor-client-core:$ktor_version") - implementation("org.apache.logging.log4j:log4j-api:$log4j_version") - implementation("org.apache.logging.log4j:log4j-core:$log4j_version") - implementation("org.jetbrains.exposed:exposed-core:$exposed_version") - implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version") - implementation("org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version") - implementation("io.ktor:ktor-client-okhttp-jvm:2.3.12") - testImplementation(platform("org.junit:junit-bom:5.10.0")) - testImplementation("org.junit.jupiter:junit-jupiter") - } +repositories { + mavenCentral() } -tasks.test { - useJUnitPlatform() +dependencies { + implementation(kotlin("stdlib")) + implementation(kotlin("reflect")) + implementation("net.dv8tion:JDA:5.1.0") + implementation("io.ktor:ktor-client-cio:$ktor_version") + implementation("io.ktor:ktor-client-core:$ktor_version") + implementation("org.apache.logging.log4j:log4j-api:$log4j_version") + implementation("org.apache.logging.log4j:log4j-core:$log4j_version") + implementation("org.jetbrains.exposed:exposed-core:$exposed_version") + implementation("org.jetbrains.exposed:exposed-jdbc:$exposed_version") + implementation("org.apache.logging.log4j:log4j-slf4j2-impl:$log4j_version") + implementation("io.ktor:ktor-client-okhttp-jvm:2.3.12") + testImplementation(platform("org.junit:junit-bom:5.10.0")) + testImplementation("org.junit.jupiter:junit-jupiter") +} + +tasks { + test { + useJUnitPlatform() + } } diff --git a/compose.yml b/compose.yml deleted file mode 100644 index 1a035ff..0000000 --- a/compose.yml +++ /dev/null @@ -1,17 +0,0 @@ -services: - bot: - container_name: "P_x32-bot" - build: - context: . - dockerfile: "./Dockerfile" - env_file: - - ".env" - environment: - - BOT_TOKEN=${BOT_TOKEN} - networks: - - "bot" - volumes: - - "/etc/localtime:/etc/localtime:ro" - -networks: - bot: {} diff --git a/px32-bot-api/build.gradle.kts b/px32-bot-api/build.gradle.kts deleted file mode 100644 index 2da79c1..0000000 --- a/px32-bot-api/build.gradle.kts +++ /dev/null @@ -1,15 +0,0 @@ -plugins { - id("java") -} - -group = rootProject.group -version = rootProject.version - -dependencies { - testImplementation(platform("org.junit:junit-bom:5.10.0")) - testImplementation("org.junit.jupiter:junit-jupiter") -} - -tasks.test { - useJUnitPlatform() -} \ No newline at end of file diff --git a/px32-bot-core/build.gradle.kts b/px32-bot-core/build.gradle.kts deleted file mode 100644 index 8f676dd..0000000 --- a/px32-bot-core/build.gradle.kts +++ /dev/null @@ -1,14 +0,0 @@ -plugins { - id("java") -} - -group = rootProject.group -version = rootProject.version - -repositories { - mavenCentral() -} - -tasks.test { - useJUnitPlatform() -} \ No newline at end of file diff --git a/px32-bot-core/src/main/java/net/wh64/p/x32/KernelCore.java b/px32-bot-core/src/main/java/net/wh64/p/x32/KernelCore.java deleted file mode 100644 index 884cc76..0000000 --- a/px32-bot-core/src/main/java/net/wh64/p/x32/KernelCore.java +++ /dev/null @@ -1,18 +0,0 @@ -package net.wh64.p.x32; - -import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.JDABuilder; - -public class KernelCore { - private final JDABuilder builder; - - public KernelCore(String token) { - this.builder = JDABuilder.createDefault(token); - } - - public JDA build() { - JDA jda = builder.build(); - - return jda; - } -} diff --git a/px32-bot-core/src/main/kotlin/net/wh64/p/x32/GlobalCommandHandler.kt b/px32-bot-core/src/main/kotlin/net/wh64/p/x32/GlobalCommandHandler.kt deleted file mode 100644 index 4f11585..0000000 --- a/px32-bot-core/src/main/kotlin/net/wh64/p/x32/GlobalCommandHandler.kt +++ /dev/null @@ -1,17 +0,0 @@ -package net.wh64.p.x32 - -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.UserContextInteractionEvent -import net.dv8tion.jda.api.hooks.ListenerAdapter - -class GlobalCommandHandler : ListenerAdapter() { - override fun onSlashCommandInteraction(event: SlashCommandInteractionEvent) { - } - - override fun onUserContextInteraction(event: UserContextInteractionEvent) { - } - - override fun onMessageContextInteraction(event: MessageContextInteractionEvent) { - } -} \ No newline at end of file diff --git a/px32-bot-core/src/main/kotlin/net/wh64/p/x32/SlashCommandExecutor.kt b/px32-bot-core/src/main/kotlin/net/wh64/p/x32/SlashCommandExecutor.kt deleted file mode 100644 index 8139280..0000000 --- a/px32-bot-core/src/main/kotlin/net/wh64/p/x32/SlashCommandExecutor.kt +++ /dev/null @@ -1,39 +0,0 @@ -package net.wh64.p.x32 - -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.UserContextInteractionEvent -import net.dv8tion.jda.api.interactions.commands.build.CommandData - -interface SlashCommandExecutor { - val data: CommandData - fun execute(ev: SlashCommandInteractionEvent) -} - -interface UserContextExecutor { - val data: CommandData - fun execute(ev: UserContextInteractionEvent) -} - -interface MessageContextExecutor { - val data: CommandData - fun execute(ev: MessageContextInteractionEvent) -} - -abstract class CommandAdapter : SlashCommandExecutor, UserContextExecutor, MessageContextExecutor { - abstract override val data: CommandData - - override fun execute(ev: SlashCommandInteractionEvent) { - executor(ev) - } - - override fun execute(ev: UserContextInteractionEvent) { - executor(ev) - } - - override fun execute(ev: MessageContextInteractionEvent) { - executor(ev) - } - - abstract fun executor(ev: Any) -} diff --git a/px32-bot-runner/build.gradle.kts b/px32-bot-runner/build.gradle.kts deleted file mode 100644 index e162800..0000000 --- a/px32-bot-runner/build.gradle.kts +++ /dev/null @@ -1,31 +0,0 @@ -import org.jetbrains.kotlin.gradle.dsl.JvmTarget -import org.jetbrains.kotlin.gradle.tasks.KotlinCompile - -plugins { - id("com.gradleup.shadow") version "8.3.0" -} - -group = rootProject.group -version = rootProject.version - -tasks { - test { - useJUnitPlatform() - } - - processResources { - filesMatching("default.properties") { - expand(project.properties) - } - } - - withType { - options.encoding = "UTF-8" - } - - withType { - compilerOptions { - jvmTarget.set(JvmTarget.JVM_21) - } - } -} \ No newline at end of file diff --git a/px32-bot-runner/src/main/java/net/projecttl/p/x32/exec/Px32.java b/px32-bot-runner/src/main/java/net/projecttl/p/x32/exec/Px32.java deleted file mode 100644 index f00177c..0000000 --- a/px32-bot-runner/src/main/java/net/projecttl/p/x32/exec/Px32.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.projecttl.p.x32.exec; - -import net.dv8tion.jda.api.JDA; -import net.dv8tion.jda.api.JDABuilder; -import net.projecttl.p.x32.exec.config.DefaultConfig; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class Px32 { - public static final Logger log = LoggerFactory.getLogger(Px32.class); - private static JDA jda; - - public static void main(String[] args) { - JDABuilder builder = JDABuilder.createDefault(System.getenv("BOT_TOKEN")); - log.info("Px32 {}", DefaultConfig.INSTANCE.getVersion()); - - builder.setAutoReconnect(true); - jda = builder.build(); - } -} diff --git a/settings.gradle.kts b/settings.gradle.kts index e1bdce5..7d276bd 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,4 +1 @@ rootProject.name = "px32-bot" -include("px32-bot-runner") -include("px32-bot-core") -include("px32-bot-api") diff --git a/src/main/kotlin/net/projecttl/p/x32/DefaultConfig.kt b/src/main/kotlin/net/projecttl/p/x32/DefaultConfig.kt new file mode 100644 index 0000000..99ec715 --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/DefaultConfig.kt @@ -0,0 +1,16 @@ +package net.projecttl.p.x32 + +import java.util.* +import kotlin.reflect.KProperty + +private class DefaultConfigDelegate { + private val props = Properties() + + init { + props.load(this.javaClass.getResourceAsStream("/default.properties")) + } + + operator fun getValue(thisRef: Any?, property: KProperty<*>): String { + return props.getProperty(property.name).toString() + } +} diff --git a/src/main/kotlin/net/projecttl/p/x32/Px32.kt b/src/main/kotlin/net/projecttl/p/x32/Px32.kt new file mode 100644 index 0000000..0316b9d --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/Px32.kt @@ -0,0 +1,23 @@ +package net.projecttl.p.x32 + +import net.projecttl.p.x32.command.Avatar +import net.projecttl.p.x32.command.Ping +import net.projecttl.p.x32.handler.Ready +import net.projecttl.p.x32.kernel.CoreKernel +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +val logger: Logger = LoggerFactory.getLogger(Px32::class.java) + +fun main() { + val kernel = CoreKernel(System.getenv("TOKEN")) + kernel.addHandler(Ready) + + val handler = kernel.getGlobalCommandHandler() + handler.addCommand(Avatar) + handler.addCommand(Ping) + + kernel.build() +} + +class Px32 diff --git a/src/main/kotlin/net/projecttl/p/x32/command/Avatar.kt b/src/main/kotlin/net/projecttl/p/x32/command/Avatar.kt new file mode 100644 index 0000000..621438a --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/command/Avatar.kt @@ -0,0 +1,21 @@ +package net.projecttl.p.x32.command + +import net.dv8tion.jda.api.EmbedBuilder +import net.dv8tion.jda.api.events.interaction.command.UserContextInteractionEvent +import net.dv8tion.jda.api.interactions.commands.build.CommandData +import net.dv8tion.jda.internal.interactions.CommandDataImpl +import net.projecttl.p.x32.handler.UserContext +import net.projecttl.p.x32.util.colour + +object Avatar : UserContext { + override val data = CommandData.fromData(CommandDataImpl("avatar", "유저의 프로필 이미지를 가져 옵니다").toData()) + + override suspend fun execute(ev: UserContextInteractionEvent) { + val embed = EmbedBuilder() + embed.setTitle(":frame_photo: ${ev.name} Avatar") + embed.setImage(ev.target.effectiveAvatarUrl) + embed.colour() + + ev.replyEmbeds(embed.build()).queue() + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/projecttl/p/x32/command/Ping.kt b/src/main/kotlin/net/projecttl/p/x32/command/Ping.kt new file mode 100644 index 0000000..cdd75e2 --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/command/Ping.kt @@ -0,0 +1,32 @@ +package net.projecttl.p.x32.command + +import net.dv8tion.jda.api.EmbedBuilder +import net.dv8tion.jda.api.JDA +import net.dv8tion.jda.api.entities.MessageEmbed +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.handler.GlobalCommand +import net.projecttl.p.x32.util.colour +import kotlin.random.Random + +object Ping : GlobalCommand { + override val data: CommandData = CommandData.fromData(CommandDataImpl( + "ping", + "Discord API 레이턴시 확인 합니다" + ).toData()) + + override suspend fun execute(ev: SlashCommandInteractionEvent) { + val embed = measure(ev.jda) + ev.replyEmbeds(embed).queue() + } + + private fun measure(jda: JDA): MessageEmbed { + val embed = EmbedBuilder() + embed.setTitle(":ping_pong: **Pong!**") + embed.addField(":electric_plug: **API**", "`${jda.gatewayPing}ms`", true) + embed.colour() + + return embed.build() + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/projecttl/p/x32/config/Config.kt b/src/main/kotlin/net/projecttl/p/x32/config/Config.kt new file mode 100644 index 0000000..6565d54 --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/config/Config.kt @@ -0,0 +1,7 @@ +package net.projecttl.p.x32.config + +object Config { +} + +class ConfigDelegate { +} \ No newline at end of file diff --git a/px32-bot-runner/src/main/kotlin/net/projecttl/p/x32/exec/config/DefaultConfig.kt b/src/main/kotlin/net/projecttl/p/x32/config/DefaultConfig.kt similarity index 92% rename from px32-bot-runner/src/main/kotlin/net/projecttl/p/x32/exec/config/DefaultConfig.kt rename to src/main/kotlin/net/projecttl/p/x32/config/DefaultConfig.kt index b4c0d58..3b19c27 100644 --- a/px32-bot-runner/src/main/kotlin/net/projecttl/p/x32/exec/config/DefaultConfig.kt +++ b/src/main/kotlin/net/projecttl/p/x32/config/DefaultConfig.kt @@ -1,4 +1,4 @@ -package net.projecttl.p.x32.exec.config +package net.projecttl.p.x32.config import java.util.* import kotlin.reflect.KProperty diff --git a/src/main/kotlin/net/projecttl/p/x32/handler/CommandExecutor.kt b/src/main/kotlin/net/projecttl/p/x32/handler/CommandExecutor.kt new file mode 100644 index 0000000..b9de5e8 --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/handler/CommandExecutor.kt @@ -0,0 +1,25 @@ +package net.projecttl.p.x32.handler + +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.UserContextInteractionEvent +import net.dv8tion.jda.api.interactions.commands.build.CommandData + +interface CommandExecutor { + val data: CommandData +} + +interface GlobalCommand : CommandExecutor { + override val data: CommandData + suspend fun execute(ev: SlashCommandInteractionEvent) +} + +interface UserContext : CommandExecutor { + override val data: CommandData + suspend fun execute(ev: UserContextInteractionEvent) +} + +interface MessageContext : CommandExecutor { + override val data: CommandData + suspend fun execute(ev: MessageContextInteractionEvent) +} diff --git a/src/main/kotlin/net/projecttl/p/x32/handler/CommandHandler.kt b/src/main/kotlin/net/projecttl/p/x32/handler/CommandHandler.kt new file mode 100644 index 0000000..51dd23d --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/handler/CommandHandler.kt @@ -0,0 +1,130 @@ +package net.projecttl.p.x32.handler + +import kotlinx.coroutines.runBlocking +import net.dv8tion.jda.api.JDA +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.UserContextInteractionEvent +import net.dv8tion.jda.api.hooks.ListenerAdapter +import net.dv8tion.jda.api.interactions.commands.Command +import net.dv8tion.jda.api.interactions.commands.build.Commands +import net.projecttl.p.x32.logger + +class CommandHandler(val guildId: Long = 0L) : ListenerAdapter() { + private val commands = mutableListOf() + + override fun onSlashCommandInteraction(ev: SlashCommandInteractionEvent) { + val name = ev.interaction.name + + commands.forEach { command -> + if (command.data.name == name) { + if (command is GlobalCommand) { + runBlocking { + command.execute(ev) + } + + return@forEach + } + } + } + } + + override fun onUserContextInteraction(ev: UserContextInteractionEvent) { + val name = ev.interaction.name + + commands.forEach { command -> + if (command.data.name == name) { + if (command is UserContext) { + runBlocking { + command.execute(ev) + } + + return@forEach + } + } + } + } + + override fun onMessageContextInteraction(ev: MessageContextInteractionEvent) { + val name = ev.interaction.name + + commands.forEach { command -> + if (command.data.name == name) { + if (command is MessageContext) { + runBlocking { + command.execute(ev) + } + + return@forEach + } + } + } + } + + fun addCommand(command: CommandExecutor) { + commands.add(command) + } + + fun delCommand(command: CommandExecutor) { + commands.remove(command) + } + + fun register(jda: JDA) { + val guild = jda.getGuildById(guildId) + if (guildId != 0L) { + if (guild == null) { + logger.info("'${guildId}' guild is not exists!") + return + } + } + + commands.forEach { command -> + val data = command.data + + if (command is GlobalCommand) { + if (guild == null) { + jda.upsertCommand(data).queue() + logger.info("Register Global Command: /${data.name}") + } else { + guild.upsertCommand(data).queue() + logger.info("Register '${guild.id}' Guild's Command: /${data.name}") + } + } + + if (command is UserContext) { + if (guild == null) { + jda.updateCommands().addCommands( + Commands.context(Command.Type.USER, data.name), + Commands.message(data.name) + ).queue() + + logger.info("Register User Context Command: /${data.name}") + } else { + guild.updateCommands().addCommands( + Commands.context(Command.Type.USER, data.name), + Commands.message(data.name) + ).queue() + logger.info("Register '${guild.id}' Guild's User Context Command: /${data.name}") + } + } + + if (command is MessageContext) { + if (guild == null) { + jda.updateCommands().addCommands( + Commands.context(Command.Type.MESSAGE, data.name), + Commands.message(data.name) + ) + + logger.info("Register Message Context Command: /${data.name}") + } else { + guild.updateCommands().addCommands( + Commands.context(Command.Type.MESSAGE, data.name), + Commands.message(data.name) + ) + + logger.info("Register '${guild.id}' Guild's Message Context Command: /${data.name}") + } + } + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/projecttl/p/x32/handler/Ready.kt b/src/main/kotlin/net/projecttl/p/x32/handler/Ready.kt new file mode 100644 index 0000000..33d7699 --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/handler/Ready.kt @@ -0,0 +1,11 @@ +package net.projecttl.p.x32.handler + +import net.dv8tion.jda.api.events.session.ReadyEvent +import net.dv8tion.jda.api.hooks.ListenerAdapter +import net.projecttl.p.x32.logger + +object Ready : ListenerAdapter() { + override fun onReady(ev: ReadyEvent) { + logger.info("Logged in as ${ev.jda.selfUser.asTag}") + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/projecttl/p/x32/kernel/CoreKernel.kt b/src/main/kotlin/net/projecttl/p/x32/kernel/CoreKernel.kt new file mode 100644 index 0000000..8e4a18d --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/kernel/CoreKernel.kt @@ -0,0 +1,42 @@ +package net.projecttl.p.x32.kernel + +import net.dv8tion.jda.api.JDA +import net.dv8tion.jda.api.JDABuilder +import net.dv8tion.jda.api.hooks.ListenerAdapter +import net.projecttl.p.x32.handler.CommandHandler + +class CoreKernel(token: String) { + private val builder = JDABuilder.createDefault(token) + private val handlers = mutableListOf() + + private val handler = CommandHandler() + + fun getGlobalCommandHandler(): CommandHandler { + return handler + } + + fun addHandler(handler: ListenerAdapter) { + handlers.add(handler) + } + + fun delHandler(handler: ListenerAdapter) { + handlers.remove(handler) + } + + fun build(): JDA { + handlers.map { + builder.addEventListeners(it) + } + builder.addEventListeners(handler) + + val jda = builder.build() + handler.register(jda) + handlers.forEach { h -> + if (h is CommandHandler) { + h.register(jda) + } + } + + return jda + } +} \ No newline at end of file diff --git a/src/main/kotlin/net/projecttl/p/x32/util/Color.kt b/src/main/kotlin/net/projecttl/p/x32/util/Color.kt new file mode 100644 index 0000000..537821a --- /dev/null +++ b/src/main/kotlin/net/projecttl/p/x32/util/Color.kt @@ -0,0 +1,9 @@ +package net.projecttl.p.x32.util + +import net.dv8tion.jda.api.EmbedBuilder +import kotlin.random.Random + +fun EmbedBuilder.colour(): EmbedBuilder { + val rand = Random.nextInt(0x000001, 0xffffff) + return this.setColor(rand) +} diff --git a/px32-bot-runner/src/main/resources/default.properties b/src/main/resources/default.properties similarity index 100% rename from px32-bot-runner/src/main/resources/default.properties rename to src/main/resources/default.properties diff --git a/px32-bot-runner/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml similarity index 100% rename from px32-bot-runner/src/main/resources/log4j2.xml rename to src/main/resources/log4j2.xml