""" █▀▀ ▄▀█ █▄▀ █▀▀ █▀ ▀█▀ █░█░█ █ ▀▄▀ █▄▄ █▀█ █░█ ██▄ ▄█ ░█░ ▀▄▀▄▀ █ █░█ Copyleft 2022 t.me/CakesTwix This program is free software; you can redistribute it and/or modify """ __version__ = (1, 2, 0) # requires: aiohttp timeago # meta pic: https://b.thumbs.redditmedia.com/-cDkj6PuQHqdLEhPh1JYsYplTArOOUuBnKs5FC8sgKs.png # meta developer: @cakestwix_mods # scope: inline import logging import uuid from datetime import datetime from typing import Union import aiohttp import timeago from .. import loader, utils # noqa logger = logging.getLogger(__name__) # From Hikka https://github.com/hikariatama/Hikka/blob/master/hikka/utils.py#L459-L461 def chunks(_list: Union[list, tuple, set], n: int, /) -> list: """Split provided `_list` into chunks of `n`""" return [_list[i : i + n] for i in range(0, len(_list), n)] @loader.tds class InlineWynnCraftInfoMod(loader.Module): """A module for displaying player information on the WynnCraft rpg server""" strings = { "name": "InlineWynnCraft", "error_message": "🚫 This entity does not exist or you entered it incorrectly", "about_user": "Available player information {} {}\n", "rank_user": "Rank: ", "last_join_user": "\nLast Seen: ", "first_join_user": "\nFirst Join: ", "professions_user": "\nProfessions: ", "guild_user": "\nGuild: {} ({})", "general_info_user": "\n\n👉 General Information", "chestsFound": "\n 🔍 Chests Found: ", "blocksWalked": "\n 🚶‍♀️ Walked blocks: ", "mobsKilled": "\n 🐗 Mobs Killed: ", "itemsIdentified": "\n 🧰 Items analyzed: ", "logins": "\n 🎟 Logins: ", "discoveries": "\n 🔎 Discoveries: ", "dungeons": "\n 🪨 Dungeons: ", "raids": "\n ⚔️ Raids: ", "quests": "\n 📕 Quests: ", "eventsWon": "\n 🎊 Events Won: ", "pvp_user": "\n\n🗡 PVP: ", "deaths": "\n ☠️ Deaths: ", "kills": "\n ⚔️ Kills: ", "completed": "\n✅ Completed", "skills": "\n\n🔧 Skills", "strength": "\n 💪 Strength: ", "dexterity": "\n 💨 Dexterity: ", "intelligence": "\n 🧐 Intelligence: ", "defense": "\n 🧱 Defence: ", "defence": "\n 🛡 Defence: ", "agility": "\n 🤸‍♂️ Agility: ", "professions": "\n\n👷‍♀️ Professions: ", "alchemism": "\n 💧 Alchemism: ", "armouring": "\n 🛡 Armouring: ", "combat": "\n ⚔️ Combat: ", "cooking": "\n 🍽 Cooking: ", "farming": "\n 🌾️ Farming: ", "fishing": "\n 🎣 Fishing: ", "jeweling": "\n 💎 Jeweling: ", "mining": "\n ⛏ Mining: ", "scribing": "\n 🖋 Scribing: ", "tailoring": "\n 🪡 Tailoring: ", "weaponsmithing": "\n 🗡️ Weaponsmithing: ", "woodcutting": "\n 🪓 Woodcutting: ", "woodworking": "\n 🌳️ Woodworking: ", "btn_back": "Back", "btn_close": "Close", "top_list": "Top list:", } strings_ru = { "error_message": "🚫 Этот объект не существует или вы ввели его неправильно", "about_user": "Доступная информация об игроке {} {}\n", "rank_user": "Ранг: ", "last_join_user": "\nПоследнее посещение: ", "first_join_user": "\nПервое присоединение: ", "professions_user": "\nПрофессии: ", "guild_user": "\nГильдия: {} ({})", "general_info_user": "\n\n👉 Главная Информация", "chestsFound": "\n 🔍 Найдено сундуков: ", "blocksWalked": "\n 🚶‍♀️ Пройдено блоков: ", "mobsKilled": "\n 🐗 Мобов убито: ", "itemsIdentified": "\n 🧰 Проанализировано предметов: ", "logins": "\n 🎟 Заходил на сервер: ", "discoveries": "\n 🔎 Открытий: ", "dungeons": "\n 🪨 Подземелья: ", "raids": "\n ⚔️ Рейды: ", "quests": "\n 📕 Квесты: ", "eventsWon": "\n 🎊 Выигранные события: ", "pvp_user": "\n\n🗡 PVP: ", "deaths": "\n ☠️ Смертей: ", "kills": "\n ⚔️ Убийств: ", "completed": "\n✅ Завершено", "skills": "\n\n🔧 Навыки", "strength": "\n 💪 Прочность: ", "dexterity": "\n 💨 Ловкость: ", "intelligence": "\n 🧐 Интеллект: ", "defense": "\n 🧱 Оборона: ", "defence": "\n 🛡 Защита: ", "agility": "\n 🤸‍♂️ Ловкость: ", "professions": "\n\n👷‍♀️ Профессии: ", "alchemism": "\n 💧 Алхимизм: ", "armouring": "\n 🛡 Бронирование: ", "combat": "\n ⚔️ Бой: ", "cooking": "\n 🍽 Готовка: ", "farming": "\n 🌾️ Сельское хозяйство: ", "fishing": "\n 🎣 Рыбалка: ", "jeweling": "\n 💎 Ювелирное дело: ", "mining": "\n ⛏ Добыча: ", "scribing": "\n 🖋 Скрайбирование: ", "tailoring": "\n 🪡 Портняжное дело: ", "weaponsmithing": "\n 🗡️ Оружейное дело: ", "woodcutting": "\n 🪓 Резьба по дереву: ", "woodworking": "\n 🌳️ Деревообработка: ", "btn_back": "Назад", "btn_close": "Закрыть", "top_list": "Топ:", } base_url = "https://mc-heads.net/minecraft/profile/" wynncraft_api = "https://api.wynncraft.com/v2/" def general_info_builder(self, user) -> str: text = self.strings["about_user"].format( f'🟢 ({user["meta"]["location"]["server"]})' if user["meta"]["location"]["online"] else "🔴", user["username"], ) text += ( self.strings["rank_user"] + user["rank"] + ( f' ({user["meta"]["tag"]["value"]})' if user["meta"]["tag"]["value"] else "" ) ) # Guild text += ( self.strings["guild_user"].format( user["guild"]["name"], user["guild"]["rank"] ) if user["guild"]["name"] else "" ) text += self.strings["last_join_user"] + timeago.format( datetime.strptime(user["meta"]["lastJoin"][:-5], "%Y-%m-%dT%H:%M:%S"), datetime.now(), ) text += self.strings["first_join_user"] + timeago.format( datetime.strptime(user["meta"]["firstJoin"][:-5], "%Y-%m-%dT%H:%M:%S"), datetime.now(), ) # Global stuff text += self.strings["general_info_user"] for general_stuff in user["global"]: if general_stuff in ["pvp", "totalLevel"]: continue text += ( self.strings[general_stuff] + f"{user['global'][general_stuff]}" ) # PvP text += self.strings["pvp_user"] text += self.strings["kills"] + f"{user['global']['pvp']['kills']}" text += ( self.strings["deaths"] + f"{user['global']['pvp']['deaths']}" ) return text def class_info_builder(self, class_) -> str: text = self.strings["about_user"].format( "".join([i for i in class_["name"].title() if not i.isdigit()]), f"[{class_['level']}]", ) # Completed stuff text += self.strings["completed"] for some_item in class_: if some_item not in ["dungeons", "raids", "quests"]: continue text += ( self.strings[some_item] + f"{class_[some_item]['completed']}" ) # Some stuff text += self.strings["general_info_user"] for some_item in class_: if some_item in [ "itemsIdentified", "mobsKilled", "chestsFound", "blocksWalked", "logins", "discoveries", "eventsWon", ]: text += self.strings[some_item] + f"{class_[some_item]}" # PvP text += self.strings["pvp_user"] text += self.strings["kills"] + f"{class_['pvp']['kills']}" text += self.strings["deaths"] + f"{class_['pvp']['deaths']}" # Skills stuff text += self.strings["skills"] for skill in class_["skills"]: text += self.strings[skill] + f"{class_['skills'][skill]}" # Professions stuff text += self.strings["professions"] for skill in class_["professions"]: text += self.strings[skill] + f"{class_['professions'][skill]['level']} ({class_['professions'][skill]['xp']})" return text def keyboard_class_builder(self, user): return [ { "text": f'[{class_["level"]}] {"".join([i for i in class_["name"].title() if not i.isdigit()])}', "callback": self.inline__get_class, "args": [class_, user], } for class_ in user["classes"] ] async def wucheckcmd(self, message): """Check user by username""" if not (args := utils.get_args_raw(message)): return async with aiohttp.ClientSession() as session: async with session.get(f"{self.base_url}{args}") as get: if get.status != 200: return await utils.answer(message, self.strings["error_message"]) uuid_str = (await get.json())["id"] # Get info about user async with session.get( self.wynncraft_api + "player/{}/stats".format(uuid.UUID(hex=uuid_str)) ) as get: logger.debug(str(await get.json())) if (await get.json())["code"] != 200: return await utils.answer(message, self.strings["error_message"]) user = (await get.json())["data"][0] await self.inline.form( text=self.general_info_builder(user), message=message, reply_markup=chunks(self.keyboard_class_builder(user), 3), photo=f"https://wynndata.tk/gen/stats/{args}.png", force_me=False, # optional: Allow other users to access form (all) ) async def wplayertopcmd(self, message): """Top players""" async with aiohttp.ClientSession() as session: async with session.get(f"{self.wynncraft_api}leaderboards/player/overall/all") as get: if get.status != 200: return await utils.answer(message, self.strings["error_message"]) top_list = list(reversed(chunks((await get.json())["data"],10))) # oh no, cringe code string = f"{self.strings['top_list']}\n\n" for player in reversed(top_list[0]): string += f"╭ {player['name']} 🎮\n" string += f"╰─ LvL: {player['level']} / XP: {player['xp']} / Time: {player['minPlayed']}\n" await self.inline.form(text=string, message=message, reply_markup=chunks([{"text": str(i + 1), "callback": self.inline__toplayer, "args": (top_list, i),} for i in range(10)], 5), force_me=False) async def inline__toplayer(self, call, top_list: list, num: int): string = f"{self.strings['top_list']}\n\n" for player in reversed(top_list[num]): string += f"╭ {player['name']} 🎮\n" string += f"╰─ LvL: {player['level']} / XP: {player['xp']} / Time: {player['minPlayed']}\n" await call.edit(text=string, reply_markup=chunks([{"text": str(i + 1), "callback": self.inline__toplayer, "args": (top_list, i),} for i in range(10)], 5), force_me=False) async def inline__get_class(self, call, class_, player): await call.edit( text=self.class_info_builder(class_), reply_markup=[ { "text": self.strings["btn_back"], "callback": self.inline__back, "args": [player], } ], ) async def inline__back(self, call, player): await call.edit( text=self.general_info_builder(player), reply_markup=chunks(self.keyboard_class_builder(player), 3), )