OttoBot/src/main/kotlin/nl/voidcorp/dbot/commands/UnityCommandClient.kt

276 lines
7.7 KiB
Kotlin

package nl.voidcorp.dbot.commands
import com.github.salomonbrys.kotson.fromJson
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.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.CommandString
import nl.voidcorp.dbot.storage.GuildSettings
import java.io.File
import java.time.LocalDateTime
import java.time.OffsetDateTime
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.ScheduledThreadPoolExecutor
import kotlin.math.absoluteValue
val gmap = mutableMapOf<Long, GuildSettings>()
object GSM {
private val f = File("settings.json")
fun getSettings(it: Guild): GuildSettings {
val res = gmap[it.idLong]
return if (res != null) {
res
} else {
val gm = GuildSettings()
gmap[it.idLong] = gm
gm
}
}
fun init() {
if (f.exists()) {
try {
val m = gson.fromJson<Map<Long, GuildSettings>>(f.readText())
gmap.putAll(m)
} catch (ex: IllegalStateException) {
}
}
}
fun shutdown() {
gson.toJson(gmap, f.bufferedWriter())
}
}
data class UnityCommandClient(
private val prefix: String,
private val commands: MutableList<UnityCommand> = mutableListOf()
) : ListenerAdapter() {
private val cooldownMap = mutableMapOf<String, LocalDateTime>()
fun applyCooldown(name: String, seconds: Int) {
cooldownMap[name] = LocalDateTime.now().plusSeconds(seconds.toLong())
}
fun getRemainingCooldown(name: String): Int {
val cd = cooldownMap[name]
return if (cd == null) {
0
} else {
(LocalDateTime.now().second - cd.second).absoluteValue
}
}
fun isOnCooldown(name: String): Boolean {
val cooldown: Boolean? = LocalDateTime.now().isBefore(cooldownMap[name] ?: LocalDateTime.MIN)
return cooldown ?: false
}
fun cleanCooldowns() {
for ((k, v) in cooldownMap) {
if (v.isBefore(LocalDateTime.now())) {
cooldownMap.remove(k)
}
}
}
fun getError(): String = ""
fun getServerInvite(): String {
return ""
}
private val ses = ScheduledThreadPoolExecutor(8)
fun getScheduleExecutor(): ScheduledExecutorService = ses
fun getWarning(): String = "⚠️"
fun addCommand(command: UnityCommand) {
commands.add(command)
}
fun addCommand(command: UnityCommand, index: Int) {
commands.add(index, command)
}
fun <T : UnityCommand> addCommands(commands: List<T>) {
for (c in commands) {
addCommand(c)
}
}
private fun getSettings(guild: Guild): GuildSettings = GSM.getSettings(guild)
private val start = OffsetDateTime.now()
fun getStartTime(): OffsetDateTime = start
fun getSuccess(): String = "✔️"
private val usageMap = mutableMapOf<String, Int>()
private operator fun <T> MutableMap<T, Int>.plus(t: T) {
val res = this[t]
if (res != null) {
this[t] = res + 1
} else {
this[t] = 1
}
}
fun getCommandUses(name: String): Int = usageMap[name] ?: 0
fun shutdown() {
ses.shutdown()
GSM.shutdown()
}
fun usesLinkedDeletion(): Boolean = false
fun getTextualPrefix(): String = prefix
fun getTotalGuilds(): Int = bot.guilds.size
val ownerId = "168743656738521088"
fun getOwnerIdLong(): Long = ownerId.toLong()
private fun splitOnPrefixLength(rawContent: String, length: Int): CommandString {
val m = rawContent.substring(length).trim { it <= ' ' }.split("\\s+".toRegex(), 2)
val cmds = if (m.size == 2) {
CommandString(m[0], m[1])
} else {
CommandString(m[0])
}
return cmds
}
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 commandString: CommandString? = null
val rawContent = event.message.contentRaw
val settings = getSettings(event.guild)
//Check for mention
if (rawContent.startsWith("<@" + event.jda.selfUser.id + ">") || rawContent.startsWith("<@!" + event.jda.selfUser.id + ">")) {
commandString = splitOnPrefixLength(rawContent, rawContent.indexOf(">") + 1)
}
//check for default prefix if not overridden
if (rawContent.startsWith(prefix) and settings.prefixes.isEmpty())
commandString = splitOnPrefixLength(rawContent, prefix.length)
// Check for guild specific prefixes
if (commandString == null) {
val prefixes = settings.getPrefixes()
for (prefix in prefixes) {
if (commandString == null && rawContent.toLowerCase().startsWith(prefix.toLowerCase()))
commandString = splitOnPrefixLength(rawContent, prefix.length)
}
}
if (commandString != null)
//starts with valid prefix
{
if ((event.channel.type == ChannelType.PRIVATE) or event.textChannel.canTalk()) {
var command: UnityCommand?// this will be null if it's not a command
command = commands.firstOrNull { it.name == commandString.command }
if (command == null) {
command = commands.firstOrNull { commandString.command in it.aliases }
}
if (command != null) {
val cevent = UnityCommandEvent(event, commandString.args, this)
/*if (cmdListener != null)
cmdListener!!.onCommand(cevent, command)*/
usageMap + command.name
try {
command.run(cevent)
} catch (ex: UnknownCommandError) {
unknownCommandHandler(event, commandString.command)
}
return // Command is done
} else {
unknownCommandHandler(event, commandString.command)
}
}
}
}
fun onException(t: Throwable) {
val channel = bot.getPrivateChannelById("501009066479452170")
channel.sendMessage("There was an error: ${t.message}").queue()
}
private val status = OnlineStatus.ONLINE
var version = "?.?"
set(value) {
game = Game.watching("fraud and \uD83C\uDFB5 (v$value)")
}
private var game: 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,
game
)
// Start SettingsManager if necessary
GSM.init()
}
}