Last active
August 2, 2018 23:39
-
-
Save aikar/6a19c30f358d9dd3c8d75c996e9103eb to your computer and use it in GitHub Desktop.
EMC JDA Discord Bot in Kotlin, with ACF and IDB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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!") | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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