|
|
|
@ -2,14 +2,24 @@ package net.pingex.dbotm;
|
|
|
|
|
|
|
|
|
|
import com.robrua.orianna.api.core.RiotAPI;
|
|
|
|
|
import com.robrua.orianna.type.core.champion.ChampionStatus;
|
|
|
|
|
import com.robrua.orianna.type.core.common.QueueType;
|
|
|
|
|
import com.robrua.orianna.type.core.common.Region;
|
|
|
|
|
import com.robrua.orianna.type.core.common.Side;
|
|
|
|
|
import com.robrua.orianna.type.core.currentgame.CurrentGame;
|
|
|
|
|
import com.robrua.orianna.type.core.currentgame.MasteryRank;
|
|
|
|
|
import com.robrua.orianna.type.core.currentgame.Participant;
|
|
|
|
|
import com.robrua.orianna.type.core.league.League;
|
|
|
|
|
import com.robrua.orianna.type.core.staticdata.Champion;
|
|
|
|
|
import com.robrua.orianna.type.core.staticdata.Mastery;
|
|
|
|
|
import com.robrua.orianna.type.core.summoner.Summoner;
|
|
|
|
|
import com.robrua.orianna.type.exception.APIException;
|
|
|
|
|
import net.pingex.discordbot.AbstractModule;
|
|
|
|
|
import net.pingex.discordbot.Command;
|
|
|
|
|
import net.pingex.discordbot.Configuration;
|
|
|
|
|
import net.pingex.discordbot.Controllable;
|
|
|
|
|
import sx.blah.discord.api.IDiscordClient;
|
|
|
|
|
import sx.blah.discord.handle.impl.events.MessageReceivedEvent;
|
|
|
|
|
import sx.blah.discord.handle.obj.IMessage;
|
|
|
|
|
import sx.blah.discord.util.DiscordException;
|
|
|
|
|
import sx.blah.discord.util.HTTP429Exception;
|
|
|
|
|
import sx.blah.discord.util.MissingPermissionsException;
|
|
|
|
@ -19,8 +29,9 @@ import java.awt.image.BufferedImage;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.net.URL;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.stream.LongStream;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* League of Discord, all the stuff related to League of Legends !
|
|
|
|
@ -40,6 +51,21 @@ public class LeagueOfDiscordModule extends AbstractModule
|
|
|
|
|
*/
|
|
|
|
|
private static final int LSI_UNIT_HEIGHT = 560;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Time shift when spectating games (3 minutes)
|
|
|
|
|
*/
|
|
|
|
|
private static final int SPECTATE_TIMESHIFT = 180;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* All keystones ID.
|
|
|
|
|
*/
|
|
|
|
|
private static final long[] KEYSTONES_ID = {6161, 6162, 6164, 6361, 6362, 6363, 6261, 6262, 6263};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Time to wait when the Rate Limit has been reached.
|
|
|
|
|
*/
|
|
|
|
|
private static final int RATELIMIT_SLEEP = 5;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Constructor doing all the basic stuff, like registering as a Listener to Discord, getting a logger, etc.
|
|
|
|
|
* @param client Discord Client instance used to register self.
|
|
|
|
@ -73,6 +99,10 @@ public class LeagueOfDiscordModule extends AbstractModule
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns this week F2P champs
|
|
|
|
|
* @return A list of the F2P champions, plus a picture with all the splash.
|
|
|
|
|
*/
|
|
|
|
|
@Command(description = "Returns this week F2P champions.")
|
|
|
|
|
public String fwr(MessageReceivedEvent event)
|
|
|
|
|
{
|
|
|
|
@ -119,4 +149,129 @@ public class LeagueOfDiscordModule extends AbstractModule
|
|
|
|
|
}
|
|
|
|
|
return toReturn.toString();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Tell cur game info for given player.
|
|
|
|
|
* @param summonerName Summoner username
|
|
|
|
|
* @return Text-based game info
|
|
|
|
|
*/
|
|
|
|
|
@Command(description = "Tell the current game info of given summoner", shorthand = "lolcur")
|
|
|
|
|
public String currentGame(MessageReceivedEvent event, String summonerName) throws HTTP429Exception, DiscordException, MissingPermissionsException, InterruptedException
|
|
|
|
|
{
|
|
|
|
|
IMessage loadingMessage = event.getMessage().getChannel().sendMessage("Fetching data from Riot API...");
|
|
|
|
|
CurrentGame ginfo = null;
|
|
|
|
|
Summoner targetPlayer = null;
|
|
|
|
|
|
|
|
|
|
// Data-fetching marathon
|
|
|
|
|
for(int i=1;; i++)
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
ginfo = RiotAPI.getCurrentGame(summonerName);
|
|
|
|
|
targetPlayer = RiotAPI.getSummonerByName(summonerName);
|
|
|
|
|
if(ginfo == null) return "Summoner is not in a game.";
|
|
|
|
|
else break;
|
|
|
|
|
}
|
|
|
|
|
catch (APIException e)
|
|
|
|
|
{
|
|
|
|
|
switch(e.getStatus())
|
|
|
|
|
{
|
|
|
|
|
case NOT_FOUND:
|
|
|
|
|
return "Summoner not found.";
|
|
|
|
|
case RATE_LIMIT_EXCEEDED:
|
|
|
|
|
Thread.sleep(TimeUnit.SECONDS.toMillis(RATELIMIT_SLEEP));
|
|
|
|
|
break;
|
|
|
|
|
case INTERNAL_SERVER_ERROR:
|
|
|
|
|
case SERVICE_UNAVAILABLE:
|
|
|
|
|
if(i>=5) return "Command failed. Please try again later.";
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// General game info
|
|
|
|
|
StringBuffer sb = new StringBuffer("Current game info for " + targetPlayer.getName() + ": ");
|
|
|
|
|
String timeStarted = String.format("%d:%d", TimeUnit.SECONDS.toMinutes(ginfo.getLength()+SPECTATE_TIMESHIFT), ginfo.getLength()+SPECTATE_TIMESHIFT - TimeUnit.MINUTES.toSeconds(TimeUnit.SECONDS.toMinutes(ginfo.getLength()+SPECTATE_TIMESHIFT)));
|
|
|
|
|
sb.append(ginfo.getQueueType()).append(" started ").append(timeStarted).append(" ago.\n\n");
|
|
|
|
|
|
|
|
|
|
loadingMessage.edit("Game found. Fetching summoners data...");
|
|
|
|
|
sb.append("Team Blue\n");
|
|
|
|
|
boolean swapped = false;
|
|
|
|
|
for(Participant i : ginfo.getParticipants())
|
|
|
|
|
{
|
|
|
|
|
if(i.getTeam().equals(Side.PURPLE) && !swapped)
|
|
|
|
|
{
|
|
|
|
|
sb.append("\nTeam Purple\n");
|
|
|
|
|
swapped = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Summoner Name + Champ
|
|
|
|
|
sb.append("* ").append(i.getSummonerName()).append(" (").append(i.getChampion().getName()).append(") - ");
|
|
|
|
|
|
|
|
|
|
// SoloQ Ranked stats
|
|
|
|
|
for(int count=1; count>0; count++)
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
for(League j : i.getSummoner().getLeagueEntries())
|
|
|
|
|
if(j.getQueueType().equals(QueueType.RANKED_SOLO_5x5))
|
|
|
|
|
{
|
|
|
|
|
sb.append(j.getTier().toString()).append(" ").append(j.getParticipantEntry().getDivision());
|
|
|
|
|
count = -1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (APIException e)
|
|
|
|
|
{
|
|
|
|
|
switch(e.getStatus())
|
|
|
|
|
{
|
|
|
|
|
case NOT_FOUND: // Silently ignore HTTP404 which is OK and means "Unranked"
|
|
|
|
|
sb.append("Unranked");
|
|
|
|
|
count = -1;
|
|
|
|
|
break;
|
|
|
|
|
case RATE_LIMIT_EXCEEDED:
|
|
|
|
|
Thread.sleep(TimeUnit.SECONDS.toMillis(RATELIMIT_SLEEP));
|
|
|
|
|
break;
|
|
|
|
|
case INTERNAL_SERVER_ERROR:
|
|
|
|
|
case SERVICE_UNAVAILABLE:
|
|
|
|
|
if(count>=5) sb.append("(Unavailable)");
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
throw e;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sb.append(" - ");
|
|
|
|
|
|
|
|
|
|
// Summoner Spells
|
|
|
|
|
sb.append(i.getSummonerSpell1().getName()).append("/").append(i.getSummonerSpell2()).append(" - ");
|
|
|
|
|
|
|
|
|
|
// Masteries
|
|
|
|
|
Mastery keystone = null;
|
|
|
|
|
int ferocity = 0, cunning = 0, resolve = 0;
|
|
|
|
|
for(MasteryRank j : i.getMasteries()) // TODO: May crash ? Wait and see
|
|
|
|
|
{
|
|
|
|
|
if(LongStream.of(KEYSTONES_ID).anyMatch(x -> x == j.getMasteryID()))
|
|
|
|
|
keystone = j.getMastery();
|
|
|
|
|
|
|
|
|
|
switch(j.getMastery().getType())
|
|
|
|
|
{
|
|
|
|
|
case Ferocity:
|
|
|
|
|
ferocity+=j.getRank();
|
|
|
|
|
break;
|
|
|
|
|
case Cunning:
|
|
|
|
|
cunning+=j.getRank();
|
|
|
|
|
break;
|
|
|
|
|
case Resolve:
|
|
|
|
|
resolve+=j.getRank();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sb.append("[").append(ferocity).append("/").append(cunning).append("/").append(resolve).append("] ")
|
|
|
|
|
.append(keystone != null ? keystone.getName() : "No keystone");
|
|
|
|
|
|
|
|
|
|
// Next guy
|
|
|
|
|
sb.append("\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return sb.toString();
|
|
|
|
|
}
|
|
|
|
|
}
|