Skip to content

Instantly share code, notes, and snippets.

@aikar
Last active August 2, 2018 23:39
Show Gist options
  • Save aikar/6a19c30f358d9dd3c8d75c996e9103eb to your computer and use it in GitHub Desktop.
Save aikar/6a19c30f358d9dd3c8d75c996e9103eb to your computer and use it in GitHub Desktop.
EMC JDA Discord Bot in Kotlin, with ACF and IDB
import co.aikar.commands.BaseCommand
import co.aikar.commands.JDACommandEvent
import co.aikar.commands.annotation.CommandAlias
import co.aikar.commands.annotation.Dependency
import net.dv8tion.jda.core.JDA
import net.dv8tion.jda.core.entities.Guild
class BaseCommands : BaseCommand() {
@Dependency
lateinit var bot: Bot;
@Dependency
lateinit var jda: JDA;
@CommandAlias("ping")
fun ping(event : JDACommandEvent, guild: Guild) {
event.sendMessage("pong!")
}
}
import co.aikar.commands.JDACommandManager
import co.aikar.commands.JDAOptions
import co.aikar.idb.DB
import co.aikar.idb.DatabaseOptions
import co.aikar.idb.PooledDatabaseOptions
import net.dv8tion.jda.core.AccountType
import net.dv8tion.jda.core.JDA
import net.dv8tion.jda.core.JDABuilder
import net.dv8tion.jda.core.entities.Member
import net.dv8tion.jda.core.entities.Role
import java.io.FileInputStream
import java.util.*
import java.util.logging.Logger
import kotlin.concurrent.fixedRateTimer
fun main(args: Array<String>) {
val options = JDAOptions();
val properties = Properties();
val file = FileInputStream("bot.properties");
properties.load(file);
file.close()
val logger = Logger.getLogger("EMCBot")
val jda = JDABuilder(AccountType.BOT).setToken(properties.getProperty("discord.token")).buildAsync();
val db = PooledDatabaseOptions
.builder()
.options(DatabaseOptions.builder()
.poolName("EMCBot DB")
.onFatalError({
logger.info("DB Fatal Error!")
DB.logException(it)
Runtime.getRuntime().exit(1)
})
.logger(logger)
.mysql(
properties.getProperty("db.user"),
properties.getProperty("db.pass"),
properties.getProperty("db.name"),
properties.getProperty("db.host")
).build()
).createHikariDatabase()
DB.setGlobalDatabase(db)
val bot = Bot(jda, options, logger);
Runtime.getRuntime().addShutdownHook(Thread {
logger.info("Shutting Down")
bot.close();
db.close();
})
}
class Bot(jda: JDA, options: JDAOptions, private val botLogger: Logger) : JDACommandManager(jda, options) {
private var timer: Timer
init {
this.registerDependency(javaClass, this)
this.registerDependency(botLogger.javaClass, botLogger)
this.registerCommand(BaseCommands())
//this.setConfigProvider {}
//this.setPermissionResolver { event, permission -> false };
val listener = Listener(jda, this)
jda.addEventListener(listener)
this.timer = fixedRateTimer(name = "RankCheckTimer", initialDelay = 0, period = 60*1000) {
listener.checkAllGuilds();
}
}
override fun getLogger(): Logger {
return botLogger
}
fun addRole(member: Member, id: Long) {
val role = getRole(id)
if (member.roles.contains(role)) {
return;
}
logger.info("Adding role ${role.name} to ${member.effectiveName}");
member.guild.controller.addRolesToMember(member, role).queue();
}
fun rmRole(member: Member, id: Long) {
val role = getRole(id)
if (!member.roles.contains(role)) {
return;
}
logger.info("Removing role ${role.name} from ${member.effectiveName}");
member.guild.controller.removeRolesFromMember(member, role).queue();
}
fun getRole(id: Long): Role {
return jda.getRoleById(id);
}
fun close() {
this.timer.cancel()
}
}
buildscript {
ext.kotlin_version = '1.2.30'
repositories {
jcenter();
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.github.jengelman.gradle.plugins:shadow:2.0.2"
}
}
group 'com.empireminecraft'
version '1.0.0-SNAPSHOT'
apply plugin: "com.github.johnrengelman.shadow"
apply plugin: 'kotlin'
repositories {
jcenter()
mavenLocal()
maven { url = "https://repo.aikar.co/content/groups/aikar/" }
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile "com.google.guava:guava:19.0"
compile "co.aikar:acf-core:0.5.0-SNAPSHOT"
compile "co.aikar:acf-jda:0.5.0-SNAPSHOT"
compile "co.aikar:idb-core:1.0.0-SNAPSHOT"
compile 'net.dv8tion:JDA:3.5.1_347'
compile 'org.slf4j:slf4j-simple:1.7.25'
compile 'com.zaxxer:HikariCP:2.4.1'
compile 'mysql:mysql-connector-java:5.1.33'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
kotlinOptions.javaParameters = true
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
shadowJar {
}
build.dependsOn shadowJar
jar {
manifest {
attributes 'Implementation-Title': 'EMC Bot'
attributes 'Implementation-Version': version
attributes 'Main-Class': 'BotKt'
}
}
//create a single Jar with all dependencies
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'EMC Bot'
attributes 'Implementation-Version': version
attributes 'Main-Class': 'BotKt'
}
baseName = project.name
version = ""
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
with jar
}
import net.dv8tion.jda.core.JDA
import net.dv8tion.jda.core.entities.Guild
import net.dv8tion.jda.core.entities.Member
import net.dv8tion.jda.core.events.ReadyEvent
import net.dv8tion.jda.core.events.guild.GuildAvailableEvent
import net.dv8tion.jda.core.events.guild.voice.GuildVoiceJoinEvent
import net.dv8tion.jda.core.events.guild.voice.GuildVoiceLeaveEvent
import net.dv8tion.jda.core.events.guild.voice.GuildVoiceMoveEvent
import net.dv8tion.jda.core.hooks.ListenerAdapter
class Listener(var jda: JDA, private var bot: Bot) : ListenerAdapter() {
private val emc = 368557034305486871;
private val comm1 = 369615347193479183;
private val comm2 = 369616432041951232;
private val comm3 = 369616589982531586;
private val comm1Role = 370399311814590474;
private val comm2Role = 370399358425890818;
private val comm3Role = 370399366810435585;
override fun onReady(event: ReadyEvent?) {
checkAllGuilds()
}
fun checkAllGuilds() {
jda.guilds.forEach {
checkGuild(it);
}
}
override fun onGuildAvailable(event: GuildAvailableEvent) {
checkGuild(event.guild)
}
private fun checkGuild(guild: Guild) {
if (guild.idLong != emc) {
return;
}
bot.logger.info("Checking")
checkChannel(guild, comm1, comm1Role);
checkChannel(guild, comm2, comm2Role);
checkChannel(guild, comm3, comm3Role);
}
private fun checkChannel(guild: Guild, channel: Long, roleId: Long) {
val role = jda.getRoleById(roleId)
val members = guild.getMembersWithRoles(role)
members.forEach {
val voiceState = it.voiceState
if (!voiceState.inVoiceChannel() || voiceState.channel.idLong != channel) {
bot.rmRole(it, roleId);
}
}
for (member in guild.getVoiceChannelById(channel).members) {
bot.addRole(member, roleId)
}
}
override fun onGuildVoiceJoin(event: GuildVoiceJoinEvent) {
if (event.guild.idLong != emc) {
return;
}
val member = event.member
val channel = event.channelJoined.idLong;
processChannelJoin(channel, member)
}
override fun onGuildVoiceLeave(event: GuildVoiceLeaveEvent) {
if (event.guild.idLong != emc) {
return;
}
val member = event.member
val channel = event.channelLeft.idLong;
processChannelLeave(channel, member)
}
override fun onGuildVoiceMove(event: GuildVoiceMoveEvent) {
if (event.guild.idLong != emc) {
return;
}
val member = event.member
processChannelLeave(event.channelLeft.idLong, member);
processChannelJoin(event.channelJoined.idLong, member);
}
private fun processChannelJoin(channel: Long, member: Member) {
if (channel == comm1) {
bot.addRole(member, comm1Role);
} else if (channel == comm2) {
bot.addRole(member, comm2Role);
} else if (channel == comm3) {
bot.addRole(member, comm3Role);
}
}
private fun processChannelLeave(channel: Long, member: Member) {
if (channel == comm1) {
bot.rmRole(member, comm1Role);
} else if (channel == comm2) {
bot.rmRole(member, comm2Role);
} else if (channel == comm3) {
bot.rmRole(member, comm3Role);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment