package moe.oko.Kiafumi; import moe.oko.Kiafumi.command.*; import moe.oko.Kiafumi.listener.MainListener; import moe.oko.Kiafumi.model.KiafumiDB; import moe.oko.Kiafumi.model.ServerManager; import moe.oko.Kiafumi.util.CommandInfo; import moe.oko.Kiafumi.util.EmbedUI; import net.dv8tion.jda.api.EmbedBuilder; import net.dv8tion.jda.api.JDA; import net.dv8tion.jda.api.JDABuilder; import net.dv8tion.jda.api.OnlineStatus; import net.dv8tion.jda.api.entities.Activity; import net.dv8tion.jda.api.entities.Guild; import net.dv8tion.jda.api.interactions.commands.OptionType; import net.dv8tion.jda.api.interactions.commands.build.OptionData; import net.dv8tion.jda.api.interactions.commands.build.SubcommandData; import net.dv8tion.jda.api.requests.GatewayIntent; import net.dv8tion.jda.api.requests.restaction.CommandCreateAction; import net.dv8tion.jda.api.utils.ChunkingFilter; import net.dv8tion.jda.api.utils.MemberCachePolicy; import net.dv8tion.jda.api.utils.cache.CacheFlag; import org.simpleyaml.configuration.file.YamlConfiguration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.awt.*; import java.io.File; import java.io.FileNotFoundException; import java.io.InputStream; import java.nio.file.Files; import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.List; /** * Kiafumi Main Class */ public class Kiafumi { private final File CONFIG_FILE = new File("config.yml"); public YamlConfiguration yamlConfiguration = new YamlConfiguration(); public Logger logger = LoggerFactory.getLogger("Kiafumi"); public static Kiafumi instance; public static JDA JDA; public List activeCommands; public KiafumiConfig config; public KiafumiDB database; public ServerManager serverManager; /** * Main Class function, makes the classes work or some shit. * @param args - Arguments for program start. */ public static void main(String[] args) { try { Kiafumi kia = new Kiafumi(); kia.start(); } catch (Exception ex) { System.out.println("Failed to start Kiafumi Instance, check your Java installation."); ex.printStackTrace(); } } /** * Ran on program start. Anything in here can determine whether the program will start. */ public void start() { //All commands to be loaded on startup! activeCommands = new ArrayList<>(); activeCommands.add(new PingCommand()); activeCommands.add(new SettingCommand()); activeCommands.add(new DuckCommand()); activeCommands.add(new InviteCommand()); activeCommands.add(new MusicCommand()); activeCommands.add(new FightCommand()); activeCommands.add(new AvatarCommand()); activeCommands.add(new SeptemberDateCommand()); activeCommands.add(new DreidelCommand()); activeCommands.add(new ModCommand()); activeCommands.add(new CatCommand()); instance = this; logger.info("Starting Kiafumi."); //Logger check System.out.println("If no other messages are present, logger failed to instantiate."); logger.info("Config load start..."); //Ensuring the configuration file is generated and/or exists. if (!CONFIG_FILE.exists()) { try (InputStream is = this.getClass().getClassLoader().getResourceAsStream("config.yml")) { //Save the default cfg Files.copy(is, CONFIG_FILE.toPath()); } catch (Exception ex) { logger.warn("Failed to create the configuration file. Stopping. (" + CONFIG_FILE.getAbsolutePath() + ")"); ex.printStackTrace(); return; } } //Try to load configuration into our local friendly configuration API. try { yamlConfiguration.load("config.yml"); } catch (FileNotFoundException e) { e.printStackTrace(); logger.warn("File not found, must've failed to create..."); } catch (Exception e) { logger.warn("Ensure all values are inputted properly."); e.printStackTrace(); } //Initializes our configuration helper & ensures it loads properly. config = new KiafumiConfig(yamlConfiguration); if(config.load()) { logger.info("Config loaded, proceeding."); } else { logger.error("Failed to load configuration. Stopping process."); Runtime.getRuntime().exit(0); } //Registers the stop() function if the program is stopped. logger.info("Registering shutdown hook."); Runtime.getRuntime().addShutdownHook(new Thread(this::stop)); //We have the prefix as a static thing that can be referenced anywhere, this is for simplicity. //Initializes database and loads credentials. database = config.createDb(); serverManager = new ServerManager(); //Makes our JDA instance. startDiscord(); } /** * Ran on program shutdown. */ public void stop() { EmbedBuilder build = new EmbedBuilder() .setColor(EmbedUI.FAILURE) .setFooter(EmbedUI.BRAND) .setTimestamp(ZonedDateTime.now()) .setTitle("Offline") .setDescription("Shutdown SIGINT Received."); JDA.getTextChannelById(config.getLogChannel()).sendMessageEmbeds(build.build()).queue(); if(database.saveServerInformation()) { info("Successfully saved server information. Shutting down peacefully."); } else { for(int i = 0; i < 15; i++) { error("FAILED TO SAVE SERVER INFORMATION."); } } } /** * Starts a JDA Instance. */ public void startDiscord() { try { JDA = JDABuilder.create(config.getToken(), GatewayIntent.GUILD_MEMBERS, GatewayIntent.GUILD_MESSAGES, GatewayIntent.DIRECT_MESSAGES, GatewayIntent.GUILD_PRESENCES, GatewayIntent.GUILD_VOICE_STATES) .setChunkingFilter(ChunkingFilter.ALL) .setMemberCachePolicy(MemberCachePolicy.ALL) .disableCache(CacheFlag.EMOTE) .setActivity(Activity.of(Activity.ActivityType.valueOf(config.getActivityType()), config.getActivityMsg())) .setStatus(OnlineStatus.valueOf(config.getStatusType())) .addEventListeners(new MainListener()).build().awaitReady(); } catch(Exception ex) { error("Initialization broke..."); ex.printStackTrace(); return; } registerAllCommands(); info("Loaded " + activeCommands.size() + " commands."); EmbedBuilder eb = new EmbedBuilder() .setColor(EmbedUI.SUCCESS) .setAuthor("Kiafumi", null, Kiafumi.JDA.getSelfUser().getAvatarUrl()) .setTitle("Online") .setFooter("Created by Oko, Laika, and Tiddy") .setTimestamp(ZonedDateTime.now()); JDA.getTextChannelById(config.getLogChannel()).sendMessageEmbeds(eb.build()).queue(); } /** * Quick method to register commands in all servers. */ private void registerAllCommands() { //Registers our slash commands for(Guild guild : JDA.getGuilds()) { registerForGuild(guild); } //Registers the event listeners for those commands. for(CommandClass cmd : activeCommands) { JDA.addEventListener(cmd); } } /** * Registers all bot commands with the guild provided * @param guild - guild to have commands provided to */ public void registerForGuild(Guild guild) { info("Standby for command strip on guild " + guild.getId()); info("Registering commands for " + guild.getId()); int i = 0; for(CommandClass cmd : activeCommands) { for(CommandInfo ci : cmd.getSlashCommandInfo()) { info("Registering Command: " + ci.getName()); CommandCreateAction cca = guild.upsertCommand(ci.getName(), ci.getDescription()); i++; if(ci.hasSubCommands()) { info("Command has sub-commands."); for (String name : ci.getSubCommands().keySet()) { CommandInfo si = ci.getSubCommands().get(name); SubcommandData sd = new SubcommandData(si.getName(), si.getDescription()); for (String option : si.getOptions().keySet()) { sd.addOption(si.getOptions().get(option), option, si.getOptionDescriptions().get(option), si.getOptionRequirements().get(option)); } cca.addSubcommands(sd); info("Added subcommand: " + name); } } if(ci.hasOptions()) { info("Command has options."); for(String name : ci.getOptions().keySet()) { //Any intelligent IDE will rage about the option not being used, it's added to the action then executed later, DO not edit this (please). cca.addOption(ci.getOptions().get(name), name, ci.getOptionDescriptions().get(name), ci.getOptionRequirements().get(name)); } } //Push w/ modifications. info("Command: " + ci.getName() + " registration on " + guild.getId() + " completed."); cca.queue(); } } info("Registered " + i + " commands."); } /* Static logger info reference. */ public static void info(String str) { instance.logger.info(str); } /* Static Logger Error reference. */ public static void error(String str) { instance.logger.error(str); } //Gets the active database. public KiafumiDB getDatabase() { return database; } //Gets active ServerManager public ServerManager getServerManager() { return serverManager; } }