diff --git a/royalnet/packs/royal/commands/leagueoflegends.py b/royalnet/packs/royal/commands/leagueoflegends.py new file mode 100644 index 00000000..360f7671 --- /dev/null +++ b/royalnet/packs/royal/commands/leagueoflegends.py @@ -0,0 +1,88 @@ +import typing +import riotwatcher +from royalnet.commands import * +from royalnet.utils import * +from ..tables import LeagueOfLegends +from ..utils import LeagueLeague + + +class LeagueoflegendsCommand(Command): + name: str = "leagueoflegends" + + aliases = ["lol", "league"] + + description: str = "Connetti un account di League of Legends a un account Royalnet, e visualizzane le statistiche." + + syntax = "[regione] [nomeevocatore] OPPURE [nomeevocatore]" + + tables = {LeagueOfLegends} + + def __init__(self, interface: CommandInterface): + super().__init__(interface) + self._riotwatcher = riotwatcher.RiotWatcher(self.interface.bot.get_secret("riotgames")) + + async def run(self, args: CommandArgs, data: CommandData) -> None: + author = await data.get_author(error_if_none=True) + name = args.optional(1) + + if not name: + # Update and display the League of Legends stats for the current account + if len(author.leagueoflegends) == 0: + raise CommandError("Nessun account di League of Legends trovato.") + elif len(author.leagueoflegends) > 1: + name = args.optional(0) + if name is None: + raise CommandError("Più account di League of Legends sono registrati a questo account.\n" + "Specifica di quale account vuoi vedere le statistiche.\n" + f"Sintassi: [c]{self.interface.prefix}{self.name} [nomeevocatore][/c]") + for account in author.leagueoflegends: + if account.summoner_name == name: + leagueoflegends = account + else: + raise CommandError("Nessun account con il nome specificato trovato.") + else: + leagueoflegends = author.leagueoflegends[0] + else: + region = args[0] + # Connect a new League of Legends account to Royalnet + summoner = self._riotwatcher.summoner.by_name(region=region, summoner_name=name) + # Ensure the account isn't already connected to something else + leagueoflegends = await asyncify(data.session.query(self.alchemy.LeagueOfLegends).filter_by(summoner_id=summoner["id"]).one_or_none()) + if leagueoflegends: + raise CommandError(f"L'account {leagueoflegends} è già registrato su Royalnet.") + # Get rank information + leagues = self._riotwatcher.league.by_summoner(region=region, encrypted_summoner_id=summoner["id"]) + soloq = None + flexq = None + twtrq = None + tftq = None + for league in leagues: + if league["queueType"] == "RANKED_SOLO_5x5": + soloq = league + if league["queueType"] == "RANKED_FLEX_SR": + flexq = league + if league["queueType"] == "RANKED_FLEX_TT": + twtrq = league + if league["queueType"] == "RANKED_TFT": + tftq = league + # Get mastery score + mastery = self._riotwatcher.champion_mastery.by_summoner(region=region, encrypted_summoner_id=summoner["id"]) + # Create database row + leagueoflegends = self.alchemy.LeagueOfLegends( + region=region, + user=author, + profile_icon_id=summoner["profileIconId"], + summoner_name=summoner["name"], + puuid=summoner["puuid"], + summoner_level=summoner["summonerLevel"], + summoner_id=summoner["id"], + account_id=summoner["accountId"], + rank_soloq=soloq, + rank_flexq=flexq, + rank_twtrq=twtrq, + rank_tftq=tftq, + mastery_score=mastery + ) + data.session.add(leagueoflegends) + await data.session_commit() + await data.reply(f"↔️ Account {leagueoflegends} connesso a {author}!") diff --git a/royalnet/packs/royal/tables/__init__.py b/royalnet/packs/royal/tables/__init__.py index 3566b857..34cd4564 100644 --- a/royalnet/packs/royal/tables/__init__.py +++ b/royalnet/packs/royal/tables/__init__.py @@ -12,6 +12,7 @@ from .reminders import Reminder from .triviascores import TriviaScore from .mmevents import MMEvent from .mmresponse import MMResponse +from .leagueoflegends import LeagueOfLegends # Enter the tables of your Pack here! available_tables = [ @@ -27,6 +28,7 @@ available_tables = [ TriviaScore, MMEvent, MMResponse, + LeagueOfLegends ] # Don't change this, it should automatically generate __all__ diff --git a/royalnet/packs/royal/tables/leagueoflegends.py b/royalnet/packs/royal/tables/leagueoflegends.py new file mode 100644 index 00000000..ea9fc1a2 --- /dev/null +++ b/royalnet/packs/royal/tables/leagueoflegends.py @@ -0,0 +1,258 @@ +from sqlalchemy import * +from sqlalchemy.orm import relationship, composite +from sqlalchemy.ext.declarative import declared_attr +# noinspection PyUnresolvedReferences +from .users import User +from ..utils import LeagueRank, LeagueTier, LeagueLeague + + +class LeagueOfLegends: + __tablename__ = "leagueoflegends" + + @declared_attr + def region(self): + return Column(String, nullable=False) + + @declared_attr + def user_id(self): + return Column(Integer, ForeignKey("users.uid")) + + @declared_attr + def user(self): + return relationship("User", backref="leagueoflegends") + + @declared_attr + def profile_icon_id(self): + # 3777 + return Column(Integer, nullable=False) + + @declared_attr + def summoner_name(self): + # SteffoRYG + return Column(String, nullable=False) + + @declared_attr + def puuid(self): + # iNW0i7w_cC2kxgNB13UhyGPeyxZChmRqKylZ--bzbZAhFM6EXAImUqeRWmGtK6iKiYbz3bkCV8fMQQ + return Column(String, nullable=False) + + @declared_attr + def summoner_level(self): + # 68 + return Column(Integer, nullable=False) + + @declared_attr + def summoner_id(self): + # aEsHyfXA2q8bK-g7GlT4kFK_0uLL3w-jBPyfMAy8kOXTJXo + return Column(String, nullable=False) + + @declared_attr + def account_id(self): + # -2Ex-VpkkNBN4ceQev8oJsamxY5iGb2liRUqkES5TU_7vtI + return Column(String, nullable=False) + + @declared_attr + def rank_soloq_tier(self): + return Column(Enum(LeagueTier)) + + @declared_attr + def rank_soloq_rank(self): + return Column(Enum(LeagueRank)) + + @declared_attr + def rank_soloq_points(self): + return Column(Integer) + + @declared_attr + def rank_soloq_wins(self): + return Column(Integer) + + @declared_attr + def rank_soloq_losses(self): + return Column(Integer) + + @declared_attr + def rank_soloq_inactive(self): + return Column(Boolean) + + @declared_attr + def rank_soloq_hot_streak(self): + return Column(Boolean) + + @declared_attr + def rank_soloq_fresh_blood(self): + return Column(Boolean) + + @declared_attr + def rank_soloq_veteran(self): + return Column(Boolean) + + @declared_attr + def rank_soloq(self): + return composite(LeagueLeague, + self.rank_soloq_tier, + self.rank_soloq_rank, + self.rank_soloq_points, + self.rank_soloq_wins, + self.rank_soloq_losses, + self.rank_soloq_inactive, + self.rank_soloq_hot_streak, + self.rank_soloq_fresh_blood, + self.rank_soloq_veteran) + + @declared_attr + def rank_flexq_tier(self): + return Column(Enum(LeagueTier)) + + @declared_attr + def rank_flexq_rank(self): + return Column(Enum(LeagueRank)) + + @declared_attr + def rank_flexq_points(self): + return Column(Integer) + + @declared_attr + def rank_flexq_wins(self): + return Column(Integer) + + @declared_attr + def rank_flexq_losses(self): + return Column(Integer) + + @declared_attr + def rank_flexq_inactive(self): + return Column(Boolean) + + @declared_attr + def rank_flexq_hot_streak(self): + return Column(Boolean) + + @declared_attr + def rank_flexq_fresh_blood(self): + return Column(Boolean) + + @declared_attr + def rank_flexq_veteran(self): + return Column(Boolean) + + @declared_attr + def rank_flexq(self): + return composite(LeagueLeague, + self.rank_flexq_tier, + self.rank_flexq_rank, + self.rank_flexq_points, + self.rank_flexq_wins, + self.rank_flexq_losses, + self.rank_flexq_inactive, + self.rank_flexq_hot_streak, + self.rank_flexq_fresh_blood, + self.rank_flexq_veteran) + + @declared_attr + def rank_twtrq_tier(self): + return Column(Enum(LeagueTier)) + + @declared_attr + def rank_twtrq_rank(self): + return Column(Enum(LeagueRank)) + + @declared_attr + def rank_twtrq_points(self): + return Column(Integer) + + @declared_attr + def rank_twtrq_wins(self): + return Column(Integer) + + @declared_attr + def rank_twtrq_losses(self): + return Column(Integer) + + @declared_attr + def rank_twtrq_inactive(self): + return Column(Boolean) + + @declared_attr + def rank_twtrq_hot_streak(self): + return Column(Boolean) + + @declared_attr + def rank_twtrq_fresh_blood(self): + return Column(Boolean) + + @declared_attr + def rank_twtrq_veteran(self): + return Column(Boolean) + + @declared_attr + def rank_twtrq(self): + return composite(LeagueLeague, + self.rank_twtrq_tier, + self.rank_twtrq_rank, + self.rank_twtrq_points, + self.rank_twtrq_wins, + self.rank_twtrq_losses, + self.rank_twtrq_inactive, + self.rank_twtrq_hot_streak, + self.rank_twtrq_fresh_blood, + self.rank_twtrq_veteran) + + @declared_attr + def rank_tftq_tier(self): + return Column(Enum(LeagueTier)) + + @declared_attr + def rank_tftq_rank(self): + return Column(Enum(LeagueRank)) + + @declared_attr + def rank_tftq_points(self): + return Column(Integer) + + @declared_attr + def rank_tftq_wins(self): + return Column(Integer) + + @declared_attr + def rank_tftq_losses(self): + return Column(Integer) + + @declared_attr + def rank_tftq_inactive(self): + return Column(Boolean) + + @declared_attr + def rank_tftq_hot_streak(self): + return Column(Boolean) + + @declared_attr + def rank_tftq_fresh_blood(self): + return Column(Boolean) + + @declared_attr + def rank_tftq_veteran(self): + return Column(Boolean) + + @declared_attr + def rank_tftq(self): + return composite(LeagueLeague, + self.rank_tftq_tier, + self.rank_tftq_rank, + self.rank_tftq_points, + self.rank_tftq_wins, + self.rank_tftq_losses, + self.rank_tftq_inactive, + self.rank_tftq_hot_streak, + self.rank_tftq_fresh_blood, + self.rank_tftq_veteran) + + @declared_attr + def mastery_score(self): + return Column(Integer, nullable=False, default=0) + + def __repr__(self): + return f"<{self.__class__.__qualname__} {str(self)}>" + + def __str__(self): + return f"[c]{self.__tablename__}:{self.summoner_name}[/c]" diff --git a/royalnet/packs/royal/utils/__init__.py b/royalnet/packs/royal/utils/__init__.py index 399ceac2..aaab3673 100644 --- a/royalnet/packs/royal/utils/__init__.py +++ b/royalnet/packs/royal/utils/__init__.py @@ -1,4 +1,7 @@ from .mmchoice import MMChoice from .mminterfacedata import MMInterfaceData, MMInterfaceDataTelegram +from .leaguetier import LeagueTier +from .leaguerank import LeagueRank +from .leagueleague import LeagueLeague -__all__ = ["MMChoice", "MMInterfaceData", "MMInterfaceDataTelegram"] +__all__ = ["MMChoice", "MMInterfaceData", "MMInterfaceDataTelegram", "LeagueTier", "LeagueRank", "LeagueLeague"] diff --git a/royalnet/packs/royal/utils/leagueleague.py b/royalnet/packs/royal/utils/leagueleague.py new file mode 100644 index 00000000..5f578f75 --- /dev/null +++ b/royalnet/packs/royal/utils/leagueleague.py @@ -0,0 +1,91 @@ +from .leaguetier import LeagueTier +from .leaguerank import LeagueRank + + +class LeagueLeague: + def __init__(self, + tier: LeagueTier = None, + rank: LeagueRank = None, + points: int = None, + wins: int = None, + losses: int = None, + inactive: bool = None, + hot_streak: bool = None, + fresh_blood: bool = None, + veteran: bool = None): + self.tier: LeagueTier = tier # IRON + self.rank: LeagueRank = rank # I + self.points: int = points # 40 LP + self.wins: int = wins + self.losses: int = losses + self.inactive: bool = inactive + self.hot_streak: bool = hot_streak + self.fresh_blood: bool = fresh_blood + self.veteran: bool = veteran + + def __str__(self): + return f"{self.tier} {self.rank} ({self.points} LP)" + + def __repr__(self): + return f"<{self.__class__.__qualname__} {self}>" + + def __eq__(self, other): + if isinstance(other, LeagueLeague): + equal = True + if other.veteran: + equal &= self.veteran == other.veteran + if other.fresh_blood: + equal &= self.fresh_blood == other.fresh_blood + if other.hot_streak: + equal &= self.hot_streak == other.hot_streak + if other.inactive: + equal &= self.inactive == other.inactive + if other.losses: + equal &= self.losses == other.losses + if other.wins: + equal &= self.wins == other.wins + if other.points: + equal &= self.points == other.points + if other.rank: + equal &= self.rank == other.rank + if other.tier: + equal &= self.tier == other.tier + return equal + else: + raise TypeError(f"Can't compare {self.__class__.__qualname__} with {other.__class__.__qualname__}") + + def __ne__(self, other): + return not self.__eq__(other) + + def __composite_values__(self): + return self.tier, \ + self.rank, \ + self.points, \ + self.wins, \ + self.losses, \ + self.inactive, \ + self.hot_streak, \ + self.fresh_blood, \ + self.veteran + + @property + def played(self): + return self.wins + self.losses + + @property + def winrate(self): + return self.wins / self.played + + @classmethod + def from_dict(cls, d: dict): + return cls( + tier=d["tier"], + rank=d["rank"], + points=d["leaguePoints"], + wins=d["wins"], + losses=d["losses"], + inactive=d["inactive"], + hot_streak=d["hotStreak"], + fresh_blood=d["freshBlood"], + veteran=d["veteran"], + ) diff --git a/royalnet/packs/royal/utils/leaguerank.py b/royalnet/packs/royal/utils/leaguerank.py new file mode 100644 index 00000000..014af610 --- /dev/null +++ b/royalnet/packs/royal/utils/leaguerank.py @@ -0,0 +1,14 @@ +import enum + + +class LeagueRank(enum.Enum): + I = 1 + II = 2 + III = 3 + IV = 4 + + def __str__(self): + return self.name + + def __repr__(self): + return f"{self.__class__.__qualname__}.{self.name}" diff --git a/royalnet/packs/royal/utils/leaguetier.py b/royalnet/packs/royal/utils/leaguetier.py new file mode 100644 index 00000000..249b7598 --- /dev/null +++ b/royalnet/packs/royal/utils/leaguetier.py @@ -0,0 +1,19 @@ +import enum + + +class LeagueTier(enum.Enum): + IRON = 0 + BRONZE = 1 + SILVER = 2 + GOLD = 3 + PLATINUM = 4 + DIAMOND = 5 + MASTER = 6 + GRANDMASTER = 7 + CHALLENGER = 8 + + def __str__(self): + return self.name + + def __repr__(self): + return f"{self.__class__.__qualname__}.{self.name}"