package nl.voidcorp.dbot.commands import com.github.salomonbrys.kotson.fromJson import com.jagrosh.jdautilities.command.* import net.dv8tion.jda.core.EmbedBuilder import net.dv8tion.jda.core.OnlineStatus import net.dv8tion.jda.core.entities.ChannelType import net.dv8tion.jda.core.entities.Game import net.dv8tion.jda.core.entities.Guild import net.dv8tion.jda.core.entities.Message import net.dv8tion.jda.core.events.ReadyEvent import net.dv8tion.jda.core.events.message.MessageReceivedEvent import net.dv8tion.jda.core.hooks.ListenerAdapter import nl.voidcorp.dbot.bot import nl.voidcorp.dbot.gson import nl.voidcorp.dbot.log import nl.voidcorp.dbot.storage.GuildSettings import java.io.File import java.time.LocalDateTime import java.time.OffsetDateTime import java.util.* import java.util.concurrent.ScheduledExecutorService import java.util.concurrent.ScheduledThreadPoolExecutor import java.util.function.Function val gmap = mutableMapOf() object GSM : GuildSettingsManager { private val f = File("settings.json") override fun getSettings(it: Guild): GuildSettings { val res = gmap[it.idLong] return if (res != null) { res } else { val gm = GuildSettings() gmap[it.idLong] = gm gm } } override fun init() { if (f.exists()) { gmap.putAll(gson.fromJson(f.readText())) } } override fun shutdown() { gson.toJson(gmap, f.bufferedWriter()) } } data class UnityCommandClient(private val prefix: String, private val commands: MutableList = mutableListOf() ) : CommandClient, ListenerAdapter() { private val cooldownMap = mutableMapOf() override fun applyCooldown(name: String, seconds: Int) { cooldownMap[name] = OffsetDateTime.now().plusSeconds(seconds.toLong()) } override fun > getSettingsManager(): M? { return null } override fun getError(): String = "❌" override fun addAnnotatedModule(module: Any?) { //NOP } override fun addAnnotatedModule(module: Any?, mapFunction: Function?) { //NOP } override fun getServerInvite(): String? { return null } private val ses = ScheduledThreadPoolExecutor(8) override fun getScheduleExecutor(): ScheduledExecutorService = ses override fun cleanCooldowns() { for ((k, v) in cooldownMap) { if (v.isBefore(OffsetDateTime.now())) { cooldownMap.remove(k) } } } override fun getWarning(): String = "⚠️" override fun addCommand(command: Command) { commands.add(command) } override fun addCommand(command: Command, index: Int) { commands.add(index, command) } fun addCommands(commands: List) { for (c in commands) { addCommand(c) } } override fun getSettingsFor(guild: Guild): S? = null private fun getSettings(guild: Guild): GuildSettings = GSM.getSettings(guild) private var cmdListener: CommandListener? = null override fun setListener(listener: CommandListener) { cmdListener = listener } private val start = OffsetDateTime.now() override fun getStartTime(): OffsetDateTime = start override fun getListener(): CommandListener? = cmdListener override fun getSuccess(): String = "✔️" private val usageMap = mutableMapOf() override fun getCommandUses(command: Command): Int = usageMap[command.name] ?: 0 private operator fun MutableMap.plus(t: T) { val res = this[t] if (res != null) { this[t] = res + 1 } else { this[t] = 1 } } override fun getCommandUses(name: String): Int = usageMap[name] ?: 0 override fun getCooldown(name: String): OffsetDateTime? = cooldownMap[name] override fun getHelpWord(): String = "help" override fun shutdown() { ses.shutdown() GSM.shutdown() } override fun removeCommand(name: String) { commands.removeIf { it.name == name } } override fun usesLinkedDeletion(): Boolean = false override fun getTextualPrefix(): String = prefix override fun getTotalGuilds(): Int = bot.guilds.size override fun getRemainingCooldown(name: String): Int { val cd = cooldownMap[name] return if (cd == null) { 0 } else { (OffsetDateTime.now().toEpochSecond() - cd.toEpochSecond()).toInt() } } override fun getCoOwnerIds(): Array { return arrayOf() } override fun getAltPrefix(): String? = null override fun getPrefix(): String = prefix override fun getCommands(): MutableList = commands override fun getCoOwnerIdsLong(): LongArray = coOwnerIds.toList().map { it.toLong() }.toLongArray() override fun getOwnerId(): String = "168743656738521088" override fun getOwnerIdLong(): Long = ownerId.toLong() private fun splitOnPrefixLength(rawContent: String, length: Int): Array { return Arrays.copyOf(rawContent.substring(length).trim { it <= ' ' }.split("\\s+".toRegex(), 2).toTypedArray(), 2) } var unknownCommandHandler: (MessageReceivedEvent, String?) -> Unit = { event, command -> val eb = EmbedBuilder().setTitle("Something went wrong...") .addField("Unknown command: `$command`", "I don't know this command...", false) .setColor(event.guild.selfMember.color).setFooter("Requested by ${event.member.effectiveName}", event.author.effectiveAvatarUrl).setTimestamp(LocalDateTime.now()) event.textChannel.sendMessage(eb.build()).queue() } override fun onMessageReceived(event: MessageReceivedEvent) { if (event.author.isBot) return var parts: Array? = null val rawContent = event.message.contentRaw val settings = getSettings(event.guild) //Check for mention if (settings.prefixes.isEmpty()) { if (rawContent.startsWith("<@" + event.jda.selfUser.id + ">") || rawContent.startsWith("<@!" + event.jda.selfUser.id + ">")) { parts = splitOnPrefixLength(rawContent, rawContent.indexOf(">") + 1) } } //check for default prefix if not overridden if (rawContent.startsWith(prefix) and settings.prefixes.isEmpty()) parts = splitOnPrefixLength(rawContent, rawContent.indexOf(prefix)) // Check for guild specific prefixes if (parts == null) { val prefixes = settings.getPrefixes() for (prefix in prefixes) { if (parts == null && rawContent.toLowerCase().startsWith(prefix.toLowerCase())) parts = splitOnPrefixLength(rawContent, prefix.length) } } if (parts != null) //starts with valid prefix { if ((event.channel.type == ChannelType.PRIVATE) or event.textChannel.canTalk()) { val name = parts[0] val args = if (parts[1] == null) "" else parts[1] var command: Command? // this will be null if it's not a command command = commands.firstOrNull { it.name == name } if (command == null) { command = commands.firstOrNull { name in it.aliases } } if (command != null) { val cevent = CommandEventOverride(event, args, this) if (cmdListener != null) cmdListener!!.onCommand(cevent, command) usageMap + command.name command.run(cevent) return // Command is done } else { unknownCommandHandler(event, name) } } } } private val status = OnlineStatus.ONLINE var version = "?.?" private val game = Game.watching("fraud and \uD83C\uDFB5 (v$version)") override fun onReady(event: ReadyEvent) { if (!event.jda.selfUser.isBot) { log.error("This bot can't run as a client!") return } event.jda.presence.setPresence(status, when { game == null -> null "default" == game.name -> Game.playing("Type ${prefix}help") else -> game }) // Start SettingsManager if necessary GSM.init() } } class CommandEventOverride(event: MessageReceivedEvent, args: String?, client: UnityCommandClient) : CommandEvent(event, args, client) { override fun linkId(message: Message?) { } }