diff --git a/.idea/HytaleUpdateBot.iml b/.idea/HytaleUpdateBot.iml
new file mode 100644
index 0000000..b7756dd
--- /dev/null
+++ b/.idea/HytaleUpdateBot.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..2ce531d
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 65650db..f5619da 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,11 +4,9 @@
-
-
+
-
-
+
@@ -33,6 +31,11 @@
+
+
+
+
+
@@ -61,6 +64,9 @@
+
+
+
@@ -70,24 +76,25 @@
-
+
+
+
+
+
+
-
-
-
-
@@ -106,7 +113,9 @@
- true
+ true
+ true
+ false
@@ -125,7 +134,9 @@
- true
+ true
+ true
+ false
@@ -144,7 +155,9 @@
- true
+ true
+ true
+ false
@@ -166,14 +179,15 @@
-
-
-
-
+
+
+
+
+
@@ -220,7 +234,14 @@
1601042375685
-
+
+ 1601042672099
+
+
+
+ 1601042672099
+
+
@@ -229,13 +250,14 @@
-
+
+
-
+
-
+
@@ -260,34 +282,34 @@
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
@@ -308,6 +330,10 @@
+
+
+
+
@@ -317,10 +343,10 @@
-
+
-
+
diff --git a/src/main/kotlin/de/wulkanat/OwnerCli.kt b/src/main/kotlin/de/wulkanat/OwnerCli.kt
index 3c7cfec..01b042a 100644
--- a/src/main/kotlin/de/wulkanat/OwnerCli.kt
+++ b/src/main/kotlin/de/wulkanat/OwnerCli.kt
@@ -1,12 +1,103 @@
package de.wulkanat
-import net.dv8tion.jda.api.EmbedBuilder
-import net.dv8tion.jda.api.Permission
-import net.dv8tion.jda.api.events.message.MessageReceivedEvent
+import de.wulkanat.cli.Cli
+import de.wulkanat.cli.makeCli
+import net.dv8tion.jda.api.events.message.priv.PrivateMessageReceivedEvent
import net.dv8tion.jda.api.hooks.ListenerAdapter
-import java.awt.Color
class OwnerCli : ListenerAdapter() {
+ private val cli: Cli = makeCli(prefix = "!") {
+ command name "add" does "Add this channel to the notified list" through ::OwnerCliStuff.addChannel
+ command name "remove" does "Remove this channel to the notified list" through removeChannel
+ command name "publish" with { required literal argument with "on" or "off" } does
+ "[Community|Partner|Verified only] Auto publish the message if in an announcement channel" through publish
+ command name "ping" with { required string argument } does "What role to ping" through ping
+ command name "setMessage" with { required string argument } does "Set a custom message to show" through setMessage
+
+ }
+}
+
+object OwnerCliStuff {
+ private fun addChannel(_required: List, _optional: MutableMap, event: PrivateMessageReceivedEvent) {
+ val result = Channels.addChannel(event.channel.idLong, null)
+ if (result == null) {
+ event.message.channel.sendMessage("Already added.").queue()
+ } else {
+ event.message.channel.sendMessage("Added.").queue()
+ Admin.info()
+ }
+ }
+
+ private val removeChannel =
+ { _: List, _: MutableMap, event: PrivateMessageReceivedEvent ->
+ val result = Channels.channels.removeAll { it.id == event.channel.idLong }
+ Channels.saveChannels()
+ if (result) {
+ event.message.channel.sendMessage("Removed.").queue()
+ } else {
+ event.message.channel.sendMessage("This channel is not registered.").queue()
+ }
+ }
+
+ private val publish =
+ publish@{ required: List, _: MutableMap, event: PrivateMessageReceivedEvent ->
+ val channel = Channels.channels.find { it.id == event.channel.idLong } ?: run {
+ event.message.channel.sendMessage("Channel not registered.").queue()
+ return@publish
+ }
+
+ channel.autoPublish = required.first() == "on"
+ Channels.saveChannels()
+
+ event.message.channel.sendMessage("Auto publish is now ${required.first()}").queue()
+ }
+
+ private val ping =
+ ping@{ required: List, _: MutableMap, event: PrivateMessageReceivedEvent ->
+ val channel = Channels.channels.find { it.id == event.channel.idLong } ?: run {
+ event.message.channel.sendMessage("Channel is not registered.").queue()
+ return@ping
+ }
+
+ val roleName = required.first()
+ val role = event.message.guild.getRolesByName(required.first(), false).firstOrNull()
+
+ channel.mentionedRole = when {
+ roleName == "everyone" -> {
+ event.message.channel.sendMessage("Now pinging $roleName.").queue()
+ roleName
+ }
+ roleName == "none" -> {
+ event.message.channel.sendMessage("Now pinging $roleName.").queue()
+ null
+ }
+ role != null -> {
+ event.message.channel.sendMessage("Now pinging ${role.name}").queue()
+ role.id
+ }
+ else -> {
+ event.message.channel.sendMessage("Unknown role.").queue()
+ channel.mentionedRole
+ }
+ }
+ Channels.saveChannels()
+ }
+
+ private val setMessage =
+ setMessage@{ required: List, _: MutableMap, event: PrivateMessageReceivedEvent ->
+ val result = Channels.channels.find { it.id == event.channel.channelId } ?: run {
+ event.message.channel.sendMessage("Channel is not registered.").queue()
+ return@setMessage
+ }
+
+ val message = required.first()
+ result.message = CustomMessage(message)
+ Channels.saveChannels()
+ event.message.channel.sendMessage("Set `$message` as message.").queue()
+ }
+}
+
+/*class OwnerCli2 : ListenerAdapter() {
private val prefix = "%!"
override fun onMessageReceived(event: MessageReceivedEvent) {
@@ -211,5 +302,5 @@ class OwnerCli : ListenerAdapter() {
).queue()
}
}
- }
-}
\ No newline at end of file
+ }*
+}*/
\ No newline at end of file
diff --git a/src/main/kotlin/de/wulkanat/cli/ArgumentType.kt b/src/main/kotlin/de/wulkanat/cli/ArgumentType.kt
new file mode 100644
index 0000000..773cc51
--- /dev/null
+++ b/src/main/kotlin/de/wulkanat/cli/ArgumentType.kt
@@ -0,0 +1,18 @@
+package de.wulkanat.cli
+
+enum class ArgumentType(val match: Regex, val stringName: String) {
+ INT(Regex("\\d+"), "int"),
+ FLOAT(Regex("\\d+(?:.\\d+)?"), "float"),
+ STRING(Regex("[\\s\\S]+"), "string"),
+ BOOLEAN(Regex("true|false"), "bool"),
+ LITERAL(Regex("[\\s\\S]+"), "literal"),
+ EXISTS(Regex("[\\s\\S]+"), "existence");
+
+ fun usage(literals: Map>, name: String): String {
+ return when (this) {
+ LITERAL -> "${literals[name]?.joinToString(separator = "|")}"
+ EXISTS -> ""
+ else -> stringName
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/de/wulkanat/cli/Cli.kt b/src/main/kotlin/de/wulkanat/cli/Cli.kt
new file mode 100644
index 0000000..ee59acc
--- /dev/null
+++ b/src/main/kotlin/de/wulkanat/cli/Cli.kt
@@ -0,0 +1,216 @@
+package de.wulkanat.cli
+
+class Cli(var prefix: String = ".") {
+ val commands = mutableMapOf>()
+
+ fun parse(
+ command: String,
+ passThrough: T,
+ helpMessage: (Cli) -> Unit = {},
+ commandMisuse: (Command, String) -> Unit = { _, _ -> }
+ ): Boolean? {
+ if (!command.startsWith(prefix)) return false // not a command
+
+ val msg =
+ Regex("[^\\s`]+|`[^`]*`").findAll(command.removePrefix(prefix)).toList().map { it.value }
+
+ if (msg[0] == "help") {
+ helpMessage(this)
+ return true
+ }
+
+ val realCommand = commands[msg[0]] ?: return false // command not found
+ val (required, optional) = realCommand.arguments
+ if (msg.size < required.list.size + 1) {
+ commandMisuse(realCommand, "Too few arguments!")
+ return null
+ }
+
+ val requiredOut: MutableList = mutableListOf()
+ val optionalOut: MutableMap = mutableMapOf()
+
+ for (i in 1..required.list.size) {
+ val (name, type) = required.list[i - 1]
+
+ requiredOut.add(
+ when (type) {
+ ArgumentType.LITERAL -> required.literals[name]?.find { it == msg[i] }?.toString()
+ else -> type.match.matchEntire(msg[i])?.value
+ } ?: kotlin.run {
+ commandMisuse(realCommand, "Argument '${msg[i]}' is not of type ${type.stringName}!")
+ return@parse null
+ }
+ )
+ }
+
+ var i = required.list.size + 1
+ while (i < required.list.size + 1) {
+ val key = optional.shorts[msg[i]] ?: msg[i]
+ val value = optional.list[optional.shorts[msg[i]] ?: msg[i]] ?: kotlin.run {
+ commandMisuse(realCommand, "Unknown optional argument '$key'")
+ return@parse null
+ }
+
+ optionalOut[key] = when (value) {
+ ArgumentType.LITERAL -> optional.literals[key]?.find { it == msg[i] }?.toString()
+ else -> value.match.matchEntire(msg[i])?.value
+ } ?: kotlin.run {
+ commandMisuse(realCommand, "Argument '$key' is not of type ${value.stringName}!")
+ return@parse null
+ }
+
+ i += if (value == ArgumentType.EXISTS) 1 else 2
+ }
+
+ realCommand.action(requiredOut, optionalOut, passThrough)
+ return true // success
+ }
+
+ fun usage(): String {
+ return commands.map { "$prefix${it.value.usage()}" }.joinToString("\n")
+ }
+
+ infix fun prefix(func: Cli.() -> Unit): Cli {
+ func()
+ return this
+ }
+
+ inner class CommandBuilder {
+ infix fun name(name: String): CommandBuilder2 {
+ return CommandBuilder2(name)
+ }
+ }
+
+ inner class CommandBuilder2(val name: String) {
+ val argumentBuilder = ArgumentBuilder()
+ var descriptionLocal = ""
+
+ infix fun does(description: String): DoesHelper {
+ descriptionLocal = description
+ return DoesHelper()
+ }
+
+ inner class DoesHelper {
+ infix fun through(action: (required: List, optional: MutableMap, passthrough: T) -> Unit): Command {
+ return Command(name, descriptionLocal, action, argumentBuilder).also { commands[name] = it }
+ }
+ }
+
+ infix fun with(action: ArgumentBuilder.() -> Unit): CommandBuilder2 {
+ argumentBuilder.action()
+ return this
+ }
+
+ inner class ArgumentBuilder {
+ val required = RequiredArgHelper()
+ val optional = OptionalArgHelper()
+
+ operator fun component1() = required
+ operator fun component2() = optional
+
+ inner class RequiredArgHelper {
+ val list: MutableList> = mutableListOf()
+ val literals: MutableMap> = mutableMapOf()
+
+ infix fun int(name: String) {
+ list.add(Pair(name, ArgumentType.INT))
+ }
+
+ infix fun float(name: String) {
+ list.add(Pair(name, ArgumentType.FLOAT))
+ }
+
+ infix fun string(name: String) {
+ list.add(Pair(name, ArgumentType.STRING))
+ }
+
+ infix fun literal(name: String): LiteralHelper {
+ list.add(Pair(name, ArgumentType.LITERAL))
+ return LiteralHelper(name)
+ }
+
+ infix fun bool(name: String) {
+ list.add(Pair(name, ArgumentType.BOOLEAN))
+ }
+
+ inner class LiteralHelper(val name: String) {
+ infix fun with(literalsList: String): LiteralHelperHelper {
+ val list = mutableListOf(literalsList)
+ literals[name] = list
+
+ return LiteralHelperHelper(list)
+ }
+
+ inner class LiteralHelperHelper(private val listListList: MutableList) {
+ infix fun or(other: String): LiteralHelperHelper {
+ listListList.add(other)
+ return this
+ }
+ }
+ }
+ }
+
+ inner class OptionalArgHelper {
+ val list: MutableMap = mutableMapOf()
+ val shorts: MutableMap = mutableMapOf()
+ val literals: MutableMap> = mutableMapOf()
+
+ inner class ShortsHelper(val name: String, val shortsMap: MutableMap) {
+ infix fun short(shortName: String) {
+ shortsMap[shortName] = name
+ }
+ }
+
+ infix fun int(name: String): ShortsHelper {
+ list[name] = ArgumentType.INT
+ return ShortsHelper(name, shorts)
+ }
+
+ infix fun float(name: String): ShortsHelper {
+ list[name] = ArgumentType.FLOAT
+ return ShortsHelper(name, shorts)
+ }
+
+ infix fun string(name: String): ShortsHelper {
+ list[name] = ArgumentType.STRING
+ return ShortsHelper(name, shorts)
+ }
+
+ infix fun bool(name: String): ShortsHelper {
+ list[name] = ArgumentType.BOOLEAN
+ return ShortsHelper(name, shorts)
+ }
+
+ infix fun literal(name: String): LiteralHelper {
+ list[name] = ArgumentType.LITERAL
+ return LiteralHelper(name)
+ }
+
+ infix fun existence(name: String): ShortsHelper {
+ list[name] = ArgumentType.EXISTS
+ return ShortsHelper(name, shorts)
+ }
+
+ inner class LiteralHelper(val name: String) {
+ infix fun with(literalsList: String): LiteralHelperHelper {
+ val list = mutableListOf()
+ literals[name] = list
+
+ return LiteralHelperHelper(list)
+ }
+
+ inner class LiteralHelperHelper(private val listListList: MutableList) {
+ infix fun or(other: String): LiteralHelperHelper {
+ listListList.add(other)
+ return this
+ }
+ }
+ }
+ }
+ }
+ }
+
+ val argument = "REQUIRED_TYPE"
+ val command = CommandBuilder()
+ val nothing: (List, MutableMap, T) -> Unit = { _, _, _ -> }
+}
diff --git a/src/main/kotlin/de/wulkanat/cli/CliDiscordExtension.kt b/src/main/kotlin/de/wulkanat/cli/CliDiscordExtension.kt
new file mode 100644
index 0000000..00d768b
--- /dev/null
+++ b/src/main/kotlin/de/wulkanat/cli/CliDiscordExtension.kt
@@ -0,0 +1,52 @@
+package de.wulkanat.cli
+
+import net.dv8tion.jda.api.EmbedBuilder
+import net.dv8tion.jda.api.entities.MessageEmbed
+
+fun Command.discordUsage(): String {
+ return "${name}_ ${arguments.required.list
+ .joinToString(separator = " ") {
+ "**[**${it.first/*it.second.discordUsage(
+ arguments.required.literals,
+ it.first
+ )*/}**]**"
+ }} ${arguments.optional.list
+ .map {
+ "--${it.key}${arguments.optional.shorts[name]?.let { short -> " _-${short}_ " } ?: ""
+ }${if (it.value == ArgumentType.EXISTS) "" else " **<**${it.value.stringName}**>**"}"
+ }
+ .joinToString(separator = " ")}"
+}
+
+fun ArgumentType.discordUsage(literals: Map>, name: String): String {
+ return when (this) {
+ ArgumentType.LITERAL -> "${literals[name]?.joinToString(separator = "**|**")}"
+ ArgumentType.EXISTS -> ""
+ else -> stringName
+ }
+}
+
+fun Command.discordUsageEmbed(footer: String?): MessageEmbed {
+ return EmbedBuilder()
+ .setTitle("Usage:")
+ .setDescription("_${discordUsage()}")
+ .also { builder -> footer?.let { builder.setFooter(footer) } }
+ .build()
+}
+
+fun Cli.discordUsage(): String {
+ return commands.map { "_$prefix${it.value.discordUsage()}" }.joinToString("\n")
+}
+
+fun Cli.discordUsageEmbed(): MessageEmbed {
+ return EmbedBuilder()
+ .setTitle("Help")
+ .also {
+ commands.map { Pair(it.value.description, "_$prefix${it.value.discordUsage()}") }
+ .forEach { (title, description) ->
+ it.addField(title, description, false)
+ }
+ }
+ .setFooter("Commands are case-sensitive.")
+ .build()
+}
diff --git a/src/main/kotlin/de/wulkanat/cli/CliPublic.kt b/src/main/kotlin/de/wulkanat/cli/CliPublic.kt
new file mode 100644
index 0000000..3d0aa08
--- /dev/null
+++ b/src/main/kotlin/de/wulkanat/cli/CliPublic.kt
@@ -0,0 +1,7 @@
+package de.wulkanat.cli
+
+fun makeCli(prefix: String = "!", func: Cli.() -> Unit): Cli {
+ val cli = Cli(prefix)
+ cli.func()
+ return cli
+}
diff --git a/src/main/kotlin/de/wulkanat/cli/Command.kt b/src/main/kotlin/de/wulkanat/cli/Command.kt
new file mode 100644
index 0000000..683d005
--- /dev/null
+++ b/src/main/kotlin/de/wulkanat/cli/Command.kt
@@ -0,0 +1,23 @@
+package de.wulkanat.cli
+
+class Command(
+ val name: String,
+ val description: String,
+ val action: (required: List, optional: MutableMap, passthrough: T) -> Unit,
+ val arguments: Cli.CommandBuilder2.ArgumentBuilder
+) {
+ fun usage(): String {
+ return "$name ${arguments.required.list
+ .joinToString(separator = " ") {
+ "[${it.second.usage(
+ arguments.required.literals,
+ it.first
+ )}]"
+ }} ${arguments.optional.list
+ .map {
+ "--${it.key}${arguments.optional.shorts[name]?.let { short -> " -$short " } ?: ""
+ }${if (it.value == ArgumentType.EXISTS) "" else " <${it.value.stringName}>"}"
+ }
+ .joinToString(separator = " ")}"
+ }
+}
\ No newline at end of file
diff --git a/twitter.json b/twitter.json
new file mode 100644
index 0000000..25e9fcf
--- /dev/null
+++ b/twitter.json
@@ -0,0 +1,8 @@
+{
+ "env": "dev",
+ "accessToken": "1075173710557011968-OfPSjYUF6IDYtOl8yeo1x1EzXVlZWD",
+ "accessTokenSecret": "ikcLkku0lSNMVY7kgWcj7j7tfk3IHpHUYIkvJACp0zZXh",
+ "apiKey": "8rm4wAHVLXYauBbRDKAVro0kw",
+ "apiSecretKey": "vPZgiPxwqqHZXQGMPyxyuQrg8y45t1fAlOar9DpVlPa10JRAfC",
+ "bearerToken": "AAAAAAAAAAAAAAAAAAAAAJNnHwEAAAAAKVRDEbr2dzzum2wswMGOyJOQHJw%3DgniWSdhaXgcey4XBHQckZSVVXtP6y83wAp0sxnSp3CwbWpXoA3"
+}
\ No newline at end of file