Java tutorial
/* * Copyright 2017 github.com/kaaz * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package emily.command.administrative; import emily.command.meta.AbstractCommand; import emily.main.BotContainer; import emily.main.DiscordBot; import emily.permission.SimpleRank; import emily.templates.Templates; import emily.util.DebugUtil; import emily.util.Misc; import net.dv8tion.jda.core.entities.Guild; import net.dv8tion.jda.core.entities.Member; import net.dv8tion.jda.core.entities.Message; import net.dv8tion.jda.core.entities.MessageChannel; import net.dv8tion.jda.core.entities.TextChannel; import net.dv8tion.jda.core.entities.User; import org.apache.commons.lang3.time.DateUtils; import org.knowm.xchart.BitmapEncoder; import org.knowm.xchart.XYChart; import org.knowm.xchart.XYSeries; import org.knowm.xchart.style.GGPlot2Theme; import org.knowm.xchart.style.markers.SeriesMarkers; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.TreeMap; /** * !reboot * restarts the bot */ public class GuildStatsCommand extends AbstractCommand { public GuildStatsCommand() { super(); } @Override public String getDescription() { return "shows some statistics"; } @Override public String getCommand() { return "guildstats"; } @Override public boolean isListed() { return true; } @Override public String[] getUsage() { return new String[] { "stats //stats!", "stats mini //minified!", "stats users //graph of when users joined!", "stats activity//last activity per shard" }; } @Override public String[] getAliases() { return new String[] { "stats" }; } @Override public String execute(DiscordBot bot, String[] args, MessageChannel channel, User author, Message inputMessage) { if (!bot.getContainer().allShardsReady()) { return "Not fully loaded yet!"; } if (args.length == 0) { return "Statistics! \n" + getTotalTable(bot, false) + "\nYou are on shard # " + bot.getShardId(); } SimpleRank userrank = bot.security.getSimpleRank(author, channel); switch (args[0].toLowerCase()) { case "mini": return "Statistics! \n" + getTotalTable(bot, true); case "music": return DebugUtil .sendToHastebin(getPlayingOn(bot.getContainer(), userrank.isAtLeast(SimpleRank.BOT_ADMIN) || (args.length >= 2 && args[1].equalsIgnoreCase("guilds")))); case "activity": return lastShardActivity(bot.getContainer()); case "users": if (!(channel instanceof TextChannel)) { return Templates.invalid_use.formatGuild(channel); } TreeMap<Date, Integer> map = new TreeMap<>(); Guild guild = ((TextChannel) channel).getGuild(); List<Member> joins = new ArrayList<>(guild.getMembers()); for (Member join : joins) { Date time = DateUtils.round(new Date(join.getJoinDate().toInstant().toEpochMilli()), Calendar.DAY_OF_MONTH); if (!map.containsKey(time)) { map.put(time, 0); } map.put(time, map.get(time) + 1); } List<Date> xData = new ArrayList<>(); List<Integer> yData = new ArrayList<>(); int total = 0; for (Map.Entry<Date, Integer> entry : map.entrySet()) { total += entry.getValue(); xData.add(entry.getKey()); yData.add(total); } XYChart chart = new XYChart(1024, 600); chart.setTitle("Users over time for " + guild.getName()); chart.setXAxisTitle("Date"); chart.setYAxisTitle("Users"); chart.getStyler().setTheme(new GGPlot2Theme()); XYSeries series = chart.addSeries("Users", xData, yData); series.setMarker(SeriesMarkers.CIRCLE); try { File f = new File("./Sample_Chart.png"); BitmapEncoder.saveBitmap(chart, f.getAbsolutePath(), BitmapEncoder.BitmapFormat.PNG); bot.queue.add(channel.sendFile(f), message -> f.delete()); } catch (IOException e) { e.printStackTrace(); } return ""; } return "Statistics! \n" + getTotalTable(bot, false); } private String getPlayingOn(BotContainer container, boolean showGuildnames) { int activeVoice = 0; int totUsersInVoice = 0, totUsersInGuilds = 0; List<List<String>> body = new ArrayList<>(); for (DiscordBot discordBot : container.getShards()) { for (Guild guild : discordBot.getJda().getGuilds()) { if (guild.getAudioManager().isConnected()) { activeVoice++; int guildUsersInVoice = 0; for (Member user : guild.getAudioManager().getConnectedChannel().getMembers()) { if (user != null && !user.getUser().isBot()) { guildUsersInVoice++; } } int guildUsers = guild.getMembers().size(); body.add( Arrays.asList(guild.getId(), guild.getName(), "" + guildUsers, "" + guildUsersInVoice)); totUsersInVoice += guildUsersInVoice; totUsersInGuilds += guildUsers; } } } if (activeVoice == 0) { return Templates.command.stats.not_playing_music.format(); } if (!showGuildnames) { return Templates.command.stats.playing_music_on.format(activeVoice); } return Templates.command.stats.playing_music_on.format(activeVoice) + "\n" + Misc.makeAsciiTable(Arrays.asList("Discord Id", "Name", "users", "in voice"), body, activeVoice > 1 ? Arrays.asList("TOTAL", "" + activeVoice, "" + totUsersInGuilds, "" + totUsersInVoice) : null); } private String getTotalTable(DiscordBot bot, boolean minified) { List<List<String>> body = new ArrayList<>(); int totGuilds = 0, totUsers = 0, totChannels = 0, totVoice = 0, totActiveVoice = 0; double totRequestPerSec = 0D; for (DiscordBot shard : bot.getContainer().getShards()) { List<Guild> guilds = shard.getJda().getGuilds(); int numGuilds = guilds.size(); int users = shard.getJda().getUsers().size(); int channels = shard.getJda().getTextChannels().size(); int voiceChannels = shard.getJda().getVoiceChannels().size(); int activeVoice = 0; long requests = shard.getJda().getResponseTotal(); for (Guild guild : shard.getJda().getGuilds()) { if (guild.getAudioManager().isConnected()) { activeVoice++; } } double requestPerSec = ((double) requests) / (System.currentTimeMillis() / 1000D - bot.startupTimeStamp); totRequestPerSec += requestPerSec; totGuilds += numGuilds; totUsers += users; totChannels += channels; totVoice += voiceChannels; totActiveVoice += activeVoice; if (!minified) { body.add(Arrays.asList("" + shard.getShardId(), "" + numGuilds, "" + users, "" + channels, "" + voiceChannels, activeVoice == 0 ? "-" : "" + activeVoice, String.format("%.2f/s", requestPerSec))); } else { body.add(Arrays.asList("" + numGuilds, "" + users, "" + channels, "" + voiceChannels, activeVoice == 0 ? "-" : "" + activeVoice)); } } List<String> header = Arrays.asList("Shard", "Guilds", "Users", "Text", "Voice", "DJ", "Requests"); if (minified) { header = Arrays.asList("G", "U", "T", "V", "DJ"); } if (bot.getContainer().getShards().length > 1) { if (minified) { return Misc.makeAsciiTable(header, body, Arrays.asList("" + totGuilds, "" + totUsers, "" + totChannels, "" + totVoice, "" + totActiveVoice)); } return Misc.makeAsciiTable(header, body, Arrays.asList("TOTAL", "" + totGuilds, "" + totUsers, "" + totChannels, "" + totVoice, "" + totActiveVoice, String.format("%.2f/s", totRequestPerSec))); } return Misc.makeAsciiTable(header, body, null); } private String lastShardActivity(BotContainer container) { long now = System.currentTimeMillis(); StringBuilder msg = new StringBuilder("Last event per shard: " + new Date(now).toString() + "\n\n"); String comment = ""; for (DiscordBot shard : container.getShards()) { if (shard == null || !shard.isReady()) { msg.append("#shard is being reset and is reloading\n"); continue; } long lastEventReceived = now - container.getLastAction(shard.getShardId()); msg.append(String.format("#%02d: %s sec ago\n", shard.getShardId(), lastEventReceived / 1000L)); } return msg.toString() + comment; } }