def from_data(cls, data: ExtDict, user_2: Union[ExtDict, AbstractUser], client: Client) -> FriendRequest: user_1 = AbstractUser( name=data.get(Index.REQUEST_SENDER_NAME, "unknown"), id=data.getcast(Index.REQUEST_SENDER_ID, 0, int), account_id=data.getcast(Index.REQUEST_SENDER_ACCOUNT_ID, 0, int), client=client, ) if isinstance(user_2, ExtDict): user_2 = AbstractUser(**user_2, client=client) indicator = data.getcast(Index.REQUEST_INDICATOR, 0, int) is_normal = indicator ^ 1 return cls( id=data.getcast(Index.REQUEST_ID, 0, int), timestamp=str(data.get(Index.REQUEST_TIMESTAMP, "unknown")), body=Coder.do_base64(data.get(Index.REQUEST_BODY, ""), encode=False, errors="replace"), is_read=(not data.get(Index.REQUEST_STATUS)), author=(user_1 if is_normal else user_2), recipient=(user_2 if is_normal else user_1), type=MessageOrRequestType.from_value(indicator, 0), client=client, )
def from_data(cls, data: ExtDict, user_2: Union[ExtDict, AbstractUser], client: Client) -> Message: user_1 = AbstractUser( name=data.get(Index.MESSAGE_SENDER_NAME, "unknown"), id=data.getcast(Index.MESSAGE_SENDER_ID, 0, int), account_id=data.getcast(Index.MESSAGE_SENDER_ACCOUNT_ID, 0, int), client=client, ) if isinstance(user_2, ExtDict): user_2 = AbstractUser(**user_2, client=client) indicator = data.getcast(Index.MESSAGE_INDICATOR, 0, int) is_normal = indicator ^ 1 subject = Coder.do_base64(data.get(Index.MESSAGE_SUBJECT, ""), encode=False, errors="replace") return Message( id=data.getcast(Index.MESSAGE_ID, 0, int), timestamp=data.get(Index.MESSAGE_TIMESTAMP, "unknown"), subject=subject, is_read=bool(data.getcast(Index.MESSAGE_IS_READ, 0, int)), author=(user_1 if is_normal else user_2), recipient=(user_2 if is_normal else user_1), type=MessageOrRequestType.from_value(indicator, 0), client=client, )
def from_data(cls, data: ExtDict, author: Union[ExtDict, AbstractUser], client: Client) -> Comment: if isinstance(author, ExtDict): if any(key.isdigit() for key in author.keys()): author = AbstractUser.from_data(author, client=client) else: author = AbstractUser(**author, client=client) color_string = data.get(Index.COMMENT_COLOR, "255,255,255") color = Color.from_rgb(*map(int, color_string.split(","))) return cls( body=Coder.do_base64(data.get(Index.COMMENT_BODY, ""), encode=False, errors="replace"), rating=data.getcast(Index.COMMENT_RATING, 0, int), timestamp=data.get(Index.COMMENT_TIMESTAMP, "unknown"), id=data.getcast(Index.COMMENT_ID, 0, int), is_spam=bool(data.getcast(Index.COMMENT_IS_SPAM, 0, int)), type=CommentType.from_value( data.getcast(Index.COMMENT_TYPE, 0, int), 0), color=color, level_id=data.getcast(Index.COMMENT_LEVEL_ID, 0, int), level_percentage=data.getcast(Index.COMMENT_LEVEL_PERCENTAGE, -1, int), author=author, client=client, )
def into_level( self, client: Optional[Client] = None, get_data: bool = True, server_style: bool = False, ) -> Level: if self.is_demon(): difficulty = DemonDifficulty.from_name(self.difficulty) else: difficulty = LevelDifficulty.from_name(self.difficulty) if get_data: data = official_levels_data.get(self.name, "") if data: data = Coder.unzip(data) else: data = "" return Level( id=self.level_id, name=self.name, description=f"Official Level: {self.name}", version=1, creator=AbstractUser(name="RobTop", id=16, account_id=71, client=client), song=Song.official(self.get_song_id(server_style), client=client, server_style=server_style), data=data, password=None, copyable=False, is_demon=self.is_demon(), is_auto=self.is_auto(), difficulty=difficulty, stars=self.stars, coins=self.coins, verified_coins=True, is_epic=False, original=True, low_detail_mode=False, downloads=0, rating=0, score=1, uploaded_timestamp="unknown", last_updated_timestamp="unknown", length=LevelLength.from_name(self.length), stars_requested=self.stars, object_count=0, type=TimelyType.from_value(0), time_n=-1, cooldown=-1, client=client, )
def creator(self) -> AbstractUser: """:class:`.AbstractUser`: Creator of the level.""" return self.options.get("creator", AbstractUser(client=self.options.get("client")))
def from_data( cls, data: ExtDict, creator: Union[ExtDict, AbstractUser], song: Union[ExtDict, Song], client: Client, ) -> Level: if isinstance(creator, ExtDict): creator = AbstractUser(**creator, client=client) if isinstance(song, ExtDict): if any(key.isdigit() for key in song.keys()): song = Song.from_data(song, client=client) else: song = Song(**song, client=client) string = data.get(Index.LEVEL_PASS) if string is None: copyable, password = False, None else: if string == ZERO_STR: copyable, password = False, None else: try: # decode password password = Coder.decode(type="levelpass", string=string) except Exception: # failed to get password copyable, password = False, None else: copyable = True if not password: password = None else: # password is in format 1XXXXXX password = password[1:] password = int(password) if password.isdigit() else None desc = Coder.do_base64( data.get(Index.LEVEL_DESCRIPTION, ""), encode=False, errors="replace" ) level_data = data.get(Index.LEVEL_DATA, "") try: level_data = Coder.unzip(level_data) except Exception: # conversion failed pass diff = data.getcast(Index.LEVEL_DIFFICULTY, 0, int) demon_diff = data.getcast(Index.LEVEL_DEMON_DIFFICULTY, 0, int) is_demon = bool(data.getcast(Index.LEVEL_IS_DEMON, 0, int)) is_auto = bool(data.getcast(Index.LEVEL_IS_AUTO, 0, int)) difficulty = Converter.convert_level_difficulty( diff=diff, demon_diff=demon_diff, is_demon=is_demon, is_auto=is_auto ) return cls( id=data.getcast(Index.LEVEL_ID, 0, int), name=data.get(Index.LEVEL_NAME, "unknown"), description=desc, version=data.getcast(Index.LEVEL_VERSION, 0, int), creator=creator, song=song, data=level_data, password=password, copyable=copyable, is_demon=is_demon, is_auto=is_auto, low_detail_mode=bool(data.get(Index.LEVEL_HAS_LDM)), difficulty=difficulty, stars=data.getcast(Index.LEVEL_STARS, 0, int), coins=data.getcast(Index.LEVEL_COIN_COUNT, 0, int), verified_coins=bool(data.getcast(Index.LEVEL_COIN_VERIFIED, 0, int)), is_epic=bool(data.getcast(Index.LEVEL_IS_EPIC, 0, int)), original=data.getcast(Index.LEVEL_ORIGINAL, 0, int), downloads=data.getcast(Index.LEVEL_DOWNLOADS, 0, int), rating=data.getcast(Index.LEVEL_LIKES, 0, int), score=data.getcast(Index.LEVEL_FEATURED_SCORE, 0, int), uploaded_timestamp=data.get(Index.LEVEL_UPLOADED_TIMESTAMP, "unknown"), last_updated_timestamp=data.get(Index.LEVEL_LAST_UPDATED_TIMESTAMP, "unknown"), length=LevelLength.from_value(data.getcast(Index.LEVEL_LENGTH, 0, int), "XL"), game_version=data.getcast(Index.LEVEL_GAME_VERSION, 0, int), stars_requested=data.getcast(Index.LEVEL_REQUESTED_STARS, 0, int), object_count=data.getcast(Index.LEVEL_OBJECT_COUNT, 0, int), type=TimelyType.from_value(data.getcast(Index.LEVEL_TIMELY_TYPE, 0, int), 0), time_n=data.getcast(Index.LEVEL_TIMELY_INDEX, -1, int), cooldown=data.getcast(Index.LEVEL_TIMELY_COOLDOWN, -1, int), client=client, )
def recipient(self) -> AbstractUser: """:class:`.AbstractUser`: A recipient of the friend request.""" return self.options.get("recipient", AbstractUser(client=self.client))
def author(self) -> AbstractUser: """:class:`.AbstractUser`: An author of the friend request.""" return self.options.get("author", AbstractUser(client=self.client))
def official(cls, level_id: int, client: Optional[Client] = None) -> None: mapping = { # ID: (name, stars, difficulty, coins, length) 1: ("Stereo Madness", 1, "easy", 3, 3), 2: ("Back On Track", 2, "easy", 3, 3), 3: ("Polargeist", 3, "normal", 3, 3), 4: ("Dry Out", 4, "normal", 3, 3), 5: ("Base After Base", 5, "hard", 3, 3), 6: ("Cant Let Go", 6, "hard", 3, 3), 7: ("Jumper", 7, "harder", 3, 3), 8: ("Time Machine", 8, "harder", 3, 3), 9: ("Cycles", 9, "harder", 3, 3), 10: ("xStep", 10, "insane", 3, 3), 11: ("Clutterfunk", 11, "insane", 3, 3), 12: ("Theory of Everything", 12, "insane", 3, 3), 13: ("Electroman Adventures", 10, "insane", 3, 3), 14: ("Clubstep", 14, "easy_demon", 3, 3), 15: ("Electrodynamix", 12, "insane", 3, 3), 16: ("Hexagon Force", 12, "insane", 3, 3), 17: ("Blast Processing", 10, "harder", 3, 3), 18: ("Theory of Everything 2", 14, "easy_demon", 3, 3), 19: ("Geometrical Dominator", 10, "harder", 3, 3), 20: ("Deadlocked", 15, "easy_demon", 3, 3), 21: ("Fingerdash", 12, "insane", 3, 3), 1001: ("The Seven Seas", 1, "easy", 3, 3), 1002: ("Viking Arena", 2, "normal", 3, 3), 1003: ("Airborne Robots", 3, "hard", 3, 3), 2001: ("Payload", 2, "easy", 0, 1), 2002: ("Beast Mode", 3, "normal", 0, 2), 2003: ("Machina", 3, "normal", 0, 2), 2004: ("Years", 3, "normal", 0, 2), 2005: ("Frontlines", 3, "normal", 0, 2), 2006: ("Space Pirates", 3, "normal", 0, 2), 2007: ("Striker", 3, "normal", 0, 2), 2008: ("Embers", 3, "normal", 0, 1), 2009: ("Round 1", 3, "normal", 0, 2), 2010: ("Monster Dance Off", 3, "normal", 0, 2), 3001: ("The Challenge", 3, "hard", 0, 1), # well... 4001: ("Press Start", 4, "normal", 3, 3), 4002: ("Nock Em", 6, "hard", 3, 3), 4003: ("Power Trip", 8, "harder", 3, 3), } translate = { 1001: 22, 1002: 23, 1003: 24, 3001: 25, 2001: 26, 2002: 27, 2003: 28, 2004: 29, 2005: 30, 2006: 31, 2007: 32, 2008: 33, 2009: 34, 2010: 35, 4001: 36, 4002: 37, 4003: 38, } if level_id not in mapping: raise ValueError( f"Level ID [{level_id}] is not known to be official.") song_id, (name, stars, str_diff, coins, length) = ( translate.get(level_id, level_id), mapping[level_id], ) creator, song = ( AbstractUser(client=client), Song.official(song_id, server_style=False, client=client), ) is_demon = "demon" in str_diff if is_demon: difficulty = DemonDifficulty.from_value(str_diff) else: difficulty = LevelDifficulty.from_value(str_diff) return cls( id=level_id, name=name, description=f"Official Level: {name}", version=1, creator=creator, song=song, data= "", # XXX: maybe we can dump all official levels and load their data password=None, copyable=False, is_demon=is_demon, is_auto=(str_diff == "auto"), difficulty=difficulty, stars=stars, coins=coins, verified_coins=True, is_epic=False, # XXX: are Rob's levels epic? ~ nekit original=True, # would be fun if this was false haha low_detail_mode=False, downloads=0, rating=0, score=1, uploaded_timestamp="unknown", last_updated_timestamp="unknown", length=length, game_version=21, stars_requested=0, object_count=0, type=0, time_n=-1, cooldown=-1, client=client, )